Wednesday, February 17, 2010
Multipart series on Spring Security customization
1. Practical example on using Jasypt decryption algorithm on user password.
2. Practical example on using Jasypt String Digester interface as the password encoder.
Saturday, April 18, 2009
JPA/Hibernate - One to One Mapping Quirks
I have been working on a product where I am currently using Hibernate implementation of JPA (Java Persistence Architecture) as data persistence mechanism. While working, I came across an interesting finding about one-to-one mapping using annotations. In this short article, I would like to explain my findings that may be of help to some novice JPA/Hibernate developers.
Technical Details
Let us take Users.java and Contacts.java as domain examples to explain the scenario. In this case, User object has certain attributes and Contact object also has its own specific attributes. Assume a user can have only one contact, then one of the common ways of expressing one-to-one relationships is to have the dependent object share the same primary key as the controlling object. In UML, it is called "compositional relationships".
User.java
@Entity
@Table (name="Users")
public class Users implements Serializable{
private static final long serialVersionUID = -3174184215665687091L;
/** The cached hash code value for this instance. Setting to 0 triggers re-calculation. */
@Transient
private int hashValue = 0;
/** The composite primary key value. */
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column (name="id")
private Long Id;
/** The value of the simple username property. */
@Column(name = "username", unique=true, nullable=false)
private String username;
/** The value of the contacts association. */
@OneToOne(cascade = {CascadeType.ALL}, fetch=FetchType.LAZY, optional=true)
@PrimaryKeyJoinColumn
@JoinColumn (name="id", nullable=false)
private Contacts contacts;
.....
public Users(){}
/**
* @return Id
*/
public Long getId(){
return this.Id;
}
/**
* @param id - The Id to set
*/
public void setId(Long id){
this.hashValue = 0;
this.Id = Id;
}
/**
* @return Contacts
*/
public Contacts getContacts(){
return this.contacts;
}
/**
* @param Contacts - The contacts to set
*/
public void setContacts(Contacts contacts){
this.contacts = contacts;
}
....
}
Contacts.java
@Entity
@Table (name="Contacts")
public class Contacts implements Serializable{
private static final long serialVersionUID = -1079313023058953957L;
@Id
@Column (name="id")
private Long Id;
/** The value of the users association. */
@OneToOne(optional=false)
@JoinColumn (name="id")
private Users users;
....
public Contacts (){}
/**
* @return Id
*/
public Long getId(){
return this.Id;
}
/**
* @param id - The Id to set
*/
public void setId(Long id){
this.hashValue = 0;
this.Id = id;
}
/**
* @return Users
*/
public Users getUsers(){
return this.users;
}
/**
* @param users - The users to set
*/
public void setUsers(Users users){
this.users = users;
}
....
}
The above set up will result in an error message that says like the following:
Exception raised - org.hibernate.id.IdentifierGenerationException:
ids for this class must be manually assigned before calling save(): com.vbose.Contacts
The problem is that Hibernate is confused in this case. It thinks that it should look at the Id column to determine the primary id of the table. In reality, we should have told Hibernate that the Users object is the thing that provides the id. In order to help Hibernate understand how to properly resolve the id, we need to annotate the id column of the Contacts with a special "Generator", like so:
The one below is an enhanced Contacts.java domain object:
@Entity
@Table (name="Contacts")
public class Contacts implements Serializable{
private static final long serialVersionUID = -1079313023058953957L;
@Id
@GeneratedValue(generator="foreign")
@GenericGenerator(name="foreign", strategy = "foreign", parameters={
@Parameter(name="property", value="users")
})
@Column (name="id")
private Long Id;
/** The value of the users association. */
@OneToOne(optional=false)
@JoinColumn (name="id")
private Users users;
....
public Contacts (){}
/**
* @return Id
*/
public Long getId(){
return this.Id;
}
/**
* @param id - The Id to set
*/
public void setId(Long id){
this.hashValue = 0;
this.Id = id;
}
/**
* @return Users
*/
public Users getUsers(){
return this.users;
}
/**
* @param users - The users to set
*/
public void setUsers(Users users){
this.users = users;
}
....
}
The additional annotation at the "Id" property says that the generated value of the Id column comes from a special generator that simply reads a foreign key value off of the users object. Please note that contacts object has to be set in Users and vice versa in order to establish bi-directional relationship before setting other properties of each objects. This bi-directional setup will prevent the users from getting the following exception
org.hibernate.id.IdentifierGenerationException: attempted to assign id fromFor e.g.
null one-to-one property:
Users users = new Users();
Contacts contacts = new Contacts();
users.setContacts(contacts);
contacts.setUsers(users);
The above set up works for inserting a new record using cascade option set for the child object association at the parent level. So you can safely use entityManager.persist(object). However, please note the "optional" parameter set for Contacts one-to-one association at the Users object. This optional parameter plays a key role while saving the child association via its parent using cascade option. If you do not set the "optional" parameter at the parent as well as its child object, then you will likely get the above said exception while updating the parent and its child association via cascade option. This error is prominent if you add a new child through its parent while updating the parent that has reference to a new child entity.
For e.g. If you replace the existing contact instance with a new contact instance (with the foreign key assigned from its parent object as the child object's parent key as well as its foreign key to its parent) and update the changes using entityManager.merge(users) operation will result in the same above said error if the "optional" parameter is not set properly at the one-to-one association annotation.
The "optional" parameter should be set to true at the parent level and should be set to false at the child object level.
However please note the "optional" parameter at the one-to-one mapping is not really required if you just do plain update to the existing child entity or its parent entity.
Conclusion
The above said quirk is not documented in Hibernate reference document. I hope it will help any novice JPA/Hibernate developers who are facing problems with one-to-one mapping using annotations.
Wednesday, March 18, 2009
Apache Commons DBCP and Tomcat JDBC Connection Pool
The SpringSource tomcat architects are coming up with a new connection pool called Tomcat JDBC Connection Pool. This poses many questions to so many people like why do we need another connection pool when there is already an established Apache Commons DBCP pool available. In this article, I would like to point out some drastic differences between Apache DBCP and the new Tomcat JDBC Connection Pool. I strongly feel Tomcat JDBC Connection Pool is much superior to DBCP and highly recommend all users to check it out.
Database connection
A database connection is a facility in computer science that allows the client software to talk to database server. The database server could be running on the same machine where the client software runs or not. A database connection is required to send commands and receive answers via result set.
Connection Pool
Database connections are finite and expensive and can take disproportionately long time to create relative to the operations performed on them. It is very inefficient for an application to create and close a database connection whenever it needs to send a read request or update request to the database.
Connection Pooling is a technique designed to alleviate the above mentioned problem. A pool of database connections can be created and then shared among the applications that need to access the database. When an application needs database access, it requests a connection from the pool. When it is finished, it returns the connection to the pool, where it becomes available for use by other applications.
Apache Commons DBCP Connection Pool
There are several Database Connection Pools already available, both within Jakarta products and elsewhere. This Commons package provides an opportunity to coordinate the efforts required to create and maintain an efficient, feature-rich package under the ASF license.
Applications can use the
commons-dbcp component directly or through the existing interface of their container / supporting framework.Jakarta Tomcat the leading application server is also packaged with DBCP Datasource as the JNDI Datasource. The beauty of DBCP is that it can be used with so many applications or frameworks and it works with almost all databases in the market.
However, DBCP presents some challenges or concerns as well in spite of its popularity. Some of the challenges or concerns with DBCP are given below.
- commons-dbcp is single threaded. In order to be thread safe commons-dbcp locks the entire pool, even during query validation.
- commons-dbcp is slow - As the number of logical CPUs grow, the performance suffers, the above point shows that there is no support for high concurrency even with the enormous optimizations of the
synchronizedstatement in Java 6, commons-dbcp still suffers in speed and concurrency. - commons-dbcp is complex, over 60 classes. tomcat-jdbc-pool, is 8 classes, hence modifications for future requirement will require much less changes.
- commons-dbcp uses static interfaces. This means you can't compile it with JDK 1.6, or if you run on JDK 1.6/1.7 you will get NoSuchMethodException for all the methods not implemented, even if the driver supports it.
- The commons-dbcp has become fairly stagnant. Sparse updates, releases, and new feature support.
- It's not worth rewriting over 60 classes, when something as a connection pool can be accomplished with a much simpler implementation.
- Tomcat jdbc pool implements a fairness option not available in commons-dbcp and still performs faster than commons-dbcp.
- Tomcat jdbc pool implements the ability to retrieve a connection asynchronously, without adding additional threads to the library itself.
- Tomcat jdbc pool is a Tomcat module, it depends on Tomcat JULI, a simplified logging framework used in Tomcat.
- Support for highly concurrent environments and multi core/cpu systems.
- Dynamic implementation of interface, will support java.sql and javax.sql interfaces for your runtime environment (as long as your JDBC driver does the same), even when compiled with a lower version of the JDK.
- Validation intervals - we don't have to validate every single time we use the connection, we can do this when we borrow or return the connection, just not more frequent than an interval we can configure.
- Run-Once query, a configurable query that will be run only once, when the connection to the database is established. Very useful to setup session settings, that you want to exist during the entire time the connection is established.
- Ability to configure custom interceptors. This allows you to write custom interceptors to enhance the functionality. You can use interceptors to gather query stats, cache session states, reconnect the connection upon failures, retry queries, cache query results, and so on. Your options are endless and the interceptors are dynamic, not tied to a JDK version of a java.sql/javax.sql interface.
- High performance
- Extremely simple, due to the very simplified implementation, the line count and source file count are very low, compare with c3p0 that has over 200 source files. Tomcat jdbc has a core of 8 files, the connection pool itself is about half that.
- Asynchronous connection retrieval - you can queue your request for a connection and receive a Future
back.
The Tomcat connection pool offers a few additional features over what most other pools let you do:
initSQL- the ability to run a SQL statement exactly once, when the connection is created.validationInterval- in addition to running validations on connections, avoid running them too frequently.jdbcInterceptors- flexible and pluggable interceptors to create any customizations around the pool, the query execution and the result set handling.fairQueue- Set the fair flag to true to achieve thread fairness or to use asynchronous connection retrieval.
Most attributes are same and have the same meaning as DBCP.
factory -factory is required, and the value should beorg.apache.tomcat.jdbc.pool.DataSourceFactory
type - type should always bejavax.sql.DataSource
Common Attributes
The following attributes are shared between commons-dbcp and tomcat-jdbc-pool, in some cases default values are different.
defaultAutoCommit -(boolean) The default auto-commit state of connections created by this pool. If not set, default is JDBC driver default (If not set then the setAutoCommit method will not be called.)
defaultReadOnly -(boolean) The default read-only state of connections created by this pool. If not set then the setReadOnly method will not be called. (Some drivers don't support read only mode, ex: Informix)
defaultTransactionIsolation -(String) The default TransactionIsolation state of connections created by this pool. One of the following: (see javadoc )
- NONE
- READ_COMMITTED
- READ_UNCOMMITTED
- REPEATABLE_READ
- SERIALIZABLE
If not set, the method will not be called and it defaults to the JDBC driver.
defaultCatalog -(String) The default catalog of connections created by this pool.
driverClassName -(String) The fully qualified Java class name of the JDBC driver to be used. The driver has to be accessible from the same classloader as tomcat-jdbc.jar
-
username -(String) The connection username to be passed to our JDBC driver to establish a connection. Note, at this point,DataSource.getConnection(username,password)is not using the credentials passed into the method.
password -(String) The connection password to be passed to our JDBC driver to establish a connection. Note, at this point,DataSource.getConnection(username,password)is not using the credentials passed into the method.
maxActive -(int) The maximum number of active connections that can be allocated from this pool at the same time. The default value is100.
maxIdle -(int) The maximum number of connections that should be kept in the pool at all times. Default value ismaxActive:100Idle connections are checked periodically (if enabled) and connections that been idle for longer thanminEvictableIdleTimeMilliswill be released. (also seetestWhileIdle)
minIdle -(int) The minimum number of established connections that should be kept in the pool at all times. The connection pool can shrink below this number if validation queries fail. Default value is derived frominitialSize:10(also seetestWhileIdle)
initialSize- (int)The initial number of connections that are created when the pool is started. Default value is10
maxWait -(long) The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception. Default value is30000(30 seconds)
testOnBorrow -(boolean) The indication of whether objects will be validated before being borrowed from the pool. If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another. NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string. Default value isfalse
testOnReturn -(boolean) The indication of whether objects will be validated before being returned to the pool. NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string. The default value isfalse.
testWhileIdle -(boolean) The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to validate, it will be dropped from the pool. NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string. The default value isfalseand this property has to be set in order for the pool cleaner/test thread is to run (also seetimeBetweenEvictionRunsMillis)
validationQuery -(String) The SQL query that will be used to validate connections from this pool before returning them to the caller. If specified, this query does not have to return any data, it just can't throw a SQLException. The default value isnull. Example values areSELECT 1(mysql),select 1 from dual(oracle),SELECT 1(MS Sql Server)
timeBetweenEvictionRunsMillis -(long) The number of milliseconds to sleep between runs of the idle connection validation/cleaner thread. This value should not be set under 1 second. It dictates how often we check for idle, abandoned connections, and how often we validate idle connections. The default value is5000(5 seconds).
numTestsPerEvictionRun -(int) Property not used in tomcat-jdbc-pool.
minEvictableIdleTimeMillis -(long) The minimum amount of time an object may sit idle in the pool before it is eligible for eviction. The default value is60000(60 seconds).
accessToUnderlyingConnectionAllowed -(boolean) Property not used. Access can be achieved by callingunwrapon the pooled connection. seejavax.sql.DataSourceinterface, or callgetConnectionthrough reflection.
removeAbandoned -(boolean) Flag to remove abandoned connections if they exceed theremoveAbandonedTimout. If set to true a connection is considered abandoned and eligible for removal if it has been in use longer than theremoveAbandonedTimeoutSetting this to true can recover db connections from applications that fail to close a connection. See alsologAbandonedThe default value isfalse.
removeAbandonedTimeout -(long) Timeout in seconds before an abandoned(in use) connection can be removed. The default value is60(60 seconds). The value should be set to the longest running query your applications might have.
logAbandoned -(boolean) Flag to log stack traces for application code which abandoned a Connection. Logging of abandoned Connections adds overhead for every Connection borrow because a stack trace has to be generated. The default value isfalse.
connectionProperties -(String) The connection properties that will be sent to our JDBC driver when establishing new connections. Format of the string must be [propertyName=property;]* NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be included here. The default value isnull.
poolPreparedStatements -(boolean) Property not used. The default value isfalse.
maxOpenPreparedStatements -(int) Property not used. The default value isfalse.
initSQL -(String) A custom query to be run when a connection is first created. The default value isnull.
-
jdbcInterceptors(String) A semicolon separated list of classnames extendingorg.apache.tomcat.jdbc.pool.JdbcInterceptorclass. These interceptors will be inserted as an interceptor into the chain of operations on ajava.sql.Connectionobject. The default value isnull.
Predefined interceptors:- org.apache.tomcat.jdbc.pool.interceptor.ConnectionState - keeps track of auto commit, read only, catalog and transaction isolation level.
- org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer - keeps track of opened statements, and closes them when the connection is returned to the pool.
validationInterval- (long) avoid excess validation, only run validation at most at this frequency - time in milliseconds. If a connection is due for validation, but has been validated previously within this interval, it will not be validated again. The default value is30000(30 seconds).
jmxEnabled -(boolean) Register the pool with JMX or not. The default value istrue.
fairQueue -(boolean) Set to true if you wish that calls to getConnection should be treated fairly in a true FIFO fashion. This uses theorg.apache.tomcat.jdbc.pool.FairBlockingQueueimplementation for the list of the idle connections. The default value isfalse. This flag is required when you want to use asynchronous connection retrieval.
useEquals -(boolean) Set to true if you wish theProxyConnectionclass to useString.equalsinstead of==when comparing method names. This property does not apply to added interceptors as those are configured individually. The default value isfalse.
Please see the example below as to how to configure the Tomcat JDBC DataSource as a resource. I am using DB2 as the sample database for this example.
<Resource
auth="Container"
defaultAutoCommit="true"
defaultReadOnly="false"
defaultTransactionIsolation="READ_COMMITTED"
driverClassName="com.ibm.db2.jcc.DB2Driver"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
fairQueue="false"
initSQL="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR"
initialSize="10"
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
jmxEnabled="true"
logAbandoned="true"
maxActive="100"
maxIdle="100"
maxWait="6000"
minEvictableIdleTimeMillis="30000"
minIdle="10"
name="jdbc/sampleDS"
password="xxxxxxxxxxx"
removeAbandoned="true"
removeAbandonedTimeout="60"
testOnBorrow="true"
testOnReturn="false"
testWhileIdle="false"
timeBetweenEvictionRunsMillis="30000"
type="javax.sql.DataSource"
url="jdbc:db2://os01.in.vbose.com:4745/DSNQ:currentFunctionPath=SAMPLE;IGNORE_DONE_IN_PROC=true;currentSchema=SAMPLE;"
useEquals="false"
username="abcdefg"
validationInterval="1800000" validationQuery="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR"/>
Wiring Tomcat JDBC DataSource using Spring Application Context
The DataSource class available within Tomcat JDBC Pool can also be instantiated through IoC and implements the DataSource interface since the DataSourceProxy is used as a generic proxy. The following is an example of using Spring application context to wire the DataSource dependency. The example database used is DB2 9 running on mainframe z/OS.
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:property-placeholder location="classpath:sample/jdbc.properties"/>
<bean id="datasource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close"
p:driverClassName="${jdbc.sample.db.driverClassName}"
p:url="${jdbc.sample.db.url}"
p:username="${jdbc.sample.db.username}"
p:password="${jdbc.sample.db.password}"
p:initialSize="10"
p:initSQL="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR"
p:minIdle="10"
p:maxIdle="100"
p:maxActive="100"
p:maxWait="6000"
p:jmxEnabled="true"
p:jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
p:removeAbandoned="true"
p:removeAbandonedTimeout="60"
p:logAbandoned="true"
p:testOnBorrow="true"
p:testOnReturn="false"
p:testWhileIdle="false"
p:useEquals="false"
p:fairQueue="false"
p:timeBetweenEvictionRunsMillis="30000"
p:minEvictableIdleTimeMillis="30000"
p:validationInterval="1800000"
p:validationQuery="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR"
/>
In order to keep track of query performance and issues log entries when queries exceed a time threshold of fail, you may also use another built-in interceptor called org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport(threshold=10000). In this case, the log level used is
WARN.
Additionally, if used within tomcat, you can add a JMX enabled interceptor called org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx(threshold=10000). This class uses Tomcat's JMX engine so it wont work outside of the Tomcat container.Conclusion
The tomcat JDBC connection pool (tomcat-jdbc.jar) is currently available as part of SpringSource tc Server, the enterprise version of Tomcat Server. In tc server, both DBCP and Tomcat JDBC are available and it is upto the system architect to decide which option is best to use in their applications.
The tomcat JDBC also depends on Tomcat JULI, a simplified logging framework used in Tomcat. So you may need tomcat-juli.jar if you want to use it outside tomcat container.
Monday, February 23, 2009
.NET client consuming Spring WS 1.5.5 using XWSS WS security Implementation
I am currently working on an integration project where a .NET client has to consume a Java Web Service. Since I have been using Spring framework for a very long time, my natural inclination is to try out Spring WS 1.5.5 as the web service framework. So I picked spring framework 2.5.6, spring security 2.0.4 and spring web services 1.5.5 for the java web service implementation. I am using XWSS implementation of WS security under the hoods for the username token with password digest authentication mechanism.
The service consumer is a .NET client and apparently there were configuration issues with .NET that prevented them from consuming our service successfully. So I searched in google and posted the issue with Spring forums with no luck. So finally with the help of our .NET Software Engineer, I have managed to come up with a standard procedure as to how to consume a Java Web Service that implements WS security from a .NET client perspective.
Java Web Service Implementation
I am using Spring WS 1.5.5 Airline sample application that comes with its distribution to demonstrate the integration capability. The Airline sample is a normal web application that connects to an embedded HSQLDB database. This application uses XWSS implementation of WS-Security.
applicationContext-security.xml
<?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-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<description>
This application context contains the WS-Security and Sprign Security beans.
</description>
<security:global-method-security secured-annotations="enabled"/>
<security:authentication-provider user-service-ref="securityService"/>
<bean id="securityService"
class="org.springframework.ws.samples.airline.security.SpringFrequentFlyerSecurityService">
<description>
A security service used to obtain Frequent Flyer information.
</description>
<constructor-arg ref="frequentFlyerDao"/>
</bean>
<bean id="wsSecurityInterceptor" class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<description>
This interceptor validates incoming messages according to the policy defined in 'securityPolicy.xml'.
The policy defines that all incoming requests must have a UsernameToken with a password digest in it.
The actual authentication is performed by the Spring Security callback handler.
</description>
<property name="secureResponse" value="false"/>
<property name="policyConfiguration"
value="classpath:org/springframework/ws/samples/airline/security/securityPolicy.xml"/>
<property name="callbackHandler">
<bean class="org.springframework.ws.soap.security.xwss.callback.SpringDigestPasswordValidationCallbackHandler">
<property name="userDetailsService" ref="securityService"/>
</bean>
</property>
</bean>
</beans>Spring ws currently supports two implementations of WS Security. One is based on XWSS and the other one is WSS4J from Apache.XWSS
XWSS stands for XML and WebServices Security runtime. It is part of Project GlassFish and is used for securing WebServices requests and responses.
XWSS 2.0 was based on OASIS WSS specification version 1.0 and XWSS 3.0 is based on OASIS WSS specification 1.1
XwsSecurityInterceptor
The XwsSecurityInterceptor is an EndpointInterceptor that is based on SUN's XML and Web Services Security package (XWSS). This WS-Security implementation is part of the Java Web Services Developer Pack ( Java WSDP ). Like any other endpoint interceptor, it is defined in the endpoint mapping. This means that you can be selective about adding WS-Security support: some endpoint mappings require it, while others do not.
Note that XWSS requires both a SUN 1.5 JDK and the SUN SAAJ reference implementation. The WSS4J interceptor does not have these requirements.
The XwsSecurityInterceptor requires a security policy file to operate. This XML file tells the interceptor what security aspects to require from incoming SOAP messages, and what aspects to add to outgoing messages.
securityPolicy.xml
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireUsernameToken passwordDigestRequired="true" nonceRequired="true"/>
</xwss:SecurityConfiguration>
Spring WS endpoint Mappings
The endpoint mapping is responsible for mapping incoming messages to appropriate endpoints. There are some endpoint mappings you can use out of the box. Please refer the example in the applicationContext-ws.xml file below.
applicationContext-ws.xml
<?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:oxm="http://www.springframework.org/schema/oxm"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-1.5.xsd">
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="messageReceiver" class="org.springframework.ws.soap.server.SoapMessageDispatcher"/>
<bean id="schemaCollection" class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<description>
This bean wrap the messages.xsd (which imports types.xsd), and inlines them as a one.
</description>
<property name="xsds" value="/messages.xsd"/>
<property name="inline" value="true"/>
</bean>
<!-- ===================== ENDPOINTS ===================================== -->
<!--
The marshallingEndpoint and xpathEndpoint handle the same messages. So, you can only use one of them at the
same time. This is done for illustration purposes only, typically you would not create two endpoints which
handle the same messages.
-->
<bean id="marshallingEndpoint" class="org.springframework.ws.samples.airline.ws.MarshallingAirlineEndpoint">
<description>
This endpoint handles the Airline Web Service messages using JAXB2 marshalling.
</description>
<constructor-arg ref="airlineService"/>
</bean>
<!--
<bean id="xpathEndpoint" class="org.springframework.ws.samples.airline.ws.XPathAirlineEndpoint">
<description>
This endpoint handles the Airline Web Service messages using XPath expressions and JAXB2 marshalling.
</description>
<constructor-arg ref="airlineService"/>
<constructor-arg ref="marshaller"/>
</bean>
-->
<bean id="getFrequentFlyerMileageEndpoint"
class="org.springframework.ws.samples.airline.ws.GetFrequentFlyerMileageEndpoint">
<description>
This endpoint handles get frequent flyer mileage requests.
</description>
<constructor-arg ref="airlineService"/>
</bean>
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>
<!-- ===================== ENDPOINT MAPPINGS ============================== -->
<!--
The endpoint mappings map from a request to an endpoint. Because we only want the security interception to
occur for the GetFrequentFlyerMileageEndpoint, we define two mappings: one with the securityInterceptor, and
a general one without it.
-->
<bean id="annotationMapping"
class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<description>
Detects @PayloadRoot annotations on @Endpoint bean methods. The MarshallingAirlineEndpoint
has such annotations. It uses two interceptors: one that logs the message payload, and the other validates
it accoring to the 'airline.xsd' schema file.
</description>
<property name="interceptors">
<list>
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
<bean class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="xsdSchemaCollection" ref="schemaCollection"/>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
</list>
</property>
<property name="order" value="1"/>
</bean>
<bean id="secureMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<description>
This endpoint mapping is used for endpoints that are secured via WS-Security. It uses a
securityInterceptor, defined in applicationContext-security.xml, to validate incoming messages.
</description>
<property name="mappings">
<props>
<prop key="{http://www.springframework.org/spring-ws/samples/airline/schemas/messages}GetFrequentFlyerMileageRequest">
getFrequentFlyerMileageEndpoint
</prop>
</props>
</property>
<property name="interceptors">
<list>
<bean class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor"/>
<ref bean="wsSecurityInterceptor"/>
</list>
</property>
<property name="order" value="2"/>
</bean>
<!-- ===================== ENDPOINT ADAPTERS ============================== -->
<!--
Endpoint adapters adapt from the incoming message to a specific object or method signature. Because this
example application uses three different endpoint programming models, we have to define three adapters. This
is done for illustration purposes only, typically you would use one adapter, for instance the
MarshallingMethodEndpointAdapter.
-->
<sws:marshalling-endpoints/>
<sws:xpath-endpoints>
<sws:namespace prefix="messages"
uri="http://www.springframework.org/spring-ws/samples/airline/schemas/messages"/>
</sws:xpath-endpoints>
<bean class="org.springframework.ws.server.endpoint.adapter.PayloadEndpointAdapter">
<description>
This adapter allows for endpoints which implement the PayloadEndpoint interface. The Get
FrequentFlyerMileageEndpoint implements this interface.
</description>
</bean>
<!-- ===================== ENDPOINT EXCEPTION RESOLVER ===================== -->
<!--
Endpoint exception resolvers can handle exceptions as they occur in the Web service. We have two sorts of
exceptions we want to handle: the business logic exceptions NoSeatAvailableException and NoSuchFlightException,
which both have a @SoapFault annotation, and other exceptions, which don't have the annotation. Therefore, we
have two exception resolvers here.
-->
<bean class="org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver">
<description>
This exception resolver maps exceptions with the @SoapFault annotation to SOAP Faults. The business logic
exceptions NoSeatAvailableException and NoSuchFlightException have these.
</description>
<property name="order" value="1"/>
</bean>
<bean class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
<description>
This exception resolver maps other exceptions to SOAP Faults. Both UnmarshallingException and
ValidationFailureException are mapped to a SOAP Fault with a "Client" fault code.
All other exceptions are mapped to a "Server" error code, the default.
</description>
<property name="defaultFault" value="SERVER"/>
<property name="exceptionMappings">
<props>
<prop key="org.springframework.oxm.UnmarshallingFailureException">CLIENT,Invalid request</prop>
<prop key="org.springframework.oxm.ValidationFailureException">CLIENT,Invalid request</prop>
</props>
</property>
<property name="order" value="2"/>
</bean>
</beans>
After deploying the above said service, the service will run at http://localhost:8080/airline/services. The wsdl is published at http://localhost:8080/airline/airline.wsdl
NOTE: There are other applicationContext xml files within the airline sample application which I am not mentioning here in this article for brevity. I would highly recommend you refer the sample airline application that comes with Spring WS 1.5.5 or 1.5.6.
There is already a .NET example within airline application which does not require to go to WS security intereceptor configured at the airline service level. The next section will give you enough details as to how to configure the .NET client side to access the airline sample service that goes through XWSS security interceptor configured within the application.
.NET client configuration using WSE 2.0
Prerequisites:
1) Make sure you have WSE2.0 installed and .NET 1.1 (at least)
How do you verify the above prerequisite?
Check whether Microsoft.Web.Services2.dll exists under C:\Program Files\Microsoft WSE\v2.0\Microsoft.Web.Services2.dll
If WSE 2.0 is not installed, please download it from here.
NOTE: The dll Microsoft.Web.Services2.dll plays the role of encrypting or decrypting the request and responses of the service.
.NET consuming Java Web Service
Please follow the steps below to consume web service using WSE 2.0
1. Enable WSE 2.0 extensions
- Select your project and right click
- Select WSE setting 2.0 from the context menu
- In the General tab, check 'Enable this project for Web Services Enhancements' checkbox
- check 'Enable Microsoft Web Services Enhancement soap extensions'
2. Add Web References
In visual studio,
- Select your project and right click
- Select 'Add Web References' from the context menu
- Enter the web service URL. For e.g. http://localhost:8080/airline/airline.wsdl
- Hit go button to search the service
- If the service is found, name the service and 'Add Reference'
3. How to verify whether the added service has WSE 2.0 service extension
- Expand the service and open the source code of 'Reference.cs'
- Class should extend Microsoft.Web.Services2.WebServicesClientProtocol
4. Changes in .NET Client class which consume the service
- Include following namespace (this is to create 'UsernameToken')
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;- In the code, add UsernameToken in the soap header
For e.g.,
UsernameToken un =
new UsernameToken("UN","Pwd", PasswordOption.SendHashed);
svc.RequestSoapContext.Security.Tokens.Add(un);
In the above example, replace UN with 'john' and PWD with 'changeme' since this is what airline sample application uses.
5. Changes in web.config
Add <configSections> element under the <configuration> element if it is not already added
<configSections>
<section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration,
Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
Add <webServices> element under <system.web> element if not added
<webServices>
<soapExtensionTypes>
<add type="Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" />
</soapExtensionTypes>
</webServices>
References
1. Spring WS 1.5.5 Reference Document
2. Spring WS forum
3. Microsoft .NET framework developer center (Article 1 and Article 2)
Conclusion
I hope this article will help any novice .NET software engineer in integrating with Java Web Services that implements WS Security. I sincerely thank my friend and colleague Mr. Thanasekaran Mariappan for helping me put together this article.
Friday, January 23, 2009
Virtualization on Ubuntu 810 server using VMWare Server 2.0, i7 chipset and MSI Eclipse x58
I have recently built a machine using Intel's latest i7 processor and MSI Eclipse x58 motherboard. The idea was to build a high end machine for my application development and research work at home and I wanted to make use of server virtualization technology. This will dramatically improve the efficiency and availability of resources and applications that are hosted in a machine. I have chosen 10 GB RAM and 2 TB Harddrive with hardware raid in addition to the facilities provided by i7 64 bit processor and MSI Eclipse x58 motherboard offers.
Intel i7 Processor
Intel has brought back Hyper Threading technology with this latest i7 processor. Some of the core features of i7 processor are given below.
- 2.93 GHz and 2.66 GHz core speed
- 8 processing threads with Intel® HT technology
- 8 MB of Intel® Smart Cach
- 3 Channels of DDR3 1066 MHz memory
- Intel 64 Bit Architecture
- Intel Virtualization technology
I have chosen MSI's latest x58 mother board for my machine. The MSI Eclipse x58 is the company’s first X58 motherboard for Intel Core i7. MSI stands for Micro Star International.
The motherboard is black in color. The copper heatpipes and attached heatsinks are moderate in size, implicitly assuming that the X58 chip, VRM's and Southbridge won't get too hot. Please click here to see MSI Eclipse x58 photo gallery.
Fig 1. MSI Eclipse x58 Motherboard
The MSI Eclipse features ten DrMOS High-C capacitors (six for the CPU, two for the northbridge and two for the QuickPath memory controller) which are designed for reliability and efficiency.This motherboard features six DIMM slots to take advantage of Nehalem’s triple-channel DDR3 memory controller and can utilize up to 24GB of DDR3-1333+ RAM. It also supports overclocking as well.
HardWare Raid
The hardware-based system manages the RAID subsystem independently from the host and presents to the host only a single disk per RAID array.
An example of a Hardware RAID device would be one that connects to a SCSI controller and presents the RAID arrays as a single SCSI drive. An external RAID system moves all RAID handling "intelligence" into a controller located in the external disk subsystem. The whole subsystem is connected to the host via a normal SCSI controller and appears to the host as a single disk.
RAID controllers also come in the form of cards that act like a SCSI controller to the operating system but handle all of the actual drive communications themselves. In these cases, you plug the drives into the RAID controller just like you would a SCSI controller, but then you add them to the RAID controller's configuration, and the operating system never knows the difference.
Software Raid
Software RAID implements the various RAID levels in the kernel disk (block device) code. It offers the cheapest possible solution, as expensive disk controller cards or hot-swap chassis are not required. Software RAID also works with cheaper IDE disks as well as SCSI disks. With today's fast CPUs, Software RAID performance can excel against Hardware RAID.
The MD driver in the Linux kernel is an example of a RAID solution that is completely hardware independent. The performance of a software-based array is dependent on the server CPU performance and load.
Virtualization
Virtualization is a proven software technology that is rapidly transforming the IT landscape and fundamentally changing the way that people compute. Today’s powerful x86 computer hardware was designed to run a single operating system and a single application. This leaves most machines vastly underutilized. Virtualization lets you run multiple virtual machines on a single physical machine, sharing the resources of that single computer across multiple environments. I have picked VMWare because they are the market leader in Virtualization.
I wanted to use VMWare's latest ESX 3i 3.5 build as my server virtualization software. However, it did not support the hardware I have. The reason why I chose ESX3i over other VMWare products was because ESX3i is an OS-independent VMware hypervisor. So it does not need a host OS to run. VMware ESXi’s 32MB disk footprint is a fraction of the size of a general purpose operating system, reducing complexity and providing unmatched security and reliability.
Ubuntu 8.10 64 bit Server
Since ESX3i did not work for me. My other alternative was to try VMWare's latest VMWare server 2.0. This needs a host OS to run. I wanted to use Linux as the base server since the overhead with Linux is very minimum compared to Windows. I have initially chosen Ubuntu 8.0.4.02 LTS server as my base server. However, it also had issues with my hardware and seemed to hang some times. So I uninstalled Ubuntu 8.0.4.02 and installed Ubuntu 8.10 64 bit Server. Some of the issues with Ubuntu 8.0.4.02 were to do with the linux kernel version itslef. The kernel that comes with Ubuntu 8.10 is 2.6.27.x. The installation of Ubuntu 8.10 64 bit server was breeze and it detected all my hardware with no problems at all. Ubuntu 8.10 has a better support for software raid. However, I have chosen the hardware raid over the software raid simply because it was so easy to set it up at the BIOS level and I have two 1 TB hard drives for the mirror. The sata ports 7 and 8 in MSI Eclipse x58 Motherboard are dedicated for hard ware raid whereas 9 and 10 for eSata raid (External Hard Drives).
On distrowatch.com Ubuntu is listed as the most accessed distribution. The popularity of Ubuntu suggests that there will be business and job opportunities for those who are trained in configuration of the Ubuntu Server.
The Ubuntu Server Edition - built on the solid foundation of Debian which is known for its robust server installations — has a strong heritage for reliable performance and predictable evolution. It also supports server virtualization out of the box.
Ubuntu Server Edition JeOS (pronounced "Juice") is an efficient variant of the server operating system, configured specifically for virtual appliances.
JeOS is no longer provided as a separate ISO. Instead, it is an option that is activated on the server installer by pressing F4 on the first screen and selecting the "Install a minimal virtual machine" option. I have used JeOs from the same server installable CD to create other virtual machines.
Please click here to read more about Ubuntu 8.10 server features.
VMWare Server 2.0
I have downloaded VMWare Server 2.0 for 64 bit Linux TAR image (not the RPM image) from VMWare web site. I also activated the license key for the server. Obtaining the free license key or serial number is a very simple procedure from VMWare web site. You need to create an account with VMWare first and follow the instructions on the web site.
Instructions to install VMWare server 2.0 on Ubuntu 8.10 64 bit Server
Step 1. Log on to Ubuntu 8.10 server. Make sure the login id has administrator privileges.
Step 2.Install kernel headers which in my case was 2.6.27-7-generic (to do this use synaptic or apt-get )
Note : for finding your running kernel version use the command uname -a
sudo apt-get install linux-headers-`uname -r` build-essential xinetd
Step3. Then go to the location where you saved the VMware Server .tar.gz file, e.g. /home/administrator
cd /home/administrator
Unpack the VMware Server .tar.gz file and run the installer:
tar xvfz VMware-server-*.tar.gz
cd vmware-server-distrib
sudo ./vmware-install.plThe installer will ask you a lot of questions. You can always accept the default values simply by hitting
When the installer asks you
In which directory do you want to keep your virtual machine files?
[/var/lib/vmware/Virtual Machines]
you can either accept the default value or specify a location that has enough free space to store your virtual machines.
At the end of the installation, you will be asked to enter a serial number:
Please enter your 20-character serial number.
Type XXXXX-XXXXX-XXXXX-XXXXX or 'Enter' to cancel:
Fill in your serial number for VMware Server.
After the successful installation, you can delete the VMware Server download file and the installation directory:
cd /home/administrator
rm -f VMware-server*
rm -fr vmware-server-distrib/
vsock = VM communication interface socket
If you have accepted all default values during the installation, root is now the VMware Server login name. On Ubuntu, root has no password by default, therefore we create a password now:
sudo passwd
Enter new UNIX password:
Retype new UNIX password:After reset root password. It will show this message in Shell.
passwd: password updated successfullyVMware Server 2 does not have a desktop application for managing virtual machines - this is now done through a browser (e.g. Firefox). You can access the management interface over HTTPS (https://
Fig 2: VMWare Server 2.0 Management Web Interface
If you're using Firefox 3 and use HTTPS, Firefox will complain about the self-signed certificate, therefore you must tell Firefox to accept the certificate - to do this, click on the kink Or you can add an exception.Alternately, you can also manage the virtual machines using Virtual Machine Infrastructure Client that comes with ESX3i. The default https port Virtual Machine Infrastructure Client uses is 443. So if you have chosen 8333 as the default port for VMWare Server 2.0 , then in the Virtual Machine Infrastructure Client login, you may also have to use the port 8333 as seen in the following figure.
Fig 3. Virtual Machine Infrastructure Client Login

Fig 4: Virtual Machine Infrastructure Client Management Interface
References
1. VMWare - http://www.vmware.com/products/server/
2. Ubuntu Web Site - https://help.ubuntu.com/8.10/serverguide/C/index.html
3. Ubuntu Installation Guide - https://help.ubuntu.com/8.10/installation-guide/amd64/index.html
4. Ubuntu Forums - http://ubuntuforums.org/
Conclusion
VMware Server Infrastructure unifies discrete hardware resources to create a shared dynamic platform, while delivering built–in availability, security and scalability to applications. It supports a wide range of operating system and application environments, as well as networking and storage infrastructure.
Wednesday, December 31, 2008
DB2 9 JDBC configuration with IBM Webspehere 6.1
It is important to understand the confuguration of DB2 for the successful implementation of J2EE application hosted under IBM Websphere. To access the Websphere administration console that is running as localhost, use the URL: *http://localhost:9060/ibm/console* The default port the server is running is 9060. This is where you will configure JDBC, deploy applications, set environment variables, and define login configurations etc. (see Figure 1). In this example, I am using DB2 9 Enterprise Server Edition to configure a JDBC connection from WAS 6.1.
Select the Resources -> JDBC -> JDBC Providers node to configure a new JDBC provider. A JDBC provider, which is used to access a database, consists of database settings, the JDBC driver type, and the driver class.
Select the server scope (Server=server1) for defining a new JDBC provider. Click the New button to configure a new JDBC provider. In the Configuration window, select DB2 as the database type. Select DB2 Universal JDBC Driver Provider as the provider type. Select the implementation type Connection pool data source. Click Next.

The Class path field specifies the Jar files in the class path. The environment variable DB2Universal_JDBC_Driver_Path is specified in the class path field of the DB2 JDBC Provider. The db2jcc.jar (which has the DB2 JDBC Type 4 driver) and the db2jcc_license_cu.jar (which is the license file for the DB2 server), are included in the Class path setting.
In the Directory location for the db2jcc.jar field, specify the directory which has the dbj2cc.jar and the db2jcc_license_cu.jar files, which in this example is C:\DB2\JDBC\java directory by default. Click Next to see the summary for the JDBC provider. The environment variable DB2UNIVERSAL_JDBC_DRIVER_Path value is set to the directory that contains the dbj2cc.jar and the db2jcc_license_cu.jar files is C:\DB2\JDBC\java.
The driver class name is com.ibm.db2.jcc.DB2ConnectionPoolDataSource. Click Finish. The settings you specified are applied to the local configuration. Click on Save in the Messages frame to apply the changes to the master configuration. In the JDBC Providers frame, click Save to apply the changes to the workspace to the master configuration. A JDBC provider for the DB2 database gets configured and added to the list of JDBC Providers (see Figure 2).
DB2 Connection Pooling DataSource
The com.ibm.db2.jcc.DB2ConnectionPoolDataSource class extends the com.ibm.db2.jcc.DB2BaseDataSource class, and implements the javax.sql.ConnectionPoolDataSource, java.io.Serializable, and javax.naming.Referenceable interfaces.
DB2ConnectionPoolDataSource is a factory for PooledConnection objects. An object that implements this interface is registered with a naming service that is based on the Java Naming and Directory Interface (JNDI).
The connection pooling properties are defined only for the IBM DB2 Driver for JDBC and SQLJ. Click here for explanations of these properties. The following are the list of different DB2 implementation of data sources.
- com.ibm.db2.jc c.DB2SimpleDataSource, which does not support connection pooling. You can use the implementation with the Universal Type 2 driver or the Type 4 driver.
- com.ibm.db2.jcc.DB2DataSource, which supports connections pooling. You can use this implementation only with the Type 2 driver. With this implementation, connection pooling is handled internally and is transparent to the application.
- com.ibm.db2.jc c.DB2ConnectionPoolDataSource, which supports connection pooling. With this implementation, you must manage connection pooling yourself, either by writing custom code or by using a tool like IBM WebSphere.
- com.ibm.db2.jcc.DB2XADataSource--same as DB2ConnectionPoolDataSource, but supports distributed transactions
Configuring a J2C authentication data entry
J2EE connector authentication data entries are used by a JDBC datasource to log in to a database. In this section we'll create a J2C authentication data entry to log in to the DB2 database.
Select the Secure administration, applications, and infrastructure node in the WebSphere administration console. Next, select Java Authentication and Authorization Service -> J2C Authentication data in the Authentication sub-header. A table of J2C authentication data entries gets displayed. Click on the New button to add a J2C authentication data entry. In the J2C authentication data entry configuration frame, specify an alias for the data entry. Specify the user ID and password used to log in to the DB2 database. Click Apply. Click Save to save the workspace changes to the master configuration. A new J2C authentication data entry gets added.Configuring a data source
We will now configure a JDBC data source to access data from the DB2 database. The JDBC provider configured earlier supplies the driver class for the data source. To configure a new data source, select the link for the JDBC provider DB2 Universal JDBC Driver Provider and click on the Data sources link in the Additional Properties header. A table of data sources is displayed. Click on the New button to add a new data source. In the data source configuration frame specify a data source name, and a JNDI name for the data source (see Figure 3). In the Component-managed authentication alias field, select the J2C authentication data entry configured in the previous section. Click Next.
Figure 3. Specifying datasource JNDI names.
In the data source properties frame, specify the database name (DSNQ), driver type (Type 4), server name (os19.in.vbose.com), and port number(4763). The JNDI (Java Naming Directory Interface) is what we will use to look up the data source name from the application code is named as jdbc/SampleDS
Click Next. The summary page displays the data source summary. Click Finish to apply the data source configuration. Click Save to save the data source configuration. A new data source gets added to the data sources table. Select the data source check box and click on Test connection frame to test the JDBC connection with the DB2 database. A message indicates if the JDBC connection with the DB2 database was successful.
Next, configure additional connection pool properties for the data source by selecting the Connection Pool Properties link in the Additional Properties header on the data source page. Specify the connection pool properties. Connection timeout is the maximum number of seconds an application waits for a connection from the connection pool before timing out; the default value is 180 seconds. Maximum connections is the maximum number of connections in the connection pool; the default value is 10. Minimum connections is the minimum number of connections in the connection pool; the default is 1.Access Managed DB2 Connection via JNDI from the application code
Now, we will use the JNDI name configured above to look up the data source name to access DB2 database. At this point, the database connection and the connection pool are managed by the application server. Since the database connection and the connection pooling are managed by the application server, it is called a managed connection. The application code has to ensure that the connection resource is closed after its use to avoid expensive resource leaks. Closing connection resource is nothing but the connection that the application obtained from the pool via JNDI look up is now returned back to the pool and is available for other requests or threads to use.
In the application code example below, I will use the sophisticated, simple, less invasive and well established industry standard J2EE framework called Spring to obtain the connection via JNDI look up of the application server and the framework closes the same after running a query. I am also using iBatis data mapper framework to map the data to the objects.
Let us now design the business service API named LookUpServiceImpl.java which implements the interface ILookUpService.java
ILookUpService.java
/**
* Created on : Dec 31, 2008
* File : ILookUpService.java
* $ Revision : $
* Copyright © Vigil Bose
* All Rights Reserved
* This is unpublished proprietary source code.
* The copyright notice above does not evidence any actual or
* intended publication of such source code.
*/
package com.vbose.bus;
import java.util.Set;
import com.vbose.domain.EventActions;
/**
* ILookUpService.java : A java business service interface
* that exposes the APIs used by user interface layer to access
* the read only business data
* @author Vigil Bose
*/
public interface ILookUpService {
/**
* The API findEventActionsByActionId() is used to find the EventActions domain object
* for the given actionId
* @param actionId - The event action identifier
* @return an instance of EventActions domain object
*/
public EventActions findEventActionsByActionId(Integer actionId);
}
LookUpServiceImpl.java
/**
* Created on : Dec 31, 2008
* File : LookUpServiceImpl.java
* $ Revision : $
* Copyright © Vigil Bose
* All Rights Reserved
* This is unpublished proprietary source code.
* The copyright notice above does not evidence any actual or
* intended publication of such source code.
*/
package com.vbose.bus.impl;
import java.util.Set;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.service;
import com.vbose.bus.ILookUpService;
import com.vbose.domain.EventActions;
/**
* LookUpServiceImpl.java : A java business service implementation
* that implements the APIs used by user interface layer to access
* read only data.
* @author Vigil Bose
*/
@Service("lookupService")
public class LookUpServiceImpl
implements ILookUpService{
private ILookUpServiceIBatisDao lookUpServiceIBatisDao;
/**
* A setter method of dependency injection
* @param lookUpServiceIBatisDao the lookUpServiceIBatisDao to set
*/
public void setLookUpServiceIBatisDao(
ILookUpServiceIBatisDao lookUpServiceIBatisDao) {
this.lookUpServiceIBatisDao = lookUpServiceIBatisDao;
}
/**
* The API findEventActionsByActionId() is used to find the EventActions domain object
* for the given actionId
* @param actionId - The event action identifier
* @return an instance of EventActions domain object
*/
@Transactional (readOnly = true)
public EventActions findEventActionsByActionId(Integer actionId) {
return this.lookUpServiceIBatisDao().
findEventActionsByActionId(actionId);
}
}
The business service implementation API has @Transactional annotation which is used by the Spring framework to initiate a read only transaction to the database.
The
On WebSphere 6.0 and above, the recommended Spring JTA transaction manager to use is WebSphereUowTransactionManager. This special adapter leverages IBM's UOWManager API which is available in WebSphere Application Server 6.0.2.19 or above and 6.1.0.9 or above. With this adapter, Spring-driven transaction suspension (suspend/resume as initiated by PROPAGATION_REQUIRES_NEW) is officially supported by IBM!
The business service API findEventActionsByActionId() shown above delegates the call to the data access interface where the query gets executed and returns the results. With this set up the business service is agnostic about the data access infrastructure. The service does not know whether the underlying connection is obtained via JNDI app server managed connection or local non-managed connection or even using iBatis data mapper framework under the hoods.
ILookUpServiceIBatisDao.java (Data access repository interface)
/**
* Created on : Dec 31, 2008
* File : ILookUpServiceDao.java
* $ Revision : $
* Copyright © Vigil Bose
* All Rights Reserved
* This is unpublished proprietary source code.
* The copyright notice above does not evidence any actual or
* intended publication of such source code.
*/
package com.vbose.bus.dao;
import java.util.Set;
import org.springframework.dao.DataAccessException;
import com.vbose.domain.EventActions;
/**
* ILookUpServiceDao.java : Data Access Interface that exposes
* read only APIs that facilitate the business service to get
* access to the data
* @author Vigil Bose
*/
public interface ILookUpServiceIBatisDao {
/**
* The API findEventActionsByActionId() is used to find the EventActions domain object
* for the given actionId
* @param actionId - The event action identifier
* @return an instance of EventActions domain object
* @throws DataAccessException
*/
public EventActions findEventActionsByActionId(Integer actionId) throws DataAccessException;
}
LookUpServiceIBatisDaoImpl.java (Data access repository implementation)
/**
* Created on : Dec 31, 2008
* File : LookUpServiceIBatisDaoImpl.java
* $ Revision : $
* Copyright © Vigil Bose
* All Rights Reserved
* This is unpublished proprietary source code.
* The copyright notice above does not evidence any actual or
* intended publication of such source code.
*/
package com.vbose.bus.dao.impl;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import com.vbose.bus.dao.ILookUpServiceIBatisDao;
import com.vbose.domain.EventActions;
/**
* LookUpServiceIBatisDaoImpl : A data access strategy implementation
* based on iBatis Data Mapper framework that implements the APIs of
* {@link ILookUpServiceIBatisDao}
* @author Vigil Bose
*/
public class LookUpServiceIBatisDaoImpl
extends SqlMapClientDaoSupport
implements ILookUpServiceIBatisDao {
/**
* The API findEventActionsByActionId() is used to find the EventActions domain object
* for the given actionId
* @param actionId - The event action identifier
* @return an instance of EventActions domain object
* @throws DataAccessException
*/
public EventActions findEventActionsByActionId(Integer actionId)
throws DataAccessException {
return (EventActions)getSqlMapClientTemplate().
queryForObject("findEventActionsByActionId",actionId);
}
}
The data access service shown above is executed in read only transaction. Before executing the API, this service has access to the two core infrastructure objects that facilitate the query execution. One is sqlMapClient provided by SqlMapClientDaoSupport class and the other one is data source to obtain the connection. The framework handles all the plumbing of code that makes the application code cleaner. The framework opens the connection before the query is executed and closes the connection after the query is executed.sql-map-config.xmll (iBatis SQL mapper infrastructure configuration)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings lazyLoadingEnabled="true" enhancementEnabled="true"/>
<sqlMap resource="com/vbose/domain/ibatis/maps/EventActions.xml"/>
</sqlMapConfig>
EventActions.xml (Data mapper for EventActions.java)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap namespace="EventActions">
<resultMap id="eventActionsResult" class="com.vbose.domain.EventActions">
<result column="ACTION_ID" property="actionId" jdbcType="INTEGER" />
<result column="ACTION_DESC" property="actionDesc" jdbcType="VARCHAR" />
<result column="SUSP_ID" property="suspensionId" jdbcType="INTEGER" />
</resultMap>
<select id="findEventActionsByActionId" resultMap="eventActionsResult">
SELECT ea.ACTION_ID,
ea.ACTION_DESC,
ea.SUSP_ID
FROM SS_EVENT_ACTIONS ea
WHERE ea.ACTION_ID = #value#
WITH UR
</select>
</sqlMap>
EventActions.java (Domain Object)
/**
* Created on : Dec 31, 2008
* File : EventActions.java
* $ Revision : $
* Copyright © Vigil Bose
* All Rights Reserved
* This is unpublished proprietary source code.
* The copyright notice above does not evidence any actual or
* intended publication of such source code.
*/
package com.vbose.domain;
import java.io.Serializable;
/**
* EventActions.java : A class that represents a row in
* the 'EVENT_ACTIONS' table.
* @author Vigil Bose
*/
public class EventActions implements Serializable {
private static final long serialVersionUID = 1L;
/** The cached hash code value for this instance. Settting to 0 triggers re-calculation. */
private int hashValue = 0;
private Integer actionId;
private String actionDesc;
private Integer suspensionId;
/**
* Simple constructor of EventActions instances.
*/
public EventActions() {
}
/**
* Constructor of EventActions instances given a simple primary key.
* @param eventId
*/
public EventActions(Integer actionId) {
this.actionId = actionId;
}
/**
* @return the actionId
*/
public Integer getActionId() {
return actionId;
}
/**
* @param actionId the actionId to set
*/
public void setActionId(Integer actionId) {
this.hashValue = 0;
this.actionId = actionId;
}
/**
* @return the actionDesc
*/
public String getActionDesc() {
return actionDesc;
}
/**
* @param actionDesc the actionDesc to set
*/
public void setActionDesc(String actionDesc) {
this.actionDesc = actionDesc;
}
/**
* @return the suspensionId
*/
public Integer getSuspensionId() {
return suspensionId;
}
/**
* @param suspensionId the suspensionId to set
*/
public void setSuspensionId(Integer suspensionId) {
this.suspensionId = suspensionId;
}
/**
* Implementation of the equals comparison on the basis of equality of the primary key values.
* @param rhs
* @return boolean
*/
public boolean equals(Object rhs){
if (rhs == null){
return false;
}
if (! (rhs instanceof EventActions)){
return false;
}
EventActions that = (EventActions) rhs;
if (this.getActionId() == null || that.getActionId() == null){
return false;
}
return (this.getActionId().equals(that.getActionId()));
}
/**
* Implementation of the hashCode method conforming to the Bloch pattern with
* the exception of array properties (these are very unlikely primary key types).
* @return int
*/
public int hashCode() {
if (this.hashValue == 0) {
int result = 17;
int actionIdValue = this.getActionId() == null ? 0 :
this.getActionId().hashCode();
result = result * 37 + actionIdValue;
this.hashValue = result;
}
return this.hashValue;
}
}
Now, wire the JDBC infrastructure and the data access object in the Spring application context. See below.
Spring Application Context
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<jee:jndi-lookup id="sampleDS" jndi-name="jdbc/SampleDS" proxyInterface="javax.sql.DataSource" resourceRef="true"/>
<context:annotation-config>
<tx:annotation-driven order="2"/>
<!--JTA appserver managed distributed transaction manager reference-->
<tx:jta-transaction-manager />
<!-- SqlMap setup for iBATIS Database Layer -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:/com/vbose/domain/ibatis/maps/sql-map-config.xml"/>
<property name="dataSource" ref="sampleDS"/>
</bean>
<bean id="lookUpServiceIBatisDao" class="com.vbose.bus.dao.impl.LookUpServiceIBatisDaoImpl">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
</beans>
RAR Deployment
Since Spring 2.5, it is possible to deploy a Spring ApplicationContext as a RAR file, encapsulating the context and all of its required bean classes and library JARs in a J2EE RAR deployment unit. This is the equivalent of bootstrapping a standalone ApplicationContext, just hosted in J2EE environment, being able to access the J2EE server's facilities. RAR deployment is intended as a more 'natural' alternative to the not uncommon scenario of deploying a headless WAR file - i.e. a WAR file without any HTTP entry points, just used for bootstrapping a Spring ApplicationContext in a J2EE environment.
RAR deployment is ideal for application contexts that do not need any HTTP entry points but rather just consist of message endpoints and scheduled jobs etc. Beans in such a context may use application server resources such as the JTA transaction manager and JNDI-bound JDBC DataSources and JMS ConnectionFactory instances, and may also register with the platform's JMX server - all through Spring's standard transaction management and JNDI and JMX support facilities. Application components may also interact with the application's server JCA WorkManager through Spring's TaskExecutor abstraction.
Access DB2 Connection locally using Apache DBCP
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Transaction manager for a single JDBC DataSource (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="sampleDS"/>
<bean id="sampleDS" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.ibm.db2.jcc.DB2Driver"
p:url="jdbc:db2://os19.in.vbose.com:4763/DSNQ:currentFunctionPath=SAMPLE;IGNORE_DONE_IN_PROC=true;currentSchema=SAMPLE;"
p:username="xxxxxx"
p:password="xxxxxxx"
p:maxActive="3"
p:maxIdle="3"
p:validationQuery="SELECT DTS FROM DT_TM_TS WITH UR"
p:testWhileIdle="true"
p:timeBetweenEvictionRunsMillis="1800000"
/>
<context:annotation-config>
<tx:annotation-driven order="2"/>
<!-- SqlMap setup for iBATIS Database Layer -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:/com/vbose/domain/ibatis/maps/sql-map-config.xml"/>
<property name="dataSource" ref="sampleDS"/>
</bean>
<bean id="lookUpServiceIBatisDao" class="com.vbose.bus.dao.impl.LookUpServiceIBatisDaoImpl">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
</beans>
In the above configuration, I changed two bean configurations. One is datasource and the other is the transactionManager. The datasource and connection pool are obtained via Apache database connection pool mechanism. Since it is not managed by application server, it is called non-managed connection. Here, the application's business layer remains unchanged. This set up does not require application server environment and it also enables unit testing without the dependency on the application server.
References
- Spring Framework 2.5.6 Reference Document
- IBM Websphere RedBooks
- iBatis 2.3.4 Reference Document
Vigil Bose works as Principal System Architect (Java/J2EE) at OCTO, Washington DC Government. OCTO develops, implements and maintains the District's IT and Telecommunications infrstructure; develops and implements major city wide applications. Mr. Bose primarily focuses on light-weight architectures and open source frameworks to build J2EE solutions for his clients. Mr. Bose has designed and built successful enterprise software solutions using Spring, and other open source tools and implemented them in production for his clients. He enjoys creating business value by applying simple techniques and principles to application architecture.

