- Changing the default Object factory: In order to change the Ojbect factory to Spring, you have to add a declaration in the struts.properties file.
struts.objectFactory = spring
struts.devMode = true
struts.enable.DynamicMethodInvocation = falsesrc/struts.properties - The Action class: Here is the code for the action class
package actions;
import java.util.List;
import business.BusinessInterface;
import com.opensymphony.xwork2.ActionSupport;
public class SearchAction extends ActionSupport {
private BusinessInterface businessInterface;
private String minSalary;
private String submit;
private List data;
public String getSubmit() {
return submit;
}
public void setSubmit(String submit) {
this.submit = submit;
}
public BusinessInterface getBusinessInterface() {
return businessInterface;
}
public String execute() throws Exception {
try {
long minSal = Long.parseLong(getMinSalary());
System.out.println("Business Interface: " + businessInterface + "Minimum salary : " + minSal);
data = businessInterface.getData(minSal);
System.out.println("Data : " + data);
} catch (Exception e) {
e.printStackTrace();
}
return SUCCESS;
}
public void setBusinessInterface(BusinessInterface bi) {
businessInterface = bi;
}
public String getMinSalary() {
return minSalary;
}
public void setMinSalary(String minSalary) {
this.minSalary = minSalary;
}
public List getData() {
return data;
}
public void setData(List data) {
this.data = data;
}
}SearchAction.java - The Action class here does not have access to the HttpServetRequest and HttpServletResponse. Hence the action class itself was changed to the session scope for this example (see below)
- In order for the action class to be aware of the Http Session, the action class has to implement the ServletRequestAware interface, and define a setServletRequest method, which will be used to inject the ServletRequest into the action class.
- The BusinessInterface property is injected by Spring framework.
- The struts Configuration:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="Struts2Spring" namespace="/actions" extends="struts-default">
<action name="search" class="actions.SearchAction">
<result>/search.jsp</result>
</action>
</package>
</struts>src/struts.xml - The action's class attribute has to map the id attribute of the bean defined in the spring bean factory definition.
- The Spring bean factory definition
<?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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
default-autowire="autodetect">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@localhost:1521:orcl</value>
</property>
<property name="username">
<value>scott</value>
</property>
<property name="password">
<value>tiger</value>
</property>
</bean>
<!-- Configure DAO -->
<bean id="empDao" class="data.DAO">
<property name="dataSource">
<ref bean="dataSource"></ref>
</property>
</bean>
<!-- Configure Business Service -->
<bean id="businessInterface" class="business.BusinessInterface">
<property name="dao">
<ref bean="empDao"></ref>
</property>
</bean>
<bean id="actions.SearchAction" name="search" class="actions.SearchAction" scope="session">
<property name="businessInterface" ref="businessInterface" />
</bean>
</beans>WEB-INF/applicationContext.xml - The bean definition for the action class contains the id attribute which matches the class attribute of the action in struts.xml
- Spring 2's bean scope feature can be used to scope an Action instance to the session, application, or a custom scope, providing advanced customization above the default per-request scoping.
- The web deployment descriptor
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" 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>Struts2Spring</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>web.xml The only significant addition here is that of the RequestContextListener. This listener allows Spring framework, access to the HTTP session information. - The JSP file: The JSP file is shown below. The only change here is that the action class, instead of the Data list is accessed from the session.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://displaytag.sf.net" prefix="display"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<%@ page import="actions.SearchAction,beans.Employee,business.Sorter,java.util.List,org.displaytag.tags.TableTagParameters,org.displaytag.util.ParamEncoder"%>
<html>
<head>
<title>Search page</title>
<link rel="stylesheet" type="text/css" href="/StrutsPaging/css/screen.css" />
</head>
<body bgcolor="white">
<s:form action="/actions/search.action">
<table>
<tr>
<td>Minimum Salary:</td>
<td><s:textfield label="minSalary" name="minSalary" /></td>
</tr>
<tr>
<td colspan="2"><s:submit name="submit" /></td>
</tr>
</table>
</s:form>
<jsp:scriptlet>
SearchAction action = (SearchAction)session.getAttribute("actions.SearchAction");
session.setAttribute("empList", action.getData());
if (session.getAttribute("empList") != null) {
String sortBy = request.getParameter((new ParamEncoder("empTable")).encodeParameterName(TableTagParameters.PARAMETER_SORT));
Sorter.sort((List) session.getAttribute("empList"), sortBy);
</jsp:scriptlet>
<display:table name="sessionScope.empList" pagesize="4" id="empTable" sort="external" defaultsort="1" defaultorder="ascending" requestURI="">
<display:column property="empId" title="ID" sortable="true" sortName="empId" headerClass="sortable" />
<display:column property="empName" title="Name" sortName="empName" sortable="true" headerClass="sortable" />
<display:column property="empJob" title="Job" sortable="true" sortName="empJob" headerClass="sortable" />
<display:column property="empSal" title="Salary" sortable="true" headerClass="sortable" sortName="empSal" />
</display:table>
<jsp:scriptlet>
}
</jsp:scriptlet>
</body>
</html:html>search.jsp - The Other required classes: The following other classes have been used for the example, and they can be obtained from the previous posts (1, 2).
- Employee.java
- BusinessInterface.java
- Sorter.java
- DAO.java
- EmpMapper.java
Monday, January 29, 2007
Integrating Struts 2.0 with Spring
In the past, I posted an example on how to use Displaytag with Struts and Spring, using Spring JDBC for data access(1, 2). In this post, I will describe how to do the same using Struts 2.0. The only major step that needs to be done here is to override the default Struts 2.0 OjbectFactory. Changing the ObjectFactory to Spring give control to Spring framework to instantiate action instances etc. Most of the code is from the previous post, but I will list only the additional changes here.
Tuesday, January 23, 2007
Spring: Prototype beans with Singletons - 2
The previous post described how to implement Lookup method injection and ServiceLocatorFactoryBean and BeanFactoryAware to enable singleton classes to use Prototype beans. This post will describe how to use Scoped beans (session or request or globalSession) from Spring managed beans in a Web application and also give the client servlet for testing the previous and the current examples.
Using in Web Applications
This is not for Singleton or Prototype beans. This solution is for using beans that are saved in the request of session scope. To implement this solution, you must inject an AOP proxy in place of the scoped bean, the proxy will then delegate the method call to the object that is in currently in the specified scope. All you have to do is to put the following in the bean definitionNewCommand.java
The Command Manager is shown belowCmdMgrWeb.java
The Servlet
The following is the servlet used for testing the beans used here.MethodInjectionServlet.java
The Web Deployment Descriptor
The web.xml file is shown below. You can see the two listeners required for using spring and the scoped beans.WEB-INF/web.xml
The Bean Definitions
The following is the code for the applicationContext.xml file. It is quite self explanatory.WEB-INF/applicationContext.xml
Using in Web Applications
This is not for Singleton or Prototype beans. This solution is for using beans that are saved in the request of session scope. To implement this solution, you must inject an AOP proxy in place of the scoped bean, the proxy will then delegate the method call to the object that is in currently in the specified scope. All you have to do is to put the following in the bean definition
<aop:scoped-proxy/>In the Web deployment descriptor (Shown in a following section), you will have to put a RequestContextListener in addition to the ContextLoaderListener. The RequestContextListener binds the HTTP request object to the Thread that is servicing that request. This makes beans that are request and session-scoped available further down the call chain (i.e. for spring managed beans invoked in the same thread of execution). For the Web Application scenario, I used a different Command bean shown below
package beans;
public class NewCommand {
private String someProperty;
public String getSomeProperty() {
return someProperty;
}
public void setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}
public String execute() {
return "Command property : " + someProperty;
}
}
The Command Manager is shown below
package beans;
public class CmdMgrWeb {
private NewCommand command;
public Object process(String prop) {
command.setSomeProperty(prop);
return command.execute();
}
public NewCommand getCommand() {
return command;
}
public void setCommand(NewCommand command) {
this.command = command;
}
}
The Servlet
The following is the servlet used for testing the beans used here.
package servlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import beans.CmdMgrNoBFA;
import beans.CmdMgrServiceFactory;
import beans.CmdMgrWeb;
import beans.CommandManager;
import beans.NewCommand;
public class MethodInjectionServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
public MethodInjectionServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
request.getSession().setAttribute("command", new NewCommand());
BeanFactory factory = (BeanFactory) context;
PrintWriter writer = response.getWriter();
CommandManager commandManager = (CommandManager) factory.getBean("commandManager");
writer.println(commandManager.process("test"));
CmdMgrNoBFA cmdMgrNoBFA = (CmdMgrNoBFA) factory.getBean("cmdMgrNoBFA");
writer.println(cmdMgrNoBFA.process("test"));
CmdMgrServiceFactory cmdMgrServiceFactory = (CmdMgrServiceFactory) factory.getBean("cmdMgrServiceFactory");
writer.println(cmdMgrServiceFactory.process("test"));
CmdMgrWeb cmdMgrWeb = (CmdMgrWeb) factory.getBean("cmdMgrWeb");
writer.println(cmdMgrWeb.process("test"));
}
}
The Web Deployment Descriptor
The web.xml file is shown below. You can see the two listeners required for using spring and the scoped beans.
<?xml version="1.0" encoding="UTF-8"?>
<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>MethodInjectionWeb</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<description></description>
<display-name>MethodInjectionServlet</display-name>
<servlet-name>MethodInjectionServlet</servlet-name>
<servlet-class>servlets.MethodInjectionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MethodInjectionServlet</servlet-name>
<url-pattern>/MethodInjectionServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
The Bean Definitions
The following is the code for the applicationContext.xml file. It is quite self explanatory.
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="command" class="beans.Command" scope="prototype"></bean>
<!-- Basic implementation by extending BeanFactoryAware -->
<bean id="commandManager" class="beans.CommandManager"></bean>
<!-- The lookup-method is implemented by Spring -->
<bean id="cmdMgrNoBFA" class="beans.CmdMgrNoBFA">
<lookup-method name="createCommand" bean="command" />
</bean>
<!-- Use Service locator factory to obtain a reference -->
<bean id="springServiceFactory" class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value="beans.ServiceFactory" />
</bean>
<bean id="cmdMgrServiceFactory" class="beans.CmdMgrServiceFactory">
<property name="serviceFactory" ref="springServiceFactory"></property>
</bean>
<!-- Using in Web Applications -->
<bean id="newCommand" class="beans.NewCommand" scope="session">
<aop:scoped-proxy />
</bean>
<bean id="cmdMgrWeb" class="beans.CmdMgrWeb">
<property name="command" ref="newCommand" />
</bean>
</beans>
Spring: Prototype beans with Singletons - 1
In a Spring application, when a singleton bean uses another singleton bean, or a non-singleton bean uses another non-singleton bean, setting one bean as a property of the other is quite adequate. But when the two beans are not of the same Scope i.e. When a singleton bean has to use a non-singleton (prototype) bean, the container will create the singleton bean just once, and the prototype bean that it depends on will also be set only once. The container cannot provide the Singleton bean with a new instance of the prototype bean each time it is needed. This post and the next describe four different approaches to address this problem.
The Command
The following is the code fo the Command class that will be used by the different Command Managers in the example.Command.java
Using BeanFactory Aware
In this approach, we delegate the creation of the prototype bean to the Singleton itself. This can be achieved by implementing the BeanFactoryAware interface as shown below.CommandManager.java
You can see here that the createCommand method uses the beanFactory.getBean() method to get the Command bean. This dependency on the Spring API is not that desirable.
Lookup Method Injection
Lookup method injection refers to the ability of the container to override methods on container managed beans, to return the result of looking up another named bean in the container.The Spring Framework implements this method injection by dynamically generating a subclass overriding the method, using bytecode generation via the CGLIB library. The command manager of the above implementation is changed in the following to allow lookup method injection.CmdMgrNoBFA.java
You can see here that the Command Manager does not implement the BeanFactoryAware interface. The createCommand was declared as abstract method, but it may also be defined here (the container will override it any way). The signature of the lookup method must have the following form
Using ServiceLocatorFactoryBean
Service locators help avoid the usage of the BeanFactory API using a custom locator interface. Service locators are typically used for prototype beans. Setter or constructor injection of the target bean is preferable, where the target bean is a Singleton. The custom locator interface shown below does not depend on the bean factory API.ServiceFactory.java
The corresponding Command Manager must have a ServiceFactory property that will be injected by the container. This is the code for the CommandManager used here.CmdMgrServiceFactory.java
Invoking the no-arg getCommand() method or the single-arg method with null, will return an instance of the Command object by matching it's type if there is only one bean of the type beans.Command. If there are more then beans.Command beans, then a NoSuchBeanDefinitionException is thrown. By default, the single string argument is matched to the bean names defined in the applicationContext.xml file. Alternatively, you can set a mapping of the string argument to bean names using a Properties object for mapping. This Properties object can be injected in using the serviceMappings property. Using with Web applications and rest of the definitions are in the next post.
| Using BeanFactoryAware | Forgo dependency injection. |
| Using Lookup Method Injection | Dynamically generate a subclass overriding the method, using bytecode generation via the CGLIB library |
| Using ServiceLocatorFactoryBean | A custom locator interface. |
| In Web Applications | Uses RequestContextListener in addition to ContextLoaderListener |
The Command
The following is the code fo the Command class that will be used by the different Command Managers in the example.
package beans;
public class Command {
private String someProperty;
public String getSomeProperty() {
return someProperty;
}
public void setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}
public String execute() {
return "Command property : " + someProperty;
}
}
Using BeanFactory Aware
In this approach, we delegate the creation of the prototype bean to the Singleton itself. This can be achieved by implementing the BeanFactoryAware interface as shown below.
package beans;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
public class CommandManager implements BeanFactoryAware {
private BeanFactory beanFactory;
public Object process(String prop) {
Command command = createCommand();
command.setSomeProperty(prop);
return command.execute();
}
protected Command createCommand() {
return (Command) this.beanFactory.getBean("command");
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
You can see here that the createCommand method uses the beanFactory.getBean() method to get the Command bean. This dependency on the Spring API is not that desirable.
Lookup Method Injection
Lookup method injection refers to the ability of the container to override methods on container managed beans, to return the result of looking up another named bean in the container.The Spring Framework implements this method injection by dynamically generating a subclass overriding the method, using bytecode generation via the CGLIB library. The command manager of the above implementation is changed in the following to allow lookup method injection.
package beans;
public abstract class CmdMgrNoBFA {
public Object process(String prop) {
Command command = createCommand();
command.setSomeProperty(prop);
return command.execute();
}
protected abstract Command createCommand();
}
You can see here that the Command Manager does not implement the BeanFactoryAware interface. The createCommand was declared as abstract method, but it may also be defined here (the container will override it any way). The signature of the lookup method must have the following form
<public|protected> [abstract] <return-type> theMethodName(no-arguments);Note that beans that have been the target of method injection cannot be serialized.
Using ServiceLocatorFactoryBean
Service locators help avoid the usage of the BeanFactory API using a custom locator interface. Service locators are typically used for prototype beans. Setter or constructor injection of the target bean is preferable, where the target bean is a Singleton. The custom locator interface shown below does not depend on the bean factory API.
package beans;
public interface ServiceFactory {
public Command getCommand();
public Command getCommand(String beanName);
}
The corresponding Command Manager must have a ServiceFactory property that will be injected by the container. This is the code for the CommandManager used here.
package beans;
public class CmdMgrServiceFactory {
public ServiceFactory serviceFactory;
public Object process(String prop) {
Command command = serviceFactory.getCommand("command");
command.setSomeProperty(prop);
return command.execute();
}
public ServiceFactory getServiceFactory() {
return serviceFactory;
}
public void setServiceFactory(ServiceFactory serviceFactory) {
this.serviceFactory = serviceFactory;
}
}
Invoking the no-arg getCommand() method or the single-arg method with null, will return an instance of the Command object by matching it's type if there is only one bean of the type beans.Command. If there are more then beans.Command beans, then a NoSuchBeanDefinitionException is thrown. By default, the single string argument is matched to the bean names defined in the applicationContext.xml file. Alternatively, you can set a mapping of the string argument to bean names using a Properties object for mapping. This Properties object can be injected in using the serviceMappings property. Using with Web applications and rest of the definitions are in the next post.
Monday, January 22, 2007
Implementing Observer Pattern in Java
The Observer pattern allows an object (an Observer) to watch another object (a Subject). The subject and observer to have a publish/subscribe relationship. Observers can register to receive events from the Subject. When the subject can update the Observers when certain expected events occur. In Design Patterns, the Observer Pattern is defined as
When To Use
Pros and Cons
Issues

ObserverTest.java
Define a one-to-many dependency between objects so that when one object changes state,The Observer pattern helps create a family of cooperating classes, while maintaining consistency and avoiding tight-coupling.
all its dependents are notified and updated automatically.
When To Use
- In a mailing list, where every time an event happens (a new product, a gathering, etc.) a message is sent to the people subscribed to the list.
- When a change to one object requires changing others, and you don't know how many objects need to be changed.
- When an object should be able to notify other objects without making assumptions about who these objects are (avoid tight-coupling).
Pros and Cons
- Loose coupling between Subject and Observer: The subject knows only a list of observers, that implement the Observer interface, it does no know the concrete implementation of the Observer.
- Broadcast communication: An event notification is broadcast observers irrespective of the number of Observers
- Unexpected updates: The can be blind to the cost of changing the subject.
Issues
- Mapping subjects to their observers: A subject can keep track it's observers as a list of all observer references or in a hash table, depending on whether space of time is the criteria respectively.
- Observing more than one subject: Using the Observer pattern you can implement a many-to-many relationship between subjects and observers. In this case, the Observer may need to know which subject is sending the notification. One way is to pass the Subject as an argument to the Update operation.
- Who triggers the update (Notify operation in Subject):
- State setting operation in subject to trigger Notify.
- Client trigger Notify at the right time.
- Dangling references to deleted subjects: Deleting a subject or a observer should not produce dangling references.
- Making sure subject state is self-consistent before notification: Otherwise, an observer can query subject's intermediate state through GetState operation.
- Avoiding observer-specific update protocols: push and pull models:
- Push model: subject sends details change information to observer, for this the subject has to know about the Observers.
- Pull model: subject sends minimum change information to observer and observer query for the rest of the information, as a result there might be more method calls that necessary.
- Specifying modifications of interest explicitly: One can register observer for only specific events. This can improve update efficiency.

- Subject: Maintains a list of Observer references. Subject also provides an interface for attaching and detaching Observer objects.
- Observer: Defines an updating interface for objects that should be notified of changes in a subject.
- ConcreteSubject: Stores state of interest to ConcreteObserver objects and sends notifications to its observers upon state changes.
- ConcreteObserver: Maintains a reference to a ConcreteSubject object and a state that should stay consistent with the subject's.
package patterns;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
interface Subject {
public void addObserver(Observer o);
public void removeObserver(Observer o);
public String getState();
public void setState(String state);
}
interface Observer {
public void update(Subject o);
}
class ObserverImpl implements Observer {
private String state = "";
public void update(Subject o) {
state = o.getState();
System.out.println("Update received from Subject, state changed to : " + state);
}
}
class SubjectImpl implements Subject {
private List observers = new ArrayList();
private String state = "";
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
notifyObservers();
}
public void addObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
Iterator i = observers.iterator();
while (i.hasNext()) {
Observer o = (Observer) i.next();
o.update(this);
}
}
}
public class ObserverTest {
public static void main(String[] args) {
Observer o = new ObserverImpl();
Subject s = new SubjectImpl();
s.addObserver(o);
s.setState("New State");
}
}
Thursday, January 18, 2007
EJB 3 Timer Service
Applications with business processes that are dependent on periodic notifications (for state transitions etc.) need a timer/scheduler service. In the past I posted how to use the Quartz Scheduler for scheduling jobs. In this post, I will describe the use of the EJB 3 Timer Service for scheduling, or temporal event driven processing.
The EJB Timer Service is a container-managed service that provides a way to allow methods to be invoked at specific times or time intervals. The EJB Timer may be set to invoke certain EJB methods at a specific time, after a specific duration, or at specific recurring intervals. The Timer Service is implemented by the EJB container and injected into the EJB through the EJBContext interface, or the EJB can access it through a JNDI lookup. In the example presented below, the EJB timer is set when the client invokes the startTimer method. The checkStatus() method is used to get the time left for the next timeout. The example was implemented on Glassfish server, with Eclipse 3.2 used for development.
Follow these steps to implement the example.
The EJB
The Timer Client
For this example, I used a web client. The client has a context listener which loads the timer when the application is deployed. A single servlet is used to invoke the checkStatus() method on the client.
Timer Service Additional Info (From the EJB 3.0 Specification)
The EJB Timer Service is a container-managed service that provides a way to allow methods to be invoked at specific times or time intervals. The EJB Timer may be set to invoke certain EJB methods at a specific time, after a specific duration, or at specific recurring intervals. The Timer Service is implemented by the EJB container and injected into the EJB through the EJBContext interface, or the EJB can access it through a JNDI lookup. In the example presented below, the EJB timer is set when the client invokes the startTimer method. The checkStatus() method is used to get the time left for the next timeout. The example was implemented on Glassfish server, with Eclipse 3.2 used for development.
Follow these steps to implement the example.
The EJB
- The EJB interface: The interface for the EJB is shown below.
package ejb;
public interface ITimedBean {
public String checkStatus();
public void startTimer();
}ITimedBean.java - The Bean: The following is the code for the EJB followed by a brief explanation
package ejb;
import java.util.Collection;
import java.util.Iterator;
import javax.annotation.Resource;
import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
@Stateless(mappedName="ejb/timedBean")
@Remote
public class TimedBean implements ITimedBean {
@Resource
private SessionContext ctx;
public void startTimer() {
ctx.getTimerService().createTimer(1000, 1000, null);
System.out.println("Timers set");
}
public String checkStatus() {
Timer timer = null;
Collection timers = ctx.getTimerService().getTimers();
Iterator iter = timers.iterator();
while (iter.hasNext()) {
timer = (Timer) iter.next();
return ("Timer will expire after " + timer.getTimeRemaining() + " milliseconds.");
}
return ("No timer found");
}
@Timeout
public void handleTimeout(Timer timer) {
System.out.println("HandleTimeout called.");
}
}TimedBean.java - The @Stateless(mappedName="ejb/timedBean") annotation declares the bean as a stateless EJB. The mappedName attribute defines the global JNDI name to which this EJB will be bound.
- In the startTimer method, the ctx.getTimerService().createTimer(1000, 1000, null); call is used to create the timer, this call will create a timer that invokes the methods at specific intervals. Another way to create a timer would be to use the call ctx.getTimerService().createTimer(1000, null);, in which case, the timer will invoke the EJB method just once.
- The EJB 3 Timer Service also allows you to send client-specific information at timer creation, throught the public Timer createTimer(long initialDuration, long intervalDuration, java.io.Serializable info); and some overloaded methods as shown below in the TimerService interface.
public interface javax.ejb.TimerService {
public Timer createTimer(long duration,java.io.Serializable info);
public Timer createTimer(long initialDuration,long intervalDuration, java.io.Serializable info);
public Timer createTimer(java.util.Date expiration,java.io.Serializable info);
public Timer createTimer(java.util.Date initialExpiration,long intervalDuration, java.io.Serializable info);
public Collection getTimers();
} - A timer may be cancelled at any time, by using the cancel() method in the Timer interface.
- The @Timeout annotation declares the handleTimeout() method to be a callback method for the timer.
- Deploying: When deploying on Glassfish using the Admin console, check the "Generate RMI Stubs in a Jar File" option. The Jar file will be created in the GLASSFISH_HOME/domains/DOMAIN_NAME/generated/xml/j2ee-modules/APPLICATION_NAME directory.
The Timer Client
For this example, I used a web client. The client has a context listener which loads the timer when the application is deployed. A single servlet is used to invoke the checkStatus() method on the client.
- Start with a Dynamic Web Application in Eclipse. Include the generated client Jar file as a dependency.
- The Context Listener: The code for the context listener is shown below.
package servlets;
import javax.ejb.EJB;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import ejb.ITimedBean;
public class LoadTimer implements ServletContextListener {
@EJB(name="timerBean", mappedName="corbaname:iiop:localhost:3700#ejb/timedBean")
private ITimedBean timerBean;
public void contextInitialized(ServletContextEvent servletcontextevent) {
System.out.println("Starting timer");
timerBean.startTimer();
}
public void contextDestroyed(ServletContextEvent servletcontextevent) {
}
public ITimedBean getTimerBean() {
return timerBean;
}
public void setTimerBean(ITimedBean timerBean) {
this.timerBean = timerBean;
}
}LoadTimer.java
You will notice that the Context listener has a timerBean field with @EJB annotation. The mapped name for the EJB is defined to be the full JNDI name.@EJB(name="timerBean", mappedName="corbaname:iiop:localhost:3700#ejb/timedBean")
This is only needed in case of remote deployments on different clusters. In the same cluster you could simply use "ejb/timedBean". - The Servlet: The servlet is has a similar @EJB annotation.
package servlets;
import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ejb.ITimedBean;
public class TimerClient extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
@EJB(name="timerBean", mappedName="corbaname:iiop:localhost:3700#ejb/timedBean")
private ITimedBean timerBean;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println(timerBean.checkStatus());
response.getWriter().println(timerBean.checkStatus());
response.getWriter().println(timerBean.checkStatus());
}
public ITimedBean getTimerBean() {
return timerBean;
}
public void setTimerBean(ITimedBean timerBean) {
this.timerBean = timerBean;
}
}TimerClient.java - The Deployment descriptor: The deployment descriptor is listed below.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 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">
<display-name>TimerClientWeb</display-name>
<listener>
<listener-class>servlets.LoadTimer</listener-class>
</listener>
<servlet>
<description></description>
<display-name>TimerClient</display-name>
<servlet-name>TimerClient</servlet-name>
<servlet-class>servlets.TimerClient</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TimerClient</servlet-name>
<url-pattern>/timerClient</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>web.xml
Timer Service Additional Info (From the EJB 3.0 Specification)
- Invocations of the methods to create and cancel timers and of the timeout callback method are typically made within a transaction.
- If the transaction is rolled back, the timer creation is rolled back and so is the case with timer cancellation.
- If container-managed transaction demarcation is used and the REQUIRED or REQUIRES_NEW transaction attribute is specified or defaulted (Required or RequiresNew if the deployment descriptor is used), the container must begin a new transaction prior to invoking the timeout callback method.
- If the transaction fails or is rolled back, the container must retry the timeout at least once.
- Timers survive container crashes, server shutdown, and the activation/passivation and load/store cycles of the enterprise beans that are registered with them.
- Since the timeout callback method is an internal method of the bean class, it has no client security context. When getCallerPrincipal is called from within the timeout callback method, it returns the container's representation of the unauthenticated identity.
Wednesday, January 17, 2007
Securing Java EE 5 Web Applications
In this post I will give a brief overview of securing web applications in Java EE 5 with the help of a simple example. The example application consists of a Servlet (securityServlet) and two pages (index.jsp and secure/index.jsp). Two users (newemployee and newguest) with roles employee and guest, will be created, with the following permissions
Create Users in Glassfish
- The "guest" user will have access to index.jsp
- The "employee" user will have access to secure/index.jsp.
- Both users have access to the servlet.
Create Users in Glassfish
- Go to Configuration->Security->Realms->file in the Glassfish admin console.
- In the file realm, click on manage users.
- Add new users by clicking on add there.
- The Web Deployment Descriptor: The following listing shows the complete deployment descriptor used for this example, followed by a quick explanation.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5" 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">
<display-name>Java5Security</display-name>
<servlet>
<description></description>
<display-name>SecurityServlet</display-name>
<servlet-name>SecurityServlet</servlet-name>
<servlet-class>servlets.SecurityServlet</servlet-class>
<security-role-ref>
<role-name>emp</role-name>
<role-link>employee</role-link>
</security-role-ref>
</servlet>
<servlet-mapping>
<servlet-name>SecurityServlet</servlet-name>
<url-pattern>/securityServlet</url-pattern>
</servlet-mapping>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>guest</role-name>
<role-name>employee</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/secure/*</url-pattern>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>employee</role-name>
</auth-constraint>
</security-constraint>
<!-- Security roles referenced by this web application -->
<security-role>
<role-name>guest</role-name>
</security-role>
<security-role>
<role-name>employee</role-name>
</security-role>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>WEB-INF/web.xml - In the servlet declaration, the <security-role-ref> element maps the rolename used in the servlet to role declared in the deployment descritpor (this is needed only when the role declared in the deployment descriptor is different from the role used in the servlet (employee and emp)).
- In the login-config, the <realm-name> element is used to declare the realm in which authentication takes place
- Realms: A realm is a database of users and groups that identify valid users of a Web application and are controlled by the same authentication policy. Three realms, file, admin-realm, and certificate realms come preconfigured in Glassfish Application Server. For this example I use the file realm, where the user credentials are stored locally in a file.
- Mapping Roles to Users/Groups in Security Realm: In order to map the roles used in the application to the users defined in the security realm, you have to add the role mappings in the WEB-INF/sun-web.xml. The file is shown below.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.1 Servlet 2.4//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_2_4-1.dtd">
<sun-web-app>
<context-root>/Java5Security</context-root>
<security-role-mapping>
<role-name>guest</role-name>
<principal-name>newguest</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>employee</role-name>
<principal-name>newemployee</principal-name>
</security-role-mapping>
</sun-web-app>WEB-INF/sun-web.xml - The Servlet: The following is a listing of the servlet used for this example
package servlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.annotation.security.DeclareRoles;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@DeclareRoles("emp")
public class SecurityServlet extends javax.servlet.http.HttpServlet implements
javax.servlet.Servlet {
public SecurityServlet() {
super();
}
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
if (request.isUserInRole("emp"))
out.println(request.getUserPrincipal() + " is an Authorized User");
else
out.println(request.getUserPrincipal() + " is not an Authorized to see this page.");
}
}SecurityServlet.java - The @DeclareRoles annotation is used to define the security roles in the application. This annotation is specified on a class, and it typically would be used to define roles that could be tested (i.e., by calling isUserInRole) from within the methods of the annotated class.
- The isUserInRole() method is from J2EE.
- The login page: The following is the listing for the login.jsp page. There is nothing new here.
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core'%>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<h2>Hello, please login:</h2>
<br>
<br>
<form action="j_security_check" method=post>
<table>
<tr>
<td>User:</td>
<td><input type="text" name="j_username" size="25"></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='j_password'></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"></td>
</tr>
<tr>
<td colspan='2'><input name="reset" type="reset"></td>
</tr>
</table>
</form>
</body>
</html>/login.jsp - The index.jsp and error.jsp could be any JSP page
- This post did not describe how to logout. But that has been discussed earlier in the Form-based Authentication Logout post.
Tuesday, January 16, 2007
Handling Oracle Large Objects with JDBC
LOBs (Large OBjects) are are designed to support large unstructured data such as text, images, video etc. Oracle supports the following two types of LOBs:
Working with LOB Data
CLOB and the BLOB objects are not created and managed in the same way as the ordinary types such as VARCHAR. To work with LOB data, you must first obtain a LOB locator. Then you can read or write LOB data and perform data manipulation. Use the ResultSet's getBlob method to obtain the LOB locator, and then you can obtain the a Stream of the blob to read/write to the BlobBlobTest.java
Insert Blob into Oracle
The insertBlob method takes the image id and the image file name as arguments. If the image file is an empty string, then an empty blob is inserted into the table. The empty_blob() function returns an empty locator of type BLOB, this is used in the INSERT.
Read from a Blob
The getBinaryStream of java.sql.Blob class returns an InputStream, which can be used to read from the blob.
Write to a Blob
The writeBlob method writes to the first row retrieved from the table. The SQL statement uses FOR UPDATE. In the absence of FOR UPDATE, you will get an IOException
- Character Large Object (CLOB) and Binary Large Object(BLOB) are stored in the database either in-line in the table or in a separate segment or tablespace.
- BFILEs are large binary data objects stored in operating system files outside of database tablespaces.
Working with LOB Data
CLOB and the BLOB objects are not created and managed in the same way as the ordinary types such as VARCHAR. To work with LOB data, you must first obtain a LOB locator. Then you can read or write LOB data and perform data manipulation. Use the ResultSet's getBlob method to obtain the LOB locator, and then you can obtain the a Stream of the blob to read/write to the Blob
Blob blob = rs.getBlob(1);The following example shows how to insert, read and write Blobs to Oracle from Java. The table here has only two columns (IMAGE_ID and IMAGE) IMAGE is a BLOB.
InputStream is = blob.getBinaryStream();
OutputStream os = blob.setBinaryStream(1);
package data;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class BlobTest {
public void insertBlob(String imageId, String fileName) {
Connection conn = null;
try {
conn = getConnection();
if (!fileName.equals("")) {
PreparedStatement ps = conn.prepareStatement("INSERT INTO IMAGES VALUES(?, ?)");
ps.setString(1, imageId);
FileInputStream fis = new FileInputStream(fileName);
ps.setBinaryStream(2, fis, fis.available());
ps.execute();
ps.close();
} else {
PreparedStatement ps = conn.prepareStatement("INSERT INTO IMAGES VALUES (?, empty_blob())");
ps.setString(1, imageId);
ps.execute();
ps.close();
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void readBlob(String fileName) {
Connection conn = null;
try {
conn = getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT IMAGE FROM IMAGES");
while (rs.next()) {
// The following two lines can be replaced by
// InputStream is = rs.getBinaryStream(1);
Blob blob = rs.getBlob(1);
InputStream is = blob.getBinaryStream();
FileOutputStream fos = null;
fos = new FileOutputStream("c:/TEMP/" + fileName);
byte[] data = new byte[1024];
int i = 0;
while ((i = is.read(data)) != -1) {
fos.write(data, 0, i);
}
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void writeBlob(String fileName) {
Connection conn = null;
try {
conn = getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT IMAGE FROM IMAGES FOR UPDATE");
while (rs.next()) {
Blob blob = rs.getBlob(1);
System.out.println(blob);
OutputStream os = blob.setBinaryStream(1);
FileInputStream fis = null;
fis = new FileInputStream("c:/TEMP/" + fileName);
byte[] data = new byte[1];
int i;
while ((i = fis.read(data)) != -1) {
os.write(data, 0, i);
}
os.close();
break;
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL", "scott", "tiger");
return conn;
}
public static void main(String[] args) {
BlobTest blobTest = new BlobTest();
blobTest.insertBlob("img1", "");
blobTest.writeBlob("2.gif");
}
}
Insert Blob into Oracle
The insertBlob method takes the image id and the image file name as arguments. If the image file is an empty string, then an empty blob is inserted into the table. The empty_blob() function returns an empty locator of type BLOB, this is used in the INSERT.
Read from a Blob
The getBinaryStream of java.sql.Blob class returns an InputStream, which can be used to read from the blob.
Write to a Blob
The writeBlob method writes to the first row retrieved from the table. The SQL statement uses FOR UPDATE. In the absence of FOR UPDATE, you will get an IOException
java.io.IOException: ORA-22920: row containing the LOB value is not lockedThe following article describes how to handle CLOB using JDBC
at oracle.jdbc.driver.DatabaseError.SQLToIOException(DatabaseError.java:517)
at oracle.jdbc.driver.OracleBlobOutputStream.flushBuffer(OracleBlobOutputStream.java:214)
at oracle.jdbc.driver.OracleBlobOutputStream.close(OracleBlobOutputStream.java:179)
at data.BlobTest.writeBlob(BlobTest.java:90)
at data.BlobTest.main(BlobTest.java:111)
Subscribe to:
Posts (Atom)
Popular Posts
-
This post will describe how to create and deploy a Java Web Application war to Heroku using Heroku CLI. You will need a basic understanding ...
-
In a previous post, I described how to use Quartz scheduler for scheduling . In this post, I describe the configuration changes required for...
-
The previous post described how to implement a JMS messaging client using Spring JMS . This post will describe how to implement the Message ...
-
JUnit 4 introduces a completely different API to the older versions. JUnit 4 uses Java 5 annotations to describe tests instead of using in...
-
Last week, I described how to implement JMS, using a stand-alone client and a Message Driven Bean . In this post and the next, I will descr...
-
In this post we will see how to do an offline install Jenkins and required plugins on a Red Hat Enterprise Linux Server release 7.3. This is...
-
New posts with iText 5.5.12 Following are two new posts for PDF Merge with iText 5.5.12 Merge PDF files using iText 5 Merge and Paginate PDF...
-
In the previous post, I described the use of Displaytag to implement paging in a simple JSP. In this example, I describe the use of Displayt...
-
Displaytag is an opensource tag library that can be used to display tables on JSPs. Apart from being able to display tables, the displaytag...
-
In the past, I had a few posts on how to implement pagination using displaytag( 1 , 2 ). That solution is feasible only with small result se...