initial commit of the finished twitter support.
This commit is contained in:
1
pom.xml
1
pom.xml
@@ -30,6 +30,7 @@
|
||||
<module>spring-integration-xmpp</module>
|
||||
<module>spring-integration-ftp</module>
|
||||
<module>spring-integration-sftp</module>
|
||||
<module>spring-integration-twitter</module>
|
||||
</modules>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
100
spring-integration-twitter/pom.xml
Normal file
100
spring-integration-twitter/pom.xml
Normal file
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-parent</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-twitter</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Integration Twitter Support</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.twitter4j</groupId>
|
||||
<artifactId>twitter4j-core</artifactId>
|
||||
<!--<version>[2.1,)</version>-->
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>nlog4j</artifactId>
|
||||
<version>1.2.25</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>${cglib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<version>${org.easymock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymockclassextension</artifactId>
|
||||
<version>${org.easymock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>${org.springframework.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${org.springframework.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-stream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
|
||||
import org.springframework.context.Lifecycle;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.twitter.oauth.OAuthConfiguration;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import twitter4j.RateLimitStatus;
|
||||
import twitter4j.ResponseList;
|
||||
import twitter4j.Twitter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* There are a lot of operations that are common to receiving the various types of messages when using the Twitter API, and this
|
||||
* class abstracts most of them for you. Implementers must take note of {@link org.springframework.integration.twitter.AbstractInboundTwitterEndpointSupport#runAsAPIRateLimitsPermit(org.springframework.integration.twitter.AbstractInboundTwitterEndpointSupport.ApiCallback)}
|
||||
* which will invoke the instance of {@link org.springframework.integration.twitter.AbstractInboundTwitterEndpointSupport.ApiCallback} when the rate-limit API
|
||||
* deems that its OK to do so. This class handles keeping tabs on that and on spacing out requests as required.
|
||||
*
|
||||
* Simialarly, this class handles keeping track on the latest inbound message its received and avoiding, where possible, redelivery of
|
||||
* common messages. This functionality is enabled using the {@link org.springframework.integration.context.metadata.MetadataPersister} implementation
|
||||
*
|
||||
* @author Josh Long
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractInboundTwitterEndpointSupport<T> extends AbstractEndpoint implements Lifecycle {
|
||||
protected volatile OAuthConfiguration configuration;
|
||||
protected final MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
private volatile MessageChannel requestChannel;
|
||||
protected volatile long markerId = -1;
|
||||
protected Twitter twitter;
|
||||
private final Object markerGuard = new Object();
|
||||
private final Object apiPermitGuard = new Object();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setConfiguration(OAuthConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
abstract protected void markLastStatusId(T statusId);
|
||||
|
||||
abstract protected List<T> sort(List<T> rl);
|
||||
|
||||
protected void forwardAll(ResponseList<T> tResponses) {
|
||||
List<T> stats = new ArrayList<T>();
|
||||
|
||||
for (T t : tResponses)
|
||||
stats.add(t);
|
||||
|
||||
for (T twitterResponse : sort(stats))
|
||||
forward(twitterResponse);
|
||||
}
|
||||
|
||||
public long getMarkerId() {
|
||||
return markerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
try {
|
||||
refresh();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void forward(T status) {
|
||||
synchronized (this.markerGuard) {
|
||||
Message<T> twtMsg = MessageBuilder.withPayload(status).build();
|
||||
messagingTemplate.send(requestChannel, twtMsg);
|
||||
markLastStatusId(status);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void runAsAPIRateLimitsPermit(ApiCallback cb)
|
||||
throws Exception {
|
||||
synchronized (this.apiPermitGuard) {
|
||||
while (waitUntilPullAvailable()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("have room to make an API request now");
|
||||
}
|
||||
|
||||
cb.run(this, twitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean handleReceivingRateLimitStatus(RateLimitStatus rateLimitStatus) {
|
||||
try {
|
||||
int secondsUntilReset = rateLimitStatus.getSecondsUntilReset();
|
||||
int remainingHits = rateLimitStatus.getRemainingHits();
|
||||
|
||||
if (remainingHits == 0) {
|
||||
logger.debug("rate status limit service returned 0 for the remaining hits value");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (secondsUntilReset == 0) {
|
||||
logger.debug("rate status limit service returned 0 for the seconds until reset period value");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int secondsUntilWeCanPullAgain = secondsUntilReset / remainingHits;
|
||||
long msUntilWeCanPullAgain = secondsUntilWeCanPullAgain * 1000;
|
||||
|
||||
logger.debug("need to Thread.sleep() " + secondsUntilWeCanPullAgain + " seconds until the next timeline pull. Have " + remainingHits +
|
||||
" remaining pull this rate period. The period ends in " + secondsUntilReset);
|
||||
|
||||
Thread.sleep(msUntilWeCanPullAgain);
|
||||
} catch (Throwable throwable) {
|
||||
logger.debug("encountered an error when" + " trying to refresh the timeline: " + ExceptionUtils.getFullStackTrace(throwable));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean waitUntilPullAvailable() throws Exception {
|
||||
return this.handleReceivingRateLimitStatus(this.twitter.getRateLimitStatus());
|
||||
}
|
||||
|
||||
protected boolean hasMarkedStatus() {
|
||||
return markerId > -1;
|
||||
}
|
||||
|
||||
abstract protected void refresh() throws Exception;
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
messagingTemplate.afterPropertiesSet();
|
||||
Assert.notNull(this.configuration, "'configuration' can't be null");
|
||||
this.twitter = this.configuration.getTwitter();
|
||||
Assert.notNull(this.twitter, "'twitter' instance can't be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setRequestChannel(MessageChannel requestChannel) {
|
||||
this.messagingTemplate.setDefaultChannel(requestChannel);
|
||||
this.requestChannel = requestChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for clients to run logic when the API rate limiting lets us
|
||||
*
|
||||
* Simply register your callback using #runAsAPIRateLimitsPermit
|
||||
*
|
||||
* @param <C>
|
||||
*/
|
||||
public static interface ApiCallback<C> {
|
||||
void run(C t, Twitter twitter) throws Exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import twitter4j.Status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Simple base class for the reply and timeline cases (as well as any other {@link twitter4j.Status} implementations of
|
||||
* {@link twitter4j.TwitterResponse}.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
abstract public class AbstractInboundTwitterStatusEndpointSupport extends AbstractInboundTwitterEndpointSupport<Status> {
|
||||
private Comparator<Status> statusComparator = new Comparator<Status>() {
|
||||
public int compare(Status status, Status status1) {
|
||||
return status.getCreatedAt().compareTo(status1.getCreatedAt());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void markLastStatusId(Status statusId) {
|
||||
this.markerId = statusId.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Status> sort(List<Status> rl) {
|
||||
List<Status> statusArrayList = new ArrayList<Status>();
|
||||
statusArrayList.addAll(rl);
|
||||
Collections.sort(statusArrayList, statusComparator);
|
||||
|
||||
return statusArrayList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.twitter.oauth.OAuthConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import twitter4j.Twitter;
|
||||
|
||||
|
||||
/**
|
||||
* The adapters that support 'sending' / 'updating status' messages will do so on top of this implementation for convenience, only.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public abstract class AbstractOutboundTwitterEndpointSupport extends AbstractEndpoint implements MessageHandler {
|
||||
protected volatile OAuthConfiguration configuration;
|
||||
protected volatile Twitter twitter;
|
||||
protected volatile StatusUpdateSupport statusUpdateSupport = new StatusUpdateSupport();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setConfiguration(OAuthConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
Assert.notNull(this.configuration, "'configuration' can't be null");
|
||||
this.twitter = this.configuration.getTwitter();
|
||||
Assert.notNull(this.twitter, "'twitter' can't be null");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import twitter4j.DirectMessage;
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.Twitter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* This class handles support for receiving DMs (direct messages) using Twitter.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class InboundDMStatusEndpoint extends AbstractInboundTwitterEndpointSupport<DirectMessage> {
|
||||
private Comparator<DirectMessage> dmComparator = new Comparator<DirectMessage>() {
|
||||
public int compare(DirectMessage directMessage, DirectMessage directMessage1) {
|
||||
return directMessage.getCreatedAt().compareTo(directMessage1.getCreatedAt());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void markLastStatusId(DirectMessage dm) {
|
||||
this.markerId = dm.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DirectMessage> sort(List<DirectMessage> rl) {
|
||||
List<DirectMessage> dms = new ArrayList<DirectMessage>();
|
||||
dms.addAll(rl);
|
||||
Collections.sort(dms, dmComparator);
|
||||
|
||||
return dms;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refresh() throws Exception {
|
||||
this.runAsAPIRateLimitsPermit(new ApiCallback<InboundDMStatusEndpoint>() {
|
||||
public void run(InboundDMStatusEndpoint t, Twitter twitter)
|
||||
throws Exception {
|
||||
forwardAll((!hasMarkedStatus()) ? t.twitter.getDirectMessages() : t.twitter.getDirectMessages(new Paging(t.getMarkerId())));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.Twitter;
|
||||
|
||||
|
||||
/**
|
||||
* Handles forwarding all new {@link twitter4j.Status} that are 'replies' or 'mentions' to some other tweet.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class InboundMentionStatusEndpoint extends AbstractInboundTwitterStatusEndpointSupport {
|
||||
@Override
|
||||
protected void refresh() throws Exception {
|
||||
this.runAsAPIRateLimitsPermit(new ApiCallback<InboundMentionStatusEndpoint>() {
|
||||
public void run(InboundMentionStatusEndpoint ctx, Twitter twitter)
|
||||
throws Exception {
|
||||
forwardAll((!hasMarkedStatus()) ? twitter.getMentions() : twitter.getMentions(new Paging(ctx.getMarkerId())));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.Twitter;
|
||||
|
||||
|
||||
/**
|
||||
* This {@link org.springframework.integration.core.MessageSource} lets Spring Integration consume a given account's timeline
|
||||
* as messages. It has support for dynamic throttling of API requests.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @since 2.0
|
||||
*/
|
||||
public class InboundUpdatedStatusEndpoint extends AbstractInboundTwitterStatusEndpointSupport {
|
||||
@Override
|
||||
protected void refresh() throws Exception {
|
||||
this.runAsAPIRateLimitsPermit(new ApiCallback<InboundUpdatedStatusEndpoint>() {
|
||||
public void run(InboundUpdatedStatusEndpoint t, Twitter twitter)
|
||||
throws Exception {
|
||||
forwardAll((!t.hasMarkedStatus()) ? twitter.getFriendsTimeline() : twitter.getFriendsTimeline(new Paging(t.getMarkerId())));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageDeliveryException;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.MessageRejectedException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import twitter4j.TwitterException;
|
||||
|
||||
|
||||
/**
|
||||
* Simple adapter to support sending outbound direct messages ("DM"s) using twitter
|
||||
*
|
||||
* @author Josh Long
|
||||
* @see org.springframework.integration.twitter.TwitterHeaders
|
||||
* @see twitter4j.Twitter
|
||||
*/
|
||||
public class OutboundDMStatusMessageHandler extends AbstractOutboundTwitterEndpointSupport {
|
||||
public void handleMessage(Message<?> message) throws MessageRejectedException, MessageHandlingException, MessageDeliveryException {
|
||||
try {
|
||||
String txt = (String) message.getPayload();
|
||||
Object toUser =
|
||||
message.getHeaders().containsKey(TwitterHeaders.TWITTER_DM_TARGET_USER_ID)?
|
||||
message.getHeaders().get(TwitterHeaders.TWITTER_DM_TARGET_USER_ID) :
|
||||
null;
|
||||
|
||||
Assert.notNull(txt, "the message payload must be a String to be used as the direct message body text");
|
||||
|
||||
Assert.notNull(toUser, "the header '" + TwitterHeaders.TWITTER_DM_TARGET_USER_ID + "' must be present");
|
||||
|
||||
Assert.state(toUser instanceof String || toUser instanceof Integer,
|
||||
"the header '" + TwitterHeaders.TWITTER_DM_TARGET_USER_ID + "' must be either a String (a screenname) or an int (a user ID)");
|
||||
|
||||
if (toUser instanceof Integer) {
|
||||
this.twitter.sendDirectMessage((Integer) toUser, txt);
|
||||
} else if (toUser instanceof String) {
|
||||
this.twitter.sendDirectMessage((String) toUser, txt);
|
||||
}
|
||||
} catch (TwitterException e) {
|
||||
logger.debug(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageDeliveryException;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.MessageRejectedException;
|
||||
import org.springframework.util.Assert;
|
||||
import twitter4j.StatusUpdate;
|
||||
|
||||
|
||||
/**
|
||||
* This class is useful for both sending regular status updates as well as 'replies' or 'mentions'
|
||||
*
|
||||
* @author Josh Long
|
||||
* @since 2.0
|
||||
*/
|
||||
public class OutboundUpdatedStatusMessageHandler extends AbstractOutboundTwitterEndpointSupport {
|
||||
public void handleMessage(Message<?> message) throws MessageRejectedException, MessageHandlingException, MessageDeliveryException {
|
||||
try {
|
||||
StatusUpdate statusUpdate = this.statusUpdateSupport.fromMessage(message);
|
||||
Assert.notNull(statusUpdate, "couldn't send message, unable to build a StatusUpdate instance correctly");
|
||||
this.twitter.updateStatus(statusUpdate);
|
||||
} catch (Throwable e) {
|
||||
this.logger.debug(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import twitter4j.GeoLocation;
|
||||
import twitter4j.StatusUpdate;
|
||||
|
||||
|
||||
/**
|
||||
* Convenience class that can take a seemingly disparate jumble of headers and a payload and do a best-faith attempt at vending a {@link twitter4j.StatusUpdate} instance
|
||||
*
|
||||
* @author Josh Long
|
||||
* @see twitter4j.StatusUpdate
|
||||
* @see org.springframework.integration.twitter.TwitterHeaders
|
||||
* @since 2.0
|
||||
*/
|
||||
public class StatusUpdateSupport {
|
||||
/**
|
||||
* {@link StatusUpdate} instances are used to drive status updates.
|
||||
*
|
||||
* @param message the inbound messages
|
||||
* @return a {@link StatusUpdate} that's been materialized from the inbound message
|
||||
* @throws Throwable thrown if something goes wrong
|
||||
*/
|
||||
public StatusUpdate fromMessage(Message<?> message)
|
||||
throws Throwable {
|
||||
Object payload = message.getPayload();
|
||||
StatusUpdate statusUpdate = null;
|
||||
|
||||
if (payload instanceof String) {
|
||||
statusUpdate = new StatusUpdate((String) payload);
|
||||
|
||||
if (message.getHeaders().containsKey(TwitterHeaders.TWITTER_IN_REPLY_TO_STATUS_ID)) {
|
||||
Long replyId = (Long) message.getHeaders().get(TwitterHeaders.TWITTER_IN_REPLY_TO_STATUS_ID);
|
||||
|
||||
if ((replyId != null) && (replyId > 0)) {
|
||||
statusUpdate.inReplyToStatusId(replyId);
|
||||
}
|
||||
}
|
||||
|
||||
if (message.getHeaders().containsKey(TwitterHeaders.TWITTER_PLACE_ID)) {
|
||||
String placeId = (String) message.getHeaders().get(TwitterHeaders.TWITTER_PLACE_ID);
|
||||
|
||||
if (StringUtils.hasText(placeId)) {
|
||||
statusUpdate.placeId(placeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (message.getHeaders().containsKey(TwitterHeaders.TWITTER_GEOLOCATION)) {
|
||||
GeoLocation geoLocation = (GeoLocation) message.getHeaders().get(TwitterHeaders.TWITTER_GEOLOCATION);
|
||||
|
||||
if (null != geoLocation) {
|
||||
statusUpdate.location(geoLocation);
|
||||
}
|
||||
}
|
||||
|
||||
if (message.getHeaders().containsKey(TwitterHeaders.TWITTER_DISPLAY_COORDINATES)) {
|
||||
Boolean displayCoords = (Boolean) message.getHeaders().get(TwitterHeaders.TWITTER_DISPLAY_COORDINATES);
|
||||
|
||||
if (displayCoords != null) {
|
||||
statusUpdate.displayCoordinates(displayCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (payload instanceof StatusUpdate) {
|
||||
statusUpdate = (StatusUpdate) payload;
|
||||
}
|
||||
|
||||
return statusUpdate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
|
||||
/**
|
||||
* An enum to allow users to express interest in particular kinds of tweets.
|
||||
*
|
||||
* Contains header keys used by the various adapters.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @since 2.0
|
||||
*/
|
||||
public class TwitterHeaders {
|
||||
public static final String TWITTER_IN_REPLY_TO_STATUS_ID = "TWITTER_IN_REPLY_TO_STATUS_ID";
|
||||
public static final String TWITTER_PLACE_ID = "TWITTER_PLACE_ID";
|
||||
public static final String TWITTER_GEOLOCATION = "TWITTER_GEOLOCATION";
|
||||
public static final String TWITTER_DISPLAY_COORDINATES = "TWITTER_DISPLAY_COORDINATES";
|
||||
public static final String TWITTER_DM_TARGET_USER_ID = "TWITTER_DM_TARGET_USER_ID";
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.twitter.config;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
||||
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.twitter.*;
|
||||
import org.springframework.integration.twitter.oauth.OAuthConfigurationFactoryBean;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
/**
|
||||
* @author Josh Long
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TwitterNamespaceHandler extends org.springframework.beans.factory.xml.NamespaceHandlerSupport {
|
||||
public static final String DIRECT_MESSAGES = "direct-messages";
|
||||
public static final String MENTIONS = "mentions";
|
||||
public static final String FRIENDS = "friends";
|
||||
|
||||
public void init() {
|
||||
// twitter connections
|
||||
registerBeanDefinitionParser("twitter-connection", new TwitterConnectionParser());
|
||||
|
||||
// inbound
|
||||
registerBeanDefinitionParser("inbound-update-channel-adapter", new TwitterUpdatedStatusInboundEndpointParser());
|
||||
registerBeanDefinitionParser("inbound-dm-channel-adapter", new TwitterDMInboundEndpointParser());
|
||||
registerBeanDefinitionParser("inbound-mention-channel-adapter", new TwitterMentionInboundEndpointParser());
|
||||
|
||||
// outbound
|
||||
registerBeanDefinitionParser("outbound-update-channel-adapter", new TwitterUpdatedStatusOutboundEndpointParser());
|
||||
registerBeanDefinitionParser("outbound-dm-channel-adapter", new TwitterDMOutboundEndpointParser());
|
||||
}
|
||||
|
||||
private static void configureTwitterConnection(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String ref = element.getAttribute("twitter-connection");
|
||||
|
||||
if (org.springframework.util.StringUtils.hasText(ref)) {
|
||||
builder.addPropertyReference("twitterConnection", ref);
|
||||
} else {
|
||||
for (String attribute : new String[] { "consumer-key", "consumer-secret", "access-token", "access-token-secret" }) {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, attribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// twitter:twitter-connection
|
||||
private static class TwitterConnectionParser extends AbstractSingleBeanDefinitionParser {
|
||||
@Override
|
||||
protected Class getBeanClass(Element element) {
|
||||
return OAuthConfigurationFactoryBean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
configureTwitterConnection(element, parserContext, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// twitter:inbound-mention-channel-adapter
|
||||
private static class TwitterMentionInboundEndpointParser extends AbstractSingleBeanDefinitionParser {
|
||||
@Override
|
||||
protected String getBeanClassName(Element element) {
|
||||
return InboundMentionStatusEndpoint.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "channel", "requestChannel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "twitter-connection", "configuration");
|
||||
}
|
||||
}
|
||||
|
||||
// twitter:inbound-dm-channel-adapter
|
||||
private static class TwitterDMInboundEndpointParser extends AbstractSingleBeanDefinitionParser {
|
||||
@Override
|
||||
protected String getBeanClassName(Element element) {
|
||||
return InboundDMStatusEndpoint.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "channel", "requestChannel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "twitter-connection", "configuration");
|
||||
}
|
||||
}
|
||||
|
||||
// twitter:inbound-update-channel-adapter
|
||||
private static class TwitterUpdatedStatusInboundEndpointParser extends AbstractSingleBeanDefinitionParser {
|
||||
@Override
|
||||
protected String getBeanClassName(Element element) {
|
||||
return InboundUpdatedStatusEndpoint.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "channel", "requestChannel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "twitter-connection", "configuration");
|
||||
}
|
||||
}
|
||||
|
||||
// twitter:outbound-update-channel-adapter
|
||||
private static class TwitterUpdatedStatusOutboundEndpointParser extends AbstractOutboundChannelAdapterParser {
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(OutboundUpdatedStatusMessageHandler.class.getName());
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "twitter-connection", "configuration");
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
// twitter:outbound-dm-channel-adapter
|
||||
private static class TwitterDMOutboundEndpointParser extends AbstractOutboundChannelAdapterParser {
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(OutboundDMStatusMessageHandler.class.getName());
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "twitter-connection", "configuration");
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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.twitter.oauth;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import twitter4j.http.AccessToken;
|
||||
import twitter4j.http.RequestToken;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* base-class for {@link org.springframework.integration.twitter.oauth.OAuthAccessTokenBasedTwitterFactoryBean}.
|
||||
* <p/>
|
||||
* Provides hooks so that subclasses able to reference a concrete implementation of the generic type parameter can call methods for us. Most hooks are to handle the case
|
||||
* of the first time subscription, where no accessToken is present.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @param <T>
|
||||
* @see org.springframework.integration.twitter.oauth.OAuthAccessTokenBasedTwitterFactoryBean
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract public class AbstractOAuthAccessTokenBasedFactoryBean<T> implements InitializingBean, FactoryBean<T> {
|
||||
protected OAuthConfiguration configuration;
|
||||
protected final Object monitor = new Object();
|
||||
protected volatile T twitter;
|
||||
protected volatile AccessTokenInitialRequestProcessListener accessTokenInitialRequestProcessListener;
|
||||
protected volatile boolean initialized = false;
|
||||
|
||||
/**
|
||||
* Nasty little bit of circular indirection here: the {@link org.springframework.integration.twitter.oauth.OAuthConfiguration} hosts the String values for authentication,
|
||||
* which we need to build up this instance, but the {@link org.springframework.integration.twitter.oauth.OAuthConfiguration} in turn needs references to the instances provided by
|
||||
* this {@link org.springframework.beans.factory.FactoryBean}. So, they collaborate and guard each others state. Ultimately, clients should use {@link org.springframework.integration.twitter.oauth.OAuthConfiguration}
|
||||
* to correctly any implementations of this factory bean as well as the {@link org.springframework.integration.twitter.oauth.OAuthConfiguration} reference itself.
|
||||
*
|
||||
* @param configuration the configuration object
|
||||
*/
|
||||
protected AbstractOAuthAccessTokenBasedFactoryBean(OAuthConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* This probably doesn't belong here. It's more for support for running the {@link OAuthAccessTokenBasedTwitterFactoryBean#main(String[])} or
|
||||
* {@link OAuthAccessTokenBasedTwitterFactoryBean#main(String[])} methods that run the user through a command line tool to approve a user for the first
|
||||
* time if the user hasn't obtained her {@code accessToken } yet
|
||||
*
|
||||
* @param resource the resource where properties file lives
|
||||
* @return returns a fully configured {@link java.util.Properties} instance
|
||||
* @throws Exception thrown if anythign goes wrong
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected static Properties fromResource(Resource resource)
|
||||
throws Exception {
|
||||
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
|
||||
propertiesFactoryBean.setLocation(resource);
|
||||
propertiesFactoryBean.setSingleton(true);
|
||||
propertiesFactoryBean.afterPropertiesSet();
|
||||
|
||||
return propertiesFactoryBean.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* provides lifecycle for initiation of the reference. By the time this method is left we should have a fully configured twitter connection that can connect and make calls
|
||||
* @throws Exception
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
synchronized (this.monitor) {
|
||||
if (this.accessTokenInitialRequestProcessListener == null) {
|
||||
accessTokenInitialRequestProcessListener = new ConsoleBasedAccessTokenInitialRequestProcessListener();
|
||||
}
|
||||
|
||||
Assert.notNull(this.configuration.getConsumerKey(), "'consumerKey' mustn't be null");
|
||||
Assert.notNull(this.configuration.getConsumerSecret(), "'consumerSecret' mustn't be null");
|
||||
|
||||
AccessToken accessTokenObj;
|
||||
|
||||
if (StringUtils.hasText(this.configuration.getAccessToken()) && StringUtils.hasText(this.configuration.getAccessTokenSecret())) {
|
||||
accessTokenObj = new AccessToken(this.configuration.getAccessToken(), this.configuration.getAccessTokenSecret());
|
||||
} else {
|
||||
accessTokenObj = initialAuthorizationWizard();
|
||||
}
|
||||
|
||||
establishTwitterObject(accessTokenObj);
|
||||
|
||||
Assert.notNull(accessTokenObj, "'accessTokenObj' can't be null");
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setAccessTokenInitialRequestProcessListener(AccessTokenInitialRequestProcessListener accessTokenInitialRequestProcessListener) {
|
||||
this.accessTokenInitialRequestProcessListener = accessTokenInitialRequestProcessListener;
|
||||
}
|
||||
|
||||
public abstract void establishTwitterObject(AccessToken accessToken)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* because we are not able to dereference the {@link twitter4j.Twitter} or {@link twitter4j.AsyncTwitter} instances, we need to ask subclasses to call
|
||||
* us how to call {@link twitter4j.AsyncTwitter#getOAuthRequestToken()} or {@link twitter4j.Twitter#getOAuthRequestToken()} for us.This method
|
||||
* will never be evaluated as long as the {@link org.springframework.integration.twitter.oauth.OAuthConfiguration#accessToken}
|
||||
* and {@link org.springframework.integration.twitter.oauth.OAuthConfiguration#accessTokenSecret} beans are not null.
|
||||
*
|
||||
* @return the {@link twitter4j.http.RequestToken} as vended by the service. Ths will contain a verification URl required to obtain an access key and secret.
|
||||
* @throws Exception thrown if anything should go wrong
|
||||
*/
|
||||
public abstract RequestToken getOAuthRequestToken()
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Only used if the impementation is trying to get an {@link twitter4j.http.AccessToken} for the first time. This method
|
||||
* will never be evaluated as long as the {@link org.springframework.integration.twitter.oauth.OAuthConfiguration#accessToken}
|
||||
* and {@link org.springframework.integration.twitter.oauth.OAuthConfiguration#accessTokenSecret} beans are not null.
|
||||
*
|
||||
* @param token the initiating {@link twitter4j.http.RequestToken}
|
||||
* @param pin the string returned from the verification URL
|
||||
* @return returns the {@link twitter4j.http.AccessToken} fetched from the twitter service.
|
||||
* @throws Exception thrown if anything should go wrong
|
||||
*/
|
||||
public abstract AccessToken getOAuthAccessToken(RequestToken token, String pin)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Only used if the impementation is trying to get an {@link twitter4j.http.AccessToken} for the first time. This method
|
||||
* will never be evaluated as long as the {@link org.springframework.integration.twitter.oauth.OAuthConfiguration#accessToken}
|
||||
* and {@link org.springframework.integration.twitter.oauth.OAuthConfiguration#accessTokenSecret} beans are not null.
|
||||
*
|
||||
* @return returns the {@link twitter4j.http.AccessToken} fetched from the twitter service.
|
||||
* @throws Exception thrown if anything should go wrong
|
||||
*/
|
||||
public abstract AccessToken getOAuthAccessToken() throws Exception;
|
||||
|
||||
/**
|
||||
* @return returns the freshly created {@link twitter4j.http.AccessToken} object from the service
|
||||
* @throws Exception for just about any deviation from the expected
|
||||
*/
|
||||
private AccessToken initialAuthorizationWizard() throws Exception {
|
||||
Assert.notNull(this.accessTokenInitialRequestProcessListener, "'accessTokenInitialRequestProcessListener' can't be null");
|
||||
|
||||
try {
|
||||
RequestToken requestToken = getOAuthRequestToken();
|
||||
String pin = this.accessTokenInitialRequestProcessListener.openUrlAndReturnPin(requestToken.getAuthorizationURL());
|
||||
AccessToken at = StringUtils.hasText(pin) ? getOAuthAccessToken(requestToken, pin) : getOAuthAccessToken();
|
||||
this.accessTokenInitialRequestProcessListener.persistReturnedAccessToken(at);
|
||||
|
||||
return at;
|
||||
} catch (Throwable th) {
|
||||
this.accessTokenInitialRequestProcessListener.failure(th);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsibility of subclasses to call this because we cant dereference the generic type appropriately. The responsibility is
|
||||
* to call {@link twitter4j.Twitter#verifyCredentials()} or {@link twitter4j.AsyncTwitter#verifyCredentials()} as appropriate
|
||||
*
|
||||
* @throws Exception if there's an inability to authenticate
|
||||
*/
|
||||
public abstract void verifyCredentials() throws Exception;
|
||||
|
||||
/**
|
||||
* Rubber meets the road: builds up a reference to the twitter4j.(Async)Twitter instance
|
||||
*
|
||||
* @return the instance
|
||||
* @throws Exception thrown in case some condition isn't met correctly in construction
|
||||
*/
|
||||
public T getObject() throws Exception {
|
||||
if (!initialized) {
|
||||
afterPropertiesSet();
|
||||
}
|
||||
|
||||
return this.twitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* this method is delegated to implementations because we can't correctly dereference the generic type's class
|
||||
*
|
||||
* @return a class
|
||||
*/
|
||||
abstract public Class<?> getObjectType();
|
||||
|
||||
/**
|
||||
* Standard {@link org.springframework.beans.factory.FactoryBean} method. Implementations may override if there's a specific method
|
||||
*
|
||||
* @return whether or not this is a singleton
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.twitter.oauth;
|
||||
|
||||
import twitter4j.http.AccessToken;
|
||||
|
||||
|
||||
/**
|
||||
* if the factory bean isn't provided a 'accesstoken' and 'accesstokensecret', then it will try to obtain those bits of informatio on the users behalf.
|
||||
* <p/>
|
||||
* In doing so it will need input fro the user (automatic or human intervention is required)
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public interface AccessTokenInitialRequestProcessListener {
|
||||
String openUrlAndReturnPin(String urlToOpen) throws Exception;
|
||||
|
||||
void persistReturnedAccessToken(AccessToken accessToken)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Callback in case something goes wrong at any point in the process. Up to client to intervene
|
||||
* @param t the exception thrown (if any). Could be null if none available
|
||||
*/
|
||||
void failure(Throwable t);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.twitter.oauth;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.SystemUtils;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
|
||||
import twitter4j.http.AccessToken;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* Default System.(out|in) based implementation of the {@link org.springframework.integration.twitter.oauth.AccessTokenInitialRequestProcessListener} interface
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class ConsoleBasedAccessTokenInitialRequestProcessListener implements AccessTokenInitialRequestProcessListener {
|
||||
public String openUrlAndReturnPin(String urlToOpen)
|
||||
throws Exception {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
|
||||
System.out.println("Open the following URL and grant access to your account:");
|
||||
System.out.println(urlToOpen);
|
||||
System.out.print("Enter the PIN(if aviailable) or just hit enter.[PIN]:");
|
||||
|
||||
return StringUtils.trim(br.readLine());
|
||||
}
|
||||
|
||||
public void persistReturnedAccessToken(AccessToken accessToken)
|
||||
throws Exception {
|
||||
Map<String, String> output = new HashMap<String, String>();
|
||||
output.put(OAuthConfigurationFactoryBean.WELL_KNOWN_CONSUMER_ACCESS_TOKEN, accessToken.getToken());
|
||||
output.put(OAuthConfigurationFactoryBean.WELL_KNOWN_CONSUMER_ACCESS_TOKEN_SECRET, accessToken.getTokenSecret());
|
||||
|
||||
File accessTokenCreds = new File(SystemUtils.getJavaIoTmpDir(), "twitter-accesstoken.properties");
|
||||
FileWriter writer = new FileWriter(accessTokenCreds);
|
||||
|
||||
Properties props = new Properties();
|
||||
props.putAll(output);
|
||||
props.store(writer, "oauth-access-token");
|
||||
IOUtils.closeQuietly(writer);
|
||||
|
||||
System.out.println("The oauth accesstoken credentials have been written to " + accessTokenCreds.getAbsolutePath());
|
||||
}
|
||||
|
||||
public void failure(Throwable t) {
|
||||
System.err.println("Exception occurred when trying to retrieve credentials: " + ExceptionUtils.getFullStackTrace(t));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.twitter.oauth;
|
||||
|
||||
import org.apache.commons.lang.SystemUtils;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
|
||||
import twitter4j.ResponseList;
|
||||
import twitter4j.Status;
|
||||
import twitter4j.Twitter;
|
||||
import twitter4j.TwitterFactory;
|
||||
|
||||
import twitter4j.http.AccessToken;
|
||||
import twitter4j.http.RequestToken;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
public class OAuthAccessTokenBasedTwitterFactoryBean extends AbstractOAuthAccessTokenBasedFactoryBean<Twitter> {
|
||||
protected OAuthAccessTokenBasedTwitterFactoryBean(OAuthConfiguration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void establishTwitterObject(AccessToken accessToken)
|
||||
throws Exception {
|
||||
this.twitter = new TwitterFactory().getOAuthAuthorizedInstance(this.configuration.getConsumerKey(), this.configuration.getConsumerSecret(), accessToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestToken getOAuthRequestToken() throws Exception {
|
||||
return twitter.getOAuthRequestToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyCredentials() throws Exception {
|
||||
this.twitter.verifyCredentials();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken getOAuthAccessToken(RequestToken token, String pin)
|
||||
throws Exception {
|
||||
return this.twitter.getOAuthAccessToken(token, pin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken getOAuthAccessToken() throws Exception {
|
||||
return this.twitter.getOAuthAccessToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Twitter.class;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
File propsFile = new File(new File(SystemUtils.getUserHome(), "Desktop"), "twitter.properties");
|
||||
FileSystemResource fileSystemResource = new FileSystemResource(propsFile);
|
||||
Properties properties = fromResource(fileSystemResource);
|
||||
|
||||
OAuthConfigurationFactoryBean oAuthConfigurationFactoryBean = new OAuthConfigurationFactoryBean();
|
||||
oAuthConfigurationFactoryBean.bootstrapFromProperties(properties);
|
||||
|
||||
OAuthConfiguration configuration = oAuthConfigurationFactoryBean.getObject();
|
||||
|
||||
Twitter twitter = configuration.getTwitter();
|
||||
|
||||
System.out.println("Used the " + OAuthAccessTokenBasedTwitterFactoryBean.class.getName() + " and arrived at " + ToStringBuilder.reflectionToString(twitter));
|
||||
|
||||
ResponseList<Status> friendsTimeline = twitter.getFriendsTimeline();
|
||||
System.out.println("Friends' timeline " + friendsTimeline);
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.twitter.oauth;
|
||||
|
||||
import twitter4j.Twitter;
|
||||
|
||||
|
||||
/**
|
||||
* Simple bean we can use to store the configuration and store shared references to both an {@link twitter4j.AsyncTwitter}
|
||||
* and an {@link twitter4j.Twitter} instance.
|
||||
* <p/>
|
||||
* client should store this bean and simply lookup the Twitter configuration from there
|
||||
*/
|
||||
public class OAuthConfiguration {
|
||||
//
|
||||
// private AsyncTwitter asyncTwitter;
|
||||
private Twitter twitter;
|
||||
private volatile String consumerKey;
|
||||
private volatile String consumerSecret;
|
||||
private volatile String accessToken;
|
||||
private volatile String accessTokenSecret;
|
||||
|
||||
public OAuthConfiguration(String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret) {
|
||||
this.consumerKey = consumerKey;
|
||||
this.consumerSecret = consumerSecret;
|
||||
this.accessToken = accessToken;
|
||||
this.accessTokenSecret = accessTokenSecret;
|
||||
}
|
||||
|
||||
/** package friendly */
|
||||
/* void setAsyncTwitter(AsyncTwitter asyncTwitter) {
|
||||
this.asyncTwitter = asyncTwitter;
|
||||
}*/
|
||||
|
||||
/** package friendly */
|
||||
void setTwitter(Twitter twitter) {
|
||||
this.twitter = twitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public Twitter getTwitter() {
|
||||
return twitter;
|
||||
}
|
||||
|
||||
/*
|
||||
public AsyncTwitter getAsyncTwitter() {
|
||||
return asyncTwitter;
|
||||
}*/
|
||||
public String getConsumerKey() {
|
||||
return consumerKey;
|
||||
}
|
||||
|
||||
public void setConsumerKey(String consumerKey) {
|
||||
this.consumerKey = consumerKey;
|
||||
}
|
||||
|
||||
public String getConsumerSecret() {
|
||||
return consumerSecret;
|
||||
}
|
||||
|
||||
public void setConsumerSecret(String consumerSecret) {
|
||||
this.consumerSecret = consumerSecret;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getAccessTokenSecret() {
|
||||
return accessTokenSecret;
|
||||
}
|
||||
|
||||
public void setAccessTokenSecret(String accessTokenSecret) {
|
||||
this.accessTokenSecret = accessTokenSecret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.twitter.oauth;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import twitter4j.Twitter;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* Center piece for configuration for all the twitter adapters
|
||||
*
|
||||
* @author Josh Long
|
||||
* @since 2.0
|
||||
*/
|
||||
public class OAuthConfigurationFactoryBean implements FactoryBean<OAuthConfiguration> {
|
||||
public static final String WELL_KNOWN_CONSUMER_KEY = "twitter.oauth.consumerKey";
|
||||
public static final String WELL_KNOWN_CONSUMER_KEY_SECRET = "twitter.oauth.consumerSecret";
|
||||
public static final String WELL_KNOWN_CONSUMER_ACCESS_TOKEN = "twitter.oauth.accessToken";
|
||||
public static final String WELL_KNOWN_CONSUMER_ACCESS_TOKEN_SECRET = "twitter.oauth.accessTokenSecret";
|
||||
private volatile String consumerKey;
|
||||
private volatile String consumerSecret;
|
||||
private volatile String accessToken;
|
||||
private volatile String accessTokenSecret;
|
||||
private Twitter twitter;
|
||||
private volatile OAuthConfiguration oAuthConfiguration;
|
||||
private final Object guard = new Object();
|
||||
|
||||
private Twitter twitter(OAuthConfiguration oAuthConfiguration)
|
||||
throws Exception {
|
||||
OAuthAccessTokenBasedTwitterFactoryBean twitterFactoryBean = new OAuthAccessTokenBasedTwitterFactoryBean(oAuthConfiguration);
|
||||
twitterFactoryBean.afterPropertiesSet();
|
||||
twitterFactoryBean.verifyCredentials();
|
||||
|
||||
return twitterFactoryBean.getObject();
|
||||
}
|
||||
|
||||
protected void bootstrapFromProperties(Properties props)
|
||||
throws Throwable {
|
||||
Assert.notNull(props, "'properties' must not be null");
|
||||
this.setAccessToken(props.getProperty(WELL_KNOWN_CONSUMER_ACCESS_TOKEN));
|
||||
this.setAccessTokenSecret(props.getProperty(WELL_KNOWN_CONSUMER_ACCESS_TOKEN_SECRET));
|
||||
this.setConsumerKey(props.getProperty(WELL_KNOWN_CONSUMER_KEY));
|
||||
this.setConsumerSecret(props.getProperty(WELL_KNOWN_CONSUMER_KEY_SECRET));
|
||||
}
|
||||
|
||||
public OAuthConfiguration getObject() throws Exception {
|
||||
return build();
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return OAuthConfiguration.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setConsumerKey(String consumerKey) {
|
||||
this.consumerKey = consumerKey;
|
||||
}
|
||||
|
||||
public void setConsumerSecret(String consumerSecret) {
|
||||
this.consumerSecret = consumerSecret;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public void setAccessTokenSecret(String accessTokenSecret) {
|
||||
this.accessTokenSecret = accessTokenSecret;
|
||||
}
|
||||
|
||||
private OAuthConfiguration build() throws Exception {
|
||||
synchronized (this.guard) {
|
||||
if (oAuthConfiguration == null) {
|
||||
oAuthConfiguration = new OAuthConfiguration(this.consumerKey, this.consumerSecret, this.accessToken, this.accessTokenSecret);
|
||||
twitter = this.twitter(oAuthConfiguration);
|
||||
oAuthConfiguration.setTwitter(twitter);
|
||||
}
|
||||
}
|
||||
|
||||
return this.oAuthConfiguration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
http\://www.springframework.org/schema/integration/twitter=org.springframework.integration.twitter.config.TwitterNamespaceHandler
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
http\://www.springframework.org/schema/integration/twitter/spring-integration-twitter-2.0.xsd=org/springframework/integration/twitter/config/spring-integration-twitter-2.0.xsd
|
||||
http\://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd=org/springframework/integration/twitter/config/spring-integration-twitter-2.0.xsd
|
||||
@@ -0,0 +1,219 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/twitter"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/twitter"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/integration"
|
||||
schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"/>
|
||||
|
||||
|
||||
<xsd:element name="twitter-connection">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Sets up an instance of OAuthConfiguration which all adapters need to function properly
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="id" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="consumer-key" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="consumer-secret" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="access-token" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="access-token-secret" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<!--
|
||||
This defines the beans we have for working with Twitter
|
||||
-->
|
||||
<xsd:element name="inbound-mention-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures an inbound channel adapter that consumes message (representing mentions of your handle)
|
||||
from twitter and sends Messages whose payloads are Status objects.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
<xsd:attribute name="channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute use="required" name="twitter-connection" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.twitter.oauth.OAuthConfiguration"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<!-- <xsd:attribute name="username" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="password" type="xsd:string" use="required"/>-->
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="inbound-dm-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures an inbound channel adapter that consumes direct messages and forwards them to Spring Integration
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="twitter-connection" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.twitter.oauth.OAuthConfiguration"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
<xsd:attribute name="channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<!--<xsd:attribute name="username" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="password" type="xsd:string" use="required"/>-->
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="inbound-update-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures an inbound channel adapter that consumes message (representing your friends' timeline updates)
|
||||
from twitter and sends Messages whose payloads are Tweet objects.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
<xsd:attribute name="twitter-connection" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.twitter.oauth.OAuthConfiguration"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
OUTBOUND
|
||||
-->
|
||||
|
||||
<xsd:element name="outbound-dm-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures an inbound channel adapter that consumes message (representing your friends' timeline updates)
|
||||
from twitter and sends Messages whose payloads are Tweet objects.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
<xsd:attribute name="twitter-connection" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.twitter.oauth.OAuthConfiguration"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
|
||||
<xsd:element name="outbound-update-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures an inbound channel adapter that consumes message (representing your friends' timeline updates)
|
||||
from twitter and sends Messages whose payloads are Tweet objects.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
<xsd:attribute name="twitter-connection" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.twitter.oauth.OAuthConfiguration"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</xsd:schema>
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.springframework.integration.twitter;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.springframework.integration.twitter.oauth.OAuthConfiguration;
|
||||
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import twitter4j.Status;
|
||||
import twitter4j.Twitter;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
|
||||
/**
|
||||
* This class is used to simply demonstrating correctly factory-ing a {@link twitter4j.Twitter} instance
|
||||
*/
|
||||
@ContextConfiguration(locations = "twitter_connection_using_ns.xml")
|
||||
public class SimpleTwitterTestClient {
|
||||
private Twitter twitter;
|
||||
@Autowired
|
||||
private volatile OAuthConfiguration oAuthConfiguration;
|
||||
|
||||
@PostConstruct
|
||||
public void begin() throws Exception {
|
||||
this.twitter = oAuthConfiguration.getTwitter();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testConnectivity() throws Throwable {
|
||||
Collection<Status> responses;
|
||||
Assert.assertNotNull(this.twitter);
|
||||
Assert.assertNotNull(responses = this.twitter.getFriendsTimeline());
|
||||
Assert.assertTrue(responses.size() > 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
|
||||
|
||||
/**
|
||||
* @author Josh Long
|
||||
*/
|
||||
@ContextConfiguration(locations = {
|
||||
"/receiving_dms_using_ns.xml"}
|
||||
)
|
||||
public class TestRecievingUsingNamespace extends AbstractJUnit4SpringContextTests {
|
||||
@Autowired
|
||||
private TwitterAnnouncer twitterAnnouncer;
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testIt() throws Throwable {
|
||||
long ctr = 0;
|
||||
long s = 1000;
|
||||
|
||||
while (ctr < (s * 60 * 3)) {
|
||||
Thread.sleep(s);
|
||||
ctr += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import twitter4j.GeoLocation;
|
||||
|
||||
|
||||
/**
|
||||
* @author Josh Long
|
||||
*/
|
||||
@ContextConfiguration(locations = {
|
||||
"/sending_dms_using_ns.xml"}
|
||||
)
|
||||
public class TestSendingDMsUsingNamespace extends AbstractJUnit4SpringContextTests {
|
||||
private volatile MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
@Value("#{out}")
|
||||
private MessageChannel channel;
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSendingATweet() throws Throwable {
|
||||
String dmUsr = System.getProperties().getProperty("twitter.dm.user");
|
||||
MessageBuilder<String> mb = MessageBuilder.withPayload("'Hello world!', from the Spring Integration outbound Twitter adapter")
|
||||
.setHeader(TwitterHeaders.TWITTER_GEOLOCATION, new GeoLocation(-76.226823, 23.642465)) // antarctica
|
||||
.setHeader(TwitterHeaders.TWITTER_DISPLAY_COORDINATES, true);
|
||||
|
||||
if (StringUtils.hasText(dmUsr)) {
|
||||
mb.setHeader(TwitterHeaders.TWITTER_DM_TARGET_USER_ID, dmUsr);
|
||||
}
|
||||
|
||||
Message<String> m = mb.build();
|
||||
|
||||
this.messagingTemplate.send(this.channel, m);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.twitter;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import twitter4j.GeoLocation;
|
||||
|
||||
|
||||
/**
|
||||
* @author Josh Long
|
||||
*/
|
||||
@ContextConfiguration(locations = {
|
||||
"/sending_updates_using_ns.xml"}
|
||||
)
|
||||
public class TestSendingUpdatesUsingNamespace extends AbstractJUnit4SpringContextTests {
|
||||
private MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
@Value("#{out}")
|
||||
private MessageChannel channel;
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSendingATweet() throws Throwable {
|
||||
MessageBuilder<String> mb = MessageBuilder.withPayload("'Hello world!', from the Spring Integration outbound Twitter adapter")
|
||||
.setHeader(TwitterHeaders.TWITTER_IN_REPLY_TO_STATUS_ID, 21927437001L)
|
||||
.setHeader(TwitterHeaders.TWITTER_GEOLOCATION, new GeoLocation(-76.226823, 23.642465)) // antarctica
|
||||
.setHeader(TwitterHeaders.TWITTER_DISPLAY_COORDINATES, true);
|
||||
Message<String> m = mb.build();
|
||||
this.messagingTemplate.send(this.channel, m);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.springframework.integration.twitter;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import twitter4j.DirectMessage;
|
||||
import twitter4j.Status;
|
||||
|
||||
|
||||
@Component
|
||||
public class TwitterAnnouncer {
|
||||
public void dm(DirectMessage directMessage) {
|
||||
System.out.println("A direct message has been received from " + directMessage.getSenderScreenName() + " with text " + directMessage.getText());
|
||||
}
|
||||
|
||||
public void mention(Status s) {
|
||||
System.out.println("A tweet mentioning (or replying) to " + "you was received having text " + s.getText() + " from " + s.getSource());
|
||||
}
|
||||
|
||||
public void friendsTimelineUpdated(Status t) {
|
||||
System.out.println("Received " + t.getText() + " from " + t.getSource());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:lang="http://www.springframework.org/schema/lang"
|
||||
xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
|
||||
|
||||
<context:component-scan
|
||||
base-package="org.springframework.integration.twitter"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="file://${user.home}/Desktop/twitter.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
<channel id="inbound_dm"/>
|
||||
|
||||
<twitter:inbound-dm-channel-adapter
|
||||
channel="inbound_dm" twitter-connection="tc"
|
||||
/>
|
||||
|
||||
<twitter:twitter-connection
|
||||
id="tc"
|
||||
access-token="${twitter.oauth.accessToken}"
|
||||
access-token-secret="${twitter.oauth.accessTokenSecret}"
|
||||
consumer-key="${twitter.oauth.consumerKey}"
|
||||
consumer-secret="${twitter.oauth.consumerSecret}"
|
||||
/>
|
||||
|
||||
<service-activator input-channel="inbound_dm"
|
||||
ref="twitterAnnouncer"
|
||||
method="dm"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:lang="http://www.springframework.org/schema/lang"
|
||||
xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
|
||||
|
||||
<context:component-scan
|
||||
base-package="org.springframework.integration.twitter"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="file://${user.home}/Desktop/twitter.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
<twitter:twitter-connection
|
||||
id="tc"
|
||||
access-token="${twitter.oauth.accessToken}"
|
||||
access-token-secret="${twitter.oauth.accessTokenSecret}"
|
||||
consumer-key="${twitter.oauth.consumerKey}"
|
||||
consumer-secret="${twitter.oauth.consumerSecret}"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<channel id="inbound_tweets"/>
|
||||
|
||||
<twitter:inbound-mention-channel-adapter twitter-connection="tc" channel="inbound_tweets" />
|
||||
|
||||
<service-activator input-channel="inbound_tweets" ref="twitterAnnouncer" method="mention"/>
|
||||
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:lang="http://www.springframework.org/schema/lang"
|
||||
xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
|
||||
|
||||
<context:component-scan
|
||||
base-package="org.springframework.integration.twitter"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="file://${user.home}/Desktop/twitter.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
|
||||
<twitter:twitter-connection
|
||||
id="tc"
|
||||
access-token="${twitter.oauth.accessToken}"
|
||||
access-token-secret="${twitter.oauth.accessTokenSecret}"
|
||||
consumer-key="${twitter.oauth.consumerKey}"
|
||||
consumer-secret="${twitter.oauth.consumerSecret}"
|
||||
/>
|
||||
|
||||
|
||||
<channel id="inbound_tweets"/>
|
||||
|
||||
|
||||
<twitter:inbound-update-channel-adapter
|
||||
twitter-connection="tc"
|
||||
channel="inbound_tweets"
|
||||
/>
|
||||
|
||||
<service-activator input-channel="inbound_tweets"
|
||||
ref="twitterAnnouncer"
|
||||
method="friendsTimelineUpdated"/>
|
||||
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:lang="http://www.springframework.org/schema/lang"
|
||||
xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
|
||||
|
||||
<context:component-scan
|
||||
base-package="org.springframework.integration.twitter"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="file://${user.home}/Desktop/twitter.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
<twitter:twitter-connection
|
||||
id="tc"
|
||||
access-token="${twitter.oauth.accessToken}"
|
||||
access-token-secret="${twitter.oauth.accessTokenSecret}"
|
||||
consumer-key="${twitter.oauth.consumerKey}"
|
||||
consumer-secret="${twitter.oauth.consumerSecret}"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<channel id="out"/>
|
||||
|
||||
<twitter:outbound-dm-channel-adapter twitter-connection="tc" channel="out"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:lang="http://www.springframework.org/schema/lang"
|
||||
xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
|
||||
|
||||
<context:component-scan
|
||||
base-package="org.springframework.integration.twitter"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="file://${user.home}/Desktop/twitter.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
<twitter:twitter-connection
|
||||
id="tc"
|
||||
access-token="${twitter.oauth.accessToken}"
|
||||
access-token-secret="${twitter.oauth.accessTokenSecret}"
|
||||
consumer-key="${twitter.oauth.consumerKey}"
|
||||
consumer-secret="${twitter.oauth.consumerSecret}"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<channel id="out"/>
|
||||
|
||||
<twitter:outbound-update-channel-adapter twitter-connection="tc" channel="out"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:lang="http://www.springframework.org/schema/lang"
|
||||
xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
|
||||
|
||||
<context:component-scan
|
||||
base-package="org.springframework.integration.twitter"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="file://${user.home}/Desktop/twitter.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
|
||||
<twitter:twitter-connection
|
||||
id="tc"
|
||||
access-token="${twitter.oauth.accessToken}"
|
||||
access-token-secret="${twitter.oauth.accessTokenSecret}"
|
||||
consumer-key="${twitter.oauth.consumerKey}"
|
||||
consumer-secret="${twitter.oauth.consumerSecret}"
|
||||
/>
|
||||
|
||||
<beans:bean class="org.springframework.integration.twitter.SimpleTwitterTestClient"/>
|
||||
|
||||
|
||||
</beans:beans>
|
||||
|
||||
|
||||
17
spring-integration-twitter/template.mf
Normal file
17
spring-integration-twitter/template.mf
Normal file
@@ -0,0 +1,17 @@
|
||||
Bundle-SymbolicName: org.springframework.integration.twitter
|
||||
Bundle-Name: Spring Integration Twitter 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.springframework.integration.*;version="[2.0.0, 2.0.1)",
|
||||
org.springframework.beans.*;version="[3.0.0, 4.0.0)",
|
||||
org.springframework.context;version="[3.0.0, 4.0.0)",
|
||||
org.springframework.core.*;version="[3.0.0, 4.0.0)",
|
||||
org.springframework.util;version="[3.0.0, 4.0.0)",
|
||||
org.jivesoftware.*;version="[3.1.0, 4.0.0)",
|
||||
org.apache.commons.io.*;version="[1.4,3.0)",
|
||||
twitter4j.*;version="[2.1.0,2.2.0]",
|
||||
javax.*;version="0",
|
||||
org.w3c.dom.*;version="0"
|
||||
Reference in New Issue
Block a user