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

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