initial commit

This commit is contained in:
markpollack
2010-06-29 22:16:39 -04:00
committed by Dave Syer
parent ff3fec90fd
commit 933acbe493
52 changed files with 2429 additions and 0 deletions

10
helloworld/.classpath Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

29
helloworld/.project Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-rabbit-helloworld</name>
<comment>a simple Hello World example</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.springframework.ide.eclipse.core.springnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>

20
helloworld/.springBeans Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[2.2.7.200909012107-CI-R3397-B453]]></pluginVersion>
<configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes>
<enableImports><![CDATA[true]]></enableImports>
<configs>
</configs>
<configSets>
<configSet>
<name><![CDATA[test]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
</configs>
</configSet>
</configSets>
</beansProjectDescription>

174
helloworld/pom.xml Normal file
View File

@@ -0,0 +1,174 @@
<?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>
<groupId>org.springframework.samples.spring</groupId>
<artifactId>spring-rabbit-helloworld</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring AMQP Hello World</name>
<url>http://www.springframework.org</url>
<description>
<![CDATA[
This project shows the usage of Spring AMQP integration classes.
]]>
</description>
<properties>
<maven.test.failure.ignore>true</maven.test.failure.ignore>
<spring.framework.version>3.0.3.RELEASE</spring.framework.version>
<spring.amqp.version>1.0.0.BUILD-SNAPSHOT</spring.amqp.version>
</properties>
<profiles>
<profile>
<id>strict</id>
<properties>
<maven.test.failure.ignore>false</maven.test.failure.ignore>
</properties>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-amqp-core</artifactId>
<version>${spring.amqp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>${spring.amqp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-admin</artifactId>
<version>${spring.amqp.version}</version>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.framework.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
<version>1.0.0.M1B</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<descriptorRefs>
<descriptorRef>project</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--forkMode>pertest</forkMode-->
<includes>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/Abstract*.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>Codehaus</id>
<url>http://repository.codehaus.org/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<distributionManagement>
<downloadUrl>http://www.springframework.org/download</downloadUrl>
<site>
<id>staging</id>
<url>file:///${user.dir}/target/staging/org.springframework.batch.archetype/${pom.artifactId}</url>
</site>
<repository>
<id>spring-release</id>
<name>Spring Release Repository</name>
<url>file:///${user.dir}/target/staging/release</url>
</repository>
<snapshotRepository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>file:///${user.dir}/target/staging/snapshot</url>
</snapshotRepository>
</distributionManagement>
</project>

View File

@@ -0,0 +1,19 @@
package org.springframework.amqp.helloworld;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Consumer {
public static void main(String[] args) {
//ApplicationContext ctx = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
ApplicationContext ctx = new AnnotationConfigApplicationContext(RabbitConfiguration.class);
RabbitTemplate rabbitTemplate = (RabbitTemplate) ctx.getBean(RabbitTemplate.class);
System.out.println("Received " + rabbitTemplate.receiveAndConvert());
}
}

View File

@@ -0,0 +1,20 @@
package org.springframework.amqp.helloworld;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConsumerConfiguration extends RabbitConfiguration {
@Bean
public SimpleMessageListenerContainer listenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.setQueueName(helloWorldQueue.getName());
container.setMessageListener(new MessageListenerAdapter(new HelloWorldHandler()));
return container;
}
}

View File

@@ -0,0 +1,8 @@
package org.springframework.amqp.helloworld;
public class HelloWorldHandler {
public void handleMessage(String text) {
System.out.println("Received: " + text);
}
}

View File

@@ -0,0 +1,21 @@
package org.springframework.amqp.helloworld;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Producer {
/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(RabbitConfiguration.class);
RabbitTemplate rabbitTemplate = (RabbitTemplate) ctx.getBean(RabbitTemplate.class);
rabbitTemplate.convertAndSend("Hello World");
System.out.println("Sent Hello World.");
}
}

View File

@@ -0,0 +1,89 @@
package org.springframework.amqp.helloworld;
import javax.annotation.PostConstruct;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.admin.config.AbstractRabbitConfiguration;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfiguration extends AbstractRabbitConfiguration {
protected Queue helloWorldQueue = new Queue("hello.world.queue");
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
return connectionFactory;
}
@Override
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
//The routing key is set to the name of the queue by the broker for the default exchange.
template.setDefaultRoutingKey(helloWorldQueue.getName());
//Where we will synchronously receive messages from
template.setDefaultReceiveQueue(helloWorldQueue);
return template;
}
@PostConstruct
private void configureBroker() {
declare(helloWorldQueue);
}
/*
@Bean
public Queue helloWorldQueue()
{
return declare(helloWorldQueue);
}*/
/*
//Each queue is bound to the default direct exchange
@Bean
public Binding binding() {
return declare(new Binding(helloWorldQueue(), defaultDirectExchange()));
}*/
/*
@Bean
public TopicExchange helloExchange() {
return declare(new TopicExchange("hello.world.exchange"));
}*/
/*
public Queue declareUniqueQueue(String namePrefix) {
Queue queue = new Queue(namePrefix + "-" + UUID.randomUUID());
rabbitAdminTemplate().declareQueue(queue);
return queue;
}
// if the default exchange isn't configured to your liking....
@Bean Binding declareP2PBinding(Queue queue, DirectExchange exchange) {
return declare(new Binding(queue, exchange, queue.getName()));
}
@Bean Binding declarePubSubBinding(String queuePrefix, FanoutExchange exchange) {
return declare(new Binding(declareUniqueQueue(queuePrefix), exchange));
}
@Bean Binding declarePubSubBinding(UniqueQueue uniqueQueue, TopicExchange exchange) {
return declare(new Binding(uniqueQueue, exchange));
}
@Bean Binding declarePubSubBinding(String queuePrefix, TopicExchange exchange, String routingKey) {
return declare(new Binding(declareUniqueQueue(queuePrefix), exchange, routingKey));
}*/
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Spring Batch: ${project.name}">
<bannerLeft>
<name>Spring Batch: ${project.name}</name>
<href>index.html</href>
</bannerLeft>
<skin>
<groupId>org.springframework.maven.skins</groupId>
<artifactId>maven-spring-skin</artifactId>
<version>1.0.5</version>
</skin>
<body>
<links>
<item name="${project.name}" href="index.html"/>
</links>
<menu ref="reports"/>
</body>
</project>

