Merge pull request #58 from garyrussell/INTSAMPLES-80

* garyrussell-INTSAMPLES-80:
  Webinar End State
  Initial State
This commit is contained in:
Gunnar Hillert
2012-08-13 11:43:44 -04:00
24 changed files with 1668 additions and 0 deletions

View File

@@ -60,6 +60,7 @@ This category targets developers who are already more familiar with the Spring I
* **rest-http** - This sample demonstrates how to send an HTTP request to a Spring Integration's HTTP service while utilizing Spring Integration's new HTTP Path usage. This sample also uses Spring Security for HTTP Basic authentication. With HTTP Path facility, the client program can send requests with URL Variables.
* **stored-procedures-derby** Provides an example of the stored procedure Outbound Gateway using *[Apache Derby](http://db.apache.org/derby/)*
* **stored-procedures-oracle** Provides an example of the stored procedure Outbound Gateway using *ORACLE XE*
* **monitoring** The project used in the *[Spring Integration Management and Monitoring Webinar](http://www.springsource.org/node/3598)* Also available on the *[SpringSourceDev YouTube Channel](http://www.youtube.com/SpringSourceDev)*
## Advanced

View File

@@ -0,0 +1,29 @@
Spring Integration - Monitoring
================================================================================
This application demonstrates managing and monitoring Spring Integration Applications.
It is based on the STS 'Spring Integration Project (war)' template project, available using
New... | Spring Template Project
It was used in the "Managing and Monitoring Spring Integration" webinar available
on the SpringSource Developer YouTube Channel http://www.youtube.com/SpringSourceDev
If you wish to see the changes made during the webinar, please use the following git command:
git log -p <The commit titled 'Webinar End State'>
To run the sample, in STS, use Run As... | Run on Server
and then use VisualVM/JConsole to explore the MBeans.
The twitter search results can be examined at http://localhost:8080/monitoring
--------------------------------------------------------------------------------
For help please see the Spring Integration documentation:
http://www.springsource.org/spring-integration

View File

@@ -0,0 +1,144 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.integration.sample</groupId>
<artifactId>monitoring</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<packaging>war</packaging>
<name>monitoring</name>
<url>http://www.springsource.org/spring-integration</url>
<prerequisites>
<maven>2.2.0</maven>
</prerequisites>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.integration.version>2.2.0.M3</spring.integration.version>
<org.springframework-version>3.1.1.RELEASE</org.springframework-version>
<log4j.version>1.2.16</log4j.version>
<junit.version>4.10</junit.version>
</properties>
<repositories>
<repository>
<id>repository.springframework.maven.milestone</id>
<name>Spring Framework Maven Release Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<wtpversion>1.5</wtpversion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- Spring Integration -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-twitter</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-groovy</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,130 @@
/*
* Copyright 2002-2010 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.model;
import java.util.Date;
/**
* Represents some common Twitter related fields.
*/
public class TwitterMessage {
private Date createdAt;
private String text;
private String fromUser;
private String profileImageUrl;
/** Default constructor. */
public TwitterMessage() {
super();
}
/** Constructor to initialize all fields available. */
public TwitterMessage(Date createdAt, String text, String fromUser,
String profileImageUrl) {
super();
this.createdAt = createdAt;
this.text = text;
this.fromUser = fromUser;
this.profileImageUrl = profileImageUrl;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getFromUser() {
return fromUser;
}
public void setFromUser(String fromUser) {
this.fromUser = fromUser;
}
public String getProfileImageUrl() {
return profileImageUrl;
}
public void setProfileImageUrl(String profileImageUrl) {
this.profileImageUrl = profileImageUrl;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((createdAt == null) ? 0 : createdAt.hashCode());
result = prime * result
+ ((fromUser == null) ? 0 : fromUser.hashCode());
result = prime * result
+ ((profileImageUrl == null) ? 0 : profileImageUrl.hashCode());
result = prime * result + ((text == null) ? 0 : text.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TwitterMessage other = (TwitterMessage) obj;
if (createdAt == null) {
if (other.createdAt != null)
return false;
} else if (!createdAt.equals(other.createdAt))
return false;
if (fromUser == null) {
if (other.fromUser != null)
return false;
} else if (!fromUser.equals(other.fromUser))
return false;
if (profileImageUrl == null) {
if (other.profileImageUrl != null)
return false;
} else if (!profileImageUrl.equals(other.profileImageUrl))
return false;
if (text == null) {
if (other.text != null)
return false;
} else if (!text.equals(other.text))
return false;
return true;
}
@Override
public String toString() {
return "Tweet [createdAt=" + createdAt + ", text=" + text
+ ", fromUser=" + fromUser + ", profileImageUrl="
+ profileImageUrl + "]";
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2002-2010 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.mvc.controller;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.model.TwitterMessage;
import org.springframework.integration.service.TwitterService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Log logger = LogFactory.getLog(HomeController.class);
@Autowired
private TwitterService twitterService;
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value="/")
public String home(Model model, @RequestParam(required=false) String startTwitter,
@RequestParam(required=false) String stopTwitter,
@RequestParam(required=false) String shutdown) {
if (startTwitter != null) {
twitterService.startTwitterAdapter();
return "redirect:/";
}
if (stopTwitter != null) {
twitterService.stopTwitterAdapter();
return "redirect:/";
}
if (shutdown != null) {
twitterService.shutdown();
return "redirect:/";
}
final Collection<TwitterMessage> twitterMessages = twitterService.getTwitterMessages();
logger.info("Retrieved " + twitterMessages.size() + " Twitter messages.");
model.addAttribute("twitterMessages", twitterMessages);
return "home";
}
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value="/ajax")
public String ajaxCall(Model model) {
final Collection<TwitterMessage> twitterMessages = twitterService.getTwitterMessages();
logger.info("Retrieved " + twitterMessages.size() + " Twitter messages.");
model.addAttribute("twitterMessages", twitterMessages);
return "twitterMessages";
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2010 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.service;
import java.util.Collection;
import org.springframework.integration.model.TwitterMessage;
/**
* Provides some basic methods for controlling the flow of Twitter messages.
*/
public interface TwitterService {
/**
* Retrieve the already polled Twitter messages. Keep in mind this
* method does not perform the actual Twitter search. It merely returns all
* the Tweets that were previously polled through Spring Integration and
* which have been cached for returning those to the web-frontend. */
Collection<TwitterMessage> getTwitterMessages();
/**
* By default - After application startup, the Spring Integration Twitter
* search-inbound-channel-adapter is stopped. Use this method to start
* the adapter.
*/
void startTwitterAdapter();
/**
* Allows for stopping the Spring Integration Twitter
* search-inbound-channel-adapter.
*/
void stopTwitterAdapter();
/**
* Performs an orderly shutdown of the Spring Integration twitter application.
*/
void shutdown();
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2002-2012 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.service.impl;
import java.util.Date;
import org.springframework.social.twitter.api.Tweet;
/**
* @author Gary Russell
* @since 2.2
*
*/
public class DummyTwitter {
private long id;
public Tweet getTweet() {
Tweet tweet = new Tweet(++this.id,
"Spring Integration is the coolest Enterprise Integration project",
new Date(),
"SomeUser",
null,
0L,
0L,
null,
null);
return tweet;
}
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright 2002-2012 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.springintegration;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.interceptor.ChannelInterceptorAdapter;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.StopWatch;
/**
* A sample channel interceptor that illustrates a technique to capture elapsed times
* based on message payload types.
*
* @author Gary Russell
* @since 2.2
*
*/
@ManagedResource
public class PayloadAwareTimingInterceptor extends ChannelInterceptorAdapter {
private ThreadLocal<StopWatchHolder> stopWatchHolder = new ThreadLocal<PayloadAwareTimingInterceptor.StopWatchHolder>();
private Map<Class<?>, Stats> statsMap = new ConcurrentHashMap<Class<?>, PayloadAwareTimingInterceptor.Stats>();
/**
*
* @param classes An array of types for which statistics will be captured; if
* not supplied {@link Object} will be added as a catch-all.
*/
public PayloadAwareTimingInterceptor(Class<?>[] classes) {
for (Class<?> clazz : classes) {
this.statsMap.put(clazz, new Stats());
}
if (!this.statsMap.containsKey(Object.class)) {
this.statsMap.put(Object.class, new Stats());
}
}
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
this.stopWatchHolder.set(new StopWatchHolder(stopWatch, message.getPayload().getClass()));
return super.preSend(message, channel);
}
@Override
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
StopWatchHolder holder = this.stopWatchHolder.get();
if (holder != null) {
holder.getStopWatch().stop();
}
Stats stats = this.statsMap.get(holder.getType());
if (stats == null) {
stats = this.statsMap.get(Object.class);
}
stats.add(holder.getStopWatch().getLastTaskTimeMillis());
}
@ManagedOperation
public String[] getSummary() {
String[] data = new String[this.statsMap.size()];
int i = 0;
for (Entry<Class<?>, Stats> entry : this.statsMap.entrySet()) {
data[i++] = entry.getKey().getName() + " " + entry.getValue().toString();
}
return data;
}
@ManagedOperation
public long getCount(String className) throws Exception {
return this.statsMap.get(Class.forName(className)).getCount();
}
@ManagedOperation
public long getLastTime(String className) throws Exception {
return this.statsMap.get(Class.forName(className)).getLastTime();
}
@ManagedOperation
public float getAverage(String className) throws Exception {
return this.statsMap.get(Class.forName(className)).getAverage();
}
private class StopWatchHolder {
private final StopWatch stopWatch;
private final Class<?> type;
/**
* @param stopWatch
* @param type
*/
public StopWatchHolder(StopWatch stopWatch, Class<?> type) {
this.stopWatch = stopWatch;
this.type = type;
}
public StopWatch getStopWatch() {
return stopWatch;
}
public Class<?> getType() {
return type;
}
}
private class Stats {
private long count;
private long totalTime;
private float average;
private long lastTime;
public long getCount() {
return count;
}
public long getLastTime() {
return lastTime;
}
public float getAverage() {
return average;
}
public synchronized void add(long time) {
this.count++;
this.lastTime = time;
this.totalTime += time;
this.average = (float) this.totalTime / (float) this.count;
}
@Override
public String toString() {
return "Stats [count=" + count + ", average=" + average + ", lastTime=" + lastTime + "]";
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2002-2012 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.springintegration.service.impl;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.model.TwitterMessage;
import org.springframework.integration.service.TwitterService;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.support.MetricType;
import org.springframework.stereotype.Service;
/**
* Implementation of the TwitterService interface.
* In the org.springintegration package because SI excludes all org.springframework.integration.*
* classes from MBean export.
*/
@Service
@ManagedResource
public class DefaultTwitterService implements TwitterService {
/** Holds a collection of polled Twitter messages */
private Map<Long, TwitterMessage> twitterMessages;
@Autowired
private MessageChannel controlBusChannel;
private long totalTweets;
@Autowired(required=false)
@Qualifier("dummyTwitter")
private SourcePollingChannelAdapter dummyTwitter;
@Autowired(required=false)
private IntegrationMBeanExporter exporter;
/**
* Constructor that initializes the 'twitterMessages' Map as a simple LRU
* cache. @See http://blogs.oracle.com/swinger/entry/collections_trick_i_lru_cache
*/
public DefaultTwitterService() {
twitterMessages = new LinkedHashMap<Long, TwitterMessage>( 10, 0.75f, true ) {
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry( java.util.Map.Entry<Long, TwitterMessage> entry ) {
return size() > 10;
}
};
}
/**
* @return the totalTweets
*/
@ManagedMetric(metricType=MetricType.COUNTER)
public long getTotalTweets() {
return totalTweets;
}
/** {@inheritDoc} */
@Override
public Collection<TwitterMessage> getTwitterMessages() {
return twitterMessages.values();
}
/** {@inheritDoc} */
@Override
public void startTwitterAdapter() {
Message<String> operation = MessageBuilder.withPayload("@twitter.start()").build();
this.controlBusChannel.send(operation);
if (this.dummyTwitter != null) {
this.controlBusChannel.send(MessageBuilder.withPayload("@dummyTwitter.start()").build());
}
}
/** {@inheritDoc} */
@Override
public void stopTwitterAdapter() {
Message<String> operation = MessageBuilder.withPayload("@twitter.stop()").build();
this.controlBusChannel.send(operation);
if (this.dummyTwitter != null) {
this.controlBusChannel.send(MessageBuilder.withPayload("@dummyTwitter.stop()").build());
}
}
@Override
public void shutdown() {
Message<String> operation = MessageBuilder.withPayload("@integrationMBeanExporter.stopActiveComponents(false, 20000)").build();
if (this.exporter != null) {
this.controlBusChannel.send(operation);
}
}
/**
* Called by Spring Integration to populate a simple LRU cache.
*
* @param tweet - The Spring Integration tweet object.
* @throws InterruptedException
*/
public void addTwitterMessages(Tweet tweet) throws Exception {
if ("SomeUser".equals(tweet.getFromUser())) {
Thread.sleep(2000);
}
this.totalTweets++;
this.twitterMessages.put(tweet.getCreatedAt().getTime(), new TwitterMessage(tweet.getCreatedAt(),
tweet.getText(),
tweet.getFromUser(),
tweet.getProfileImageUrl()));
}
}

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-twitter="http://www.springframework.org/schema/integration/twitter"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int-jmx="http://www.springframework.org/schema/integration/jmx"
xmlns:int-groovy="http://www.springframework.org/schema/integration/groovy"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jmx http://www.springframework.org/schema/integration/jmx/spring-integration-jmx.xsd
http://www.springframework.org/schema/integration/groovy http://www.springframework.org/schema/integration/groovy/spring-integration-groovy-2.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
<int-jmx:mbean-export id="integrationMBeanExporter" default-domain="spring.application"/>
<context:mbean-export default-domain="spring.application"/>
<int:message-history/>
<context:component-scan base-package="org.springframework.integration.service" />
<int-twitter:search-inbound-channel-adapter id="twitter" query="#springintegration"
channel="twitterChannel" auto-startup="true">
<int:poller fixed-rate="30000" max-messages-per-poll="10" />
</int-twitter:search-inbound-channel-adapter>
<int:inbound-channel-adapter id="dummyAdapter" channel="twitterChannel" method="getTweet">
<bean class="org.springframework.integration.service.impl.DummyTwitter"/>
<int:poller fixed-delay="5000"/>
</int:inbound-channel-adapter>
<int:header-enricher id="addFooHeader" input-channel="twitterChannel" output-channel="twitterChannel2">
<int:correlation-id value="foo"/>
</int:header-enricher>
<int:transformer id="noopButSlowTransformer" input-channel="twitterChannel2" output-channel="twitterChannel3">
<int-groovy:script>
Thread.sleep(1000)
payload
</int-groovy:script>
</int:transformer>
<int:service-activator id="twitterServiceActivator" input-channel="twitterChannel3"
ref="twitterService" method="addTwitterMessages" />
<bean id="twitterService" class="org.springintegration.service.impl.DefaultTwitterService"/>
<int:channel id="twitterChannel">
<int:interceptors>
<int:wire-tap channel="logger" />
<bean class="org.springintegration.PayloadAwareTimingInterceptor">
<constructor-arg>
<array>
<value>java.lang.String</value>
<value>org.springframework.social.twitter.api.Tweet</value>
</array>
</constructor-arg>
</bean>
</int:interceptors>
</int:channel>
<int:publish-subscribe-channel id="logger" />
<int:logging-channel-adapter id="loggingAdapter" channel="logger" level="INFO"
expression="'Id:' + payload.id + '; Date:' + payload.createdAt + '; FromUser: ' + payload.fromUser" />
<int:bridge input-channel="logger" output-channel="queue"/>
<int:channel id="queue">
<int:queue/>
</int:channel>
<int:channel id="controlBusChannel"/>
<int:control-bus id="controlBus" input-channel="controlBusChannel"/>
</beans>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scans within the base package of the application for @Components to configure as beans -->
<context:component-scan base-package="org.springframework.integration.mvc.controller" />
<!-- <mvc:default-servlet-handler /> -->
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<mvc:annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/css directory -->
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/js/**" location="/js/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
</beans>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p [%.10t][%.10c] %m%n" />
</layout>
</appender>
<!-- Loggers -->
<logger name="org.springframework">
<level value="warn" />
</logger>
<logger name="org.springframework.integration">
<level value="info" />
</logger>
<logger name="org.springframework.integration.mvc.controller">
<level value="warn" />
</logger>
<logger name="org.springframework.integration.samples">
<level value="info" />
</logger>
<!-- Root Logger -->
<root>
<priority value="warn" />
<appender-ref ref="console" />
</root>
</log4j:configuration>

View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path:

View File

@@ -0,0 +1,76 @@
<%@ include file="/WEB-INF/views/includes/taglibs.jsp"%>
<!DOCTYPE HTML>
<html>
<head>
<title>Welcome to Spring Integration</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="<c:url value='/css/blueprint/screen.css'/>" type="text/css" media="screen, projection">
<link rel="stylesheet" href="<c:url value='/css/blueprint/print.css'/>" type="text/css" media="print">
<!--[if lt IE 8]>
<link rel="stylesheet" href="/css/blueprint/ie.css" type="text/css" media="screen, projection">
<![endif]-->
<link rel="stylesheet" href="<c:url value='/css/main.css'/>" type="text/css">
<script src="<c:url value='/js/jquery-1.6.1.min.js'/>"></script>
<script src="<c:url value='/js/jquery.periodicalupdater.js'/>"></script>
</head>
<body>
<div class="container">
<div id="header" class="prepend-1 span-22 append-1 last">
<h1 class="loud">
Welcome to Spring Integration
</h1>
<div>
<form:form id="formId">
<input id="startTwitter" type="submit" name="startTwitter" value="Start Twitter Search" /> |
<input id="stopTwitter" type="submit" name="stopTwitter" value="Stop Twitter Search" /> |
<input id="shutdown" type="submit" name="shutdown" value="Shutdown Integration Flow" />
</form:form>
</div>
</div>
<div id="content" class="prepend-1 span-22 append-1 prepend-top last">
<%@ include file="/WEB-INF/views/twitterMessages.jsp"%>
</div>
</div>
<script type="text/javascript">
$.PeriodicalUpdater('<c:url value="/ajax"/>', {
method: 'get', // method; get or post
data: '', // array of values to be passed to the page - e.g. {name: "John", greeting: "hello"}
minTimeout: 5000, // starting value for the timeout in milliseconds
maxTimeout: 20000, // maximum length of time between requests
multiplier: 2, // the amount to expand the timeout by if the response hasn't changed (up to maxTimeout)
type: 'text', // response type - text, xml, json, etc. See $.ajax config options
maxCalls: 0, // maximum number of calls. 0 = no limit.
autoStop: 0 // automatically stop requests after this many returns of the same data. 0 = disabled.
}, function(remoteData, success, xhr, handle) {
$('#content').html(remoteData);
});
$(function() {
$('#startTwitter').bind('click', function() {
$.post("<c:url value='/'/>", "startTwitter=startTwitter");
return false;
});
$('#stopTwitter').bind('click', function() {
$.post("<c:url value='/'/>", "stopTwitter=stopTwitter");
return false;
});
$('#shutdown').bind('click', function() {
$.post("<c:url value='/'/>", "shutdown=shutdown");
return false;
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,13 @@
<%@page language="java" pageEncoding="UTF-8" contentType="text/html;charset=utf-8"%>
<%
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
response.setHeader("Expires","0");
%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="ctx" value="${pageContext['request'].contextPath}"/>

View File

@@ -0,0 +1,17 @@
<%@ include file="/WEB-INF/views/includes/taglibs.jsp"%>
<p>This example searches Twitter and shows the results below.</p>
<ul class="twitterMessages">
<c:choose>
<c:when test="${not empty twitterMessages}">
<c:forEach items="${twitterMessages}" var="twitterMessage">
<li>
<img alt="${twitterMessage.fromUser}"
title="${twitterMessage.fromUser}"
src="${twitterMessage.profileImageUrl}"
width="48" height="48">
<c:out value="${twitterMessage.text}"/></li>
</c:forEach>
</c:when>
<c:otherwise>No Twitter messages found. Did you start the search?</c:otherwise>
</c:choose>
</ul>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/integration/spring-integration-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/mvc/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@@ -0,0 +1,36 @@
/* -----------------------------------------------------------------------
Blueprint CSS Framework 1.0.1
http://blueprintcss.org
* Copyright (c) 2007-Present. See LICENSE for more info.
* See README for instructions on how to use Blueprint.
* For credits and origins, see AUTHORS.
* This is a compressed file. See the sources in the 'src' directory.
----------------------------------------------------------------------- */
/* ie.css */
body {text-align:center;}
.container {text-align:left;}
* html .column, * html .span-1, * html .span-2, * html .span-3, * html .span-4, * html .span-5, * html .span-6, * html .span-7, * html .span-8, * html .span-9, * html .span-10, * html .span-11, * html .span-12, * html .span-13, * html .span-14, * html .span-15, * html .span-16, * html .span-17, * html .span-18, * html .span-19, * html .span-20, * html .span-21, * html .span-22, * html .span-23, * html .span-24 {display:inline;overflow-x:hidden;}
* html legend {margin:0px -8px 16px 0;padding:0;}
sup {vertical-align:text-top;}
sub {vertical-align:text-bottom;}
html>body p code {*white-space:normal;}
hr {margin:-8px auto 11px;}
img {-ms-interpolation-mode:bicubic;}
.clearfix, .container {display:inline-block;}
* html .clearfix, * html .container {height:1%;}
fieldset {padding-top:0;}
legend {margin-top:-0.2em;margin-bottom:1em;margin-left:-0.5em;}
textarea {overflow:auto;}
label {vertical-align:middle;position:relative;top:-0.25em;}
input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;}
input.text:focus, input.title:focus {border-color:#666;}
input.text, input.title, textarea, select {margin:0.5em 0;}
input.checkbox, input.radio {position:relative;top:.25em;}
form.inline div, form.inline p {vertical-align:middle;}
form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;}
button, input.button {position:relative;top:0.25em;}

View File

@@ -0,0 +1,29 @@
/* -----------------------------------------------------------------------
Blueprint CSS Framework 1.0.1
http://blueprintcss.org
* Copyright (c) 2007-Present. See LICENSE for more info.
* See README for instructions on how to use Blueprint.
* For credits and origins, see AUTHORS.
* This is a compressed file. See the sources in the 'src' directory.
----------------------------------------------------------------------- */
/* print.css */
body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;}
.container {background:none;}
hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;}
hr.space {background:#fff;color:#fff;visibility:hidden;}
h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;}
code {font:.9em "Courier New", Monaco, Courier, monospace;}
a img {border:none;}
p img.top {margin-top:0;}
blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;}
.small {font-size:.9em;}
.large {font-size:1.1em;}
.quiet {color:#999;}
.hide {display:none;}
a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;}
a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;}

View File

@@ -0,0 +1,265 @@
/* -----------------------------------------------------------------------
Blueprint CSS Framework 1.0.1
http://blueprintcss.org
* Copyright (c) 2007-Present. See LICENSE for more info.
* See README for instructions on how to use Blueprint.
* For credits and origins, see AUTHORS.
* This is a compressed file. See the sources in the 'src' directory.
----------------------------------------------------------------------- */
/* reset.css */
html {margin:0;padding:0;border:0;}
body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;}
article, aside, details, figcaption, figure, dialog, footer, header, hgroup, menu, nav, section {display:block;}
body {line-height:1.5;background:white;}
table {border-collapse:separate;border-spacing:0;}
caption, th, td {text-align:left;font-weight:normal;float:none !important;}
table, th, td {vertical-align:middle;}
blockquote:before, blockquote:after, q:before, q:after {content:'';}
blockquote, q {quotes:"" "";}
a img {border:none;}
:focus {outline:0;}
/* typography.css */
html {font-size:100.01%;}
body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
h1 {font-size:3em;line-height:1;margin-bottom:0.5em;}
h2 {font-size:2em;margin-bottom:0.75em;}
h3 {font-size:1.5em;line-height:1;margin-bottom:1em;}
h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
h6 {font-size:1em;font-weight:bold;}
h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
p {margin:0 0 1.5em;}
.left {float:left !important;}
p .left {margin:1.5em 1.5em 1.5em 0;padding:0;}
.right {float:right !important;}
p .right {margin:1.5em 0 1.5em 1.5em;padding:0;}
a:focus, a:hover {color:#09f;}
a {color:#06c;text-decoration:underline;}
blockquote {margin:1.5em;color:#666;font-style:italic;}
strong, dfn {font-weight:bold;}
em, dfn {font-style:italic;}
sup, sub {line-height:0;}
abbr, acronym {border-bottom:1px dotted #666;}
address {margin:0 0 1.5em;font-style:italic;}
del {color:#666;}
pre {margin:1.5em 0;white-space:pre;}
pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
li ul, li ol {margin:0;}
ul, ol {margin:0 1.5em 1.5em 0;padding-left:1.5em;}
ul {list-style-type:disc;}
ol {list-style-type:decimal;}
dl {margin:0 0 1.5em 0;}
dl dt {font-weight:bold;}
dd {margin-left:1.5em;}
table {margin-bottom:1.4em;width:100%;}
th {font-weight:bold;}
thead th {background:#c3d9ff;}
th, td, caption {padding:4px 10px 4px 5px;}
tbody tr:nth-child(even) td, tbody tr.even td {background:#e5ecf9;}
tfoot {font-style:italic;}
caption {background:#eee;}
.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
.hide {display:none;}
.quiet {color:#666;}
.loud {color:#000;}
.highlight {background:#ff0;}
.added {background:#060;color:#fff;}
.removed {background:#900;color:#fff;}
.first {margin-left:0;padding-left:0;}
.last {margin-right:0;padding-right:0;}
.top {margin-top:0;padding-top:0;}
.bottom {margin-bottom:0;padding-bottom:0;}
/* forms.css */
label {font-weight:bold;}
fieldset {padding:0 1.4em 1.4em 1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;}
legend {font-weight:bold;font-size:1.2em;margin-top:-0.2em;margin-bottom:1em;}
fieldset, #IE8#HACK {padding-top:1.4em;}
legend, #IE8#HACK {margin-top:0;margin-bottom:0;}
input[type=text], input[type=password], input[type=url], input[type=email], input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;color:#000;}
input[type=text]:focus, input[type=password]:focus, input[type=url]:focus, input[type=email]:focus, input.text:focus, input.title:focus, textarea:focus {border-color:#666;}
select {background-color:#fff;border-width:1px;border-style:solid;}
input[type=text], input[type=password], input[type=url], input[type=email], input.text, input.title, textarea, select {margin:0.5em 0;}
input.text, input.title {width:300px;padding:5px;}
input.title {font-size:1.5em;}
textarea {width:390px;height:250px;padding:5px;}
form.inline {line-height:3;}
form.inline p {margin-bottom:0;}
.error, .alert, .notice, .success, .info {padding:0.8em;margin-bottom:1em;border:2px solid #ddd;}
.error, .alert {background:#fbe3e4;color:#8a1f11;border-color:#fbc2c4;}
.notice {background:#fff6bf;color:#514721;border-color:#ffd324;}
.success {background:#e6efc2;color:#264409;border-color:#c6d880;}
.info {background:#d5edf8;color:#205791;border-color:#92cae4;}
.error a, .alert a {color:#8a1f11;}
.notice a {color:#514721;}
.success a {color:#264409;}
.info a {color:#205791;}
/* grid.css */
.container {width:950px;margin:0 auto;}
.showgrid {background:url(src/grid.png);}
.column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 {float:left;margin-right:10px;}
.last {margin-right:0;}
.span-1 {width:30px;}
.span-2 {width:70px;}
.span-3 {width:110px;}
.span-4 {width:150px;}
.span-5 {width:190px;}
.span-6 {width:230px;}
.span-7 {width:270px;}
.span-8 {width:310px;}
.span-9 {width:350px;}
.span-10 {width:390px;}
.span-11 {width:430px;}
.span-12 {width:470px;}
.span-13 {width:510px;}
.span-14 {width:550px;}
.span-15 {width:590px;}
.span-16 {width:630px;}
.span-17 {width:670px;}
.span-18 {width:710px;}
.span-19 {width:750px;}
.span-20 {width:790px;}
.span-21 {width:830px;}
.span-22 {width:870px;}
.span-23 {width:910px;}
.span-24 {width:950px;margin-right:0;}
input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px;border-right-width:1px;padding-left:5px;padding-right:5px;}
input.span-1, textarea.span-1 {width:18px;}
input.span-2, textarea.span-2 {width:58px;}
input.span-3, textarea.span-3 {width:98px;}
input.span-4, textarea.span-4 {width:138px;}
input.span-5, textarea.span-5 {width:178px;}
input.span-6, textarea.span-6 {width:218px;}
input.span-7, textarea.span-7 {width:258px;}
input.span-8, textarea.span-8 {width:298px;}
input.span-9, textarea.span-9 {width:338px;}
input.span-10, textarea.span-10 {width:378px;}
input.span-11, textarea.span-11 {width:418px;}
input.span-12, textarea.span-12 {width:458px;}
input.span-13, textarea.span-13 {width:498px;}
input.span-14, textarea.span-14 {width:538px;}
input.span-15, textarea.span-15 {width:578px;}
input.span-16, textarea.span-16 {width:618px;}
input.span-17, textarea.span-17 {width:658px;}
input.span-18, textarea.span-18 {width:698px;}
input.span-19, textarea.span-19 {width:738px;}
input.span-20, textarea.span-20 {width:778px;}
input.span-21, textarea.span-21 {width:818px;}
input.span-22, textarea.span-22 {width:858px;}
input.span-23, textarea.span-23 {width:898px;}
input.span-24, textarea.span-24 {width:938px;}
.append-1 {padding-right:40px;}
.append-2 {padding-right:80px;}
.append-3 {padding-right:120px;}
.append-4 {padding-right:160px;}
.append-5 {padding-right:200px;}
.append-6 {padding-right:240px;}
.append-7 {padding-right:280px;}
.append-8 {padding-right:320px;}
.append-9 {padding-right:360px;}
.append-10 {padding-right:400px;}
.append-11 {padding-right:440px;}
.append-12 {padding-right:480px;}
.append-13 {padding-right:520px;}
.append-14 {padding-right:560px;}
.append-15 {padding-right:600px;}
.append-16 {padding-right:640px;}
.append-17 {padding-right:680px;}
.append-18 {padding-right:720px;}
.append-19 {padding-right:760px;}
.append-20 {padding-right:800px;}
.append-21 {padding-right:840px;}
.append-22 {padding-right:880px;}
.append-23 {padding-right:920px;}
.prepend-1 {padding-left:40px;}
.prepend-2 {padding-left:80px;}
.prepend-3 {padding-left:120px;}
.prepend-4 {padding-left:160px;}
.prepend-5 {padding-left:200px;}
.prepend-6 {padding-left:240px;}
.prepend-7 {padding-left:280px;}
.prepend-8 {padding-left:320px;}
.prepend-9 {padding-left:360px;}
.prepend-10 {padding-left:400px;}
.prepend-11 {padding-left:440px;}
.prepend-12 {padding-left:480px;}
.prepend-13 {padding-left:520px;}
.prepend-14 {padding-left:560px;}
.prepend-15 {padding-left:600px;}
.prepend-16 {padding-left:640px;}
.prepend-17 {padding-left:680px;}
.prepend-18 {padding-left:720px;}
.prepend-19 {padding-left:760px;}
.prepend-20 {padding-left:800px;}
.prepend-21 {padding-left:840px;}
.prepend-22 {padding-left:880px;}
.prepend-23 {padding-left:920px;}
.border {padding-right:4px;margin-right:5px;border-right:1px solid #ddd;}
.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #ddd;}
.pull-1 {margin-left:-40px;}
.pull-2 {margin-left:-80px;}
.pull-3 {margin-left:-120px;}
.pull-4 {margin-left:-160px;}
.pull-5 {margin-left:-200px;}
.pull-6 {margin-left:-240px;}
.pull-7 {margin-left:-280px;}
.pull-8 {margin-left:-320px;}
.pull-9 {margin-left:-360px;}
.pull-10 {margin-left:-400px;}
.pull-11 {margin-left:-440px;}
.pull-12 {margin-left:-480px;}
.pull-13 {margin-left:-520px;}
.pull-14 {margin-left:-560px;}
.pull-15 {margin-left:-600px;}
.pull-16 {margin-left:-640px;}
.pull-17 {margin-left:-680px;}
.pull-18 {margin-left:-720px;}
.pull-19 {margin-left:-760px;}
.pull-20 {margin-left:-800px;}
.pull-21 {margin-left:-840px;}
.pull-22 {margin-left:-880px;}
.pull-23 {margin-left:-920px;}
.pull-24 {margin-left:-960px;}
.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;}
.push-1 {margin:0 -40px 1.5em 40px;}
.push-2 {margin:0 -80px 1.5em 80px;}
.push-3 {margin:0 -120px 1.5em 120px;}
.push-4 {margin:0 -160px 1.5em 160px;}
.push-5 {margin:0 -200px 1.5em 200px;}
.push-6 {margin:0 -240px 1.5em 240px;}
.push-7 {margin:0 -280px 1.5em 280px;}
.push-8 {margin:0 -320px 1.5em 320px;}
.push-9 {margin:0 -360px 1.5em 360px;}
.push-10 {margin:0 -400px 1.5em 400px;}
.push-11 {margin:0 -440px 1.5em 440px;}
.push-12 {margin:0 -480px 1.5em 480px;}
.push-13 {margin:0 -520px 1.5em 520px;}
.push-14 {margin:0 -560px 1.5em 560px;}
.push-15 {margin:0 -600px 1.5em 600px;}
.push-16 {margin:0 -640px 1.5em 640px;}
.push-17 {margin:0 -680px 1.5em 680px;}
.push-18 {margin:0 -720px 1.5em 720px;}
.push-19 {margin:0 -760px 1.5em 760px;}
.push-20 {margin:0 -800px 1.5em 800px;}
.push-21 {margin:0 -840px 1.5em 840px;}
.push-22 {margin:0 -880px 1.5em 880px;}
.push-23 {margin:0 -920px 1.5em 920px;}
.push-24 {margin:0 -960px 1.5em 960px;}
.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:left;position:relative;}
div.prepend-top, .prepend-top {margin-top:1.5em;}
div.append-bottom, .append-bottom {margin-bottom:1.5em;}
.box {padding:1.5em;margin-bottom:1.5em;background:#e5eCf9;}
hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:1px;margin:0 0 17px;border:none;}
hr.space {background:#fff;color:#fff;visibility:hidden;}
.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
.clearfix, .container {display:block;}
.clear {clear:both;}

View File

@@ -0,0 +1,21 @@
.container {
border: 1px solid #728C16;
margin-top: 1.5em;
}
#header {
background-color: #EEEEEE;
}
.twitterMessages {
list-style: none;
}
.twitterMessages img {
vertical-align: middle;
}
.twitterMessages li {
padding-top: 2px;
padding-bottom: 2px;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,175 @@
/**
* PeriodicalUpdater - jQuery plugin for timed, decaying ajax calls
*
* http://www.360innovate.co.uk/blog/2009/03/periodicalupdater-for-jquery/
* http://enfranchisedmind.com/blog/posts/jquery-periodicalupdater-ajax-polling/
*
* Copyright (c) 2009 by the following:
* Frank White (http://customcode.info)
* Robert Fischer (http://smokejumperit.com)
* 360innovate (http://www.360innovate.co.uk)
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
(function($) {
var pu_log = function(msg) {
try {
console.log(msg);
} catch(err) {}
}
// Now back to our regularly scheduled work
$.PeriodicalUpdater = function(url, options, callback, autoStopCallback){
var settings = jQuery.extend(true, {
url: url, // URL of ajax request
cache: false, // By default, don't allow caching
method: 'GET', // method; get or post
data: '', // array of values to be passed to the page - e.g. {name: "John", greeting: "hello"}
minTimeout: 1000, // starting value for the timeout in milliseconds
maxTimeout: 8000, // maximum length of time between requests
multiplier: 2, // if set to 2, timerInterval will double each time the response hasn't changed (up to maxTimeout)
maxCalls: 0, // maximum number of calls. 0 = no limit.
autoStop: 0 // automatically stop requests after this many returns of the same data. 0 = disabled
}, options);
// set some initial values, then begin
var timer = null;
var timerInterval = settings.minTimeout;
var maxCalls = settings.maxCalls;
var autoStop = settings.autoStop;
var calls = 0;
var noChange = 0;
var originalMaxCalls = maxCalls;
var reset_timer = function(interval) {
if (timer != null) {
clearTimeout(timer);
}
timerInterval = interval;
pu_log('resetting timer to '+ timerInterval +'.');
timer = setTimeout(getdata, timerInterval);
}
// Function to boost the timer
var boostPeriod = function() {
if(settings.multiplier >= 1) {
before = timerInterval;
timerInterval = timerInterval * settings.multiplier;
if(timerInterval > settings.maxTimeout) {
timerInterval = settings.maxTimeout;
}
after = timerInterval;
pu_log('adjusting timer from '+ before +' to '+ after +'.');
reset_timer(timerInterval);
}
};
// Construct the settings for $.ajax based on settings
var ajaxSettings = jQuery.extend(true, {}, settings);
if(settings.type && !ajaxSettings.dataType) ajaxSettings.dataType = settings.type;
if(settings.sendData) ajaxSettings.data = settings.sendData;
ajaxSettings.type = settings.method; // 'type' is used internally for jQuery. Who knew?
ajaxSettings.ifModified = true;
var handle = {
restart: function() {
maxCalls = originalMaxCalls;
calls = 0;
reset_timer(timerInterval);
return;
},
stop: function() {
maxCalls = -1;
return;
}
};
// Create the function to get data
// TODO It'd be nice to do the options.data check once (a la boostPeriod)
function getdata() {
var toSend = jQuery.extend(true, {}, ajaxSettings); // jQuery screws with what you pass in
if(typeof(options.data) == 'function') {
toSend.data = options.data();
if(toSend.data) {
// Handle transformations (only strings and objects are understood)
if(typeof(toSend.data) == "number") {
toSend.data = toSend.data.toString();
}
}
}
if(maxCalls == 0) {
$.ajax(toSend);
} else if(maxCalls > 0 && calls < maxCalls) {
$.ajax(toSend);
calls++;
}
}
// Implement the tricky behind logic
var remoteData = null;
var prevData = null;
ajaxSettings.success = function(data) {
pu_log("Successful run! (In 'success')");
remoteData = data;
// timerInterval = settings.minTimeout;
};
ajaxSettings.complete = function(xhr, success) {
//pu_log("Status of call: " + success + " (In 'complete')");
if(maxCalls == -1) return;
if(success == "success" || success == "notmodified") {
var rawData = $.trim(xhr.responseText);
if(rawData == 'STOP_AJAX_CALLS') {
handle.stop();
return;
}
if(prevData == rawData) {
if(autoStop > 0) {
noChange++;
if(noChange == autoStop) {
handle.stop();
if(autoStopCallback) autoStopCallback(noChange);
return;
}
}
boostPeriod();
} else {
noChange = 0;
reset_timer(settings.minTimeout);
prevData = rawData;
if(remoteData == null) remoteData = rawData;
// jQuery 1.4+ $.ajax() automatically converts "data" into a JS Object for "type:json" requests now
// For compatibility with 1.4+ and pre1.4 jQuery only try to parse actual strings, skip when remoteData is already an Object
if((ajaxSettings.dataType === 'json') && (typeof(remoteData) === 'string') && (success == "success")) {
remoteData = JSON.parse(remoteData);
}
if(settings.success) { settings.success(remoteData, success, xhr, handle); }
if(callback) callback(remoteData, success, xhr, handle);
}
}
remoteData = null;
}
ajaxSettings.error = function (xhr, textStatus) {
//pu_log("Error message: " + textStatus + " (In 'error')");
if(textStatus != "notmodified") {
prevData = null;
reset_timer(settings.minTimeout);
}
if(settings.error) { settings.error(xhr, textStatus); }
};
// Make the first call
$(function() { reset_timer(timerInterval); });
return handle;
};
})(jQuery);

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2012 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;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Run this class to run the sample from the command line.
* @author Gary Russell
*/
public class SpringIntegrationTest {
public static void main(String[] args) throws Exception {
new ClassPathXmlApplicationContext("/META-INF/spring/integration/spring-integration-context.xml", SpringIntegrationTest.class);
System.out.println("Hit Enter to terminate");
System.in.read();
}
}