Why Angular?
Why Spring Restful?
Why CAS Authentication?
Sequence Diagram
What is Bootstrap?
Why do I choose and promote Bootstrap?
Sample Components
Easy to understand Layout
Conclusion
Why Restful?
How do you secure your restful web service?
Sequence Diagram
YourOwnSecurityInterceptor.java
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {
private AuthenticationManager authenticationManager;
private static final Logger logger = LoggerFactory.getLogger(AuthenticationInterceptor.class);
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String authorization = request.getHeader("Authorization");
if (authorization == null) {
return false;
}
String[] credentials = decodeHeader(authorization);
assert credentials.length == 2;
Authentication authentication = new UsernamePasswordAuthenticationToken(credentials[0], credentials[1]);
Authentication successfulAuthentication = authenticationManager.authenticate(authentication);
SecurityContextHolder.getContext().setAuthentication(successfulAuthentication);
return true;
}
public String[] decodeHeader(String authorization) {
try {
byte[] decoded = Base64.decode(authorization.substring(6).getBytes("UTF-8"));
String credentials = new String(decoded);
return credentials.split(":");
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
…
}
Spring Configuration
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Mvc-dispatcher-servlet.xml
<context:component-scan base-package="com.johnnyweb.stockWatcher.controller" />
<mvc:annotation-driven />
<security:global-method-security secured-annotations="enabled" />
secured-annotations="enabled"
<mvc:interceptors>
<bean id="authenticationInterceptor" class="com.johnnyweb.interceptor.AuthenticationInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
</mvc:interceptors>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service id="userService">
<security:user name="gwtrest" password="gwtrest" authorities="ROLE_CUSTOMER" />
<security:user name="gwtAdmin" password="gwtAdmin" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
Spring controller
@RequestMapping(method = RequestMethod.GET)
@Secured("ROLE_ADMIN")
public @ResponseBody List<StockPrice> getStocks( @RequestParam(value = "q", required = false) final String q ) {
String[] stockSymbols = q.split(" ");
ArrayList<StockPrice> stockPriceList= new ArrayList<StockPrice>();
for (String stockSymbol : stockSymbols) {
Random rnd = new Random();
double price = rnd.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f);
StockPrice stockPrice = new StockPrice();
stockPrice.setSymbol(stockSymbol);
stockPrice.setPrice(price);
stockPrice.setChange(change);
stockPriceList.add(stockPrice);
}
return stockPriceList;
}
Test your restful service using FIrefox RestClient
http://localhost:8080/SpringMVC/rest/stockWatcher?q=NN
Why Restful?
How do you secure your restful web service?
Sequence Diagram
Spring Configuration
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<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>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Mvc-dispatcher-servlet.xml
<context:component-scan base-package="com.johnnyweb.stockWatcher.controller" />
<mvc:annotation-driven />
<security:authentication-manager>
<security:authentication-provider>
<security:user-service id="userService">
<security:user name="gwtrest" password="gwtrest" authorities="customer" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:http create-session="stateless" use-expressions="true">
<security:intercept-url pattern="/**"
access="hasAnyRole('customer')" />
<security:http-basic />
</security:http>
Spring controller
@RequestMapping(method = RequestMethod.GET)
public @ResponseBody List<StockPrice> getStocks( @RequestParam(value = "q", required = false) final String q ) {
String[] stockSymbols = q.split(" ");
ArrayList<StockPrice> stockPriceList= new ArrayList<StockPrice>();
for (String stockSymbol : stockSymbols) {
Random rnd = new Random();
double price = rnd.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f);
StockPrice stockPrice = new StockPrice();
stockPrice.setSymbol(stockSymbol);
stockPrice.setPrice(price);
stockPrice.setChange(change);
stockPriceList.add(stockPrice);
}
return stockPriceList;
}
Test your restful service using FIrefox RestClient
Why JSON?
Spring and GWT Integration using JSON
Spring GWT StockWatcher
GWT team has already provided documents describing how to create client requests and how to process JSON reply. I am going to show you how to use Spring Framework to process the GWT request and return JSON data.
Step 1:
Create a Spring MVC application
Step 2:
Add Jackson Java JSON processor dependency in your pom file.
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.7.1</version>
</dependency>
Step 3:
Create a controller to process the GWT requests
@Controller
@RequestMapping("/stockWatcher")
public class JSONController {
private static final double MAX_PRICE = 100.0; // $100.00
private static final double MAX_PRICE_CHANGE = 0.02; // +/- 2%
@RequestMapping(method = RequestMethod.GET)
public @ResponseBody List<StockPrice> getStocks( @RequestParam(value = "q", required = false) final String q ) {
String[] stockSymbols = q.split(" ");
ArrayList<StockPrice> stockPriceList= new ArrayList<StockPrice>();
for (String stockSymbol : stockSymbols) {
Random rnd = new Random();
double price = rnd.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f);
StockPrice stockPrice = new StockPrice();
stockPrice.setSymbol(stockSymbol);
stockPrice.setPrice(price);
stockPrice.setChange(change);
stockPriceList.add(stockPrice);
}
return stockPriceList;
}
}
Step 4:
Configure Spring mvc annotation
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" 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/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.johnnyweb.stockWatcher.controller" />
<mvc:annotation-driven />
</beans>
Step 5:
Configure web.xml file
<web-app id="WebApp_ID" version="2.4"
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_4.xsd">
<display-name>Spring Web MVC Application</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Step 6:
Test your application
GWT team provides a simple tutorial: StockWatcher to demonstrate how to build GWT applications. I am going to show you the steps to use Spring Framework in this application.
public class StockPriceServiceImpl extends RemoteServiceServlet implements Controller, ServletContextAware,
StockPriceService {
private static Logger logger = Logger.getLogger(StockPriceServiceImpl.class.getName());
private static final double MAX_PRICE = 100.0; // $100.00
private static final double MAX_PRICE_CHANGE = 0.02; // +/- 2%
protected ServletContext servletContext;
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
super.doPost(request, response);
return null;
}
@Override
public ServletContext getServletContext() {
return servletContext;
}
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public StockPrice[] getPrices(String[] symbols) throws DelistedException {
Random rnd = new Random();
logger.info("getPrices is called");
StockPrice[] prices = new StockPrice[symbols.length];
for (int i=0; i<symbols.length; i++) {
if (symbols[i].equals("ERR")) {
throw new DelistedException("ERR");
}
double price = rnd.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f);
prices[i] = new StockPrice(symbols[i], price, change);
}
return prices;
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee">
<!-- Listeners -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Servlets -->
<servlet>
<servlet-name>gwtspring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gwtspring</servlet-name>
<url-pattern>/stockwatcher/greet</url-pattern>
</servlet-mapping>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>StockWatcher.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>stockPriceServiceImpl</servlet-name>
<servlet-class>com.google.gwt.sample.stockwatcher.server.StockPriceServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gwtspring</servlet-name>
<url-pattern>/stockwatcher/stockPrices</url-pattern>
</servlet-mapping>
</web-app>
<?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.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
</beans>
<?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">
<!-- The application context definition for the DispatcherServlet -->
<!-- Maps the request through to a concrete controller instance -->
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/**/stockPrices=gwtSpringDispatchController
</value>
</property>
</bean>
<bean id="gwtSpringDispatchController" class="com.google.gwt.sample.stockwatcher.server.StockPriceServiceImpl" scope="session" />
We will build a sample application which allows users to browse SESS table.
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap namespace="session">
<resultMap id="sessionResultMap" class="org.example.domain.impl.Session">
<result column="SESS_LNK" property="id" />
<result column="NM" property="name" />
<result column="OWNER" property="owner"/>
</resultMap>
<parameterMap id="searchParamMap" class="org.example.domain.impl.SessionSearch">
<parameter property="name" />
</parameterMap>
<select id="dangerousSearchMethod" parameterMap="searchParamMap" resultMap="sessionResultMap">
SELECT session.SESS_LNK,
session.NM,
session.OWNER
FROM ${jdbc.schema}.SESS session
where session.OWNER = 'TEST2'
<dynamic >
<isNotEmpty prepend="and" property="name">
session.NM like '%$name$%'
</isNotEmpty>
</dynamic>
</select>
<select id="rightSearchMethod" parameterMap="searchParamMap" resultMap="sessionResultMap">
SELECT session.SESS_LNK,
session.NM,
session.OWNER
FROM ${jdbc.schema}.SESS session
where session.OWNER = 'TEST2'
<dynamic>
<isNotEmpty prepend="and" property="name">
session.NM like '%' || #name# || '%'
</isNotEmpty>
</dynamic>
</select>
</sqlMap>
iBatis generate the following SQL Statements for the dangerousSearchMethod when a user enters ' OR 'a%'='.
<<EXECUTING>>
SELECT session.SESS_LNK,
session.NM,
session.OWNER
FROM WEBAPPS.ACEF_SESS session
where session.OWNER = 'TEST2'
and session.NM like '%name'
OR 'a%'='a%';
Big Problem
iBatis generated the following SQL Statements for rightSearchMethod when a user enters ' OR 'a%'='.
<<EXECUTING>>
SELECT session.SESS_LNK,
session.NM,
session.OWNER
FROM WEBAPPS.ACEF_SESS session
where session.OWNER = 'TEST2'
and session.NM like '%' || 'NAME' OR 'A%'='A' || '%';
No Problem at all
Why Apache Camel?
Use Case
Apache Camel Code
public class OrderProcessingRoute extends RouteBuilder {
@Override
public void configure() throws Exception {
JaxbDataFormat pubJaxb = new JaxbDataFormat();
pubJaxb.setContextPath("camel");
from("jms:incomingOrders")
.to("validator:xsd/cameleex1.xsd")
.wireTap("direct:mainprocessing")
.beanRef("orderProcessingBean", "acknowledge").inOut();
from("direct:mainprocessing")
.unmarshal(pubJaxb).beanRef("orderProcessingBean", "execute")
.marshal(pubJaxb).convertBodyTo(String.class).multicast()
.parallelProcessing().to("jms:shipping", "jms:accounting");
}
Why Spring security and role based access control
Steps to protect your web service project
Work flow
Why Soap Header and Spring Interceptor
Steps to develop Spring WS with JAXB and Spring Interceptor:
Create the WSDL contract
<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://mycompany.hr.com/hr/v1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://mycompany.hr.com/hr/v1" targetNamespace="http://mycompany.hr.com/hr/v1">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://mycompany.hr.com/hr/v1">
<xs:element name="HolidayRequest" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:sequence xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="EmployeeName" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
<xs:element name="StartDate" type="xs:date" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
<xs:element name="EndDate" type="xs:date" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="HolidayResponse" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:sequence xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Answer" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="HolidayRequestHeader" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:sequence xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="requestTimestamp" type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="HolidayRequest">
<wsdl:part element="tns:HolidayRequest" name="HolidayRequest">
</wsdl:part>
</wsdl:message>
<wsdl:message name="HolidayResponse">
<wsdl:part element="tns:HolidayResponse" name="HolidayResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="HolidayHeader">
<wsdl:part element="tns:HolidayRequestHeader" name="HolidayHeader">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="holiday">
<wsdl:operation name="Holiday">
<wsdl:input message="tns:HolidayRequest" name="HolidayRequest">
</wsdl:input>
<wsdl:output message="tns:HolidayResponse" name="HolidayResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="holidaySoap11" type="tns:holiday">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Holiday">
<soap:operation soapAction=""/>
<wsdl:input name="HolidayRequest">
<soap:header message="tns:HolidayHeader" part="HolidayHeader" use="literal" />
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="HolidayResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="holidayService">
<wsdl:port binding="tns:holidaySoap11" name="holidaySoap11">
<soap:address location="http://localhost:8080/holiday/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Generate JAXB Java classes from the schema file
Executing “xjc -p com.mycompany.hr.jaxb.holidayService hr.xsd” will generate the following classes:
Create Java Endpoint
package com.mycompany.hr.ws;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import com.mycompany.hr.jaxb.holidayService.HolidayRequest;
import com.mycompany.hr.jaxb.holidayService.HolidayResponse;
@Endpoint
public class HolidayEndpoint {
@PayloadRoot(localPart= "HolidayRequest", namespace="http://mycompany.hr.com/hr/v1")
public HolidayResponse serveRequest(HolidayRequest request){
HolidayResponse response = new HolidayResponse();
response.setAnswer("Approved");
return response;
}
}
Define Spring WS Interceptor
public class HolidayInterceptor implements SoapEndpointInterceptor {
private static final Log logger = LogFactory.getLog(HolidayInterceptor.class);
private Jaxb2Marshaller marshaller;
public boolean understands(SoapHeaderElement header) {
boolean u = header.getName().getNamespaceURI()
.equalsIgnoreCase("http://mycompany.hr.com/hr/v1");
return u;
}
public boolean handleRequest(MessageContext messageContext, Object endpoint)
throws Exception {
SoapMessage soapMsg = (SoapMessage) messageContext.getRequest();
SoapHeader soapHeader = soapMsg.getSoapHeader();
Iterator<SoapHeaderElement> iter = soapHeader.examineAllHeaderElements();
boolean found= false;
while (iter.hasNext() & (!found)) {
SoapHeaderElement she = (SoapHeaderElement) iter.next();
if (understands(she)) {
// Process the header
process(she);
found =true;
}
}
if(found)
{
return true;
}
else
{
Exception ex= new Exception();
throw ex;
}
}
private void process(SoapHeaderElement she) {
DOMResult result = (DOMResult)she.getResult();
Node node= result.getNode();
DOMSource ds= new DOMSource(node);
HolidayRequestHeader RequestHeader = (HolidayRequestHeader)marshaller.unmarshal(ds);
logger.debug("request time: "+RequestHeader.getRequestTimestamp());
}
Define and wire Endpoint in Spring
<?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-2.0.xsd">
<bean id="holiday" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
<property name="wsdl" value="classpath:holiday.wsdl" />
</bean>
<bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="classpath:hr.xsd" />
</bean>
<!-- Register PayloadRootAnnotationMethodEndpointMapping -->
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" >
<property name="interceptors">
<list merge="true">
<ref bean="holiday.interceptor"/>
</list>
</property>
</bean>
<bean name="holiday.interceptor"
class="com.mycompany.hr.interceptor.HolidayInterceptor" >
<property name="marshaller" ref="marshaller" />
</bean>
<!-- Register Endpoint -->
<bean id="HolidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint">
<description>
</description>
</bean>
<!-- Configure XML Marshaller -->
<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
<constructor-arg ref="marshaller" />
</bean>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.mycompany.hr.jaxb.holidayService.HolidayRequest</value>
<value>com.mycompany.hr.jaxb.holidayService.HolidayResponse</value>
<value>com.mycompany.hr.jaxb.holidayService.HolidayRequestHeader</value>
</list>
</property>
</bean>
</beans>
Source code and war files are attached.
Deploy the code to Tomcat and let me what happened
Why Spring WS and JAXB?
Steps to develop Spring WS with JAXB:
Create the data contract
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://mycompany.hr.com/hr/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" attributeFormDefault="unqualified">
<xs:element name="HolidayRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="EmployeeName" type="xs:string"/>
<xs:element name="StartDate" type="xs:date"/>
<xs:element name="EndDate" type="xs:date"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="HolidayResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="Answer" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Generate JAXB Java classes from the schema file
Executing “xjc -p com.mycompany.hr.jaxb.holidayService hr.xsd” will generate the following classes:
Create Java Endpoint
package com.mycompany.hr.ws;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import com.mycompany.hr.jaxb.holidayService.HolidayRequest;
import com.mycompany.hr.jaxb.holidayService.HolidayResponse;
@Endpoint
public class HolidayEndpoint {
@PayloadRoot(localPart= "HolidayRequest", namespace="http://mycompany.hr.com/hr/v1")
public HolidayResponse serveRequest(HolidayRequest request){
HolidayResponse response = new HolidayResponse();
response.setAnswer("Approved");
return response;
}
}
Define and wire Endpoint in Spring
<?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-2.0.xsd">
<!-- Add automatic WSDL generation support -->
<bean id="holiday" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
<property name="schema" ref="schema" />
<property name="portTypeName" value="holiday" />
<property name="locationUri" value="http://localhost:8080/holiday/" />
<property name="targetNamespace" value="http://mycompany.hr.com/hr/v1" />
</bean>
<bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="/WEB-INF/hr.xsd" />
</bean>
<!-- Register PayloadRootAnnotationMethodEndpointMapping -->
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />
<!-- Register Endpoint -->
<bean id="HolidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint">
<description>
This endpoint handles requests.
</description>
</bean>
<!-- Configure XML Marshaller -->
<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
<constructor-arg ref="marshaller" />
</bean>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.mycompany.hr.jaxb.holidayService.HolidayRequest</value>
<value>com.mycompany.hr.jaxb.holidayService.HolidayResponse</value>
</list>
</property>
</bean>
</beans>
Source code and war files are attached.
Deploy the code to Tomcat and let me what happened
Why Search Engine Optimization?
You have a web site. How do you get your web site noticed by your potential customers? When people search key words in Google, Bing or Yahoo, it is vital for your web site to rank high in search engines to attract visitors and turn visitors into leads and sales.
One vital SEO component is friendly URL. Unfortunately the default Seam URL is not SEO friendly.
Here is one example of Seam URL:
http://localhost:8080/seam-bay/search.seam?categoryId=11
Here is an example of SEO friendly URL:
http://localhost:8080/seam-bay/category/books
What is Tuckey URL Rewrite?
UrlRewriteFilter is a Java Web Filter for any J2EE compliant web application server, which allows you to rewrite URLs before they get to your code. Developers can specify the inbound and outbound rules in the urlwrite.xml file.
In the following example, requests for /world/usa/nyc will be transparently forwarded to /world.jsp
<rule>
<name>World Rule</name>
<from>^/world/([a-z]+)/([a-z]+)$</from>
<to>/world.jsp?country=$1&city=$2</to>
</rule>
>
Configure Seam Application to use Tuckey URL Rewrite
It is actually very easy. Just add the following lines to your web.xml file. Please look the Seam Bay application in Seam examples folder.
<!-- URL Rewrite Filter -->
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
How to create SEO friendly links?
Seam bay is already configured to use UrlRewrite filter. So I made some modification to the home.xhtml. I used <h:outputLink> to expose category as SEO friendly links.
<ui:repeat id="categories" value="#{categories}" var="cat">
<h:outputLink value="#{facesContext.externalContext.requestContextPath}/category/#{cat.name}">
#{cat.name}
</h:outputLink>
</ui:repeat>
How to process SEO friendly links?
Step1: add an inbound rule rewrite rule in the urlrewrite.xml.
<rule>
<from>^/category/([A-Za-z0-9]*)$</from>
<to last="true">/search.seam?categoryName=$1</to>
</rule>
Urlrewrite will then rewrite http://localhost:8080/seam-bay/category/Books to: http://localhost:8080/seam-bay/search.seam?categoryName=Books
Step2: modify pages.xml to handle URL parameters
<page view-id="/search.xhtml" >
<param name="categoryName" value="#{auctionSearch.bookMarkCategoryName}"/>
</page>
Step 3: modify AuctionSearch.java
private String bookMarkCategoryName;
public String getBookMarkCategoryName()
{
return bookMarkCategoryName;
}
public void setBookMarkCategoryName(String categoryName)
{
List<Category> children = entityManager.createQuery(
"from Category c where UPPER(c.name) = :name")
.setParameter("name", categoryName.toUpperCase() )
.getResultList();
if(children.size()>0)
{
this.searchCategory=children.get(0);
}
queryAuctions();
}
You are done.
Why Native SQL integration?
How to integrate native SQL and Stored Procedures?
The example below demonstrates how to use SQL in the Jboss Seam registration example.
Sql queries are defined in orm.xml. Register method is modified to use JPA named query API.
orm.xml
Registration.java
Why Facelets not JSP?
The main benefit of using Facelets over JSF is that Facelets supports code reuse through templating and composite components.
The example below shows how the address.xhtml template is used in the useraddresses.xhmtl file. A user has a mailing address and a shipping address. The address.xhtml is used twice in the useraddresses.xhtml. The big difference between Facelets template and JSP include is that you can pass object parameters from the including file to the template in Facelets and you can’t do that from JSP including file.
address.xhtml
useraddress.xhtml
What is the difference between Seam Managed Persistence and EJB managed Persistence Context?