From 31b3a8c0e6538fc445d9f5273d0150b43ef40262 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Sun, 17 Oct 2010 19:02:39 -0400 Subject: [PATCH] INT-786, added persistence to the feed adapter, added more tests, polished more code --- spring-integration-feed/pom.xml | 6 +- .../feed/FeedEntryReaderMessageSource.java | 88 ++++++++++++----- .../feed/FeedReaderMessageSource.java | 1 - ...FeedMessageSourceBeanDefinitionParser.java | 3 +- .../config/spring-integration-feed-2.0.xsd | 1 + .../FeedDeliveryEventServiceActivator.java | 32 ------ .../FeedEntryReaderMessageSourceTests.java | 87 ++++++++++++++++ .../feed/TestFeedEventDelivery-context.xml | 37 ------- .../feed/TestFeedEventDelivery.java | 33 ------- ...BeanDefinitionParserTests-file-context.xml | 8 +- ...BeanDefinitionParserTests-http-context.xml | 2 +- ...essageSourceBeanDefinitionParserTests.java | 98 ++++++++++++++++--- .../integration/feed/config/sample.rss | 40 ++++---- 13 files changed, 269 insertions(+), 167 deletions(-) delete mode 100644 spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedDeliveryEventServiceActivator.java delete mode 100644 spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery-context.xml delete mode 100644 spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery.java diff --git a/spring-integration-feed/pom.xml b/spring-integration-feed/pom.xml index 71a3f219bf..d03f8c6c9b 100644 --- a/spring-integration-feed/pom.xml +++ b/spring-integration-feed/pom.xml @@ -19,7 +19,10 @@ org.springframework.integration spring-integration-core - + + org.springframework.commons + spring-commons-serializer + commons-langcommons-lang2.5 @@ -28,7 +31,6 @@ rome-fetcher 1.0.0 - net.java.dev.rome rome diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryReaderMessageSource.java b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryReaderMessageSource.java index c8dc154fdb..1ac9072ba0 100644 --- a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryReaderMessageSource.java +++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryReaderMessageSource.java @@ -15,12 +15,15 @@ */ package org.springframework.integration.feed; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Map; +import java.util.Properties; import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import org.springframework.integration.Message; @@ -28,6 +31,8 @@ import org.springframework.integration.context.IntegrationObjectSupport; import org.springframework.integration.core.MessageSource; import org.springframework.integration.support.MessageBuilder; import org.springframework.util.Assert; +import org.springframework.util.DefaultPropertiesPersister; +import org.springframework.util.StringUtils; import com.sun.syndication.feed.synd.SyndEntry; import com.sun.syndication.feed.synd.SyndFeed; @@ -41,14 +46,17 @@ import com.sun.syndication.feed.synd.SyndFeed; * @author Oleg Zhurakousky */ public class FeedEntryReaderMessageSource extends IntegrationObjectSupport implements MessageSource{ - - private volatile Map persisterMap = new ConcurrentHashMap(); + private final DefaultPropertiesPersister persister = new DefaultPropertiesPersister(); + private volatile Properties lastPersistentEntry = new Properties(); private volatile Queue entries = new ConcurrentLinkedQueue(); private volatile FeedReaderMessageSource feedReaderMessageSource; private final Object monitor = new Object(); private volatile String feedMetadataIdKey; - private volatile boolean initialized; + private volatile String persistentIdentifier; + + private volatile boolean initialized; private volatile long lastTime = -1; + private volatile File persisterFile; private Comparator syndEntryComparator = new Comparator() { public int compare(SyndEntry syndEntry, SyndEntry syndEntry1) { @@ -68,15 +76,9 @@ public class FeedEntryReaderMessageSource extends IntegrationObjectSupport imple Assert.notNull(feedReaderMessageSource, "'feedReaderMessageSource' must not be null"); this.feedReaderMessageSource = feedReaderMessageSource; } - /** - * Allows you to provide your own implementation of 'persisterMap' instead of relying on - * your own which is in-memory. - * - * @param persisterMap - */ - public void setPersisterMap(Map persisterMap) { - Assert.notNull(persisterMap, "'persisterMap' can not be null"); - this.persisterMap = persisterMap; + + public void setPersistentIdentifier(String persistentIdentifier) { + this.persistentIdentifier = persistentIdentifier; } public String getComponentType(){ @@ -94,8 +96,9 @@ public class FeedEntryReaderMessageSource extends IntegrationObjectSupport imple @SuppressWarnings("unchecked") private SyndEntry doReceieve() { + SyndEntry nextUp = null; synchronized (this.monitor) { - SyndEntry nextUp = pollAndCache(); + nextUp = pollAndCache(); if (nextUp != null) { return nextUp; @@ -114,17 +117,33 @@ public class FeedEntryReaderMessageSource extends IntegrationObjectSupport imple } } } - return pollAndCache(); + nextUp = pollAndCache(); } + return nextUp; } @Override protected void onInit() throws Exception { - // setup persistence of metadata - this.feedMetadataIdKey = FeedEntryReaderMessageSource.class.getName() + "#" + feedReaderMessageSource.getFeedUrl(); - String lastTime = (String) this.persisterMap.get(this.feedMetadataIdKey); - if (lastTime != null && !lastTime.trim().equalsIgnoreCase("")) { - this.lastTime = Long.parseLong(lastTime); + if (StringUtils.hasText(this.persistentIdentifier)){ + File dir = new File(System.getProperty("user.home") + "/temp/spring-integration"); + dir.mkdirs(); + persisterFile = new File(dir, this.persistentIdentifier + ".last.entry"); + if (!persisterFile.exists()){ + persisterFile.createNewFile(); + } + FileInputStream inStream = new FileInputStream(persisterFile); + persister.load(lastPersistentEntry, inStream); + } + else { + logger.info("Your '" + this.getComponentType() + "' is anonymous (no ID attribute), therefore no feed entries will be persisted " + + "which may result in a duplicate feed entries once this adapter is restarted"); + } + + this.feedMetadataIdKey = this.getComponentType() + "@" + this.getComponentName() + + "#" + feedReaderMessageSource.getFeedUrl(); + String keyTime = (String) this.lastPersistentEntry.get(this.feedMetadataIdKey); + if (StringUtils.hasText(keyTime)){ + this.lastTime = Long.parseLong(keyTime); } this.initialized = true; } @@ -135,9 +154,32 @@ public class FeedEntryReaderMessageSource extends IntegrationObjectSupport imple if (next == null) { return null; } - + this.lastTime = next.getPublishedDate().getTime(); - this.persisterMap.put(this.feedMetadataIdKey, this.lastTime + ""); + this.lastPersistentEntry.put(this.feedMetadataIdKey, this.lastTime + ""); + + if (persisterFile != null){ + FileOutputStream fo = null; + try { + fo = new FileOutputStream(persisterFile); + persister.store(this.lastPersistentEntry, fo, "Last feed entry"); + } + catch (IOException e) { + // not fatal for the functionality of the component + logger.warn("Failed to persist feed entry. This may result in a duplicate " + + "feed entry after this component is restarted", e); + } + finally { + try { + fo.close(); + } + catch (IOException e) { + // not fatal for the functionality of he component + logger.warn("Failed to close output stream to " + persisterFile.getAbsolutePath(), e); + } + } + } + return next; } } \ No newline at end of file diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedReaderMessageSource.java b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedReaderMessageSource.java index e2b6f49983..7f1dfa5910 100644 --- a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedReaderMessageSource.java +++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedReaderMessageSource.java @@ -87,7 +87,6 @@ public class FeedReaderMessageSource extends IntegrationObjectSupport } } } catch (Exception e) { - e.printStackTrace(); throw new MessagingException("Exception thrown when trying to retrive feed at url '" + this.feedUrl + "'", e); } diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParser.java b/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParser.java index 12ecd2aa20..a80a291248 100644 --- a/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParser.java +++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParser.java @@ -19,6 +19,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.w3c.dom.Element; /** @@ -34,7 +35,7 @@ public class FeedMessageSourceBeanDefinitionParser extends AbstractPollingInboun BeanDefinitionBuilder feedEntryBuilder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.integration.feed.FeedEntryReaderMessageSource"); - + IntegrationNamespaceUtils.setValueIfAttributeDefined(feedEntryBuilder, element, "id", "persistentIdentifier"); BeanDefinitionBuilder feedBuilder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.integration.feed.FeedReaderMessageSource"); feedBuilder.addConstructorArgValue(element.getAttribute("feedUrl")); diff --git a/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed-2.0.xsd b/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed-2.0.xsd index 71cb01657f..9e62fbf074 100644 --- a/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed-2.0.xsd +++ b/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed-2.0.xsd @@ -27,6 +27,7 @@ + diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedDeliveryEventServiceActivator.java b/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedDeliveryEventServiceActivator.java deleted file mode 100644 index a055273b39..0000000000 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedDeliveryEventServiceActivator.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.springframework.integration.feed; - -import java.util.Properties; - -import org.springframework.integration.Message; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.integration.history.MessageHistory; -import org.springframework.stereotype.Component; - -import com.sun.syndication.feed.synd.SyndEntry; - -@Component -public class FeedDeliveryEventServiceActivator { - - @ServiceActivator - public void activate(Message message) throws Exception { - - MessageHistory history = MessageHistory.read(message); - for (Properties properties : history) { - System.out.println(properties); - } - SyndEntry syndEntry = message.getPayload(); - - System.out.println( "Publishing new SyndEntry " + syndEntry.getUri() +":"+ - syndEntry.getPublishedDate().toString()+ ":"+ syndEntry.getPublishedDate().getTime()); - -// System.out.println( syndEntry.toString()); - // System.out.println("Delivery! " + ToStringBuilder.reflectionToString(evtMsg)); - - } - -} diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryReaderMessageSourceTests.java b/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryReaderMessageSourceTests.java index 418b29cd2f..286054fd43 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryReaderMessageSourceTests.java +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryReaderMessageSourceTests.java @@ -21,10 +21,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; +import java.io.File; +import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.List; +import org.junit.Before; import org.junit.Test; import org.springframework.integration.Message; @@ -36,6 +39,13 @@ import com.sun.syndication.feed.synd.SyndFeed; * */ public class FeedEntryReaderMessageSourceTests { + @Before + public void prepare(){ + File persisterFile = new File(System.getProperty("user.home") + "/temp/spring-integration", "feedReader.last.entry"); + if (persisterFile.exists()){ + persisterFile.delete(); + } + } @Test(expected=IllegalArgumentException.class) public void testFailureWhenNotInitialized(){ @@ -49,6 +59,7 @@ public class FeedEntryReaderMessageSourceTests { SyndFeed feed = mock(SyndFeed.class); when(feedReaderSource.receiveSyndFeed()).thenReturn(feed); FeedEntryReaderMessageSource feedEntrySource = new FeedEntryReaderMessageSource(feedReaderSource); + feedEntrySource.setPersistentIdentifier("feedReader"); feedEntrySource.afterPropertiesSet(); assertNull(feedEntrySource.receive()); } @@ -68,6 +79,7 @@ public class FeedEntryReaderMessageSourceTests { when(feedReaderSource.receiveSyndFeed()).thenReturn(feed); FeedEntryReaderMessageSource feedEntrySource = new FeedEntryReaderMessageSource(feedReaderSource); + feedEntrySource.setPersistentIdentifier("feedReader"); feedEntrySource.afterPropertiesSet(); Message entryMessage = feedEntrySource.receive(); assertEquals(entry2, entryMessage.getPayload()); @@ -77,4 +89,79 @@ public class FeedEntryReaderMessageSourceTests { entryMessage = feedEntrySource.receive(); assertNull(entryMessage); } + // will test, that last feed entry is remembered between the sessions + // and no duplicate entries are retrieved + @Test + public void testReceieveFeedWithRealEntriesAndRepeatWithPersistentIdentifier() throws Exception{ + FeedReaderMessageSource feedReaderSource = + new FeedReaderMessageSource(new URL("file:src/test/java/org/springframework/integration/feed/sample.rss")); + + FeedEntryReaderMessageSource feedEntrySource = new FeedEntryReaderMessageSource(feedReaderSource); + feedEntrySource.setPersistentIdentifier("feedReader"); + feedEntrySource.afterPropertiesSet(); + SyndEntry entry1 = feedEntrySource.receive().getPayload(); + SyndEntry entry2 = feedEntrySource.receive().getPayload(); + SyndEntry entry3 = feedEntrySource.receive().getPayload(); + assertNull(feedEntrySource.receive()); // only 3 entries in the test feed + + assertEquals("Spring Integration download", entry1.getTitle().trim()); + assertEquals(1266088337000L, entry1.getPublishedDate().getTime()); + + assertEquals("Check out Spring Integration forums", entry2.getTitle().trim()); + assertEquals(1268469501000L, entry2.getPublishedDate().getTime()); + + assertEquals("Spring Integration adapters", entry3.getTitle().trim()); + assertEquals(1272044098000L, entry3.getPublishedDate().getTime()); + + // now test that what's been read is no longer retrieved + feedEntrySource = new FeedEntryReaderMessageSource(feedReaderSource); + feedEntrySource.setPersistentIdentifier("feedReader"); + feedEntrySource.afterPropertiesSet(); + assertNull(feedEntrySource.receive()); + assertNull(feedEntrySource.receive()); + assertNull(feedEntrySource.receive()); + } + // will test, that last feed entry is NOT remembered between the sessions, since + // persister is not used due to the lack of persistentIdentifier (id attribute in xml) + // and the same entries are retrieved again + @Test + public void testReceieveFeedWithRealEntriesAndRepeatNoPersistentIdentifier() throws Exception{ + FeedReaderMessageSource feedReaderSource = + new FeedReaderMessageSource(new URL("file:src/test/java/org/springframework/integration/feed/sample.rss")); + + FeedEntryReaderMessageSource feedEntrySource = new FeedEntryReaderMessageSource(feedReaderSource); + feedEntrySource.afterPropertiesSet(); + SyndEntry entry1 = feedEntrySource.receive().getPayload(); + SyndEntry entry2 = feedEntrySource.receive().getPayload(); + SyndEntry entry3 = feedEntrySource.receive().getPayload(); + assertNull(feedEntrySource.receive()); // only 3 entries in the test feed + + assertEquals("Spring Integration download", entry1.getTitle().trim()); + assertEquals(1266088337000L, entry1.getPublishedDate().getTime()); + + assertEquals("Check out Spring Integration forums", entry2.getTitle().trim()); + assertEquals(1268469501000L, entry2.getPublishedDate().getTime()); + + assertEquals("Spring Integration adapters", entry3.getTitle().trim()); + assertEquals(1272044098000L, entry3.getPublishedDate().getTime()); + + // UNLIKE the previous test + // now test that what's been read is read AGAIN + feedEntrySource = new FeedEntryReaderMessageSource(feedReaderSource); + feedEntrySource.afterPropertiesSet(); + entry1 = feedEntrySource.receive().getPayload(); + entry2 = feedEntrySource.receive().getPayload(); + entry3 = feedEntrySource.receive().getPayload(); + assertNull(feedEntrySource.receive()); // only 3 entries in the test feed + + assertEquals("Spring Integration download", entry1.getTitle().trim()); + assertEquals(1266088337000L, entry1.getPublishedDate().getTime()); + + assertEquals("Check out Spring Integration forums", entry2.getTitle().trim()); + assertEquals(1268469501000L, entry2.getPublishedDate().getTime()); + + assertEquals("Spring Integration adapters", entry3.getTitle().trim()); + assertEquals(1272044098000L, entry3.getPublishedDate().getTime()); + } + } diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery-context.xml b/spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery-context.xml deleted file mode 100644 index c5c80dca00..0000000000 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery-context.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery.java b/spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery.java deleted file mode 100644 index 5878a4acb1..0000000000 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.feed; - -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) -public class TestFeedEventDelivery { - - @Test - @Ignore - public void testDeliveryOfFeed() throws Exception { - Thread.sleep(1000 * 60); - } -} diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-file-context.xml b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-file-context.xml index 17a1c35c40..215b8fa547 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-file-context.xml +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-file-context.xml @@ -6,10 +6,14 @@ http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd http://www.springframework.org/schema/integration/feed http://www.springframework.org/schema/integration/feed/spring-integration-feed-2.0.xsd"> - - + + + + \ No newline at end of file diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-http-context.xml b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-http-context.xml index 6756557d68..0f13051342 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-http-context.xml +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests-http-context.xml @@ -6,7 +6,7 @@ http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd http://www.springframework.org/schema/integration/feed http://www.springframework.org/schema/integration/feed/spring-integration-feed-2.0.xsd"> - diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests.java b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests.java index 17f2bcab7b..66cce1826c 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests.java +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParserTests.java @@ -15,15 +15,20 @@ */ package org.springframework.integration.feed.config; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import java.io.File; +import java.util.Properties; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; @@ -36,21 +41,30 @@ import org.springframework.integration.endpoint.SourcePollingChannelAdapter; import org.springframework.integration.feed.FeedEntryReaderMessageSource; import org.springframework.integration.feed.FeedReaderMessageSource; import org.springframework.integration.feed.FileUrlFeedFetcher; +import org.springframework.integration.history.MessageHistory; import org.springframework.integration.test.util.TestUtils; +import com.sun.syndication.feed.synd.SyndEntry; import com.sun.syndication.fetcher.impl.AbstractFeedFetcher; import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher; - /** * @author Oleg Zhurakousky * */ public class FeedMessageSourceBeanDefinitionParserTests { + private static CountDownLatch latch; + @Before + public void prepare(){ + File persisterFile = new File(System.getProperty("user.home") + "/temp/spring-integration", "feedAdapter.last.entry"); + if (persisterFile.exists()){ + persisterFile.delete(); + } + } @Test public void validateSuccessfullConfiguration(){ - ApplicationContext context = + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("FeedMessageSourceBeanDefinitionParserTests-file-context.xml", this.getClass()); SourcePollingChannelAdapter adapter = context.getBean("feedAdapter", SourcePollingChannelAdapter.class); FeedEntryReaderMessageSource source = (FeedEntryReaderMessageSource) TestUtils.getPropertyValue(adapter, "source"); @@ -65,26 +79,55 @@ public class FeedMessageSourceBeanDefinitionParserTests { feedReaderMessageSource = (FeedReaderMessageSource) TestUtils.getPropertyValue(source, "feedReaderMessageSource"); fetcher = (AbstractFeedFetcher) TestUtils.getPropertyValue(feedReaderMessageSource, "fetcher"); assertTrue(fetcher instanceof HttpURLFeedFetcher); + context.destroy(); } + @Test - public void validateSuccessfullNewsRetrievalFile() throws Exception{ + public void validateSuccessfullNewsRetrievalWithFileUrlAndMessageHistory() throws Exception{ + File persisterFile = new File(System.getProperty("user.home") + "/temp/spring-integration", "feedAdapterUsage.last.entry"); + if (persisterFile.exists()){ + persisterFile.delete(); + } //Test file samples.rss has 3 news items - final CountDownLatch latch = new CountDownLatch(3); - MessageHandler handler = spy(new MessageHandler() { - public void handleMessage(Message message) throws MessagingException { - latch.countDown(); - } - }); - ApplicationContext context = - new ClassPathXmlApplicationContext("FeedMessageSourceBeanDefinitionParserTests-file-context.xml", this.getClass()); - DirectChannel feedChannel = context.getBean("feedChannel", DirectChannel.class); - feedChannel.subscribe(handler); + latch = spy(new CountDownLatch(3)); + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("FeedMessageSourceBeanDefinitionParserTests-file-usage-context.xml", this.getClass()); latch.await(5, TimeUnit.SECONDS); - verify(handler, times(3)).handleMessage(Mockito.any(Message.class)); + verify(latch, times(3)).countDown(); + context.destroy(); + + // since we are not deleting the persister file + // in this iteration no new feeds will be received and the latch will timeout + latch = spy(new CountDownLatch(3)); + context = + new ClassPathXmlApplicationContext("FeedMessageSourceBeanDefinitionParserTests-file-usage-context.xml", this.getClass()); + latch.await(5, TimeUnit.SECONDS); + verify(latch, times(0)).countDown(); + context.destroy(); } @Test - public void validateSuccessfullNewsRetrievalHttp() throws Exception{ + public void validateSuccessfullNewsRetrievalWithFileUrlNoPersistentIdentifier() throws Exception{ //Test file samples.rss has 3 news items + latch = spy(new CountDownLatch(3)); + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("FeedMessageSourceBeanDefinitionParserTests-file-usage-noid-context.xml", this.getClass()); + latch.await(5, TimeUnit.SECONDS); + verify(latch, times(3)).countDown(); + context.destroy(); + + // since we are not deleting the persister file + // in this iteration no new feeds will be received and the latch will timeout + latch = spy(new CountDownLatch(3)); + context = + new ClassPathXmlApplicationContext("FeedMessageSourceBeanDefinitionParserTests-file-usage-noid-context.xml", this.getClass()); + latch.await(5, TimeUnit.SECONDS); + verify(latch, times(3)).countDown(); + context.destroy(); + } + + @Test + @Ignore // goes against the real feed + public void validateSuccessfullNewsRetrievalWithHttpUrl() throws Exception{ final CountDownLatch latch = new CountDownLatch(3); MessageHandler handler = spy(new MessageHandler() { public void handleMessage(Message message) throws MessagingException { @@ -98,4 +141,29 @@ public class FeedMessageSourceBeanDefinitionParserTests { latch.await(5, TimeUnit.SECONDS); verify(handler, atLeast(3)).handleMessage(Mockito.any(Message.class)); } + + public static class SampleService{ + public void receiveFeedEntry(Message message){ + MessageHistory history = MessageHistory.read(message); + assertTrue(history.size() == 3); + Properties historyItem = history.get(0); + assertEquals("feedAdapterUsage", historyItem.get("name")); + assertEquals("feed:inbound-channel-adapter", historyItem.get("type")); + + historyItem = history.get(1); + assertEquals("feedChannelUsage", historyItem.get("name")); + assertEquals("channel", historyItem.get("type")); + + historyItem = history.get(2); + assertEquals("sampleActivator", historyItem.get("name")); + assertEquals("service-activator", historyItem.get("type")); + latch.countDown(); + } + } + + public static class SampleServiceNoHistory{ + public void receiveFeedEntry(SyndEntry entry){ + latch.countDown(); + } + } } diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/sample.rss b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/sample.rss index cbe572a200..31fa532a39 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/sample.rss +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/sample.rss @@ -1,52 +1,52 @@ -ASP @ BellaOnline -http://www.bellaonline.com/Site/asp +Spring Integration +http://www.springsource.org/spring-integration -Learn to program in ASP, and enhance your ASP skills to add great new functionality to your website! +Spring Integration is a really cool framework en-us -Copyright 2001-2005 BellaOnline.com +Copyright 2004-2010 SpringSource/VMWare All Rights Reserved. -Tue, 12 Apr 2005 14:21:32 EST +Tue, 12 Apr 2010 18:21:32 EST 240 -http://www.bellaonline.com/images/bella.gif -ASP @ BellaOnline -http://asp.bellaonline.com +http://www.springsource.org/sites/all/themes/dotorg09/images/dotorg09_logo.png +Spring Integration +http://www.springsource.org/spring-integration -Using ASP to Code an RSS Feed +Spring Integration adapters -http://www.bellaonline.com/articles/art30646.asp +http://www.springsource.org/extensions/se-sia -RSS feeds let you easily syndicate your content to an end user or another website. ASP can help you easily create your own RSS feed for your website. +Spring Integration adapters are realy cool -Tue, 12 Apr 2005 13:59:56 EST +Tue, 23 Apr 2010 12:34:58 EST -RecordCount and Count +Spring Integration download -http://www.bellaonline.com/articles/art30403.asp +http://www.springsource.com/products/spring-community-download -If you're trying to figure out how many records are in a given SQL result set, you can use either the RecordCount or Count command. Both work in different ways. +Download Spring Integration -Sun, 3 Apr 2005 17:12:17 EST +Sun, 13 Feb 2010 14:12:17 EST -Bubble Sort Code Technique +Check out Spring Integration forums -http://www.bellaonline.com/articles/art29843.asp +http://forum.springsource.org/forumdisplay.php?f=42 -If you are sorting content into an order, one of the most simple techniques that exists is the bubble sort technique. +Spring Integration forums are awesome -Wed, 16 Mar 2005 00:38:21 EST +Wed, 13 Mar 2010 03:38:21 EST