INTSAMPLES-36 - Adding rest-http sample to demonstrate the usage of Spring Integration's new HTTP Path facility usage

* The JIRA referenced for this sample is https://jira.springsource.org/browse/INTSAMPLES-36
This commit is contained in:
Vigil Bose
2011-11-16 15:52:37 -05:00
committed by Gunnar Hillert
parent c97fb87ae8
commit f7bd84e22f
20 changed files with 1087 additions and 1 deletions

2
.gitignore vendored
View File

@@ -1,7 +1,6 @@
application.log
application.log*
target/
.settings/
log.roo
.project
.classpath
@@ -13,3 +12,4 @@ log.roo
derby.log
.idea
activemq-data
.settings/

View File

@@ -56,6 +56,9 @@ This category targets developers who are already more familiar with the Spring I
* **tcp-client-server-multiplex** - Demonstrates the use of *Collaborating Channel Adapters*
* **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*
* **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*
## Advanced

View File

@@ -0,0 +1,188 @@
<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.samples</groupId>
<artifactId>rest-http</artifactId>
<version>2.1.0.BUILD-SNAPSHOT</version>
<packaging>war</packaging>
<name>Spring Integration Rest HTTP Path Usage Demo</name>
<description>Spring Integration Rest HTTP Path Usage Demo</description>
<properties>
<spring.integration.version>2.1.0.RELEASE</spring.integration.version>
<spring.version>3.1.0.RELEASE</spring.version>
<spring.security.version>3.1.0.RELEASE</spring.security.version>
<commons-fileupload>1.2</commons-fileupload>
<commons-io>1.3.2</commons-io>
<log4j.version>1.2.16</log4j.version>
<javax.servlet.version>2.5</javax.servlet.version>
<junit.version>4.8.1</junit.version>
<jasypt.version>1.7</jasypt.version>
<cglib.version>2.2</cglib.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-http</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>compile</scope>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<scope>compile</scope>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<scope>compile</scope>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>${jasypt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>${cglib.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Servlet dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${javax.servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>false</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>clean</id>
<configuration>
<target>
<echo>Copying jaxb.index to classes folder</echo>
</target>
<target>
<copy todir="${project.basedir}/target/classes/org/springframework/integration/samples/rest/domain" overwrite="true">
<fileset dir="${project.basedir}/src/main/java/org/springframework/integration/samples/rest/domain">
<include name="**/jaxb.index"/>
</fileset>
</copy>
</target>
</configuration>
<phase>clean</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>repository.springframework.maven.release</id>
<name>Spring Framework Maven Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
<repository>
<id>repository.springframework.maven.milestone</id>
<name>Spring Framework Maven Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
<repository>
<id>repository.springframework.maven.snapshot</id>
<name>Spring Framework Maven Snapshot Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
</repositories>
</project>

View File

@@ -0,0 +1,44 @@
# Introduction
This sample demonstrates how you can 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.
It consists of two parts - Client and Server.
The following client program can be used to test the HTTP Path usage.
1. RestHttpClientTest. It uses Spring's RestTemplate to assemble and send HTTP request
Server is Spring Integration's HTTP endpoint configuration.
To run this sample
1. deploy project
- If you are using STS and project is imported as Eclipse project in your workspace you can just execute 'Run on Server'
- You can also run 'mvn clean install' and generate the WAR file that you can deploy the conventional way
2. run the simple JUNIT Test: org.springframework.integration.samples.rest.RestHttpClientTest
You may change the URI Variable value in the test to see different results.
For example, when you give 0 as the URL Variable's value in the test, then you should see the following output from the server:
14:01:34,337 INFO main rest.RestHttpClientTest:95 - The employee list size :2
14:01:34,353 INFO main rest.RestHttpClientTest:101 - <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<EmployeeList>
<Employee>
<employeeId>1</employeeId>
<fname>John</fname>
<lname>Doe</lname>
</Employee>
<Employee>
<employeeId>2</employeeId>
<fname>Jane</fname>
<lname>Doe</lname>
</Employee>
<returnStatus>0</returnStatus>
<returnStatusMsg>Success</returnStatusMsg>
</EmployeeList>
14:01:34,556 INFO main rest.RestHttpClientTest:121 - Return Status :[0]
14:01:34,556 INFO main rest.RestHttpClientTest:122 - Return Status Message :[Success]
{"employee":[{"employeeId":1,"fname":"John","lname":"Doe"},{"employeeId":2,"fname":"Jane","lname":"Doe"}],"returnStatus":"0","returnStatusMsg":"Success"}

View File

@@ -0,0 +1,85 @@
/*
* 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.samples.rest.domain;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* Employee.java: Employee Domain class
* @author Vigil Bose
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"employeeId",
"fname",
"lname"
})
@XmlRootElement(name = "Customer")
public class Employee {
private Integer employeeId;
private String fname;
private String lname;
public Employee() {}
public Employee(Integer employeeId, String fname, String lname) {
this.employeeId = employeeId;
this.fname = fname;
this.lname = lname;
}
/**
* @return the employeeId
*/
public Integer getEmployeeId() {
return employeeId;
}
/**
* @param employeeId the employeeId to set
*/
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
/**
* @return the fname
*/
public String getFname() {
return fname;
}
/**
* @param fname the fname to set
*/
public void setFname(String fname) {
this.fname = fname;
}
/**
* @return the lname
*/
public String getLname() {
return lname;
}
/**
* @param lname the lname to set
*/
public void setLname(String lname) {
this.lname = lname;
}
}

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.samples.rest.domain;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* EmployeeList.java: EmployeeList Domain class
* @author Vigil Bose
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"employee",
"returnStatus",
"returnStatusMsg"
})
@XmlRootElement(name = "EmployeeList")
public class EmployeeList {
@XmlElement(name = "Employee", required = true)
private List<Employee> employee;
@XmlElement(name = "returnStatus", required = true)
private String returnStatus;
@XmlElement(name = "returnStatusMsg", required = true)
private String returnStatusMsg;
/**
* @return the employee
*/
public List<Employee> getEmployee() {
if (employee == null){
employee = new ArrayList<Employee>();
}
return employee;
}
/**
* @return the returnStatus
*/
public String getReturnStatus() {
return returnStatus;
}
/**
* @param returnStatus the returnStatus to set
*/
public void setReturnStatus(String returnStatus) {
this.returnStatus = returnStatus;
}
/**
* @return the returnStatusMsg
*/
public String getReturnStatusMsg() {
return returnStatusMsg;
}
/**
* @param returnStatusMsg the returnStatusMsg to set
*/
public void setReturnStatusMsg(String returnStatusMsg) {
this.returnStatusMsg = returnStatusMsg;
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.samples.rest.json;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
/**
* JaxbJacksonObjectMapper.java: This is the custom JAXB JSON ObjectMapper
* <p>
* NOTE: The source code is provided by Gunnar Hillert in his blog posted at
* http://hillert.blogspot.com/2011/01/marshal-json-data-using-jackson-in.html.
* I modified a little bit to use the latest {@link DeserializationConfig} API
* instead of deprecated ones.
* <p> *
* @author Vigil Bose
*/
public class JaxbJacksonObjectMapper extends ObjectMapper {
/**
* Annotation introspector to use for serialization process
* is configured separately for serialization and deserialization purposes
*/
public JaxbJacksonObjectMapper() {
final AnnotationIntrospector introspector
= new JacksonAnnotationIntrospector();
super.getDeserializationConfig()
.withAnnotationIntrospector(introspector);
super.getSerializationConfig()
.withAnnotationIntrospector(introspector);
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.samples.rest.json.view;
import java.util.Map;
import org.springframework.web.servlet.view.json.MappingJacksonJsonView;
/**
* ExtendedMappingJacksonJsonView.java: This class extends the Spring's MappingJacksonJsonView
* <p>
* Note: The source code for this class is taken from the forum posted by AhungerArtist
* at http://forum.springsource.org/archive/index.php/t-84006.html
* </p>
* @author Vigil Bose
*/
public class ExtendedMappingJacksonJsonView extends MappingJacksonJsonView {
@SuppressWarnings({"rawtypes" })
@Override
protected Object filterModel(Map<String, Object> model){
Object result = super.filterModel(model);
if (!(result instanceof Map)){
return result;
}
Map map = (Map) result;
if (map.size() == 1){
return map.values().toArray()[0];
}
return map;
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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.samples.rest.service;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.samples.rest.domain.Employee;
import org.springframework.integration.samples.rest.domain.EmployeeList;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
/**
* EmployeeSearchService.java: This is the default employee search service
* @author Vigil Bose
*/
@Service("employeeSearchService")
public class EmployeeSearchService {
private static Logger logger = Logger.getLogger(EmployeeSearchService.class);
/**
* The API <code>getEmployee()</code> looks up the mapped in coming message header's id param
* and fills the return object with the appropriate employee details. The return
* object is wrapped in Spring Integration Message with response headers filled in.
* This example shows the usage of URL path variables and how the service act on
* those variables.
* @param inMessage
* @return an instance of <code>{@link Message}</code> that wraps <code>{@link EmployeeList}</code>
*/
@Secured("ROLE_REST_HTTP_USER")
public Message<EmployeeList> getEmployee(Message<?> inMessage){
EmployeeList employeeList = new EmployeeList();
Map<String, Object> responseHeaderMap = new HashMap<String, Object>();
try{
MessageHeaders headers = inMessage.getHeaders();
String id = (String)headers.get("employeeId");
boolean isFound;
if (id.equals("1")){
employeeList.getEmployee().add(new Employee(1, "John", "Doe"));
isFound = true;
}else if (id.equals("2")){
employeeList.getEmployee().add(new Employee(2, "Jane", "Doe"));
isFound = true;
}else if (id.equals("0")){
employeeList.getEmployee().add(new Employee(1, "John", "Doe"));
employeeList.getEmployee().add(new Employee(2, "Jane", "Doe"));
isFound = true;
}else{
isFound = false;
}
if (isFound){
setReturnStatusAndMessage("0", "Success", employeeList, responseHeaderMap);
}else{
setReturnStatusAndMessage("2", "Employee Not Found", employeeList, responseHeaderMap);
}
}catch (Throwable e){
setReturnStatusAndMessage("1", "System Error", employeeList, responseHeaderMap);
logger.error("System error occured :"+e);
}
Message<EmployeeList> message = new GenericMessage<EmployeeList>(employeeList, responseHeaderMap);
return message;
}
/**
* The API <code>setReturnStatusAndMessage()</code> sets the return status and return message
* in the return message payload and its header.
* @param status
* @param message
* @param employeeList
* @param responseHeaderMap
*/
private void setReturnStatusAndMessage(String status,
String message,
EmployeeList employeeList,
Map<String, Object> responseHeaderMap){
employeeList.setReturnStatus(status);
employeeList.setReturnStatusMsg(message);
responseHeaderMap.put("Return-Status", status);
responseHeaderMap.put("Return-Status-Msg", message);
}
}

View File

@@ -0,0 +1,76 @@
<?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
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:int-http="http://www.springframework.org/schema/integration/http">
<int:annotation-config/>
<!-- handler mapping implementation that is aware of inbound Spring Integration
http inbound gateway's and inbound adapter's with "path" attributes -->
<bean class="org.springframework.integration.http.inbound.UriPathHandlerMapping"/>
<!-- Inbound/Outbound Channels -->
<int:channel id="employeeSearchRequest" />
<int:channel id="employeeSearchResponse" />
<int-http:inbound-gateway id="inboundEmployeeSearchRequestGateway"
supported-methods="GET, POST"
request-channel="employeeSearchRequest"
reply-channel="employeeSearchResponse"
mapped-response-headers="Return-Status, Return-Status-Msg, HTTP_RESPONSE_HEADERS"
view-name="/employee"
path="/services/employee/{id}/search"
reply-timeout="50000">
<int-http:header name="employeeId" expression="#pathVariables.id"/>
</int-http:inbound-gateway>
<!-- Note: The default parameter name for favorParameter is 'format'. For instance, when this flag is true, a request for /services/employee/{id}/search?format=json will result
in an MappingJacksonJsonView being resolved, while the Accept header can be the browser-defined text/html,application/xhtml+xml -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="defaultContentType" value="application/xml"/>
<property name="favorParameter" value="true"/>
<property name="ignoreAcceptHeader" value="true" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.integration.samples.rest.json.view.ExtendedMappingJacksonJsonView" >
<property name="objectMapper" ref="jaxbJacksonObjectMapper"/>
</bean>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg ref="marshaller"/>
</bean>
</list>
</property>
</bean>
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.integration.samples.rest.domain" />
<int:service-activator id="employeeServiceActivator"
input-channel="employeeSearchRequest"
output-channel="employeeSearchResponse"
ref="employeeSearchService"
method="getEmployee"
requires-reply="true"
send-timeout="60000"/>
<bean id="jaxbJacksonObjectMapper" class="org.springframework.integration.samples.rest.json.JaxbJacksonObjectMapper"/>
</beans>

View File

@@ -0,0 +1,24 @@
# For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
log4j.rootLogger=INFO, stdout, logfile
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.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=${rest-http.root}/WEB-INF/logs/rest-http.log
log4j.appender.logfile.MaxFileSize=25MB
# Keep three backup files.
log4j.appender.logfile.MaxBackupIndex=10
# Pattern to output: date priority [category] - message
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.logger.org.springframework.ws.client.MessageTracing.sent=TRACE
log4j.logger.org.springframework.ws.client.MessageTracing.received=DEBUG
log4j.logger.org.springframework.ws.server.MessageTracing=DEBUG
# the httpclient.wire category provides a trace of all of
# httpclient's network communication
log4j.category.httpclient.wire=INFO

View File

@@ -0,0 +1,2 @@
#REST HTTP User
SPRING=gI/OZ3yejUtSxsF9XySg5TfFJFo=,ROLE_REST_HTTP_USER,enabled

View File

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

View File

@@ -0,0 +1,50 @@
<?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:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:global-method-security
secured-annotations="enabled" />
<!-- Configure Spring Security -->
<security:http auto-config="true" use-expressions="true" realm="REST HTTP Web Service" create-session="never">
<security:http-basic />
<security:intercept-url pattern='/services/employee/*' access="hasRole('ROLE_REST_HTTP_USER')" />
</security:http>
<!-- In this example, we are using in memory authentication. The password encoder depends on
Jasypt's String Digester to digest the password stored in users.properties -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:password-encoder ref="passwordEncoder"/>
<security:user-service properties="classpath:users.properties" />
</security:authentication-provider>
</security:authentication-manager>
<!--
Use the StringDigester to create uni-directional password encryption.
All uni-directional encryption methods supported in jasypt is integrated into
Spring Security
-->
<bean id="jasyptStringDigester" class="org.jasypt.digest.StandardStringDigester" >
<property name="algorithm" value="SHA-1" />
<property name="iterations" value="100000" />
<property name="saltGenerator">
<bean id="zeroSaltGenerator" class="org.jasypt.salt.ZeroSaltGenerator"/>
</property>
<property name="saltSizeBytes" value="10"/>
</bean>
<!--
This Spring Security-friendly PasswordEncoder implementation will
wrap the StringDigester instance so that it can be used from
the security framework.
-->
<bean id="passwordEncoder" class="org.jasypt.spring.security3.PasswordEncoder">
<property name="stringDigester" ref="jasyptStringDigester"/>
</bean>
</beans>

View File

@@ -0,0 +1,16 @@
<?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">
<import resource="security-config.xml" />
<import resource="classpath:META-INF/spring/integration/applicationContext-http-int.xml"/>
<context:component-scan base-package="org.springframework.integration.samples.rest"/>
</beans>

View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
version="2.5">
<display-name>Spring Integration Rest HTTP Path Usage Demo</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!-- Spring application context declaration -->
/WEB-INF/config/web-application-config.xml
</param-value>
</context-param>
<!--
Key of the system property that should specify the root directory of this
web app. Applied by WebAppRootListener or Log4jConfigListener.
-->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>rest-http.root</param-value>
</context-param>
<!--
Location of the Log4J config file, for initialization and refresh checks.
Applied by Log4jConfigListener.
-->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<!--
- Configures Log4J for this web app.
- As this context specifies a context-param "log4jConfigLocation", its file path
- is used to load the Log4J configuration, including periodic refresh checks.
-
- Would fall back to default Log4J initialization (non-refreshing) if no special
- context-params are given.
-
- Exports a "web app root key", i.e. a system property that specifies the root
- directory of this web app, for usage in log file paths.
- This web app specifies "rest-http.root" (see log4j.properties file).
-->
<!-- Leave the listener commented-out if using JBoss -->
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!--
- Loads the root application context of this web app at startup,
- by default from "/WEB-INF/applicationContext.xml".
- Note that you need to fall back to Spring's ContextLoaderServlet for
- J2EE servers that do not follow the Servlet 2.4 initialization order.
-
- Use WebApplicationContextUtils.getWebApplicationContext(servletContext)
- to access it anywhere in the web application, outside of the framework.
-
- The root context is the parent of all servlet-specific contexts.
- This means that its beans are automatically available in these child contexts,
- both for getBean(name) calls and (external) bean references.
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>charEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Spring Integration Rest HTTP Path Usage</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring Integration Rest HTTP Path Usage</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

View File

@@ -0,0 +1,146 @@
/*
* 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.samples.rest;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.stream.StreamResult;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.integration.samples.rest.domain.EmployeeList;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.HttpMessageConverterExtractor;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.RestTemplate;
/**
* RestHttpClientTest.java: Functional Test to test the REST HTTP Path usage. This test requires
* rest-http application running in HTTP environment.
* @author Vigil Bose
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:META-INF/spring/integration/http-outbound-config.xml"})
public class RestHttpClientTest {
@Autowired
private RestTemplate restTemplate;
private HttpMessageConverterExtractor<EmployeeList> responseExtractor;
private static Logger logger = Logger.getLogger(RestHttpClientTest.class);
@Autowired
private Jaxb2Marshaller marshaller;
@Autowired
private ObjectMapper jaxbJacksonObjectMapper;
@Before
public void setUp() {
responseExtractor = new HttpMessageConverterExtractor<EmployeeList>(EmployeeList.class, restTemplate.getMessageConverters());
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(javax.xml.bind.Marshaller.JAXB_ENCODING, "UTF-8");
properties.put(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setMarshallerProperties(properties);
}
/**
*
* @throws Exception
*/
@Test
public void testGetEmployeeAsXml() throws Exception{
Map<String, Object> employeeSearchMap = getEmployeeSearchMap("0");
final String fullUrl = "http://localhost:8080/rest-http/services/employee/{id}/search";
EmployeeList employeeList = restTemplate.execute(fullUrl, HttpMethod.GET,
new RequestCallback() {
@Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
HttpHeaders headers = getHttpHeadersWithUserCredentials(request);
headers.add("Accept", "application/xml");
}
}, responseExtractor, employeeSearchMap);
logger.info("The employee list size :"+employeeList.getEmployee().size());
StringWriter sw = new StringWriter();
StreamResult sr = new StreamResult(sw);
marshaller.marshal(employeeList, sr);
logger.info(sr.getWriter().toString());
assertTrue(employeeList.getEmployee().size() > 0);
}
private Map<String, Object> getEmployeeSearchMap(String id) {
Map<String, Object> employeeSearchMap = new HashMap<String, Object>();
employeeSearchMap.put("id", id);
return employeeSearchMap;
}
@Test
public void testGetEmployeeAsJson() throws Exception{
Map<String, Object> employeeSearchMap = getEmployeeSearchMap("0");
final String fullUrl = "http://localhost:8080/rest-http/services/employee/{id}/search?format=json";
HttpHeaders headers = getHttpHeadersWithUserCredentials(new HttpHeaders());
headers.add("Accept", "application/json");
HttpEntity<Object> request = new HttpEntity<Object>(headers);
ResponseEntity<?> httpResponse = restTemplate.exchange(fullUrl, HttpMethod.GET, request, EmployeeList.class, employeeSearchMap);
logger.info("Return Status :"+httpResponse.getHeaders().get("X-Return-Status"));
logger.info("Return Status Message :"+httpResponse.getHeaders().get("X-Return-Status-Msg"));
assertTrue(httpResponse.getStatusCode().equals(HttpStatus.OK));
jaxbJacksonObjectMapper.writeValue(System.out, httpResponse.getBody());
}
private HttpHeaders getHttpHeadersWithUserCredentials(ClientHttpRequest request){
return (getHttpHeadersWithUserCredentials(request.getHeaders()));
}
private HttpHeaders getHttpHeadersWithUserCredentials(HttpHeaders headers){
String username = "SPRING";
String password = "spring";
String combinedUsernamePassword = username+":"+password;
byte[] base64Token = Base64.encode(combinedUsernamePassword.getBytes());
String base64EncodedToken = new String (base64Token);
//adding Authorization header for HTTP Basic authentication
headers.add("Authorization","Basic "+base64EncodedToken);
return headers;
}
}

View File

@@ -0,0 +1,35 @@
<?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-http="http://www.springframework.org/schema/integration/http"
xmlns:oxm="http://www.springframework.org/schema/oxm"
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/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="marshaller"/>
<property name="unmarshaller" ref="marshaller"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jaxbJacksonObjectMapper"/>
</bean>
</list>
</property>
</bean>
<context:component-scan base-package="org.springframework.integration.samples.rest"/>
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.integration.samples.rest.domain" />
<bean id="jaxbJacksonObjectMapper" class="org.springframework.integration.samples.rest.json.JaxbJacksonObjectMapper"/>
</beans>

View File

@@ -0,0 +1,15 @@
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{ABSOLUTE} %5p %t %c{2}:%L - %m%n
log4j.logger.org.springframework.ws.client.MessageTracing.sent=TRACE
log4j.logger.org.springframework.ws.client.MessageTracing.received=DEBUG
log4j.logger.org.springframework.ws.server.MessageTracing=DEBUG
# the httpclient.wire category provides a trace of all of
# httpclient's network communication
log4j.category.httpclient.wire=INFO
log4j.category.org.springframework=WARN
log4j.category.org.springframework.integration=INFO