View File

@@ -0,0 +1,7 @@
# Use Log4j
priority=1
org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
# Configuration file of the log
#log4j.configuration=file:log4j-rabbit-stocks.properties

View File

@@ -0,0 +1,11 @@
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.appender.stdout.layout.ConversionPattern=%-5p [%40.40c{4}]: %m%n
log4j.category.org.springframework.amqp.rabbit=DEBUG
log4j.category.org.springframework.beans.factory=INFO

10
stocks/.classpath Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

29
stocks/.project Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-rabbit-stocks</name>
<comment>sample of a basic trading app using RabbitMQ</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.springframework.ide.eclipse.core.springnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>

185
stocks/pom.xml Normal file
View File

@@ -0,0 +1,185 @@
<?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>
<groupId>org.springframework.samples.spring</groupId>
<artifactId>spring-rabbit-stocks</artifactId>
<version>1.0.0.CI-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring Rabbit Stocks</name>
<url>http://www.springframework.org</url>
<description>
<![CDATA[
This project shows the usage of Spring Rabbit integration classes.
]]>
</description>
<properties>
<maven.test.failure.ignore>true</maven.test.failure.ignore>
<spring.framework.version>3.0.3.RELEASE</spring.framework.version>
<spring.amqp.version>1.0.0.BUILD-SNAPSHOT</spring.amqp.version>
</properties>
<profiles>
<profile>
<id>strict</id>
<properties>
<maven.test.failure.ignore>false</maven.test.failure.ignore>
</properties>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-amqp-core</artifactId>
<version>${spring.amqp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>${spring.amqp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-admin</artifactId>
<version>${spring.amqp.version}</version>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.framework.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.jgoodies</groupId>
<artifactId>forms</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
<version>1.0.0.M1B</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<descriptorRefs>
<descriptorRef>project</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--forkMode>pertest</forkMode-->
<includes>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/Abstract*.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>Codehaus</id>
<url>http://repository.codehaus.org/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<distributionManagement>
<downloadUrl>http://www.springframework.org/download</downloadUrl>
<site>
<id>staging</id>
<url>file:///${user.dir}/target/staging/org.springframework.batch.archetype/${pom.artifactId}</url>
</site>
<repository>
<id>spring-release</id>
<name>Spring Release Repository</name>
<url>file:///${user.dir}/target/staging/release</url>
</repository>
<snapshotRepository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>file:///${user.dir}/target/staging/snapshot</url>
</snapshotRepository>
</distributionManagement>
</project>

View File

@@ -0,0 +1,98 @@
/*
* 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.amqp.rabbit.stocks.config;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.admin.config.AbstractRabbitConfiguration;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Provides shared configuration between Client and Server.
* <p>The abstract method configureRabbitTemplate lets the Client and Server further customize
* the rabbit template to their specific needs.
*
* @author Mark Pollack
* @author Mark Fisher
*/
@Configuration
public abstract class AbstractStockAppRabbitConfiguration extends AbstractRabbitConfiguration {
/**
* Shared topic exchange used for publishing any market data (e.g. stock quotes)
*/
protected static String MARKET_DATA_EXCHANGE_NAME = "app.stock.marketdata";
/**
* The server-side consumer's queue that provides point-to-point semantics for stock requests.
*/
protected static String STOCK_REQUEST_QUEUE_NAME = "app.stock.request";
/**
* Key that clients will use to send to the stock request queue via the default direct exchange.
*/
protected static String STOCK_REQUEST_ROUTING_KEY = STOCK_REQUEST_QUEUE_NAME;
//protected static TopicExchange MARKET_DATA_EXCHANGE = new TopicExchange(MARKET_DATA_EXCHANGE_NAME);
protected abstract void configureRabbitTemplate(RabbitTemplate template);
@Bean
public ConnectionFactory connectionFactory() {
//TODO make it possible to customize in subclasses.
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setChannelCacheSize(10);
return connectionFactory;
}
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
template.setMessageConverter(jsonMessageConverter());
configureRabbitTemplate(template);
return template;
}
@Bean
public MessageConverter jsonMessageConverter() {
return new JsonMessageConverter();
}
// @PostConstruct
// public void declareExchange()
// {
// declare(this.MARKET_DATA_EXCHANGE);
// }
@Bean
public TopicExchange marketDataExchange() {
return declare(new TopicExchange(MARKET_DATA_EXCHANGE_NAME));
}
}

View File

@@ -0,0 +1,27 @@
/*
* 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.amqp.rabbit.stocks.config;
/**
* Enumerations for the RoutingKeys used in the application to allow for a more fluent API
* style when configuring the broker in code.
*
* @author Mark Pollack
*/
public enum RoutingKey {
}

View File

@@ -0,0 +1,136 @@
/*
* 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.amqp.rabbit.stocks.config.client;
import javax.annotation.PostConstruct;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.UniquelyNamedQueue;
import static org.springframework.amqp.core.BindingBuilder.*;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.rabbit.stocks.config.AbstractStockAppRabbitConfiguration;
import org.springframework.amqp.rabbit.stocks.gateway.RabbitStockServiceGateway;
import org.springframework.amqp.rabbit.stocks.gateway.StockServiceGateway;
import org.springframework.amqp.rabbit.stocks.handler.ClientHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configures RabbitTemplate and creates the Trader queue and binding for the client.
*
* @author Mark Pollack
* @author Mark Fisher
*/
@Configuration
public class RabbitClientConfiguration extends AbstractStockAppRabbitConfiguration {
@Value("${stocks.quote.pattern}")
private String marketDataRoutingKey;
@Autowired
private ClientHandler clientHandler;
// Create the Queue definitions that write up the Message listener container
//private Queue marketDataQueue = new UniquelyNamedQueue("mktdata");
//private Queue traderJoeQueue = new UniquelyNamedQueue("joe");
/**
* The client's template will by default send to the exchange defined
* in {@link AbstractRabbitConfiguration.rabbitTemplate()}
* with the routing key {@link AbstractStockAppRabbitConfiguration#STOCK_REQUEST_QUEUE_NAME}
* <p>
* The default exchange will delivery to a queue whose name matches the routing key value.
*/
@Override
public void configureRabbitTemplate(RabbitTemplate rabbitTemplate) {
rabbitTemplate.setDefaultRoutingKey(STOCK_REQUEST_QUEUE_NAME);
}
@Bean
public StockServiceGateway stockServiceGateway() {
RabbitStockServiceGateway gateway = new RabbitStockServiceGateway();
gateway.setRabbitTemplate(rabbitTemplate());
gateway.setDefaultReplyToQueue(traderJoeQueue());
return gateway;
}
@Bean
public SimpleMessageListenerContainer messageListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
container.setQueues(marketDataQueue(), traderJoeQueue());
//container.setConcurrentConsumers(5); // note, now set to size of channel cache in CachingConnectionFactory by default
container.setMessageListener(messageListenerAdapter());
return container;
//container(using(connectionFactory()).listenToQueues(marketDataQueue(), traderJoeQueue()).withListener(messageListenerAdapter()).
}
@Bean
public MessageListenerAdapter messageListenerAdapter() {
return new MessageListenerAdapter(clientHandler, jsonMessageConverter());
}
// Broker Configuration
// @PostConstruct
// public void declareClientBrokerConfiguration() {
// declare(marketDataQueue);
// declare(new Binding(marketDataQueue, MARKET_DATA_EXCHANGE, marketDataRoutingKey));
// declare(traderJoeQueue);
// // no need to bind traderJoeQueue as it is automatically bound to the default direct exchanage, which is what we will use
//
// //add as many declare statements as needed like a script.
// }
@Bean
public Queue marketDataQueue() {
return declareQueue();
}
/**
* Binds to the market data exchange. Interested in any stock quotes.
* @return
*/
@Bean
public Binding marketDataBinding() {
return declare(new Binding(marketDataQueue(), marketDataExchange(), marketDataRoutingKey));
// Using BindingBuilder
//return declareBinding(from(marketDataQueue()).to(marketDataExchange()).with(marketDataRoutingKey));
}
/**
* This queue does not need a binding, since it relies on the default exchange.
*/
@Bean
public Queue traderJoeQueue() {
return declareQueue();
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.amqp.rabbit.stocks.config.server;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.stocks.config.AbstractStockAppRabbitConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configures RabbitTemplate for the server.
*
* @author Mark Pollack
* @author Mark Fisher
*/
@Configuration
public class RabbitServerConfiguration extends AbstractStockAppRabbitConfiguration {
/**
* The server's template will by default send to the topic exchange named
* {@link AbstractStockAppRabbitConfiguration#MARKET_DATA_EXCHANGE_NAME}.
*/
public void configureRabbitTemplate(RabbitTemplate rabbitTemplate) {
rabbitTemplate.setDefaultExchange(MARKET_DATA_EXCHANGE_NAME);
}
/**
* We don't need to define any binding for the stock request queue, since it's relying
* on the default (no-name) direct exchange to which every queue is implicitly bound.
*/
@Bean
public Queue stockRequestQueue() {
return declare(new Queue(STOCK_REQUEST_QUEUE_NAME));
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.amqp.rabbit.stocks.domain;
/**
* Domain object representing a stock quote.
*
* @author Mark Fisher
*/
public class Quote {
private Stock stock;
private String price;
public Quote() {
}
public Quote(Stock stock, String price) {
this.stock = stock;
this.price = price;
}
public Stock getStock() {
return this.stock;
}
public void setStock(Stock stock) {
this.stock = stock;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.amqp.rabbit.stocks.domain;
/**
* @author Mark Fisher
*/
public class Stock {
private String ticker;
private StockExchange stockExchange;
public String getTicker() {
return ticker;
}
public void setTicker(String ticker) {
this.ticker = ticker;
}
public StockExchange getStockExchange() {
return stockExchange;
}
public void setStockExchange(StockExchange stockExchange) {
this.stockExchange = stockExchange;
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.amqp.rabbit.stocks.domain;
/**
* Enumeration for Stock Exchanges.
*
* @author Mark Fisher
*/
public enum StockExchange {
nyse, nasdaq;
}

View File

@@ -0,0 +1,109 @@
/*
* 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.amqp.rabbit.stocks.domain;
import java.math.BigDecimal;
/**
* Simple trade request 'data' object. No functionality in this 'domain' class.
* @author Mark Pollack
*
*/
public class TradeRequest {
private String ticker;
private long quantity;
private BigDecimal price;
private String orderType;
private String accountName;
private boolean buyRequest;
private String userName;
private String requestId;
public String getTicker() {
return ticker;
}
public void setTicker(String ticker) {
this.ticker = ticker;
}
public long getQuantity() {
return quantity;
}
public void setQuantity(long quantity) {
this.quantity = quantity;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public String getOrderType() {
return orderType;
}
public void setOrderType(String orderType) {
this.orderType = orderType;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public boolean isBuyRequest() {
return buyRequest;
}
public void setBuyRequest(boolean buyRequest) {
this.buyRequest = buyRequest;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
}

View File

@@ -0,0 +1,107 @@
/*
* 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.amqp.rabbit.stocks.domain;
import java.math.BigDecimal;
/**
* Simple trade request 'data' object. No functionality in this 'domain' class.
* @author Mark Pollack
*
*/
public class TradeResponse {
private String ticker;
private long quantity;
private BigDecimal price;
private String orderType;
private String confirmationNumber;
private boolean error;
private String errorMessage;
public String getTicker() {
return ticker;
}
public void setTicker(String ticker) {
this.ticker = ticker;
}
public long getQuantity() {
return quantity;
}
public void setQuantity(long quantity) {
this.quantity = quantity;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public String getOrderType() {
return orderType;
}
public void setOrderType(String orderType) {
this.orderType = orderType;
}
public String getConfirmationNumber() {
return confirmationNumber;
}
public void setConfirmationNumber(String confirmationNumber) {
this.confirmationNumber = confirmationNumber;
}
public boolean isError() {
return error;
}
public void setError(boolean error) {
this.error = error;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
@Override
public String toString() {
return "TradeResponse [confirmationNumber=" + confirmationNumber
+ ", error=" + error + ", errorMessage=" + errorMessage
+ ", orderType=" + orderType + ", price=" + price
+ ", quantity=" + quantity + ", ticker=" + ticker + "]";
}
}

View File

@@ -0,0 +1,26 @@
/*
* 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.amqp.rabbit.stocks.gateway;
/**
* Gateway interface for sending market data to clients
* @author Mark Pollack
*
*/
public interface MarketDataGateway {
void sendMarketData();
}

View File

@@ -0,0 +1,95 @@
/*
* 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.amqp.rabbit.stocks.gateway;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.core.support.RabbitGatewaySupport;
import org.springframework.amqp.rabbit.stocks.domain.Quote;
import org.springframework.amqp.rabbit.stocks.domain.Stock;
import org.springframework.amqp.rabbit.stocks.domain.StockExchange;
/**
* Rabbit implementation of the {@link MarketDataGateway} for sending Market data.
*
* @author Mark Pollack
* @author Mark Fisher
*/
public class RabbitMarketDataGateway extends RabbitGatewaySupport implements MarketDataGateway {
private static Log logger = LogFactory.getLog(RabbitMarketDataGateway.class);
private static final Random random = new Random();
private final List<MockStock> stocks = new ArrayList<MockStock>();
public RabbitMarketDataGateway() {
this.stocks.add(new MockStock("AAPL", StockExchange.nasdaq, 255));
this.stocks.add(new MockStock("CSCO", StockExchange.nasdaq, 22));
this.stocks.add(new MockStock("DELL", StockExchange.nasdaq, 15));
this.stocks.add(new MockStock("GOOG", StockExchange.nasdaq, 500));
this.stocks.add(new MockStock("INTC", StockExchange.nasdaq, 22));
this.stocks.add(new MockStock("MSFT", StockExchange.nasdaq, 29));
this.stocks.add(new MockStock("ORCL", StockExchange.nasdaq, 24));
this.stocks.add(new MockStock("CAJ", StockExchange.nyse, 43));
this.stocks.add(new MockStock("F", StockExchange.nyse, 12));
this.stocks.add(new MockStock("GE", StockExchange.nyse, 18));
this.stocks.add(new MockStock("HMC", StockExchange.nyse, 32));
this.stocks.add(new MockStock("HPQ", StockExchange.nyse, 48));
this.stocks.add(new MockStock("IBM", StockExchange.nyse, 130));
this.stocks.add(new MockStock("TM", StockExchange.nyse, 76));
}
public void sendMarketData() {
Quote quote = generateFakeQuote();
Stock stock = quote.getStock();
logger.info("Sending Market Data for " + stock.getTicker());
String routingKey = "app.stock.quotes."+ stock.getStockExchange() + "." + stock.getTicker();
getRabbitTemplate().convertAndSend(routingKey, quote);
}
private Quote generateFakeQuote() {
MockStock stock = this.stocks.get(random.nextInt(this.stocks.size()));
String price = stock.randomPrice();
return new Quote(stock, price);
}
private static class MockStock extends Stock {
private final int basePrice;
private final DecimalFormat twoPlacesFormat = new DecimalFormat("0.00");
private MockStock(String ticker, StockExchange stockExchange, int basePrice) {
this.setTicker(ticker);
this.setStockExchange(stockExchange);
this.basePrice = basePrice;
}
private String randomPrice() {
return this.twoPlacesFormat.format(this.basePrice + Math.abs(random.nextGaussian()));
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.amqp.rabbit.stocks.gateway;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Address;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.support.RabbitGatewaySupport;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
/**
* Rabbit implementation of {@link StockServiceGateway} to send trade requests to an external
* process.
* @author Mark Pollack
*
*/
public class RabbitStockServiceGateway extends RabbitGatewaySupport implements
StockServiceGateway {
private String defaultReplyToQueue;
public void setDefaultReplyToQueue(String defaultReplyToQueue) {
this.defaultReplyToQueue = defaultReplyToQueue;
}
public void setDefaultReplyToQueue(Queue defaultReplyToQueue) {
this.defaultReplyToQueue = defaultReplyToQueue.getName();
}
public void send(TradeRequest tradeRequest) {
getRabbitTemplate().convertAndSend(tradeRequest, new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setReplyTo(new Address(defaultReplyToQueue));
//bytes = ((String) object).getBytes(this.defaultCharset);
try {
message.getMessageProperties().setCorrelationId(UUID.randomUUID().toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return message;
}
});
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.amqp.rabbit.stocks.gateway;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
/**
* Gateway interface that sends trades to an external process.
* @author Mark Pollack
*
*/
public interface StockServiceGateway {
void send(TradeRequest tradeRequest);
}

View File

@@ -0,0 +1,58 @@
/*
* 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.amqp.rabbit.stocks.handler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.stocks.domain.Quote;
import org.springframework.amqp.rabbit.stocks.domain.Stock;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
import org.springframework.amqp.rabbit.stocks.ui.StockController;
/**
* POJO handler that receives market data and trade responses. Calls are delegated to the UI controller.
*
* @author Mark Pollack
* @author Mark Fisher
*/
public class ClientHandler {
private static Log log = LogFactory.getLog(ClientHandler.class);
private StockController stockController;
public StockController getStockController() {
return stockController;
}
public void setStockController(StockController stockController) {
this.stockController = stockController;
}
public void handleMessage(Quote quote) {
Stock stock = quote.getStock();
log.info("Received market data. Ticker = " + stock.getTicker() + ", Price = " + quote.getPrice());
stockController.displayQuote(quote);
}
public void handleMessage(TradeResponse tradeResponse) {
log.info("Received trade repsonse. [" + tradeResponse + "]");
stockController.UpdateTrade(tradeResponse);
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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.amqp.rabbit.stocks.handler;
import java.util.ArrayList;
import java.util.List;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
import org.springframework.amqp.rabbit.stocks.service.CreditCheckService;
import org.springframework.amqp.rabbit.stocks.service.ExecutionVenueService;
import org.springframework.amqp.rabbit.stocks.service.TradingService;
import org.springframework.util.StringUtils;
/**
* POJO handler that receives trade requests and sends back a trade response. Main application
* logic sits here which coordinates between {@link ExecutionVenueService}, {@link CreditCheckService},
* and {@link TradingService}.
*
* @author Mark Pollack
*
*/
public class ServerHandler {
private ExecutionVenueService executionVenueService;
private CreditCheckService creditCheckService;
private TradingService tradingService;
public ServerHandler(ExecutionVenueService executionVenueService,
CreditCheckService creditCheckService,
TradingService tradingService) {
this.executionVenueService = executionVenueService;
this.creditCheckService = creditCheckService;
this.tradingService = tradingService;
}
public TradeResponse handleMessage(TradeRequest tradeRequest)
{
TradeResponse tradeResponse;
List errors = new ArrayList();
if (creditCheckService.canExecute(tradeRequest, errors))
{
tradeResponse = executionVenueService.executeTradeRequest(tradeRequest);
}
else
{
tradeResponse = new TradeResponse();
tradeResponse.setError(true);
tradeResponse.setErrorMessage(StringUtils.arrayToCommaDelimitedString(errors.toArray()));
}
tradingService.processTrade(tradeRequest, tradeResponse);
return tradeResponse;
}
}

View File

@@ -0,0 +1,32 @@
/*
* 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.amqp.rabbit.stocks.service;
import java.util.List;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
/**
* Credit service to see if the incoming trade can be processed. If it can not be processed
* a false value is returned and the error list contains information as to what went wrong.
*
* @author Mark Pollack
*
*/
public interface CreditCheckService {
boolean canExecute(TradeRequest tradeRequest, List errors);
}

View File

@@ -0,0 +1,30 @@
/*
* 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.amqp.rabbit.stocks.service;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
/**
* Executes the trade request, creating a Trade response. See the code flow in {@link ServerHandler} for
* its usage.
* @author Mark Pollack
*
*/
public interface ExecutionVenueService {
TradeResponse executeTradeRequest(TradeRequest request);
}

View File

@@ -0,0 +1,31 @@
/*
* 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.amqp.rabbit.stocks.service;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
/**
* Trading Service to process trade requests and response. This is the place to perform
* any trade processing after executions. See code flow in {@link ServerHandler}.
*
* @author Mark Pollack
*
*/
public interface TradingService {
void processTrade(TradeRequest request, TradeResponse response);
}

View File

@@ -0,0 +1,35 @@
/*
* 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.amqp.rabbit.stocks.service.stubs;
import java.util.List;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
import org.springframework.amqp.rabbit.stocks.service.CreditCheckService;
/***
* An implementation that always returns true (just like real-life for a mortgage check :)
*
* @author Mark Pollack
*
*/
public class CreditCheckServiceStub implements CreditCheckService {
public boolean canExecute(TradeRequest tradeRequest, List errors) {
return true;
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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.amqp.rabbit.stocks.service.stubs;
import java.math.BigDecimal;
import java.util.Random;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
import org.springframework.amqp.rabbit.stocks.service.ExecutionVenueService;
/**
* Execute the trade, setting the execution price to changing value in line with what the market data feed is producing.
*
* @author Mark Pollack
*
*/
public class ExecutionVenueServiceStub implements ExecutionVenueService {
private static Log log = LogFactory.getLog(ExecutionVenueServiceStub.class);
private Random random = new Random();
public TradeResponse executeTradeRequest(TradeRequest request) {
TradeResponse response = new TradeResponse();
response.setOrderType(request.getOrderType());
response.setPrice(calculatePrice(request.getTicker(), request.getQuantity(), request.getOrderType(), request.getPrice(), request.getUserName()));
response.setQuantity(request.getQuantity());
response.setTicker(request.getTicker());
response.setConfirmationNumber(UUID.randomUUID().toString());
try {
log.info("Sleeping 2 seconds to simulate processing..");
Thread.sleep(2000);
} catch (InterruptedException e) {
log.error("Didn't finish sleeping", e);
}
return response;
}
private BigDecimal calculatePrice(String ticker, long quantity,
String orderType, BigDecimal price, String userName) {
// provide as sophisticated implementation...for now all the same price.
if (orderType.compareTo("LIMIT") == 0)
{
return price;
}
else
{
//in line with market data implementation
return new BigDecimal(22 + Math.abs(gaussian()));
}
}
private double gaussian() {
return random.nextGaussian();
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.amqp.rabbit.stocks.service.stubs;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
import org.springframework.amqp.rabbit.stocks.service.TradingService;
/**
* No-op implementation
* @author Mark Pollack
*
*/
public class TradingServiceStub implements TradingService {
public void processTrade(TradeRequest request, TradeResponse response) {
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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.amqp.rabbit.stocks.ui;
import org.springframework.amqp.rabbit.stocks.domain.Quote;
import org.springframework.amqp.rabbit.stocks.domain.TradeRequest;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
import org.springframework.amqp.rabbit.stocks.gateway.StockServiceGateway;
/**
* Basic controller for the UI.
* TODO: Fix that the UI can receive events before it's panel has been initialized.
*
* @author Mark Pollack
* @author Mark Fisher
*/
public class StockController {
private StockPanel stockPanel;
private StockServiceGateway stockServiceGateway;
public StockPanel getStockPanel() {
return stockPanel;
}
public void setStockPanel(StockPanel stockPanel) {
this.stockPanel = stockPanel;
}
public StockServiceGateway getStockServiceGateway() {
return stockServiceGateway;
}
public void setStockServiceGateway(StockServiceGateway stockServiceGateway) {
this.stockServiceGateway = stockServiceGateway;
}
// "Actions"
public void sendTradeRequest(String text) {
String[] tokens = text.split("\\s");
String quantityString = tokens[0];
String ticker = tokens[1];
int quantity = Integer.parseInt(quantityString);
TradeRequest tr = new TradeRequest();
tr.setAccountName("ACCT-123");
tr.setBuyRequest(true);
tr.setOrderType("MARKET");
tr.setTicker(ticker);
tr.setQuantity(quantity);
tr.setRequestId("REQ-1");
tr.setUserName("Joe Trader");
tr.setUserName("Joe");
stockServiceGateway.send(tr);
}
public void displayQuote(Quote quote) {
//TODO race condition with message delivery and initalization... use @Configurable?
if (stockPanel != null) {
stockPanel.displayQuote(quote);
}
}
public void UpdateTrade(TradeResponse tradeResponse) {
stockPanel.update(tradeResponse);
}
}

View File

@@ -0,0 +1,144 @@
/*
* 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.amqp.rabbit.stocks.ui;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.stocks.domain.Quote;
import org.springframework.amqp.rabbit.stocks.domain.Stock;
import org.springframework.amqp.rabbit.stocks.domain.TradeResponse;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
/**
* A typical poor mans UI to drive the application.
*
* @author Mark Pollack
* @author Mark Fisher
*/
public class StockPanel extends JPanel {
private static Log log = LogFactory.getLog(StockPanel.class);
private JTextField tradeRequestTextField;
private JButton tradeRequestButton;
private JTextArea marketDataTextArea;
private StockController stockController;
private DecimalFormat frmt = new DecimalFormat("$0.00");
public StockPanel(StockController controller) {
this.stockController = controller;
controller.setStockPanel(this);
this.setBorder(BorderFactory.createTitledBorder("Stock Form"));
FormLayout formLayout = new FormLayout("pref, 150dlu", // columns
"pref, fill:100dlu:grow"); // rows
setLayout(formLayout);
CellConstraints c = new CellConstraints();
tradeRequestButton = new JButton("Send Trade Request");
add(tradeRequestButton, c.xy(1, 1));
tradeRequestTextField = new JTextField("");
add(tradeRequestTextField, c.xy(2, 1));
add(new JLabel("Market Data"), c.xy(1, 2));
marketDataTextArea = new JTextArea();
JScrollPane sp = new JScrollPane(marketDataTextArea);
sp.setSize(200, 300);
add(sp, c.xy(2, 2));
tradeRequestTextField.addFocusListener(new FocusListener() {
public void focusLost(FocusEvent e) {
}
public void focusGained(FocusEvent e) {
tradeRequestTextField.setText("");
tradeRequestTextField.setForeground(Color.BLACK);
}
});
tradeRequestButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sendTradeRequest();
}
});
}
private void sendTradeRequest() {
try {
stockController.sendTradeRequest(tradeRequestTextField.getText());
tradeRequestTextField.setForeground(Color.GRAY);
tradeRequestTextField.setText("Request Pending...");
log.info("Sent trade request.");
}
catch (Exception ex) {
tradeRequestTextField.setForeground(Color.RED);
tradeRequestTextField.setText("Required Format: 100 TCKR");
}
}
public static void main(String[] a) {
JFrame f = new JFrame("Rabbit Stock Demo");
f.setDefaultCloseOperation(2);
f.add(new StockPanel(new StockController()));
f.pack();
f.setVisible(true);
}
public void displayQuote(final Quote quote) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Stock stock = quote.getStock();
marketDataTextArea.append(stock.getTicker() + " " + quote.getPrice() + "\n");
}
});
}
public void update(final TradeResponse tradeResponse) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
tradeRequestTextField.setForeground(Color.GREEN);
tradeRequestTextField.setText("Confirmed. "
+ tradeResponse.getTicker() + " "
+ frmt.format(tradeResponse.getPrice().doubleValue()));
}
});
}
}

View File

@@ -0,0 +1,19 @@
<?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: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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- pick up rabbit broker configuration -->
<context:component-scan base-package="org.springframework.amqp.rabbit.stocks.config.client"/>
<context:property-placeholder location="client.properties"/>
<import resource="classpath:client-handlers.xml" />
<!--
<import resource="classpath:client-messaging.xml" />
-->
</beans>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="stockController" class="org.springframework.amqp.rabbit.stocks.ui.StockController">
<property name="stockServiceGateway" ref="stockServiceGateway"/>
</bean>
<bean id="clientHandler" class="org.springframework.amqp.rabbit.stocks.handler.ClientHandler">
<property name="stockController" ref="stockController"/>
</bean>
</beans>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="stockServiceGateway" class="org.springframework.amqp.rabbit.stocks.gateway.RabbitStockServiceGateway">
<property name="rabbitTemplate" ref="rabbitTemplate" />
<property name="defaultReplyToQueue" value="#{traderJoeQueue.name}" />
</bean>
<bean id="messageListenerContainer" class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="queueName" value="#{marketDataQueue.name},#{traderJoeQueue.name}"/>
<property name="concurrentConsumers" value="5" />
<property name="messageListener" ref="messageListenerAdapter" />
</bean>
<bean id="messageListenerAdapter" class="org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter">
<property name="delegate" ref="clientHandler" />
<property name="messageConverter" ref="jsonMessageConverter" />
</bean>
</beans>

View File

@@ -0,0 +1 @@
stocks.quote.pattern=app.stock.quotes.nasdaq.*

View File

@@ -0,0 +1,22 @@
<?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:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- pick up rabbit broker configuration -->
<context:component-scan base-package="org.springframework.amqp.rabbit.stocks.config.server"/>
<import resource="classpath:server-handlers.xml" />
<import resource="classpath:server-messaging.xml" />
<import resource="classpath:server-services.xml" />
<import resource="classpath:server-jmx.xml" />
<task:scheduled-tasks>
<task:scheduled ref="marketDataGateway" method="sendMarketData" fixed-delay="5000"/>
</task:scheduled-tasks>
</beans>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean name="serverHandler" class="org.springframework.amqp.rabbit.stocks.handler.ServerHandler">
<constructor-arg ref="executionVenueService"/>
<constructor-arg ref="creditCheckService"/>
<constructor-arg ref="tradingService"/>
</bean>
</beans>

View File

@@ -0,0 +1,19 @@
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:mbean-export/>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean"
p:port="1099" />
<!-- Expose JMX over RMI -->
<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="registry"
p:objectName="connector:name=rmi"
p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector" />
</beans>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="marketDataGateway" class="org.springframework.amqp.rabbit.stocks.gateway.RabbitMarketDataGateway">
<property name="rabbitTemplate" ref="rabbitTemplate" />
</bean>
<bean id="messageListenerContainer" class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="queueName" value="#{stockRequestQueue.name}" />
<property name="concurrentConsumers" value="5" />
<property name="messageListener" ref="messageListenerAdapter" />
</bean>
<bean id="messageListenerAdapter" class="org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter">
<property name="delegate" ref="serverHandler" />
<property name="messageConverter" ref="jsonMessageConverter" />
</bean>
</beans>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="executionVenueService"
class="org.springframework.amqp.rabbit.stocks.service.stubs.ExecutionVenueServiceStub">
</bean>
<bean id="creditCheckService"
class="org.springframework.amqp.rabbit.stocks.service.stubs.CreditCheckServiceStub">
</bean>
<bean id="tradingService"
class="org.springframework.amqp.rabbit.stocks.service.stubs.TradingServiceStub">
</bean>
</beans>

25
stocks/src/site/site.xml Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Spring Batch: ${project.name}">
<bannerLeft>
<name>Spring Batch: ${project.name}</name>
<href>index.html</href>
</bannerLeft>
<skin>
<groupId>org.springframework.maven.skins</groupId>
<artifactId>maven-spring-skin</artifactId>
<version>1.0.5</version>
</skin>
<body>
<links>
<item name="${project.name}" href="index.html"/>
</links>
<menu ref="reports"/>
</body>
</project>

View File

@@ -0,0 +1,65 @@
/*
* 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.amqp.rabbit.stocks;
import javax.swing.JFrame;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.springframework.amqp.rabbit.stocks.ui.StockController;
import org.springframework.amqp.rabbit.stocks.ui.StockPanel;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Main client application, can run as app or unit test.
* @author Mark Pollack
*
*/
public class Client {
private static Log log = LogFactory.getLog(Client.class);
/**
* @param args
*/
public static void main(String[] args) {
new Client().run();
}
@Test
public void run() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("client-bootstrap-config.xml");
StockController controller = ac.getBean(StockController.class);
JFrame f = new JFrame("Rabbit Stock Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//TODO consider @Configurable
f.add(new StockPanel(controller));
f.pack();
f.setVisible(true);
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.amqp.rabbit.stocks;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Server application than can be run as an app or unit test.
*
* @author Mark Pollack
*/
public class Server {
public static void main(String[] args) {
new Server().run();
}
@Test
public void run() {
new ClassPathXmlApplicationContext("server-bootstrap-config.xml");
}
}

View File

@@ -0,0 +1,7 @@
# Use Log4j
priority=1
org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
# Configuration file of the log
#log4j.configuration=file:log4j-rabbit-stocks.properties

View File

@@ -0,0 +1,11 @@
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.appender.stdout.layout.ConversionPattern=%-5p [%40.40c{4}]: %m%n
log4j.category.org.springframework.amqp.rabbit=DEBUG
log4j.category.org.springframework.beans.factory=INFO