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-xmpp</module>
|
||||||
<module>spring-integration-ftp</module>
|
<module>spring-integration-ftp</module>
|
||||||
<module>spring-integration-sftp</module>
|
<module>spring-integration-sftp</module>
|
||||||
|
<module>spring-integration-twitter</module>
|
||||||
</modules>
|
</modules>
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<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