diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryMessageSource.java b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryMessageSource.java index 2eed665034..0e7769c528 100644 --- a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryMessageSource.java +++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryMessageSource.java @@ -38,9 +38,9 @@ import org.springframework.util.StringUtils; import com.sun.syndication.feed.synd.SyndEntry; import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.fetcher.FeedFetcher; import com.sun.syndication.fetcher.FetcherEvent; import com.sun.syndication.fetcher.FetcherListener; -import com.sun.syndication.fetcher.impl.AbstractFeedFetcher; import com.sun.syndication.fetcher.impl.FeedFetcherCache; import com.sun.syndication.fetcher.impl.HashMapFeedInfoCache; import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher; @@ -58,7 +58,7 @@ public class FeedEntryMessageSource extends IntegrationObjectSupport implements private final URL feedUrl; - private final AbstractFeedFetcher fetcher; + private final FeedFetcher feedFetcher; private final Queue feeds = new ConcurrentLinkedQueue(); @@ -82,16 +82,17 @@ public class FeedEntryMessageSource extends IntegrationObjectSupport implements public FeedEntryMessageSource(URL feedUrl) { Assert.notNull(feedUrl, "feedUrl must not be null"); this.feedUrl = feedUrl; - if (feedUrl.getProtocol().equals("file")) { - this.fetcher = new FileUrlFeedFetcher(); - } - else if (feedUrl.getProtocol().equals("http")) { - FeedFetcherCache fetcherCache = HashMapFeedInfoCache.getInstance(); - this.fetcher = new HttpURLFeedFetcher(fetcherCache); - } - else { - throw new IllegalArgumentException("Unsupported URL protocol: " + feedUrl.getProtocol()); - } + Assert.isTrue(feedUrl.getProtocol().equals("http"), + "Only 'http' URLs are supported. Consider providing a custom FeedFetcher."); + FeedFetcherCache fetcherCache = HashMapFeedInfoCache.getInstance(); + this.feedFetcher = new HttpURLFeedFetcher(fetcherCache); + } + + public FeedEntryMessageSource(URL feedUrl, FeedFetcher feedFetcher) { + Assert.notNull(feedUrl, "feedUrl must not be null"); + Assert.notNull(feedFetcher, "feedFetcher must not be null"); + this.feedUrl = feedUrl; + this.feedFetcher = feedFetcher; } @@ -115,7 +116,7 @@ public class FeedEntryMessageSource extends IntegrationObjectSupport implements @Override protected void onInit() throws Exception { - this.fetcher.addFetcherEventListener(new FeedQueueUpdatingFetcherListener()); + this.feedFetcher.addFetcherEventListener(new FeedQueueUpdatingFetcherListener()); if (this.metadataStore == null) { // first try to look for a 'messageStore' in the context BeanFactory beanFactory = this.getBeanFactory(); @@ -189,7 +190,7 @@ public class FeedEntryMessageSource extends IntegrationObjectSupport implements SyndFeed feed = null; try { synchronized (this.feedMonitor) { - feed = this.fetcher.retrieveFeed(this.feedUrl); + feed = this.feedFetcher.retrieveFeed(this.feedUrl); if (logger.isDebugEnabled()) { logger.debug("retrieved feed at url '" + this.feedUrl + "'"); } diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParser.java b/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParser.java index 5dafbdb398..a6d120ac43 100644 --- a/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParser.java +++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParser.java @@ -23,6 +23,7 @@ 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.springframework.util.StringUtils; /** * Handles parsing the configuration for the feed inbound-channel-adapter. @@ -39,6 +40,10 @@ public class FeedInboundChannelAdapterParser extends AbstractPollingInboundChann BeanDefinitionBuilder sourceBuilder = BeanDefinitionBuilder.genericBeanDefinition( "org.springframework.integration.feed.FeedEntryMessageSource"); sourceBuilder.addConstructorArgValue(element.getAttribute("url")); + String feedFetcherRef = element.getAttribute("feed-fetcher"); + if (StringUtils.hasText(feedFetcherRef)) { + sourceBuilder.addConstructorArgReference(feedFetcherRef); + } IntegrationNamespaceUtils.setReferenceIfAttributeDefined(sourceBuilder, element, "metadata-store"); return BeanDefinitionReaderUtils.registerWithGeneratedName(sourceBuilder.getBeanDefinition(), parserContext.getRegistry()); } 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 5ec2708ded..9b02b9ea97 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 @@ -39,6 +39,20 @@ + + + + Reference to a FeedFetcher instance for retrieveing Feeds from the provided URL. + By default, the HTTP protocol is supported. For any other protocols or general + customizations, provide a reference to a different implementation. + + + + + + + + diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryMessageSourceTests.java b/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryMessageSourceTests.java index 7881996f91..affc9a252e 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryMessageSourceTests.java +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/FeedEntryMessageSourceTests.java @@ -30,6 +30,7 @@ import org.springframework.integration.Message; import org.springframework.integration.context.metadata.PropertiesPersistingMetadataStore; import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.fetcher.FeedFetcher; /** * @author Oleg Zhurakousky @@ -38,6 +39,9 @@ import com.sun.syndication.feed.synd.SyndEntry; */ public class FeedEntryMessageSourceTests { + private final FeedFetcher feedFetcher = new FileUrlFeedFetcher(); + + @Before public void prepare() { File metadataStoreFile = new File(System.getProperty("java.io.tmpdir") + "/spring-integration/", "metadata-store.properties"); @@ -56,7 +60,7 @@ public class FeedEntryMessageSourceTests { @Test public void testReceiveFeedWithNoEntries() throws Exception { URL url = new URL("file:src/test/java/org/springframework/integration/feed/empty.rss"); - FeedEntryMessageSource feedEntrySource = new FeedEntryMessageSource(url); + FeedEntryMessageSource feedEntrySource = new FeedEntryMessageSource(url, this.feedFetcher); feedEntrySource.setBeanName("feedReader"); feedEntrySource.afterPropertiesSet(); assertNull(feedEntrySource.receive()); @@ -65,7 +69,7 @@ public class FeedEntryMessageSourceTests { @Test public void testReceiveFeedWithEntriesSorted() throws Exception { URL url = new URL("file:src/test/java/org/springframework/integration/feed/sample.rss"); - FeedEntryMessageSource source = new FeedEntryMessageSource(url); + FeedEntryMessageSource source = new FeedEntryMessageSource(url, this.feedFetcher); source.setComponentName("feedReader"); source.afterPropertiesSet(); Message message1 = source.receive(); @@ -84,7 +88,7 @@ public class FeedEntryMessageSourceTests { @Test public void testReceiveFeedWithRealEntriesAndRepeatWithPersistentMetadataStore() throws Exception { URL url = new URL("file:src/test/java/org/springframework/integration/feed/sample.rss"); - FeedEntryMessageSource feedEntrySource = new FeedEntryMessageSource(url); + FeedEntryMessageSource feedEntrySource = new FeedEntryMessageSource(url, this.feedFetcher); feedEntrySource.setBeanName("feedReader"); PropertiesPersistingMetadataStore metadataStore = new PropertiesPersistingMetadataStore(); metadataStore.afterPropertiesSet(); @@ -108,7 +112,7 @@ public class FeedEntryMessageSourceTests { metadataStore.afterPropertiesSet(); // now test that what's been read is no longer retrieved - feedEntrySource = new FeedEntryMessageSource(url); + feedEntrySource = new FeedEntryMessageSource(url, this.feedFetcher); feedEntrySource.setBeanName("feedReader"); metadataStore = new PropertiesPersistingMetadataStore(); metadataStore.afterPropertiesSet(); @@ -124,7 +128,7 @@ public class FeedEntryMessageSourceTests { @Test public void testReceiveFeedWithRealEntriesAndRepeatNoPersistentMetadataStore() throws Exception { URL url = new URL("file:src/test/java/org/springframework/integration/feed/sample.rss"); - FeedEntryMessageSource feedEntrySource = new FeedEntryMessageSource(url); + FeedEntryMessageSource feedEntrySource = new FeedEntryMessageSource(url, this.feedFetcher); feedEntrySource.setBeanName("feedReader"); feedEntrySource.afterPropertiesSet(); SyndEntry entry1 = feedEntrySource.receive().getPayload(); @@ -143,7 +147,7 @@ public class FeedEntryMessageSourceTests { // UNLIKE the previous test // now test that what's been read is read AGAIN - feedEntrySource = new FeedEntryMessageSource(url); + feedEntrySource = new FeedEntryMessageSource(url, this.feedFetcher); feedEntrySource.setBeanName("feedReader"); feedEntrySource.afterPropertiesSet(); entry1 = feedEntrySource.receive().getPayload(); diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FileUrlFeedFetcher.java b/spring-integration-feed/src/test/java/org/springframework/integration/feed/FileUrlFeedFetcher.java similarity index 98% rename from spring-integration-feed/src/main/java/org/springframework/integration/feed/FileUrlFeedFetcher.java rename to spring-integration-feed/src/test/java/org/springframework/integration/feed/FileUrlFeedFetcher.java index d0244b45dd..d5a37e9305 100644 --- a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FileUrlFeedFetcher.java +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/FileUrlFeedFetcher.java @@ -39,7 +39,7 @@ import com.sun.syndication.io.XmlReader; * @author Mark Fisher * @since 2.0 */ -class FileUrlFeedFetcher extends AbstractFeedFetcher { +public class FileUrlFeedFetcher extends AbstractFeedFetcher { /** * Retrieve a SyndFeed for the given URL. diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-context.xml b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-context.xml index 21971eab13..176b200724 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-context.xml +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-context.xml @@ -9,6 +9,7 @@ @@ -18,6 +19,8 @@ + + \ No newline at end of file diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-context.xml b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-context.xml index 2a9b28321d..e2afb85ea0 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-context.xml +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-context.xml @@ -10,7 +10,8 @@ + url="file:src/test/java/org/springframework/integration/feed/config/sample.rss" + feed-fetcher="fileUrlFeedFetcher"> @@ -18,6 +19,8 @@ + + diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-noid-context.xml b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-noid-context.xml index 3978904c88..842246bea9 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-noid-context.xml +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests-file-usage-noid-context.xml @@ -7,7 +7,8 @@ http://www.springframework.org/schema/integration/feed http://www.springframework.org/schema/integration/feed/spring-integration-feed-2.0.xsd"> + url="file:src/test/java/org/springframework/integration/feed/config/sample.rss" + feed-fetcher="fileUrlFeedFetcher"> @@ -15,4 +16,6 @@ + + \ No newline at end of file diff --git a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests.java b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests.java index 4109daf834..5f27e2125f 100644 --- a/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests.java +++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/config/FeedInboundChannelAdapterParserTests.java @@ -75,7 +75,7 @@ public class FeedInboundChannelAdapterParserTests { MetadataStore metadataStore = (MetadataStore) TestUtils.getPropertyValue(source, "metadataStore"); assertTrue(metadataStore instanceof SampleMetadataStore); assertEquals(metadataStore, context.getBean("customMetadataStore")); - AbstractFeedFetcher fetcher = (AbstractFeedFetcher) TestUtils.getPropertyValue(source, "fetcher"); + AbstractFeedFetcher fetcher = (AbstractFeedFetcher) TestUtils.getPropertyValue(source, "feedFetcher"); assertEquals("FileUrlFeedFetcher", fetcher.getClass().getSimpleName()); context.destroy(); } @@ -88,7 +88,7 @@ public class FeedInboundChannelAdapterParserTests { MetadataStore metadataStore = (MetadataStore) TestUtils.getPropertyValue(source, "metadataStore"); assertTrue(metadataStore instanceof SampleMetadataStore); assertEquals(metadataStore, context.getBean("customMetadataStore")); - AbstractFeedFetcher fetcher = (AbstractFeedFetcher) TestUtils.getPropertyValue(source, "fetcher"); + AbstractFeedFetcher fetcher = (AbstractFeedFetcher) TestUtils.getPropertyValue(source, "feedFetcher"); assertTrue(fetcher instanceof HttpURLFeedFetcher); context.destroy(); }