diff --git a/README.md b/README.md index 6eae87cc..985ad8ec 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ This is a good place to get started. The samples here are technically motivated This category targets developers who are already more familiar with the Spring Integration framework (past getting started), but need some more guidance while resolving more advanced technical problems that you have to deal with when switching to a Messaging architecture. For example, if you are looking for an answer on how to handle errors in various scenarios, or how to properly configure an **Aggregator** for the situations where some messages might not ever arrive for aggregation, or any other issue that goes beyond a basic understanding and configuration of a particular component to address "what else you can do?" types of problems, this would be the right place to find relevant examples. +* **dynamic-poller** - Example shows usage of a **Poller** with a custom **Trigger** to change polling periods at runtime * **async-gateway** - Example shows usage of an **Asynchronous Gateway** * **errorhandling** - Demonstrates basic **Error Handling** capabilities of Spring Integration * **file-processing** - Sample demonstrates how to wire a message flow to process files either sequentially (maintain the order) or concurrently (no order). diff --git a/intermediate/dynamic-poller/README.md b/intermediate/dynamic-poller/README.md new file mode 100644 index 00000000..e5dfe951 --- /dev/null +++ b/intermediate/dynamic-poller/README.md @@ -0,0 +1,36 @@ +Dynamic Poller Sample +===================== + +By default this application will (poll) print out the current system time every 5 seconds. From the command line you can enter a non-negative numeric value to change the polling period (in milliseconds) at runtime. + +Under the cover an **Inbound Channel Adapter** polls for the current system time. The **Poller** which is used by the **Inbound Channel Adapter** is configured with a custom trigger. The resulting message contains as payload the time in milliseconds and the message is sent to a **Logging Channel Adapter**, which will print the time to the command prompt. + +You can run the application by either + +* running the "Main" class from within STS (Right-click on Main class --> Run As --> Java Application) +* or from the command line using the [Exec Maven Plugin](http://mojo.codehaus.org/exec-maven-plugin/): + - mvn package exec:java + +You should see output like the following: + + INFO : org.springframework.integration.samples.poller.Main - + ========================================================== + + Welcome to the Spring Integration Dynamic Poller Sample! + + For more information please visit: + http://www.springsource.org/spring-integration + + ========================================================== + INFO : org.springframework.integration.samples.poller.Main - + ========================================================= + + Please press 'q + Enter' to quit the application. + + ========================================================= + Please enter a non-negative numeric value and press : INFO : org.springframework.integration.samples.poller - 1329257519165 + INFO : org.springframework.integration.samples.poller - 1329257524207 + INFO : org.springframework.integration.samples.poller - 1329257529208 + INFO : org.springframework.integration.samples.poller - 1329257534209 + INFO : org.springframework.integration.samples.poller - 1329257539210 + diff --git a/intermediate/dynamic-poller/pom.xml b/intermediate/dynamic-poller/pom.xml new file mode 100644 index 00000000..f998dfe1 --- /dev/null +++ b/intermediate/dynamic-poller/pom.xml @@ -0,0 +1,70 @@ + + 4.0.0 + + org.springframework.integration.samples + dynamic-poller + 2.1.0.BUILD-SNAPSHOT + jar + + dynamic-poller + http://www.springsource.org/spring-integration + + + UTF-8 + 2.1.0.RELEASE + 1.2.16 + 4.10 + org.springframework.integration.samples.poller.Main + + + + + org.springframework.integration + spring-integration-core + ${spring.integration.version} + + + log4j + log4j + ${log4j.version} + + + + junit + junit + ${junit.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.5 + 1.5 + -Xlint:all + true + true + + + + org.codehaus.mojo + exec-maven-plugin + 1.2 + + ${java.main.class} + + + + + + + repo.springsource.org.milestone + Spring Framework Maven Milestone Repository + https://repo.springsource.org/milestone + + + \ No newline at end of file diff --git a/intermediate/dynamic-poller/src/main/java/org/springframework/integration/samples/poller/DynamicPeriodicTrigger.java b/intermediate/dynamic-poller/src/main/java/org/springframework/integration/samples/poller/DynamicPeriodicTrigger.java new file mode 100644 index 00000000..b0ad47d1 --- /dev/null +++ b/intermediate/dynamic-poller/src/main/java/org/springframework/integration/samples/poller/DynamicPeriodicTrigger.java @@ -0,0 +1,140 @@ +/* + * 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.samples.poller; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.TriggerContext; +import org.springframework.scheduling.support.PeriodicTrigger; +import org.springframework.util.Assert; + + +/** + * This is a dynamically changeable {@link Trigger}. It is based on the + * {@link PeriodicTrigger} implementations. However, the fields of this dynamic + * trigger are not final and the properties can be inspected and set via + * explicit getters and setters. + * + * @author Gunnar Hillert + * + */ +public class DynamicPeriodicTrigger implements Trigger { + + private volatile long period; + + private volatile TimeUnit timeUnit; + + private volatile long initialDelay = 0; + + private volatile boolean fixedRate = false; + + /** + * Create a trigger with the given period in milliseconds. + */ + public DynamicPeriodicTrigger(long period) { + this(period, null); + } + + /** + * Create a trigger with the given period and time unit. The time unit will + * apply not only to the period but also to any 'initialDelay' value, if + * configured on this Trigger later via {@link #setInitialDelay(long)}. + */ + public DynamicPeriodicTrigger(long period, TimeUnit timeUnit) { + Assert.isTrue(period >= 0, "period must not be negative"); + this.timeUnit = (timeUnit != null) ? timeUnit : TimeUnit.MILLISECONDS; + this.period = this.timeUnit.toMillis(period); + } + + /** + * Specify the delay for the initial execution. It will be evaluated in + * terms of this trigger's {@link TimeUnit}. If no time unit was explicitly + * provided upon instantiation, the default is milliseconds. + */ + public void setInitialDelay(long initialDelay) { + this.initialDelay = this.timeUnit.toMillis(initialDelay); + } + + /** + * Specify whether the periodic interval should be measured between the + * scheduled start times rather than between actual completion times. + * The latter, "fixed delay" behavior, is the default. + */ + public void setFixedRate(boolean fixedRate) { + this.fixedRate = fixedRate; + } + + /** + * Returns the time after which a task should run again. + */ + public Date nextExecutionTime(TriggerContext triggerContext) { + if (triggerContext.lastScheduledExecutionTime() == null) { + return new Date(System.currentTimeMillis() + this.initialDelay); + } + else if (this.fixedRate) { + return new Date(triggerContext.lastScheduledExecutionTime().getTime() + this.period); + } + return new Date(triggerContext.lastCompletionTime().getTime() + this.period); + } + + public long getPeriod() { + return period; + } + + public void setPeriod(long period) { + this.period = period; + } + + public TimeUnit getTimeUnit() { + return timeUnit; + } + + public void setTimeUnit(TimeUnit timeUnit) { + this.timeUnit = timeUnit; + } + + public long getInitialDelay() { + return initialDelay; + } + + public boolean isFixedRate() { + return fixedRate; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof DynamicPeriodicTrigger)) { + return false; + } + DynamicPeriodicTrigger other = (DynamicPeriodicTrigger) obj; + return this.fixedRate == other.fixedRate + && this.initialDelay == other.initialDelay + && this.period == other.period; + } + + @Override + public int hashCode() { + return (this.fixedRate ? 14 : 41) + + (int) (38 * this.period) + + (int) (43 * this.initialDelay); + } + +} diff --git a/intermediate/dynamic-poller/src/main/java/org/springframework/integration/samples/poller/Main.java b/intermediate/dynamic-poller/src/main/java/org/springframework/integration/samples/poller/Main.java new file mode 100644 index 00000000..d4f5dd90 --- /dev/null +++ b/intermediate/dynamic-poller/src/main/java/org/springframework/integration/samples/poller/Main.java @@ -0,0 +1,86 @@ +/* + * 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.samples.poller; + +import java.util.Scanner; + +import org.apache.log4j.Logger; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Starts the Spring Context and will initialize the Spring Integration routes. + * + * @author Gunnar Hillert + * @version 1.0 + * + */ +public final class Main { + + private static final Logger LOGGER = Logger.getLogger(Main.class); + + private Main() { } + + /** + * Load the Spring Integration Application Context + * + * @param args - command line arguments + */ + public static void main(final String... args) { + + LOGGER.info("\n==========================================================" + + "\n " + + "\n Welcome to the Spring Integration Dynamic Poller Sample! " + + "\n " + + "\n For more information please visit: " + + "\n http://www.springsource.org/spring-integration " + + "\n " + + "\n==========================================================" ); + + final AbstractApplicationContext context = + new ClassPathXmlApplicationContext("classpath:META-INF/spring/integration/*-context.xml"); + + context.registerShutdownHook(); + + final Scanner scanner = new Scanner(System.in); + + final DynamicPeriodicTrigger trigger = context.getBean(DynamicPeriodicTrigger.class); + + LOGGER.info("\n=========================================================" + + "\n " + + "\n Please press 'q + Enter' to quit the application. " + + "\n " + + "\n=========================================================" ); + + System.out.print("Please enter a non-negative numeric value and press : "); + + while (!scanner.hasNext("q")) { + + int triggerPeriod = scanner.nextInt(); + + System.out.println(String.format("Setting trigger period to '%s' ms", triggerPeriod)); + + trigger.setPeriod(triggerPeriod); + + System.out.print("Please enter a non-negative numeric value and press : "); + } + + LOGGER.info("Exiting application...bye."); + + System.exit(0); + + } +} diff --git a/intermediate/dynamic-poller/src/main/resources/META-INF/spring/integration/spring-integration-context.xml b/intermediate/dynamic-poller/src/main/resources/META-INF/spring/integration/spring-integration-context.xml new file mode 100644 index 00000000..15431c3b --- /dev/null +++ b/intermediate/dynamic-poller/src/main/resources/META-INF/spring/integration/spring-integration-context.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/intermediate/dynamic-poller/src/main/resources/log4j.xml b/intermediate/dynamic-poller/src/main/resources/log4j.xml new file mode 100644 index 00000000..678b69b3 --- /dev/null +++ b/intermediate/dynamic-poller/src/main/resources/log4j.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file