diff --git a/pom.xml b/pom.xml
index df7758a9d6..513a25a498 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,429 +1,469 @@
-
- 4.0.0
- org.springframework.integration
- spring-integration
- Spring Integration
- 2.0.0.BUILD-SNAPSHOT
- pom
-
- spring-integration-parent
- spring-integration-core
- spring-integration-event
- spring-integration-file
- spring-integration-groovy
- spring-integration-http
- spring-integration-httpinvoker
- spring-integration-ip
- spring-integration-jdbc
- spring-integration-jms
- spring-integration-jmx
- spring-integration-mail
- spring-integration-rmi
- spring-integration-security
- spring-integration-stream
- spring-integration-test
- spring-integration-ws
- spring-integration-xml
- spring-integration-xmpp
- spring-integration-ftp
- spring-integration-sftp
- spring-integration-twitter
-
-
- UTF-8
-
- spring-integration
- Spring Integration
- INT
- ${project.version}
- ${dist.id}-${dist.version}
- ${dist.finalName}.zip
- target/${dist.fileName}
- dist.springframework.org
-
-
-
-
- snapshot
-
- snapshot
-
-
-
- spring-snapshot
- Spring Snapshot Repository
- s3://maven.springframework.org/snapshot
-
-
-
-
- milestone
-
- milestone
-
-
-
- spring-milestone
- Spring Milestone Repository
- s3://maven.springframework.org/milestone
-
-
-
-
-
- org.apache.maven.plugins
- maven-antrun-plugin
- 1.4
-
-
- upload-dist
- deploy
-
-
-
-
-
-
-
-
- run
-
-
-
-
-
- org.springframework.build
- org.springframework.build.aws.ant
- 3.0.5.RELEASE
-
-
- net.java.dev.jets3t
- jets3t
- 0.7.2
-
-
-
-
-
-
-
- release
-
- release
-
-
-
- spring-release
- file://${java.io.tmpdir}/spring-integration-repo
-
-
-
-
-
- org.apache.maven.plugins
- maven-antrun-plugin
- 1.4
-
-
- upload-dist
- deploy
-
-
-
-
-
-
-
-
- run
-
-
-
-
-
- org.springframework.build
- org.springframework.build.aws.ant
- 3.0.5.RELEASE
-
-
- net.java.dev.jets3t
- jets3t
- 0.7.2
-
-
-
-
-
-
-
- staging
-
-
- spring-site-staging
- file:///${java.io.tmpdir}/spring-integration/docs/${project.version}
-
-
- spring-milestone-staging
- file:///${java.io.tmpdir}/spring-integration/milestone
-
-
- spring-snapshot-staging
- file:///${java.io.tmpdir}/spring-integration/snapshot
-
-
-
-
-
-
-
- http://static.springframework.org/spring-integration/site/downloads/releases.html
-
- static.springframework.org
- scp://cbeams@static.springframework.org/var/www/domains/springframework.org/static/htdocs/spring-integration/sites/${project.version}
-
-
-
-
-
-
- org.springframework.build.aws
- org.springframework.build.aws.maven
- 3.0.0.RELEASE
-
-
-
-
- com.agilejava.docbkx
- docbkx-maven-plugin
- 2.0.6
-
-
-
- generate-html
- generate-pdf
-
- package
-
-
-
-
- org.docbook
- docbook-xml
- 4.4
- runtime
-
-
-
- index.xml
- true
- ${project.basedir}/src/docbkx/resources/xsl/fopdf.xsl
-
- css/html.css
-
- false
- ${project.basedir}/src/docbkx/resources/xsl/html.xsl
-
-
-
- version
- ${pom.version}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- maven-javadoc-plugin
- 2.5
-
-
- aggregate
-
- aggregate
-
- package
-
- true
- true
-
- 1.5
- true
- ${project.basedir}/src/main/javadoc
- ${project.basedir}/src/main/javadoc/overview.html
- ${project.basedir}/src/main/javadoc/spring-javadoc.css
-
- true
-
-
- Spring Integration Core
- org.springframework.integration:org.springframework.integration.*
-
-
- Spring Integration Event Support
- org.springframework.integration.event:org.springframework.integration.event.*
-
-
- Spring Integration File Support
- org.springframework.integration.file:org.springframework.integration.file.*
-
-
- Spring Integration FTP Support
- org.springframework.integration.ftp:org.springframework.integration.ftp.*
-
-
- Spring Integration Groovy Support
- org.springframework.integration.groovy:org.springframework.integration.groovy.*
-
-
- Spring Integration HTTP Support
- org.springframework.integration.http:org.springframework.integration.http.*
-
-
- Spring Integration HttpInvoker Support
- org.springframework.integration.httpinvoker:org.springframework.integration.httpinvoker.*
-
-
- Spring Integration JDBC Support
- org.springframework.integration.jdbc:org.springframework.integration.jdbc.*
-
-
- Spring Integration JMS Support
- org.springframework.integration.jms:org.springframework.integration.jms.*
-
-
- Spring Integration JMX Support
- org.springframework.integration.control:org.springframework.integration.jmx:org.springframework.integration.jmx.*
-
-
- Spring Integration Mail Support
- org.springframework.integration.mail:org.springframework.integration.mail.*
-
-
- Spring Integration RMI Support
- org.springframework.integration.rmi:org.springframework.integration.rmi.*
-
-
- Spring Integration Web Services Support
- org.springframework.integration.ws:org.springframework.integration.ws.*
-
-
- Spring Integration Security Support
- org.springframework.integration.security:org.springframework.integration.security.*
-
-
- Spring Integration SFTP Support
- org.springframework.integration.sftp:org.springframework.integration.sftp.*
-
-
- Spring Integration Stream Support
- org.springframework.integration.stream:org.springframework.integration.stream.*
-
-
- Spring Integration TCP/UDP Support
- org.springframework.integration.ip:org.springframework.integration.ip.*
-
-
- Spring Integration Test Support
- org.springframework.integration.test:org.springframework.integration.test.*
-
-
- Spring Integration Twitter Support
- org.springframework.integration.twitter:org.springframework.integration.twitter.*
-
-
- Spring Integration XML Support
- org.springframework.integration.xml:org.springframework.integration.xml.*
-
-
- Spring Integration XMPP Support
- org.springframework.integration.xmpp:org.springframework.integration.xmpp.*
-
-
-
- http://static.springframework.org/spring/docs/3.0.3.RELEASE/javadoc-api
- http://static.springsource.org/spring-integration/sites/${project.version}/apidocs
- http://java.sun.com/javase/6/docs/api
-
-
-
-
-
-
-
- maven-assembly-plugin
- 2.2-beta-5
- false
-
-
- distribution
-
- single
-
- package
-
-
- ${project.basedir}/src/assembly/distribution.xml
-
- false
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-release-plugin
- 2.0
-
-
-
-
-
- repository.springframework.maven.release
- Spring Framework Maven Release Repository
- http://maven.springframework.org/release
-
-
- repository.springframework.maven.milestone
- Spring Framework Maven Milestone Repository
- http://maven.springframework.org/milestone
-
-
-
- repository.source.maven.release
- SpringSource Maven Release Repository
- http://repository.springsource.com/maven/bundles/release
-
-
+
+ 4.0.0
+ org.springframework.integration
+ spring-integration
+ Spring Integration
+ 2.0.0.BUILD-SNAPSHOT
+ pom
+
+ spring-integration-parent
+ spring-integration-core
+ spring-integration-event
+ spring-integration-file
+ spring-integration-feed
+ spring-integration-groovy
+ spring-integration-http
+ spring-integration-httpinvoker
+ spring-integration-ip
+ spring-integration-jdbc
+ spring-integration-jms
+ spring-integration-jmx
+ spring-integration-mail
+ spring-integration-rmi
+ spring-integration-security
+ spring-integration-stream
+ spring-integration-test
+ spring-integration-ws
+ spring-integration-xml
+ spring-integration-xmpp
+ spring-integration-ftp
+ spring-integration-sftp
+ spring-integration-twitter
+
+
+ UTF-8
+
+ spring-integration
+ Spring Integration
+ INT
+ ${project.version}
+ ${dist.id}-${dist.version}
+ ${dist.finalName}.zip
+ target/${dist.fileName}
+ dist.springframework.org
+
+
+
+
+ snapshot
+
+ snapshot
+
+
+
+ spring-snapshot
+ Spring Snapshot Repository
+ s3://maven.springframework.org/snapshot
+
+
+
+
+ milestone
+
+ milestone
+
+
+
+ spring-milestone
+ Spring Milestone Repository
+ s3://maven.springframework.org/milestone
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ 1.4
+
+
+ upload-dist
+ deploy
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+ org.springframework.build
+ org.springframework.build.aws.ant
+ 3.0.5.RELEASE
+
+
+ net.java.dev.jets3t
+ jets3t
+ 0.7.2
+
+
+
+
+
+
+
+ release
+
+ release
+
+
+
+ spring-release
+ file://${java.io.tmpdir}/spring-integration-repo
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ 1.4
+
+
+ upload-dist
+ deploy
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+ org.springframework.build
+ org.springframework.build.aws.ant
+ 3.0.5.RELEASE
+
+
+ net.java.dev.jets3t
+ jets3t
+ 0.7.2
+
+
+
+
+
+
+
+ staging
+
+
+ spring-site-staging
+ file:///${java.io.tmpdir}/spring-integration/docs/${project.version}
+
+
+ spring-milestone-staging
+ file:///${java.io.tmpdir}/spring-integration/milestone
+
+
+ spring-snapshot-staging
+ file:///${java.io.tmpdir}/spring-integration/snapshot
+
+
+
+
+
+
+
+ http://static.springframework.org/spring-integration/site/downloads/releases.html
+
+ static.springframework.org
+
+ scp://cbeams@static.springframework.org/var/www/domains/springframework.org/static/htdocs/spring-integration/sites/${project.version}
+
+
+
+
+
+
+
+ org.springframework.build.aws
+ org.springframework.build.aws.maven
+ 3.0.0.RELEASE
+
+
+
+
+ com.agilejava.docbkx
+ docbkx-maven-plugin
+ 2.0.6
+
+
+
+ generate-html
+ generate-pdf
+
+ package
+
+
+
+
+ org.docbook
+ docbook-xml
+ 4.4
+ runtime
+
+
+
+ index.xml
+ true
+ ${project.basedir}/src/docbkx/resources/xsl/fopdf.xsl
+
+ css/html.css
+
+ false
+ ${project.basedir}/src/docbkx/resources/xsl/html.xsl
+
+
+
+ version
+ ${pom.version}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ maven-javadoc-plugin
+ 2.5
+
+
+ aggregate
+
+ aggregate
+
+ package
+
+ true
+ true
+
+ 1.5
+ true
+ ${project.basedir}/src/main/javadoc
+ ${project.basedir}/src/main/javadoc/overview.html
+ ${project.basedir}/src/main/javadoc/spring-javadoc.css
+
+ true
+
+
+ Spring Integration Core
+ org.springframework.integration:org.springframework.integration.*
+
+
+
+ Spring Integration Event Support
+
+ org.springframework.integration.event:org.springframework.integration.event.*
+
+
+
+ Spring Integration File Support
+
+ org.springframework.integration.file:org.springframework.integration.file.*
+
+
+
+ Spring Integration FTP Support
+ org.springframework.integration.ftp:org.springframework.integration.ftp.*
+
+
+
+ Spring Integration Groovy Support
+
+ org.springframework.integration.groovy:org.springframework.integration.groovy.*
+
+
+
+ Spring Integration HTTP Support
+
+ org.springframework.integration.http:org.springframework.integration.http.*
+
+
+
+ Spring Integration HttpInvoker Support
+
+ org.springframework.integration.httpinvoker:org.springframework.integration.httpinvoker.*
+
+
+
+ Spring Integration JDBC Support
+
+ org.springframework.integration.jdbc:org.springframework.integration.jdbc.*
+
+
+
+ Spring Integration JMS Support
+ org.springframework.integration.jms:org.springframework.integration.jms.*
+
+
+
+ Spring Integration JMX Support
+
+ org.springframework.integration.control:org.springframework.integration.jmx:org.springframework.integration.jmx.*
+
+
+
+ Spring Integration Mail Support
+
+ org.springframework.integration.mail:org.springframework.integration.mail.*
+
+
+
+ Spring Integration RMI Support
+ org.springframework.integration.rmi:org.springframework.integration.rmi.*
+
+
+
+ Spring Integration Web Services Support
+ org.springframework.integration.ws:org.springframework.integration.ws.*
+
+
+
+ Spring Integration Security Support
+
+ org.springframework.integration.security:org.springframework.integration.security.*
+
+
+
+ Spring Integration SFTP Support
+
+ org.springframework.integration.sftp:org.springframework.integration.sftp.*
+
+
+
+ Spring Integration Stream Support
+
+ org.springframework.integration.stream:org.springframework.integration.stream.*
+
+
+
+ Spring Integration TCP/UDP Support
+ org.springframework.integration.ip:org.springframework.integration.ip.*
+
+
+
+ Spring Integration Test Support
+
+ org.springframework.integration.test:org.springframework.integration.test.*
+
+
+
+ Spring Integration Twitter Support
+
+ org.springframework.integration.twitter:org.springframework.integration.twitter.*
+
+
+
+ Spring Integration XML Support
+ org.springframework.integration.xml:org.springframework.integration.xml.*
+
+
+
+ Spring Integration XMPP Support
+
+ org.springframework.integration.xmpp:org.springframework.integration.xmpp.*
+
+
+
+
+ http://static.springframework.org/spring/docs/3.0.3.RELEASE/javadoc-api
+ http://static.springsource.org/spring-integration/sites/${project.version}/apidocs
+
+ http://java.sun.com/javase/6/docs/api
+
+
+
+
+
+
+
+ maven-assembly-plugin
+ 2.2-beta-5
+ false
+
+
+ distribution
+
+ single
+
+ package
+
+
+ ${project.basedir}/src/assembly/distribution.xml
+
+ false
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ 2.0
+
+
+
+
+
+ repository.springframework.maven.release
+ Spring Framework Maven Release Repository
+ http://maven.springframework.org/release
+
+
+ repository.springframework.maven.milestone
+ Spring Framework Maven Milestone Repository
+ http://maven.springframework.org/milestone
+
+
+
+ repository.source.maven.release
+ SpringSource Maven Release Repository
+ http://repository.springsource.com/maven/bundles/release
+
+
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java
index 519832c9c0..a3d27f9bd7 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java
@@ -125,6 +125,7 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
}
if (this.metadataPersister == null) {
PropertiesBasedMetadataPersister mp = new PropertiesBasedMetadataPersister();
+
try {
mp.afterPropertiesSet();
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/metadata/PropertiesBasedMetadataPersister.java b/spring-integration-core/src/main/java/org/springframework/integration/context/metadata/PropertiesBasedMetadataPersister.java
index 9b09b67b31..7809bd4df2 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/context/metadata/PropertiesBasedMetadataPersister.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/context/metadata/PropertiesBasedMetadataPersister.java
@@ -16,12 +16,6 @@ import java.util.concurrent.Executor;
* Implementation of {@link org.springframework.integration.context.metadata.MetadataPersister} that knows how to write metadata
* to a {@link java.util.Properties} instance.
*
- *
- *
- * TODO could this perhaps participate or at least be aware of our transaction synchronization mechanism? IE: no guarantees, but we at least try to write on commit()s?
- *
- *
- *
* @author Josh Long
*/
public class PropertiesBasedMetadataPersister implements MetadataPersister, InitializingBean {
@@ -87,10 +81,6 @@ public class PropertiesBasedMetadataPersister implements MetadataPersister
+
+ 4.0.0
+
+ org.springframework.integration
+ spring-integration-parent
+ 2.0.0.BUILD-SNAPSHOT
+ ../spring-integration-parent/pom.xml
+
+ spring-integration-feed
+ Spring Integration Feed Support
+ jar
+
+
+ org.springframework
+ spring-context
+
+
+ org.springframework.integration
+ spring-integration-core
+
+
+
+ commons-langcommons-lang2.5
+
+
+ net.java.dev.rome
+ rome-fetcher
+ 1.0.0
+
+
+
+ net.java.dev.rome
+ rome
+ 1.0.0
+
+
+
+ cglib
+ cglib-nodep
+
+
+ junit
+ junit
+
+
+ org.easymock
+ easymock
+
+
+ org.easymock
+ easymockclassextension
+
+
+ org.mockito
+ mockito-all
+
+
+ org.springframework
+ spring-test
+
+
+ org.springframework.integration
+ spring-integration-test
+
+
+
+
diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedConstants.java b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedConstants.java
new file mode 100644
index 0000000000..a00f9fb663
--- /dev/null
+++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedConstants.java
@@ -0,0 +1,25 @@
+/*
+* Copyright 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;
+
+/**
+ * Provides a place to store the header keys for {@link FeedReaderMessageSource}
+ *
+ * @author Josh Long
+ */
+public class FeedConstants {
+ static public final String FEED_URL = "FEED_URL";
+}
\ No newline at end of file
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
new file mode 100644
index 0000000000..8c18aebcae
--- /dev/null
+++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedEntryReaderMessageSource.java
@@ -0,0 +1,167 @@
+package org.springframework.integration.feed;
+
+
+import com.sun.syndication.feed.synd.SyndEntry;
+import com.sun.syndication.feed.synd.SyndFeed;
+import org.springframework.context.Lifecycle;
+import org.springframework.integration.Message;
+import org.springframework.integration.context.IntegrationObjectSupport;
+import org.springframework.integration.context.metadata.MetadataPersister;
+import org.springframework.integration.core.MessageSource;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.util.Assert;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+
+/**
+ * this is a slightly different use case than {@link org.springframework.integration.feed.FeedReaderMessageSource}.
+ * This returns which entries are added, which is a more nuanced use case requiring some of our own caching.
+ * NB: this does not somehow detect entry removal from a feed.
+ *
+ * @author Josh Long
+ * @author Mario Gray
+ */
+public class FeedEntryReaderMessageSource extends IntegrationObjectSupport implements MessageSource, Lifecycle {
+
+ private volatile ConcurrentLinkedQueue entries;
+ private volatile MetadataPersister persister;
+ private volatile FeedReaderMessageSource feedReaderMessageSource;
+ private final Object monitor = new Object();
+ private String feedMetadataIdKey;
+ private String feedUrl;
+ private volatile boolean running;
+
+ public boolean isRunning() {
+ return running;
+ }
+
+ public void setRunning(boolean running) {
+ this.running = running;
+ }
+ // private Queue entries;
+ private volatile long lastTime = -1;
+
+ public FeedEntryReaderMessageSource() {
+ // this.entries = new ConcurrentSkipListSet(new MyComparator());
+ this.entries = new ConcurrentLinkedQueue();
+ }
+
+ public void start() {
+ this.feedReaderMessageSource.start();
+ this.setRunning(true);
+
+ }
+
+
+ private long sortId(SyndEntry entry) {
+ return entry.getPublishedDate().getTime();
+ }
+
+
+ @Override
+ protected void onInit() throws Exception {
+
+ this.persister = this.getRequiredMetadataPersister();
+
+ Assert.notNull(this.feedUrl, "the feedUrl can't be null");
+ this.feedReaderMessageSource = new FeedReaderMessageSource();
+ this.feedReaderMessageSource.setFeedUrl(this.feedUrl);
+ this.feedReaderMessageSource.setBeanFactory(this.getBeanFactory());
+ this.feedReaderMessageSource.setBeanName(this.getComponentName());
+ this.feedReaderMessageSource.afterPropertiesSet();
+
+ // setup persistence of metadata
+ this.feedMetadataIdKey = FeedEntryReaderMessageSource.class.getName() + "#" + feedUrl;
+ String lastTime = (String) this.persister.read(this.feedMetadataIdKey);
+ if (lastTime != null && !lastTime.trim().equalsIgnoreCase("")) {
+ this.lastTime = Long.parseLong(lastTime);
+ }
+ }
+
+ public void stop() {
+ this.feedReaderMessageSource.stop();
+ this.setRunning(false);
+ }
+
+
+ public Message receive() {
+ SyndEntry se = receiveSyndEntry();
+ if (se == null) {
+ return null;
+ }
+ return MessageBuilder.withPayload(se).build();
+ }
+
+ int longToCompare(long l) {
+ if (l < -1) return -1;
+ if (l > 1) return 1;
+ return 0;
+ }
+
+ private Comparator syndEntryComparator = new Comparator() {
+ public int compare(SyndEntry syndEntry, SyndEntry syndEntry1) {
+ long x = sortId(syndEntry) - sortId(syndEntry1);
+ return longToCompare(x);
+ }
+ };
+
+ @SuppressWarnings("unchecked")
+ public SyndEntry receiveSyndEntry() {
+ synchronized (this.monitor) { // priority goes to the backlog
+ SyndEntry nextUp = pollAndCache();
+
+ if (nextUp != null) {
+ return nextUp;
+ }
+
+ // otherwise, fill the backlog up
+ SyndFeed syndFeed = this.feedReaderMessageSource.receiveSyndFeed();
+ if (syndFeed != null) {
+ List feedEntries = (List) syndFeed.getEntries();
+ if (null != feedEntries) {
+ Collections.sort(feedEntries, syndEntryComparator);
+ for (SyndEntry se : feedEntries) {
+ System.out.println("se: " + se.getPublishedDate().getTime());
+ long sort = this.sortId(se);
+ if (sort > this.lastTime)
+ entries.add(se);
+ }
+ }
+ }
+
+ return pollAndCache();
+ }
+ }
+
+
+ private SyndEntry pollAndCache() {
+ SyndEntry next = this.entries.poll();
+ if (null == next) return null;
+ this.lastTime = sortId(next);
+ this.persister.write(this.feedMetadataIdKey, this.lastTime + "");
+ return next;
+ }
+
+
+ public String getFeedUrl() {
+ return feedUrl;
+ }
+
+ public void setFeedUrl(final String feedUrl) {
+ this.feedUrl = feedUrl;
+ }
+
+
+ class MyComparator implements Comparator {
+ public int compare(final SyndEntry syndEntry, final SyndEntry syndEntry1) {
+ long val = sortId(syndEntry) - sortId(syndEntry1);
+ if (val > 0) return 1;
+ if (val < 0) return -1;
+ return 0;
+ }
+ }
+}
\ 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
new file mode 100644
index 0000000000..d5f7517153
--- /dev/null
+++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/FeedReaderMessageSource.java
@@ -0,0 +1,163 @@
+package org.springframework.integration.feed;
+
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.fetcher.FetcherEvent;
+import com.sun.syndication.fetcher.FetcherListener;
+import com.sun.syndication.fetcher.impl.FeedFetcherCache;
+import com.sun.syndication.fetcher.impl.HashMapFeedInfoCache;
+import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.Lifecycle;
+import org.springframework.integration.Message;
+import org.springframework.integration.context.IntegrationObjectSupport;
+import org.springframework.integration.context.metadata.MetadataPersister;
+import org.springframework.integration.core.MessageSource;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.util.Assert;
+
+import java.net.URL;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+
+/**
+ * The idea behind this class is that {@link org.springframework.integration.core.MessageSource#receive()} will only
+ * return a {@link SyndFeed} when the event listener tells us that a feed has been updated. If we can ascertain that
+ * it's been updated, then we can add the item to the {@link java.util.Queue} implementation.
+ *
+ * @author Josh Long
+ * @author Mario Gray
+ */
+public class FeedReaderMessageSource extends IntegrationObjectSupport
+ implements InitializingBean, Lifecycle, MessageSource {
+ private volatile boolean running;
+ private volatile String feedUrl;
+ private volatile URL feedURLObject;
+ private volatile FeedFetcherCache fetcherCache;
+ private volatile HttpURLFeedFetcher fetcher;
+ private volatile ConcurrentLinkedQueue syndFeeds;
+ private volatile MyFetcherListener myFetcherListener;
+
+ public FeedReaderMessageSource() {
+ syndFeeds = new ConcurrentLinkedQueue();
+ }
+
+ private volatile MetadataPersister persister;
+
+ @Override
+ protected void onInit() throws Exception {
+
+ this.persister = this.getRequiredMetadataPersister();
+
+ myFetcherListener = new MyFetcherListener();
+ fetcherCache = HashMapFeedInfoCache.getInstance();
+
+ fetcher = new HttpURLFeedFetcher(fetcherCache);
+
+ // fetcher.set
+ fetcher.addFetcherEventListener(myFetcherListener);
+ Assert.notNull(this.feedUrl, "the feedURL can't be null");
+ feedURLObject = new URL(this.feedUrl);
+/*
+ String id = FeedReaderMessageSource.class.getName() + "#" + feedUrl;
+
+ StringBuffer stringBuffer = new StringBuffer();
+
+ for (char c : id.toCharArray())
+ if (Character.isDigit(c) || Character.isLetter(c))
+ stringBuffer.append(c);
+ id = stringBuffer.toString();
+
+ this.feedMetadataIdKey = id;
+
+
+ long lastTimeNo = -1;
+ String lastTime = (String) this.persister.read(this.feedMetadataIdKey);
+ if (lastTime != null && !lastTime.trim().equalsIgnoreCase("")) {
+ lastTimeNo = Long.parseLong(lastTime);
+ this.lastTime = lastTimeNo;
+ }*/
+
+ }
+
+ private volatile long lastTime = -1;
+
+ public void start() {
+ this.running = true;
+ }
+
+ public void stop() {
+ this.running = false;
+ }
+
+ private String feedMetadataIdKey;
+ private final Object syndFeedMonitor = new Object();
+
+ public SyndFeed receiveSyndFeed() {
+ SyndFeed returnedSyndFeed = null;
+
+ try {
+ synchronized (syndFeedMonitor) {
+ fetcher.retrieveFeed(this.feedURLObject);
+ logger.debug("attempted to retrieve feed '" + this.feedUrl + "'");
+ returnedSyndFeed = syndFeeds.poll(); // there wont be things whose pub date is < than the lastTime
+
+ if (null == returnedSyndFeed) {
+ logger.debug("no feeds updated, return null!");
+ return null;
+ }
+ // so its OK to update the lastTime
+ //
+
+ /* this.lastTime = sortId(returnedSyndFeed);if (null != this.persister)
+ this.persister.write(this.feedMetadataIdKey, this.lastTime + "");
+*/
+ }
+ } catch (Throwable e) {
+ logger.debug("Exception thrown when trying to retrive feed at url '" + this.feedURLObject + "'", e);
+ }
+
+ return returnedSyndFeed;
+ }
+
+ public Message receive() {
+ SyndFeed syndFeed = this.receiveSyndFeed();
+
+ if (null == syndFeed) {
+ return null;
+ }
+
+ return MessageBuilder.withPayload(syndFeed).setHeader(FeedConstants.FEED_URL, this.feedURLObject).build();
+ }
+
+ public boolean isRunning() {
+ return this.running;
+ }
+
+ public String getFeedUrl() {
+ return feedUrl;
+ }
+
+ public void setFeedUrl(final String feedUrl) {
+ this.feedUrl = feedUrl;
+ }
+
+
+ class MyFetcherListener implements FetcherListener {
+ /**
+ * @see com.sun.syndication.fetcher.FetcherListener#fetcherEvent(com.sun.syndication.fetcher.FetcherEvent)
+ */
+ public void fetcherEvent(final FetcherEvent event) {
+ String eventType = event.getEventType();
+
+ if (FetcherEvent.EVENT_TYPE_FEED_POLLED.equals(eventType)) {
+ logger.debug("\tEVENT: Feed Polled. URL = " + event.getUrlString());
+ } else if (FetcherEvent.EVENT_TYPE_FEED_RETRIEVED.equals(eventType)) {
+ logger.debug("\tEVENT: Feed Retrieved. URL = " + event.getUrlString());
+ // if (sortId(event.getFeed()) > lastTime) // its true if the lastTime is -1 || N
+ syndFeeds.add(event.getFeed());
+ } else if (FetcherEvent.EVENT_TYPE_FEED_UNCHANGED.equals(eventType)) {
+ logger.debug("\tEVENT: Feed Unchanged. URL = " + event.getUrlString());
+ }
+ }
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000000..32bcd24e6e
--- /dev/null
+++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedMessageSourceBeanDefinitionParser.java
@@ -0,0 +1,43 @@
+package org.springframework.integration.feed.config;
+
+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.springframework.integration.feed.FeedEntryReaderMessageSource;
+import org.springframework.integration.feed.FeedReaderMessageSource;
+import org.w3c.dom.Element;
+
+/**
+ * Handles parsing the configuration for the feed inbound channel adapter.
+ *
+ * @author Josh Long
+ */
+public class FeedMessageSourceBeanDefinitionParser extends AbstractPollingInboundChannelAdapterParser {
+
+
+ private String packageName = FeedReaderMessageSource.class.getPackage().getName();
+
+
+ @Override
+ protected String parseSource(final Element element, final ParserContext parserContext) {
+ String pftoe = (element.getAttribute("prefer-updated-feed-to-entries"));
+
+ pftoe = pftoe == null ? "false" : pftoe.trim().toLowerCase();
+
+ boolean preferFeed = pftoe.equalsIgnoreCase(Boolean.TRUE.toString().toLowerCase());
+ String className = this.packageName + "." + (preferFeed ?
+ FeedReaderMessageSource.class.getSimpleName() :
+ FeedEntryReaderMessageSource.class.getSimpleName()
+ );
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(className);
+ builder.addPropertyValue("feedUrl", element.getAttribute("feed"));
+
+ if (!preferFeed) {
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "backlog-cache-size", "maximumBacklogCacheSize");
+ }
+
+ return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
+ }
+}
\ No newline at end of file
diff --git a/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedNamespaceHandler.java b/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedNamespaceHandler.java
new file mode 100644
index 0000000000..ace8004450
--- /dev/null
+++ b/spring-integration-feed/src/main/java/org/springframework/integration/feed/config/FeedNamespaceHandler.java
@@ -0,0 +1,40 @@
+package org.springframework.integration.feed.config;
+/*
+* Copyright 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.
+*/
+
+
+
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+
+/**
+ * This is a rather tricky one. I've decided it's best to not get cute about it and to expose *one*
+ * inbound-channel-adapter. The adapter will let the user pick which type of updated object they'd like to
+ * return. By default it'll return new {@link com.sun.syndication.feed.synd.SyndEntry} objects (which represent
+ * individual, new entries in a given feed). One adapter will return updated {@link
+ * com.sun.syndication.feed.synd.SyndFeed} objects, or it can return updated {@link
+ * com.sun.syndication.feed.synd.SyndEntry} objects.
+ *
+ * @author Josh Long
+ */
+public class FeedNamespaceHandler extends NamespaceHandlerSupport {
+
+ public void init() {
+ registerBeanDefinitionParser("inbound-channel-adapter", new FeedMessageSourceBeanDefinitionParser());
+ }
+
+
+}
\ No newline at end of file
diff --git a/spring-integration-feed/src/main/resources/META-INF/spring.handlers b/spring-integration-feed/src/main/resources/META-INF/spring.handlers
new file mode 100644
index 0000000000..f67ce32e75
--- /dev/null
+++ b/spring-integration-feed/src/main/resources/META-INF/spring.handlers
@@ -0,0 +1 @@
+http\://www.springframework.org/schema/integration/feed=org.springframework.integration.feed.config.FeedNamespaceHandler
\ No newline at end of file
diff --git a/spring-integration-feed/src/main/resources/META-INF/spring.schemas b/spring-integration-feed/src/main/resources/META-INF/spring.schemas
new file mode 100644
index 0000000000..311d93a42e
--- /dev/null
+++ b/spring-integration-feed/src/main/resources/META-INF/spring.schemas
@@ -0,0 +1,2 @@
+http\://www.springframework.org/schema/integration/feed/spring-integration-feed-2.0.xsd=org/springframework/integration/feed/config/spring-integration-feed-2.0.xsd
+http\://www.springframework.org/schema/integration/feed/spring-integration-feed.xsd=org/springframework/integration/feed/config/spring-integration-feed-2.0.xsd
\ No newline at end of file
diff --git a/spring-integration-feed/src/main/resources/META-INF/spring.tooling b/spring-integration-feed/src/main/resources/META-INF/spring.tooling
new file mode 100644
index 0000000000..c2a2ba35ad
--- /dev/null
+++ b/spring-integration-feed/src/main/resources/META-INF/spring.tooling
@@ -0,0 +1,4 @@
+# Tooling related information for the integration feed namespace
+http\://www.springframework.org/schema/integration/feed@name=integration feed Namespace
+http\://www.springframework.org/schema/integration/feed@prefix=int-feed
+http\://www.springframework.org/schema/integration/feed@icon=org/springframework/integration/feed/config/spring-integration-feed.gif
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
new file mode 100644
index 0000000000..c3f725ec50
--- /dev/null
+++ b/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed-2.0.xsd
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+ SyndFeed or SyndEntry objects.
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed.gif b/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed.gif
new file mode 100644
index 0000000000..6464056d47
Binary files /dev/null and b/spring-integration-feed/src/main/resources/org/springframework/integration/feed/config/spring-integration-feed.gif differ
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
new file mode 100644
index 0000000000..d5c0e88cb6
--- /dev/null
+++ b/spring-integration-feed/src/test/java/org/springframework/integration/feed/TestFeedEventDelivery.java
@@ -0,0 +1,36 @@
+package org.springframework.integration.feed;
+
+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
+ public void testDeliveryOfFeed() throws Exception {
+ Thread.sleep(1000 * 60);
+ }
+
+ /* public static void main(String[] args) throws Throwable {
+ String siweb = "http://twitter.com/statuses/public_timeline.atom"; //http://localhost:8080/siweb/foo.atom";
+ FeedEntryReaderMessageSource feedEntryReaderMessageSource = new FeedEntryReaderMessageSource();
+ feedEntryReaderMessageSource.setFeedUrl(siweb);
+ feedEntryReaderMessageSource.afterPropertiesSet();
+ feedEntryReaderMessageSource.start();
+
+ while (true) {
+ Message entryMessage = feedEntryReaderMessageSource.receive();
+
+ if (entryMessage != null) {
+ SyndEntry entry = entryMessage.getPayload();
+ System.out.println((entry.getTitle() + "=" + entry.getUri()));
+ }
+
+ Thread.sleep(1000);
+ }
+ }
+ */
+}
diff --git a/spring-integration-feed/src/test/resources/org/springframework/integration/feed/FeedDeliveryEventServiceActivator.java b/spring-integration-feed/src/test/resources/org/springframework/integration/feed/FeedDeliveryEventServiceActivator.java
new file mode 100644
index 0000000000..14a2d21ade
--- /dev/null
+++ b/spring-integration-feed/src/test/resources/org/springframework/integration/feed/FeedDeliveryEventServiceActivator.java
@@ -0,0 +1,25 @@
+package org.springframework.integration.feed;
+
+import com.sun.syndication.feed.synd.SyndEntry;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.springframework.integration.Message;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.stereotype.Component;
+
+@Component
+public class FeedDeliveryEventServiceActivator {
+
+ @ServiceActivator
+ public void activate(Message evtMsg) throws Exception {
+
+ SyndEntry syndEntry = evtMsg.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/resources/org/springframework/integration/feed/TestFeedEventDelivery-context.xml b/spring-integration-feed/src/test/resources/org/springframework/integration/feed/TestFeedEventDelivery-context.xml
new file mode 100644
index 0000000000..13bde9ecb6
--- /dev/null
+++ b/spring-integration-feed/src/test/resources/org/springframework/integration/feed/TestFeedEventDelivery-context.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-feed/template.mf b/spring-integration-feed/template.mf
new file mode 100644
index 0000000000..36e6277820
--- /dev/null
+++ b/spring-integration-feed/template.mf
@@ -0,0 +1,17 @@
+Bundle-SymbolicName: org.springframework.integration.ftp
+Bundle-Name: Spring Integration SFTP Support
+Bundle-Vendor: SpringSource
+Bundle-ManifestVersion: 2
+Import-Template:
+ org.apache.commons.logging;version="[1.1.1, 2.0.0)",
+ org.apache.commons.lang.*;version="[2.5.0, 3.0.0)",
+ org.apache.commons.net.*;version="[2.0.0, 3.0.0)",
+ org.springframework.integration.*;version="[2.0.0, 2.0.1)",
+ org.springframework.scheduling.*;version="[3.0.3, 4.0.0)",
+ org.springframework.beans.*;version="[3.0.3, 4.0.0)",
+ org.springframework.context;version="[3.0.3, 4.0.0)",
+ org.springframework.core.*;version="[3.0.3, 4.0.0)",
+ org.springframework.util;version="[3.0.3, 4.0.0)",
+ org.jivesoftware.*;version="[3.1.0, 4.0.0)",
+ javax.*;version="0",
+ org.w3c.dom.*;version="0"
diff --git a/spring-integration-file/pom.xml b/spring-integration-file/pom.xml
index 04e1816828..2c7dd22e59 100644
--- a/spring-integration-file/pom.xml
+++ b/spring-integration-file/pom.xml
@@ -7,7 +7,6 @@
2.0.0.BUILD-SNAPSHOT
../spring-integration-parent/pom.xml
- org.springframework.integration
spring-integration-file
Spring Integration File Support
jar
@@ -20,6 +19,10 @@
org.springframework.integration
spring-integration-core
+
+
+
+
cglib
@@ -43,11 +46,12 @@
org.springframework
- spring-test
+ spring-test
org.springframework.integration
spring-integration-test
+
diff --git a/spring-integration-parent/pom.xml b/spring-integration-parent/pom.xml
index 96ddbeb988..762ac20fe2 100644
--- a/spring-integration-parent/pom.xml
+++ b/spring-integration-parent/pom.xml
@@ -136,7 +136,17 @@
spring-aspects
${org.springframework.version}
-
+
+
org.springframework
spring-core
${org.springframework.version}