tag:blogger.com,1999:blog-37108159422712691362024-03-17T20:03:56.000-07:00Welcome to Vigil Bose's blog siteThis blog site is dedicated to technical stuff.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.comBlogger23125tag:blogger.com,1999:blog-3710815942271269136.post-21012694260678024052010-02-17T09:35:00.006-08:002010-02-22T09:45:01.320-08:00Multipart series on Spring Security customizationI have started a multipart series on spring security customization. Please click on the links below to read each article.<br /><br />1. <a href="http://simplaso.com/blog/2010/02/spring-security-customization-series-1/">Practical example on using Jasypt decryption algorithm on user password</a><a href="http://simplaso.com/blog/2010/02/spring-security-customization-series-1/">.</a><br />2. <a href="http://simplaso.com/blog/2010/02/spring-security-customization-series-part-2-add-jasypt-stringdigester/">Practical example on using Jasypt String Digester interface as the password encoder</a>.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com320tag:blogger.com,1999:blog-3710815942271269136.post-78361470450967901362009-04-18T23:09:00.016-07:002009-07-18T12:03:10.093-07:00JPA/Hibernate - One to One Mapping Quirks<span style="font-weight: bold;">Introduction<br /><br /></span>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.<br /><br /><span style="font-weight: bold;">Technical Details</span><br /><br />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".<br /><br /><span style="font-style: italic;">User.java</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;">@Entity<br />@Table (name="Users")<br />public class Users implements Serializable{<br /><br />private static final long serialVersionUID = -3174184215665687091L;<br /><br />/** The cached hash code value for this instance. Setting to 0 triggers re-calculation. */<br />@Transient<br />private int hashValue = 0;<br /><br />/** The composite primary key value. */<br />@Id<br />@GeneratedValue(strategy=GenerationType.IDENTITY)<br />@Column (name="id")<br />private Long Id;<br /><br />/** The value of the simple username property. */<br />@Column(name = "username", unique=true, nullable=false)<br />private String username;<br /><br />/** The value of the contacts association. */<br />@OneToOne(cascade = {CascadeType.ALL}, fetch=FetchType.LAZY, <span style="font-weight: bold;">optional=true</span>)<br />@PrimaryKeyJoinColumn<br />@JoinColumn (name="id", nullable=false)<br />private Contacts contacts;<br /><br />.....<br /><br />public Users(){}<br /><br />/**<br />* @return Id<br />*/<br />public Long getId(){<br />return this.Id;<br />}<br />/**<br />* @param id - The Id to set<br />*/<br />public void setId(Long id){<br /> this.hashValue = 0;<br /> this.Id = Id;<br />}<br />/**<br />* @return Contacts<br />*/<br />public Contacts getContacts(){<br /> return this.contacts;<br />}<br />/**<br />* @param Contacts - The contacts to set<br />*/<br />public void setContacts(Contacts contacts){<br /> this.contacts = contacts;<br />}<br /><br />....<br />}<br /></code><br /><span style="font-style: italic;">Contacts.java</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;">@Entity<br />@Table (name="Contacts")<br />public class Contacts implements Serializable{<br /><br />private static final long serialVersionUID = -1079313023058953957L;<br /><br />@Id<br />@Column (name="id")<br />private Long Id;<br /><br />/** The value of the users association. */<br />@OneToOne<span style="font-weight: bold;">(optional=false)</span><br />@JoinColumn (name="id")<br />private Users users;<br /><br />....<br /><br />public Contacts (){}<br /><br />/**<br />* @return Id<br />*/<br />public Long getId(){<br />return this.Id;<br />}<br />/**<br />* @param id - The Id to set<br />*/<br />public void setId(Long id){<br /> this.hashValue = 0;<br /> this.Id = id;<br />}<br />/**<br />* @return Users<br />*/<br />public Users getUsers(){<br />return this.users;<br />}<br />/**<br />* @param users - The users to set<br />*/<br />public void setUsers(Users users){<br /> this.users = users;<br />}<br /><br />....<br />}<br /><br /></code><br />The above set up will result in an error message that says like the following:<br /><br /><pre>Exception raised - org.hibernate.id.IdentifierGenerationException:<br />ids for this class must be manually assigned before calling save(): com.vbose.Contacts<span style="font-family:Georgia,serif;"><br /></span></pre><br />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:<span style="font-family:Georgia,serif;"><br /></span><br />The one below is an enhanced <span style="font-style: italic;">Contacts.java</span> domain object:<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;">@Entity<br />@Table (name="Contacts")<br />public class Contacts implements Serializable{<br /><br />private static final long serialVersionUID = -1079313023058953957L;<br /><br />@Id<br /><span style="font-weight: bold;"> @GeneratedValue(generator="foreign")</span><br /><span style="font-weight: bold;"> @GenericGenerator(name="foreign", strategy = "foreign", parameters={</span><br /><span style="font-weight: bold;"> @Parameter(name="property", value="users")</span><br /><span style="font-weight: bold;"> }) </span><br />@Column (name="id")<br />private Long Id;<br /><br />/** The value of the users association. */<br />@OneToOne<span style="font-weight: bold;">(optional=false)</span><br />@JoinColumn (name="id")<br />private Users users;<br /><br />....<br /><br />public Contacts (){}<br /><br />/**<br />* @return Id<br />*/<br />public Long getId(){<br /> return this.Id;<br />}<br />/**<br />* @param id - The Id to set<br />*/<br />public void setId(Long id){<br /> this.hashValue = 0;<br /> this.Id = id;<br />}<br />/**<br />* @return Users<br />*/<br />public Users getUsers(){<br /> return this.users;<br />}<br />/**<br />* @param users - The users to set<br />*/<br />public void setUsers(Users users){<br /> this.users = users;<br />}<br /><br />....<br />}<br /><br /></code><br />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<br /><pre>org.hibernate.id.IdentifierGenerationException: attempted to assign id from<br />null one-to-one property:</pre>For e.g.<br /><br />Users users = new Users();<br />Contacts contacts = new Contacts();<br />users.setContacts(contacts);<br />contacts.setUsers(users);<br /><br />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 <span style="font-style: italic;">entityManager.persist(object)</span>. 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.<br /><br />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 <span>entityManager.merge(users) </span> operation will result in the same above said error if the "optional" parameter is not set properly at the one-to-one association annotation.<br /><br />The "optional" parameter should be set to true at the parent level and should be set to false at the child object level. <br /><br />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.<br /><br /><span style="font-weight: bold;">Conclusion</span><br /><br />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.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com80tag:blogger.com,1999:blog-3710815942271269136.post-13056804369284729872009-03-18T06:26:00.020-08:002009-03-19T08:41:17.931-08:00Apache Commons DBCP and Tomcat JDBC Connection Pool<span style="font-weight: bold;">Introduction<br /><br /></span>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.<span style="font-weight: bold;"> </span>In this article, I would like to point out some drastic differences between Apache DBCP and the new Tomcat JDBC Connection Pool.<span style="font-weight: bold;"> </span> I strongly feel Tomcat JDBC Connection Pool is much superior to DBCP and highly recommend all users to check it out.<span style="font-weight: bold;"><br /><br />Database connection<br /><br /></span>A database<span style="font-weight: bold;"> </span>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.<br /><br /><span style="font-weight: bold;">Connection Pool</span><br /><br />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.<br /><br />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.<br /><br /><span style="font-weight: bold;">Apache Commons DBCP Connection Pool</span><br /><br />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.<br />Applications can use the <code>commons-dbcp</code> component directly or through the existing interface of their container / supporting framework.<br /><br />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.<br /><br />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.<br /><br /><ol><li>commons-dbcp is single threaded. In order to be thread safe commons-dbcp locks the entire pool, even during query validation.</li><li>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 <code>synchronized</code> statement in Java 6, commons-dbcp still suffers in speed and concurrency.</li><li>commons-dbcp is complex, over 60 classes. tomcat-jdbc-pool, is 8 classes, hence modifications for future requirement will require much less changes.</li><li>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. </li><li>The commons-dbcp has become fairly stagnant. Sparse updates, releases, and new feature support.</li><li>It's not worth rewriting over 60 classes, when something as a connection pool can be accomplished with a much simpler implementation.</li></ol>Some of the benefits of Tomcat JDBC Connection Pool are given below.<ol><li>Tomcat jdbc pool implements a fairness option not available in commons-dbcp and still performs faster than commons-dbcp.</li><li>Tomcat jdbc pool implements the ability to retrieve a connection asynchronously, without adding additional threads to the library itself.</li><li>Tomcat jdbc pool is a Tomcat module, it depends on Tomcat JULI, a simplified logging framework used in Tomcat.</li><li>Support for highly concurrent environments and multi core/cpu systems.</li><li>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.</li><li>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.</li><li>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.</li><li>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.</li><li>High performance<br /></li><li>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.<br /></li><li>Asynchronous connection retrieval - you can queue your request for a connection and receive a Future<connection> back.</connection></li></ol>The usage of Tomcat JDBC Connection Pool is very simple and for people who are already familiar with DBCP, the transistion is very simple.<br /><br />The Tomcat connection pool offers a few additional features over what most other pools let you do: <code><br /><br /></code><ul><li><code>initSQL</code> - the ability to run a SQL statement exactly once, when the connection is created.</li><li><code>validationInterval</code> - in addition to running validations on connections, avoid running them too frequently.</li><li><code>jdbcInterceptors</code> - flexible and pluggable interceptors to create any customizations around the pool, the query execution and the result set handling.<br /></li><li><code>fairQueue</code> - Set the fair flag to true to achieve thread fairness or to use asynchronous connection retrieval.</li></ul><span style="font-weight: bold;">JNDI Factory and Type<br /><br /></span>Most attributes are same and have the same meaning as DBCP.<br /><br /><ul><li><strong><code>factory - </code></strong>factory is required, and the value should be <code>org.apache.tomcat.jdbc.pool.DataSourceFactory</code><br /></li></ul><ul><li><strong><code>type - t</code></strong>ype should always be <code>javax.sql.DataSource</code><br /></li></ul><br /><span style="font-weight: bold;">Common Attributes<br /><br /></span>The following attributes are shared between commons-dbcp and tomcat-jdbc-pool, in some cases default values are different.<br /><br /><ul><li><code><span style="font-weight: bold;">defaultAutoCommit</span> - </code>(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.)<br /></li></ul><ul><li><code><span style="font-weight: bold;">defaultReadOnly</span> - </code>(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)<br /></li></ul><ul><li><code><span style="font-weight: bold;">defaultTransactionIsolation</span> - </code>(String) The default TransactionIsolation state of connections created by this pool. One of the following: (see javadoc )</li></ul><ol><li> NONE</li><li> READ_COMMITTED</li><li> READ_UNCOMMITTED</li><li> REPEATABLE_READ</li><li> SERIALIZABLE</li></ol><p> If not set, the method will not be called and it defaults to the JDBC driver. </p><ul><li><code><span>defaultCatalog</span> - </code>(String) The default catalog of connections created by this pool.<br /></li></ul><ul><li><strong><code>driverClassName - </code></strong>(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 </li></ul><ul><li> <strong><code>username -</code></strong>(String) The connection username to be passed to our JDBC driver to establish a connection. Note, at this point, <code>DataSource.getConnection(username,password)</code> is not using the credentials passed into the method. </li></ul><ul><li><strong><code>password - </code></strong>(String) The connection password to be passed to our JDBC driver to establish a connection. Note, at this point, <code>DataSource.getConnection(username,password)</code> is not using the credentials passed into the method. </li></ul><ul><li><code>maxActive - </code>(int) The maximum number of active connections that can be allocated from this pool at the same time. The default value is <code>100<span style="font-family:Georgia,serif;">.</span></code></li></ul><ul><li><code>maxIdle - </code>(int) The maximum number of connections that should be kept in the pool at all times. Default value is <code>maxActive</code>:<code>100</code> Idle connections are checked periodically (if enabled) and connections that been idle for longer than <code>minEvictableIdleTimeMillis</code> will be released. (also see <code>testWhileIdle</code>)</li></ul><ul><li><code>minIdle - </code>(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 from <code>initialSize</code>:<code>10</code> (also see <code>testWhileIdle</code>) </li></ul><ul><li><code>initialSize</code> - (int)The initial number of connections that are created when the pool is started. Default value is <code>10</code></li></ul><ul><li><code>maxWait - </code>(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 is <code>30000</code> (30 seconds)<br /></li></ul><ul><li><code>testOnBorrow - </code>(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 is <code>false</code></li></ul><ul><li><code>testOnReturn - </code>(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 is <code>false</code>. </li></ul><ul><li><code>testWhileIdle - </code>(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 is <code>false</code> and this property has to be set in order for the pool cleaner/test thread is to run (also see <code>timeBetweenEvictionRunsMillis</code>) </li></ul><ul><li><code>validationQuery - </code>(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 is <code>null</code>. Example values are <code>SELECT 1</code>(mysql), <code>select 1 from dual</code>(oracle), <code>SELECT 1</code>(MS Sql Server) </li></ul><ul><li><code>timeBetweenEvictionRunsMillis - </code>(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 is <code>5000</code> (5 seconds).</li></ul><ul><li><code>numTestsPerEvictionRun - </code>(int) Property not used in tomcat-jdbc-pool.</li></ul><ul><li><code>minEvictableIdleTimeMillis - </code>(long) The minimum amount of time an object may sit idle in the pool before it is eligible for eviction. The default value is <code>60000</code> (60 seconds).</li></ul><ul><li><code>accessToUnderlyingConnectionAllowed - </code>(boolean) Property not used. Access can be achieved by calling <code>unwrap</code> on the pooled connection. see <code>javax.sql.DataSource</code> interface, or call <code>getConnection</code> through reflection.</li></ul><ul><li><code>removeAbandoned - </code>(boolean) Flag to remove abandoned connections if they exceed the <code>removeAbandonedTimout</code>. If set to true a connection is considered abandoned and eligible for removal if it has been in use longer than the <code>removeAbandonedTimeout</code> Setting this to true can recover db connections from applications that fail to close a connection. See also <code>logAbandoned</code> The default value is <code>false</code>.</li></ul><ul><li><code>removeAbandonedTimeout - </code>(long) Timeout in seconds before an abandoned(in use) connection can be removed. The default value is <code>60</code> (60 seconds). The value should be set to the longest running query your applications might have.</li></ul><ul><li><code>logAbandoned - </code>(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 is <code>false</code>.</li></ul><ul><li><code>connectionProperties - </code>(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 is <code>null</code>.</li></ul><ul><li><code>poolPreparedStatements - </code>(boolean) Property not used. The default value is <code>false</code>.</li></ul><ul><li><code>maxOpenPreparedStatements - </code>(int) Property not used. The default value is <code>false</code>.</li></ul><span style="font-weight: bold;">Tomcat JDBC Connection Pool Specific Properties</span><br /><br /><ul><li><code>initSQL - </code>(String) A custom query to be run when a connection is first created. The default value is <code>null</code>.</li></ul><ul><li> <code>jdbcInterceptors</code> (String) A semicolon separated list of classnames extending <code>org.apache.tomcat.jdbc.pool.JdbcInterceptor</code> class. These interceptors will be inserted as an interceptor into the chain of operations on a <code>java.sql.Connection</code> object. The default value is <code>null</code>.<br /><span style="font-weight: bold;">Predefined interceptors:</span><br /><ol><li> org.apache.tomcat.jdbc.pool.interceptor.ConnectionState - keeps track of auto commit, read only, catalog and transaction isolation level.</li><li> org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer - keeps track of opened statements, and closes them when the connection is returned to the pool.</li></ol></li></ul><ul><li><code>validationInterval</code> - (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 is <code>30000</code> (30 seconds).</li></ul><ul><li><code>jmxEnabled - </code>(boolean) Register the pool with JMX or not. The default value is <code>true</code>.</li></ul><ul><li><code>fairQueue - <span style="font-family:Georgia,serif;"></span></code><code><span style="font-family:Georgia,serif;"></span></code> (boolean) Set to true if you wish that calls to getConnection should be treated fairly in a true FIFO fashion. This uses the <code>org.apache.tomcat.jdbc.pool.FairBlockingQueue</code> implementation for the list of the idle connections. The default value is <code>false</code>. This flag is required when you want to use asynchronous connection retrieval. </li></ul><ul><li><code>useEquals - </code>(boolean) Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of <code>==</code> when comparing method names. This property does not apply to added interceptors as those are configured individually. The default value is <code>false</code>. </li></ul><span style="font-weight: bold;">As a Resource</span><br /><br />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.<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><Resource<br /> auth="Container"<br /> defaultAutoCommit="true" <br /> defaultReadOnly="false"<br /> defaultTransactionIsolation="READ_COMMITTED"<br /> driverClassName="com.ibm.db2.jcc.DB2Driver"<br /> factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"<br /> fairQueue="false"<br /> initSQL="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR"<br /> initialSize="10"<br /> jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"<br /> jmxEnabled="true"<br /> logAbandoned="true"<br /> maxActive="100"<br /> maxIdle="100"<br /> maxWait="6000"<br /> minEvictableIdleTimeMillis="30000"<br /> minIdle="10"<br /> name="jdbc/sampleDS"<br /> password="xxxxxxxxxxx"<br /> removeAbandoned="true"<br /> removeAbandonedTimeout="60"<br /> testOnBorrow="true"<br /> testOnReturn="false"<br /> testWhileIdle="false"<br /> timeBetweenEvictionRunsMillis="30000"<br /> type="javax.sql.DataSource"<br /> url="jdbc:db2://os01.in.vbose.com:4745/DSNQ:currentFunctionPath=SAMPLE;IGNORE_DONE_IN_PROC=true;currentSchema=SAMPLE;"<br /> useEquals="false"<br /> username="abcdefg"<br /> validationInterval="1800000" validationQuery="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR"/><br /></code><br /><br /><span style="font-weight: bold;">Wiring Tomcat JDBC DataSource using Spring Application Context</span><br /><br />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.<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns:p="http://www.springframework.org/schema/p"<br />xmlns:context="http://www.springframework.org/schema/context"<br />xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br />http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"><br /><br /><context:property-placeholder location="classpath:sample/jdbc.properties"/><br /><bean id="datasource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close" <br /> p:driverClassName="${jdbc.sample.db.driverClassName}"<br /> p:url="${jdbc.sample.db.url}"<br /> p:username="${jdbc.sample.db.username}"<br /> p:password="${jdbc.sample.db.password}" <br /> p:initialSize="10"<br /> p:initSQL="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR"<br /> p:minIdle="10"<br /> p:maxIdle="100"<br /> p:maxActive="100"<br /> p:maxWait="6000"<br /> p:jmxEnabled="true"<br /> p:jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"<br /> p:removeAbandoned="true"<br /> p:removeAbandonedTimeout="60"<br /> p:logAbandoned="true"<br /> p:testOnBorrow="true"<br /> p:testOnReturn="false"<br /> p:testWhileIdle="false" <br /> p:useEquals="false"<br /> p:fairQueue="false" <br /> p:timeBetweenEvictionRunsMillis="30000"<br /> p:minEvictableIdleTimeMillis="30000"<br /> p:validationInterval="1800000"<br /> p:validationQuery="SELECT DTS FROM DT_TM_TS FOR READ ONLY WITH UR" <br />/><br /></code><br /><br />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 <span style="font-style: italic;">org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport(threshold=10000)</span>. In this case, the log level used is <code>WARN.</code><br /><code><br /></code>Additionally, if used within tomcat, you can add a JMX enabled interceptor called <span style="font-style: italic;">org.apache.tomcat.jdbc.pool.interceptor.</span><span style="font-style: italic;">SlowQueryReportJmx</span><span style="font-style: italic;">(threshold=10000)</span><span style="font-style: italic;">. </span> This class uses Tomcat's JMX engine so it wont work outside of the Tomcat container.<br /><br /><span style="font-weight: bold;">Conclusion</span><br /><br />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.<br /><br />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.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com179tag:blogger.com,1999:blog-3710815942271269136.post-1698585156127426372009-02-23T10:47:00.020-08:002009-02-23T18:12:34.954-08:00.NET client consuming Spring WS 1.5.5 using XWSS WS security Implementation<span style="font-weight: bold;font-family:arial;" >Introduction</span><br /><br />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.<br /><br />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.<br /><br /><span style="font-weight: bold;"><span style="font-family:arial;">Java Web Service Implementation</span><br /><br /></span>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.<br /><br /><span style="font-style: italic;">applicationContext-security.xml</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans"<br />xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns:security="http://www.springframework.org/schema/security"<br />xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd<br /> http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd"><br /><br /><description><br />This application context contains the WS-Security and Sprign Security beans.<br /></description><br /><br /><security:global-method-security secured-annotations="enabled"/><br /><br /><security:authentication-provider user-service-ref="securityService"/><br /><br /><bean id="securityService"<br />class="org.springframework.ws.samples.airline.security.SpringFrequentFlyerSecurityService"><br /><description><br /> A security service used to obtain Frequent Flyer information.<br /></description><br /><constructor-arg ref="frequentFlyerDao"/><br /></bean><br /><br /><bean id="wsSecurityInterceptor" class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor"><br /><description><br /> This interceptor validates incoming messages according to the policy defined in 'securityPolicy.xml'.<br /> The policy defines that all incoming requests must have a UsernameToken with a password digest in it.<br /> The actual authentication is performed by the Spring Security callback handler.<br /></description><br /><property name="secureResponse" value="false"/><br /><property name="policyConfiguration"<br /> value="classpath:org/springframework/ws/samples/airline/security/securityPolicy.xml"/><br /><property name="callbackHandler"><br /> <bean class="org.springframework.ws.soap.security.xwss.callback.SpringDigestPasswordValidationCallbackHandler"><br /> <property name="userDetailsService" ref="securityService"/><br /> </bean><br /></property><br /></bean><br /><br /></beans></code>Spring ws currently supports two implementations of WS Security. One is based on XWSS and the other one is WSS4J from Apache.<span style="font-weight: bold;"><br /><br /><span style="font-family:arial;">XWSS</span></span><br /><br />XWSS stands for XML and WebServices Security runtime. It is part of Project GlassFish and is used for securing WebServices requests and responses.<br /><br />XWSS 2.0 was based on OASIS WSS specification version 1.0 and XWSS 3.0 is based on OASIS WSS specification 1.1<br /><br /><span style="font-weight: bold;">XwsSecurityInterceptor</span><br /><br />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.<br /><br />Note that XWSS requires both a SUN 1.5 JDK and the SUN SAAJ reference implementation. The WSS4J interceptor does not have these requirements.<br /><br />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.<br /><br /><span style="font-style: italic;">securityPolicy.xml</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config"><br /><xwss:RequireUsernameToken passwordDigestRequired="true" nonceRequired="true"/><br /></xwss:SecurityConfiguration><br /></code><br /><span style="font-weight: bold;font-family:arial;" >Spring WS endpoint Mappings</span><br />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.<br /><br /><span style="font-style: italic;">applicationContext-ws.xml</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans"<br />xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns:oxm="http://www.springframework.org/schema/oxm"<br />xmlns:sws="http://www.springframework.org/schema/web-services"<br />xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br />http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd<br />http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-1.5.xsd"><br /><br /><bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/><br /><br /><bean id="messageReceiver" class="org.springframework.ws.soap.server.SoapMessageDispatcher"/><br /><br /><bean id="schemaCollection" class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection"><br /><description><br /> This bean wrap the messages.xsd (which imports types.xsd), and inlines them as a one.<br /></description><br /><property name="xsds" value="/messages.xsd"/><br /><property name="inline" value="true"/><br /></bean><br /><br /><!-- ===================== ENDPOINTS ===================================== --><br /><br /><!--<br />The marshallingEndpoint and xpathEndpoint handle the same messages. So, you can only use one of them at the<br />same time. This is done for illustration purposes only, typically you would not create two endpoints which<br />handle the same messages.<br />--><br /><br /><bean id="marshallingEndpoint" class="org.springframework.ws.samples.airline.ws.MarshallingAirlineEndpoint"><br /><description><br /> This endpoint handles the Airline Web Service messages using JAXB2 marshalling.<br /></description><br /><constructor-arg ref="airlineService"/><br /></bean><br /><br /><!--<br /><bean id="xpathEndpoint" class="org.springframework.ws.samples.airline.ws.XPathAirlineEndpoint"><br /> <description><br /> This endpoint handles the Airline Web Service messages using XPath expressions and JAXB2 marshalling.<br /> </description><br /> <constructor-arg ref="airlineService"/><br /> <constructor-arg ref="marshaller"/><br /></bean><br />--><br /><br /><bean id="getFrequentFlyerMileageEndpoint"<br />class="org.springframework.ws.samples.airline.ws.GetFrequentFlyerMileageEndpoint"><br /><description><br /> This endpoint handles get frequent flyer mileage requests.<br /></description><br /><constructor-arg ref="airlineService"/><br /></bean><br /><br /><oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/><br /><br /><!-- ===================== ENDPOINT MAPPINGS ============================== --><br /><br /><!--<br />The endpoint mappings map from a request to an endpoint. Because we only want the security interception to<br />occur for the GetFrequentFlyerMileageEndpoint, we define two mappings: one with the securityInterceptor, and<br />a general one without it.<br />--><br /><br /><bean id="annotationMapping"<br />class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"><br /><description><br /> Detects @PayloadRoot annotations on @Endpoint bean methods. The MarshallingAirlineEndpoint<br /> has such annotations. It uses two interceptors: one that logs the message payload, and the other validates<br /> it accoring to the 'airline.xsd' schema file.<br /></description><br /><property name="interceptors"><br /> <list><br /> <bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/><br /> <bean class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor"><br /> <property name="xsdSchemaCollection" ref="schemaCollection"/><br /> <property name="validateRequest" value="true"/><br /> <property name="validateResponse" value="true"/><br /> </bean><br /> </list><br /></property><br /><property name="order" value="1"/><br /></bean><br /><br /><bean id="secureMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping"><br /><description><br /> This endpoint mapping is used for endpoints that are secured via WS-Security. It uses a<br /> securityInterceptor, defined in applicationContext-security.xml, to validate incoming messages.<br /></description><br /><property name="mappings"><br /> <props><br /> <prop key="{http://www.springframework.org/spring-ws/samples/airline/schemas/messages}GetFrequentFlyerMileageRequest"><br /> getFrequentFlyerMileageEndpoint<br /> </prop><br /> </props><br /></property><br /><property name="interceptors"><br /> <list><br /> <bean class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor"/><br /> <ref bean="wsSecurityInterceptor"/><br /> </list><br /></property><br /><property name="order" value="2"/><br /></bean><br /><br /><br /><!-- ===================== ENDPOINT ADAPTERS ============================== --><br /><br /><!--<br />Endpoint adapters adapt from the incoming message to a specific object or method signature. Because this<br />example application uses three different endpoint programming models, we have to define three adapters. This<br />is done for illustration purposes only, typically you would use one adapter, for instance the<br />MarshallingMethodEndpointAdapter.<br />--><br /><br /><br /><sws:marshalling-endpoints/><br /><br /><sws:xpath-endpoints><br /><sws:namespace prefix="messages"<br /> uri="http://www.springframework.org/spring-ws/samples/airline/schemas/messages"/><br /></sws:xpath-endpoints><br /><br /><bean class="org.springframework.ws.server.endpoint.adapter.PayloadEndpointAdapter"><br /><description><br /> This adapter allows for endpoints which implement the PayloadEndpoint interface. The Get<br /> FrequentFlyerMileageEndpoint implements this interface.<br /></description><br /></bean><br /><br /><!-- ===================== ENDPOINT EXCEPTION RESOLVER ===================== --><br /><br /><!--<br />Endpoint exception resolvers can handle exceptions as they occur in the Web service. We have two sorts of<br />exceptions we want to handle: the business logic exceptions NoSeatAvailableException and NoSuchFlightException,<br />which both have a @SoapFault annotation, and other exceptions, which don't have the annotation. Therefore, we<br />have two exception resolvers here.<br />--><br /><br /><bean class="org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver"><br /><description><br /> This exception resolver maps exceptions with the @SoapFault annotation to SOAP Faults. The business logic<br /> exceptions NoSeatAvailableException and NoSuchFlightException have these.<br /></description><br /><property name="order" value="1"/><br /></bean><br /><br /><bean class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver"><br /><description><br /> This exception resolver maps other exceptions to SOAP Faults. Both UnmarshallingException and<br /> ValidationFailureException are mapped to a SOAP Fault with a "Client" fault code.<br /> All other exceptions are mapped to a "Server" error code, the default.<br /></description><br /><property name="defaultFault" value="SERVER"/><br /><property name="exceptionMappings"><br /> <props><br /> <prop key="org.springframework.oxm.UnmarshallingFailureException">CLIENT,Invalid request</prop><br /> <prop key="org.springframework.oxm.ValidationFailureException">CLIENT,Invalid request</prop><br /> </props><br /></property><br /><property name="order" value="2"/><br /></bean><br /><br /></beans><br /><br /><br /></code><br />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<br /><br /><span style="font-weight: bold;">NOTE:</span> 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.<br /><br />There is already a .NET example within airline application which does not require to go to WS security <span style="font-size:100%;">intereceptor </span>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.<br /><span style="font-weight: bold;font-family:arial;font-size:100%;" ><span style="font-weight: bold;"><span style="font-weight: bold;"><br />.NET client configuration using WSE 2.0<br /><br />Prerequisites</span></span></span><span style="font-family:arial;font-size:100%;">:<br /><br /><span style="font-weight: bold;"></span></span><span style="font-weight: bold;font-family:arial;font-size:100%;" ><span style="font-weight: bold;"><span style="font-weight: bold;"></span></span></span><span style="font-family:arial;font-size:100%;">1) Make sure you have WSE2.0 installed and .NET 1.1 (at least)</span><span style="font-weight: bold;font-family:arial;font-size:100%;" ><br /><br />How do you verify the above prerequisite?</span><span style="font-family:arial;font-size:100%;"><br /><br />Check</span><span style="font-family:arial;font-size:100%;"> whether Microsoft.Web.Services2.dll exists under C:\Program Files\Microsoft WSE\v2.0\Microsoft.Web.Services2.dll<br /><br />If WSE 2.0 is not installed, please download it from <a href="http://www.microsoft.com/downloads/details.aspx?familyid=fc5f06c5-821f-41d3-a4fe-6c7b56423841&displaylang=en">here.</a><br /><br />NOTE: The dll Microsoft.Web.Services2.dll plays the role of encrypting or decrypting the request and responses of the service.<br /><br /><span style="font-weight: bold;">.NET consuming Java Web Service<br /><br /></span>Please follow the steps below to consume web service using WSE 2.0<span style="font-weight: bold;"><br /></span></span><span style="font-weight: bold;font-family:arial;font-size:100%;" ><br /></span><span style="font-family:arial;font-size:100%;">1. Enable WSE 2.0 extensions</span><span style="font-weight: bold;font-family:arial;font-size:100%;" ><br /></span><p class="MsoNormal"><br /></p> In visual studio,<br /><ul><li> Select your project and right click</li></ul><ul><li> Select WSE setting 2.0 from the context menu</li></ul><ul><li> In the General tab, check 'Enable this project for Web Services Enhancements' checkbox <br /></li></ul><ul><li> check 'Enable Microsoft Web Services Enhancement soap extensions'</li></ul><br />2. Add Web References<br /><br /> In visual studio,<br /><ul><li> Select your project and right click</li></ul><ul><li> Select 'Add Web References' from the context menu</li></ul><ul><li> Enter the web service URL. For e.g. http://localhost:8080/airline/airline.wsdl</li></ul><ul><li> Hit go button to search the service</li></ul><ul><li> If the service is found, name the service and 'Add Reference'</li></ul><br />3. How to verify whether the added service has WSE 2.0 service extension<br /><br /><ul><li> Expand the service and open the source code of 'Reference.cs'</li></ul><ul><li> Class should extend <span style=";font-family:Verdana;font-size:100%;" >Microsoft.<b style="font-family: verdana;">Web.Services2.WebServicesClientProtocol</b></span></li></ul><!--[if gte mso 9]><xml> <w:worddocument> <w:view>Normal</w:View> <w:zoom>0</w:Zoom> <w:punctuationkerning/> <w:validateagainstschemas/> <w:saveifxmlinvalid>false</w:SaveIfXMLInvalid> <w:ignoremixedcontent>false</w:IgnoreMixedContent> <w:alwaysshowplaceholdertext>false</w:AlwaysShowPlaceholderText> <w:compatibility> <w:breakwrappedtables/> <w:snaptogridincell/> <w:wraptextwithpunct/> <w:useasianbreakrules/> <w:dontgrowautofit/> </w:Compatibility> <w:browserlevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:latentstyles deflockedstate="false" latentstylecount="156"> </w:LatentStyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:Verdana; panose-1:2 11 6 4 3 5 4 4 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:536871559 0 0 0 415 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.Section1 {page:Section1;} --> </style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]--><br />4. Changes in .NET Client class which consume the service<br /><br /><ul><li> Include following namespace (this is to create 'UsernameToken')</li></ul><code>using Microsoft.Web.Services2;<br /> using Microsoft.Web.Services2.Security;<br /> using Microsoft.Web.Services2.Security.Tokens;</code><br /><br /><ul><li> In the code, add UsernameToken in the soap header</li></ul> <code><br /> For e.g.,<br /><br /> UsernameToken un =<br /> new UsernameToken("UN","Pwd", PasswordOption.SendHashed);<br /> svc.RequestSoapContext.Security.Tokens.Add(un);<br /> </code><br />In the above example, replace UN with 'john' and PWD with 'changeme' since this is what airline sample application uses.<br /><br /> 5. Changes in web.config<br /><br />Add <configSections> element under the <configuration> element if it is not already added<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><code><br /><br /><configSections><br /><section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration,<br />Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /><br /></configSections><br /></code><br /></code> Add <webServices> element under <system.web> element if not added<br /><br /><code></code><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><br /><webServices><br /><soapExtensionTypes><br /><add type="Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" /><br /></soapExtensionTypes><br /></webServices><br /><br /></code><br /><span style="font-weight: bold;">References</span><br /><br />1. Spring WS 1.5.5 Reference Document<br />2. Spring WS forum<br />3. Microsoft .NET framework developer center (<a href="http://msdn.microsoft.com/en-us/library/ms977349.aspx">Article 1</a> and <a href="http://msdn.microsoft.com/en-us/library/ms977323.aspx">Article 2</a>)<br /><br /><span style="font-weight: bold;">Conclusion<br /><br /></span>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.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com66tag:blogger.com,1999:blog-3710815942271269136.post-69028479397952166762009-01-23T07:53:00.009-08:002009-02-24T12:59:49.756-08:00Virtualization on Ubuntu 810 server using VMWare Server 2.0, i7 chipset and MSI Eclipse x58<span style="font-weight: bold;">Introduction</span><br /><br />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.<br /><br /><span style="font-weight: bold;">Intel i7 Processor</span><br /><br />Intel has brought back Hyper Threading technology with this latest i7 processor. Some of the core features of i7 processor are given below.<br /><ul><li>2.93 GHz and 2.66 GHz core speed</li><li>8 processing threads with Intel® HT technology</li><li>8 MB of Intel® Smart Cach</li><li>3 Channels of DDR3 1066 MHz memory</li><li>Intel 64 Bit Architecture</li><li>Intel Virtualization technology</li></ul><span style="font-weight: bold;">MSI Eclipse x58</span><br /><br />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.<br /><br />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 <a href="http://content.zdnet.com/2346-12554_22-217925-1.html">here</a> to see MSI Eclipse x58 photo gallery.<br /><br /><span style="font-style: italic;font-size:78%;" >Fig 1. MSI Eclipse x58 Motherboard</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB0Nxs8wQFcq8QHqKjoxudd-Ee_tcluCvwQlRpj9bXlwnVOv6REngE-iEOcRkKitrHEczouCpnYwvGk3OKBH_7strwpXFAefVIRoyWsEfhnF3YA-M8l1OqYm2FtKLXZfSVFIDQjyTokJAx/s1600-h/msi_x58_01_sm.png"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 191px; height: 159px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB0Nxs8wQFcq8QHqKjoxudd-Ee_tcluCvwQlRpj9bXlwnVOv6REngE-iEOcRkKitrHEczouCpnYwvGk3OKBH_7strwpXFAefVIRoyWsEfhnF3YA-M8l1OqYm2FtKLXZfSVFIDQjyTokJAx/s400/msi_x58_01_sm.png" alt="" id="BLOGGER_PHOTO_ID_5306038702028212354" border="0" /></a>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.<br /><br />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.<br /><br /><br /><span style="font-weight: bold;">HardWare Raid<br /></span><p> The hardware-based system manages the RAID subsystem independently from the host and presents to the host only a single disk per RAID array. </p><p> 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. </p><p> RAID controllers also come in the form of cards that <i class="EMPHASIS">act</i> 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.<br /></p><p><span style="font-weight: bold;">Software Raid</span><br /></p><p> 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 <a name="AEN723" href="http://www.redhat.com/docs/manuals/linux/RHL-9-Manual/custom-guide/s1-raid-approaches.html#FTN.AEN723"></a>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. </p><p> 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. </p><br /><span style="font-weight: bold;">Virtualization</span><br /><br />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.<br /><br />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.<br /><br /><span style="font-weight: bold;">Ubuntu 8.10 64 bit Server</span><br /><br />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).<br /><br />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.<br /><br />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.<br /><br />Ubuntu Server Edition JeOS (pronounced "Juice") is an efficient variant of the server operating system, configured specifically for virtual appliances.<br /><br />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.<br /><br />Please click <a href="http://www.ubuntu.com/products/whatisubuntu/serveredition/techspecs/whatsnew">here</a> to read more about Ubuntu 8.10 server features.<br /><br /><span style="font-weight: bold;">VMWare Server 2.0</span><br /><br />I have downloaded VMWare Server 2.0 for 64 bit Linux <span class="highlight">TAR</span> 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.<br /><br /><span style="font-weight: bold;">Instructions to install VMWare server 2.0 on Ubuntu 8.10 64 bit Server</span><br /><br />Step 1. Log on to Ubuntu 8.10 server. Make sure the login id has administrator privileges.<br /><br />Step 2.Install kernel headers which in my case was 2.6.27-7-generic (to do this use synaptic or apt-get )<br />Note : for finding your running kernel version use the command uname -a<br /><code><br />sudo apt-get install linux-headers-`un</code><code>ame -r` build-essential </code><code>xinetd<br /></code><br /><code><code></code></code>Step3. Then go to the location where you saved the VMware Server .tar.gz file, e.g. <span class="system">/home/administrator</span><br /><code><br />cd /home/administrator<br /></code><br />Unpack the VMware Server <span class="system">.tar.gz</span> file and run the installer:<br /><br /><code>tar xvfz VMware-server-*.tar.gz<br />cd vmware-server-distrib<br />sudo ./vmware-install.pl</code><br /><br />The installer will ask you a lot of questions. You can always accept the default values simply by hitting <span class="system"><enter></enter></span>ENTER.<br /><p>When the installer asks you</p> <p class="system">In which directory do you want to keep your virtual machine files?<br />[/var/lib/vmware/Virtual Machines]<br /></p><p>you can either accept the default value or specify a location that has enough free space to store your virtual machines. </p> <p>At the end of the installation, you will be asked to enter a serial number:</p> <p class="system">Please enter your 20-character serial number.</p> <p class="system">Type XXXXX-XXXXX-XXXXX-XXXXX or 'Enter' to cancel:</p> <p>Fill in your serial number for VMware Server.<br /></p><p>After the successful installation, you can delete the VMware Server download file and the installation directory:</p> <p><code>cd /home/administrator<br />rm -f VMware-server*<br />rm -fr vmware-server-distrib/</code></p><span style="font-weight: bold;">NOTE</span>: In between the installations, VMWare Server has to rebuild some of the libraries. However, it will fail to rebuild the vsock library and it is a bug posted in VMWare forum and it will not do any harm to the installation or the way virtual machines work.<br /><br />vsock = VM communication interface socket<br /><br />If you have accepted all default values during the installation, <span class="system">root</span> is now the VMware Server login name. On Ubuntu, <span class="system">root</span> has no password by default, therefore we create a password now:<br /><code><br /><strong style="font-weight: normal;">sudo passwd<br /></strong>Enter new UNIX password:<br />Retype new UNIX password:</code><br /><br />After reset root password. It will show this message in Shell.<br /><br /><code>passwd: password updated successfully</code><br /><p>VMware 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 (<span class="system">https://<ip address="">:8333</ip></span>) or HTTP (<span class="system">http://<ip address="">:8222</ip></span>); the management interface can be accessed locally and also remotely. If you want to access it from the same machine, type <span class="system">https://xx.xx.xx.xx<xx.xx.xx.xx>:8333</xx.xx.xx.xx></span> or <span class="system">http://xx.xx.xx.xx<xx.xx.xx.xx>:8222</xx.xx.xx.xx></span> into the browser's address bar. Replace xx with the actual IP address of the machine.</p><p><span style="font-size:78%;"><span style="font-style: italic;">Fig 2: VMWare Server 2.0 Management Web Interface</span></span></p><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh02OoxBfjGW2UGTC8JoNsstjGBsY-xV7vCnoHIYMOZ5I8cnrcMROehzSk75oSqJv5sgBFIHtCOCexOa-OZYwRIF0BE2jZQU73d7pEh1sXC8LgMA-JycvAN8_3-dlRE1HPJmd-nuS8VlH6j/s1600-h/vmware-server-web.PNG"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 243px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh02OoxBfjGW2UGTC8JoNsstjGBsY-xV7vCnoHIYMOZ5I8cnrcMROehzSk75oSqJv5sgBFIHtCOCexOa-OZYwRIF0BE2jZQU73d7pEh1sXC8LgMA-JycvAN8_3-dlRE1HPJmd-nuS8VlH6j/s400/vmware-server-web.PNG" alt="" id="BLOGGER_PHOTO_ID_5306183093932211458" border="0" /></a></p> 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 <span class="system">Or you can add an exception.</span><br /><br />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.<br /><br /><br /><br /><br /><br /><br /><br /><span style="font-size:78%;"><span style="font-style: italic;">Fig 3. Virtual Machine Infrastructure Client Login</span></span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPBeddvS-FK1z8xwGspVa3Ru5NN5MtU2EmR3QYWbNxbe0Oy7nk7Iht8Jl6vxqpydm77iVXvfCELkoTugbDvCgccEx8QVvlAPUPhpzDU70B2oscoqW6Xf6AJxZ9T05sCD_96fNMbZyGG93P/s1600-h/vm-infrastructure-client.PNG"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 288px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPBeddvS-FK1z8xwGspVa3Ru5NN5MtU2EmR3QYWbNxbe0Oy7nk7Iht8Jl6vxqpydm77iVXvfCELkoTugbDvCgccEx8QVvlAPUPhpzDU70B2oscoqW6Xf6AJxZ9T05sCD_96fNMbZyGG93P/s400/vm-infrastructure-client.PNG" alt="" id="BLOGGER_PHOTO_ID_5306061810294096450" border="0" /></a><br /><img src="file:///C:/DOCUME%7E1/vbose/LOCALS%7E1/Temp/moz-screenshot-1.jpg" alt="" /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><span style="font-size:78%;"><span style="font-style: italic;">Fig 4: Virtual Machine Infrastructure Client Management Interface</span></span><br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhba0A-1B5lHb-6s_n4Yi0u4ObAQBthp9WAT0s971-c_PVigb_JtThvWTARrLQtPq7XdvN_Q3MzuuzFqFH9wO47NcPBSD5NYSppUzg3pxAaXmMu1FIGwJv3ujkOLU8mKuD12YYq4c-3hKKS/s1600-h/vmware-server-ic.PNG"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 243px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhba0A-1B5lHb-6s_n4Yi0u4ObAQBthp9WAT0s971-c_PVigb_JtThvWTARrLQtPq7XdvN_Q3MzuuzFqFH9wO47NcPBSD5NYSppUzg3pxAaXmMu1FIGwJv3ujkOLU8mKuD12YYq4c-3hKKS/s400/vmware-server-ic.PNG" alt="" id="BLOGGER_PHOTO_ID_5306185267824470162" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><span style="font-weight: bold;">References</span><br /><br />1. VMWare - <a href="http://www.vmware.com/products/server/"><span style="font-style: italic;">http://www.vmware.com/products/server/</span></a><br />2. Ubuntu Web Site - <a style="font-style: italic;" href="https://help.ubuntu.com/8.10/serverguide/C/index.html">https://help.ubuntu.com/8.10/serverguide/C/index.html</a><br />3. Ubuntu Installation Guide - <a href="https://help.ubuntu.com/8.10/installation-guide/amd64/index.html"><span style="font-style: italic;">https://help.ubuntu.com/8.10/installation-guide/amd64/index.html </span></a><br />4. Ubuntu Forums - <a href="http://ubuntuforums.org/">http://ubuntuforums.org/</a><br /><br /><span style="font-weight: bold;">Conclusion</span><br /><br />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 <a href="http://www.vmware.com/technology/virtual-infrastructure-apps/">application environments</a>, as well as <a href="http://www.vmware.com/technology/virtual-networking/">networking</a> and <a href="http://www.vmware.com/technology/virtual-storage/">storage</a> infrastructure.<br /><span style="font-weight: bold;"></span>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com50tag:blogger.com,1999:blog-3710815942271269136.post-15429992101945061012008-12-31T06:32:00.025-08:002008-12-31T08:54:18.409-08:00DB2 9 JDBC configuration with IBM Webspehere 6.1<span style="font-weight: bold;font-family:arial;font-size:100%;" >Configuring a JDBC Provider</span><br /><br />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: *<a href="http://localhost:9060/ibm/console*" rel="nofollow">http://localhost:9060/ibm/console*</a> 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. <p>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.</p> <p>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.<br /></p><span style="font-weight: bold;"><span style="font-size:85%;">Figure 1</span></span>. Creating a new JDBC Provider<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja7PT3-PguLN-Qp-GbySO7nHZtITw9WzGuUDCNucdhbpX27uEryOq-L-XCwDjf3Rsy9tdCSltWAYLkSd-W1JSupvdXoj4NJ17kWwc1nNR0x-3HbLYbFO56xVuxInF4Jp7jZMjW96BGXcpW/s1600-h/create-jdbc-provider.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 289px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja7PT3-PguLN-Qp-GbySO7nHZtITw9WzGuUDCNucdhbpX27uEryOq-L-XCwDjf3Rsy9tdCSltWAYLkSd-W1JSupvdXoj4NJ17kWwc1nNR0x-3HbLYbFO56xVuxInF4Jp7jZMjW96BGXcpW/s400/create-jdbc-provider.jpg" alt="" id="BLOGGER_PHOTO_ID_5285963733149514738" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p>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.</p> <p>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.</p> <p>The driver class name is <em>com.ibm.db2.jcc.DB2ConnectionPoolDataSource</em>. 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).</p><p><span style="font-size:100%;"><span style="font-weight: bold;font-family:arial;" >DB2 Connection Pooling DataSource</span><br /></span></p><span style="font-size:85%;"><b><em>DB2ConnectionPoolDataSou</em></b></span><span style="font-size:85%;"><b><em>rce.class</em></b></span><br /><br /><p>The <tt><em>com.ibm.db2.jcc.DB2ConnectionPoolDataSource</em></tt> class extends the <tt><em>com.ibm.db2.jcc.DB2BaseDataSource</em></tt> class, and implements the <tt><em>javax.sql.ConnectionPoolD</em></tt><tt><em>ataSource</em></tt>, <tt><em>java.io.Serializable</em></tt>, and <tt><em>javax.naming.Referenceable</em></tt> interfaces.</p> <p><tt>DB2ConnectionPoolDataSource</tt> is a factory for <tt>PooledConnection</tt> objects. An object that implements this interface is registered with a naming service that is based on the Java Naming and Directory Interface (JNDI).</p> <p>The connection pooling properties are defined only for the IBM DB2 Driver for JDBC and SQLJ. Click <a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp?topic=/com.ibm.db2.udb.apdv.java.doc/doc/rjvdsprp.htm" title="DB2 JDBC connection pool properties" rel="nofollow">here</a> for explanations of these properties. The following are the list of different DB2 implementation of data sources. </p> <ul><li><b>com.ibm.db2.jc</b> <b>c.DB</b><b>2SimpleDataSource</b>, which does not support connection pooling. You can use the implementation with the Universal Type 2 driver or the Type 4 driver.</li><li><b>com.ibm.db2.jcc.DB2DataSource</b>, 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.</li><li><b>com.ibm.db2.jc</b> <b>c.D</b><b>B2ConnectionPoolDataSource</b>, 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.</li><li><b>com.ibm.db2.jcc.DB2XADataSource</b>--same as DB2ConnectionPoolDataSource, but supports distributed transactions</li></ul><span style="font-size:85%;"><span style="font-weight: bold;">Figure 2</span></span>. Specifying a new JDBC Provider<br /><h3><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaFumMBomvhftdsv5QCYXyZOewMR0Pj7s4Dq4nP-fycWF7S3IN75Qiw_ODKiMUvHA7hHZd5gO9S12OJI9DsgUYgQOIueAqbFg6WPgaqGQsTYko11EMtAEiKt8RyyP_DXQtRGwOks3EY4jN/s1600-h/create-datasource.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 289px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaFumMBomvhftdsv5QCYXyZOewMR0Pj7s4Dq4nP-fycWF7S3IN75Qiw_ODKiMUvHA7hHZd5gO9S12OJI9DsgUYgQOIueAqbFg6WPgaqGQsTYko11EMtAEiKt8RyyP_DXQtRGwOks3EY4jN/s400/create-datasource.jpg" alt="" id="BLOGGER_PHOTO_ID_5285968196135364130" border="0" /></a></h3><br /><br /><br /><br /><br /><br /><span style="font-weight: bold;"><span style="font-size:85%;"><br /></span></span><br /><br /><br /><br /><br /><br /><br /><br /><span style="font-weight: bold;"><br /><br /><br /></span><span style="font-weight: bold;font-family:arial;font-size:100%;" ><br /><br />Configuring a J2C authentication data entry</span><br /><p>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.</p> 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.<br /><br /><span style="font-size:100%;"><span style="font-weight: bold;font-family:arial;" >Configuring a data source</span><br /><br /></span>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.<br /><br /><span style="font-size:85%;"><b>Figure 3</b>.</span> Specifying datasource JNDI names.<br /><h3><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbNcnTfTrwu_VvG_CXz2sjW9YFHn9KAcLvouo4vtcSIhR7ehy7ZiZanraEQ6-IcigNklnr-7UM27txpW3l8Yq7bqomsGHYlN3FqDPiVAVzGfSdZ6PDJEatsIWX2Ynw34s5uYA_p1TbpLln/s1600-h/new-jdbc-driver.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 289px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbNcnTfTrwu_VvG_CXz2sjW9YFHn9KAcLvouo4vtcSIhR7ehy7ZiZanraEQ6-IcigNklnr-7UM27txpW3l8Yq7bqomsGHYlN3FqDPiVAVzGfSdZ6PDJEatsIWX2Ynw34s5uYA_p1TbpLln/s400/new-jdbc-driver.jpg" alt="" id="BLOGGER_PHOTO_ID_5285966732995030002" border="0" /></a></h3><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p>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 <b>jdbc/SampleDS</b></p> <p>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.</p> 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.<br /><br /><span style="font-size:100%;"><span style="font-weight: bold;font-family:arial;" >Access Managed DB2 Connection via JNDI from the application code</span><br /><br /></span>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. <p>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.</p> <p>Let us now design the business service API named LookUpServiceImpl.java which implements the interface ILookUpService.java</p><br /><span style="font-style: italic;">ILookUpService.java</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br />/**<br />* Created on : Dec 31, 2008<br />* File : ILookUpService.java<br />* $ Revision : $<br />* Copyright © Vigil Bose<br />* All Rights Reserved<br />* This is unpublished proprietary source code.<br />* The copyright notice above does not evidence any actual or<br />* intended publication of such source code.<br />*/<br />package com.vbose.bus;<br /><br />import java.util.Set;<br /><br />import com.vbose.domain.EventActions;<br /><br />/**<br />* ILookUpService.java : A java business service interface<br />* that exposes the APIs used by user interface layer to access<br />* the read only business data<br />* @author Vigil Bose<br />*/<br />public interface ILookUpService {<br /><br />/**<br />* The API findEventActionsByActionId() is used to find the EventActions domain object<br />* for the given actionId<br />* @param actionId - The event action identifier<br />* @return an instance of EventActions domain object<br />*/<br />public EventActions findEventActionsByActionId(Integer actionId);<br />}<br /><br /></code><br /><br /><span style="font-style: italic;">LookUpServiceImpl.java</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br />/**<br />* Created on : Dec 31, 2008<br />* File : LookUpServiceImpl.java<br />* $ Revision : $<br />* Copyright © Vigil Bose<br />* All Rights Reserved<br />* This is unpublished proprietary source code.<br />* The copyright notice above does not evidence any actual or<br />* intended publication of such source code.<br />*/<br />package com.vbose.bus.impl;<br /><br />import java.util.Set;<br /><br />import org.springframework.transaction.annotation.Transactional;<br />import org.springframework.stereotype.service;<br /><br />import com.vbose.bus.ILookUpService;<br />import com.vbose.domain.EventActions;<br /><br />/**<br />* LookUpServiceImpl.java : A java business service implementation<br />* that implements the APIs used by user interface layer to access<br />* read only data.<br />* @author Vigil Bose<br />*/<br />@Service("lookupService")<br />public class LookUpServiceImpl<br /> implements ILookUpService{<br /><br /> private ILookUpServiceIBatisDao lookUpServiceIBatisDao;<br /><br /> /**<br /> * A setter method of dependency injection<br /> * @param lookUpServiceIBatisDao the lookUpServiceIBatisDao to set<br /> */<br /> public void setLookUpServiceIBatisDao(<br /> ILookUpServiceIBatisDao lookUpServiceIBatisDao) {<br /> this.lookUpServiceIBatisDao = lookUpServiceIBatisDao;<br /> }<br /><br /> /**<br /> * The API findEventActionsByActionId() is used to find the EventActions domain object<br /> * for the given actionId<br /> * @param actionId - The event action identifier<br /> * @return an instance of EventActions domain object<br /> */<br /> @Transactional (readOnly = true)<br /> public EventActions findEventActionsByActionId(Integer actionId) {<br /> return this.lookUpServiceIBatisDao().<br /> findEventActionsByActionId(actionId);<br /> }<br />}<br /><br /></code><p>The business service implementation API has @Transactional annotation which is used by the Spring framework to initiate a read only transaction to the database. </p> <p>The <em><tx:jta-transaction-manager></tx:jta-transaction-manager></em> configuration element declared in spring application context (See Spring application context) will automatically detect the underlying server and choose the best transaction manager available for the platform. This means that you won't have to configure server-specific adapter classes (as discussed in the following sections) explicitly; they will rather be chosen automatically, with the standard JtaTransactionManager as default fallback.</p> <p>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!</p> <p>The business service API <em>findEventActionsByActionId() shown above</em> 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.</p><span style="font-style: italic;">ILookUpServiceIBatisDao.java</span> (Data access repository interface)<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br />/**<br />* Created on : Dec 31, 2008<br />* File : ILookUpServiceDao.java<br />* $ Revision : $<br />* Copyright © Vigil Bose<br />* All Rights Reserved<br />* This is unpublished proprietary source code.<br />* The copyright notice above does not evidence any actual or<br />* intended publication of such source code.<br />*/<br />package com.vbose.bus.dao;<br /><br />import java.util.Set;<br />import org.springframework.dao.DataAccessException;<br />import com.vbose.domain.EventActions;<br /><br /><br />/**<br />* ILookUpServiceDao.java : Data Access Interface that exposes<br />* read only APIs that facilitate the business service to get<br />* access to the data<br />* @author Vigil Bose<br />*/<br />public interface ILookUpServiceIBatisDao {<br /><br />/**<br />* The API findEventActionsByActionId() is used to find the EventActions domain object<br />* for the given actionId<br />* @param actionId - The event action identifier<br />* @return an instance of EventActions domain object<br />* @throws DataAccessException<br />*/<br />public EventActions findEventActionsByActionId(Integer actionId) throws DataAccessException;<br />}<br /><br /></code><br /><span style="font-style: italic;">LookUpServiceIBatisDaoImpl.java</span> (Data access repository implementation)<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br />/**<br />* Created on : Dec 31, 2008<br />* File : LookUpServiceIBatisDaoImpl.java<br />* $ Revision : $<br />* Copyright © Vigil Bose<br />* All Rights Reserved<br />* This is unpublished proprietary source code.<br />* The copyright notice above does not evidence any actual or<br />* intended publication of such source code.<br />*/<br />package com.vbose.bus.dao.impl;<br /><br />import java.util.HashSet;<br />import java.util.Iterator;<br />import java.util.List;<br />import java.util.Set;<br /><br />import org.springframework.dao.DataAccessException;<br />import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;<br />import com.vbose.bus.dao.ILookUpServiceIBatisDao;<br />import com.vbose.domain.EventActions;<br /><br />/**<br />* LookUpServiceIBatisDaoImpl : A data access strategy implementation<br />* based on iBatis Data Mapper framework that implements the APIs of<br />* {@link ILookUpServiceIBatisDao}<br />* @author Vigil Bose<br />*/<br />public class LookUpServiceIBatisDaoImpl<br /> extends SqlMapClientDaoSupport<br /> implements ILookUpServiceIBatisDao {<br /><br />/**<br />* The API findEventActionsByActionId() is used to find the EventActions domain object<br />* for the given actionId<br />* @param actionId - The event action identifier<br />* @return an instance of EventActions domain object<br />* @throws DataAccessException<br />*/<br />public EventActions findEventActionsByActionId(Integer actionId)<br /> throws DataAccessException {<br /> return (EventActions)getSqlMapClientTemplate().<br /> queryForObject("findEventActionsByActionId",actionId);<br />}<br />}<br /><br /></code>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.<br /><br /><span style="font-style: italic;">sql-map-config.xml</span>l (iBatis SQL mapper infrastructure configuration)<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><br /><?xml version="1.0" encoding="UTF-8"?><br /><!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"<br />"http://www.ibatis.com/dtd/sql-map-config-2.dtd"><br /><br /><sqlMapConfig><br /> <settings lazyLoadingEnabled="true" enhancementEnabled="true"/><br /> <sqlMap resource="com/vbose/domain/ibatis/maps/EventActions.xml"/><br /></sqlMapConfig><br /><br /></code><br /><br /><span style="font-style: italic;">EventActions.xml</span> (Data mapper for EventActions.java)<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><br /><?xml version="1.0" encoding="UTF-8"?><br /><!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd"><br /><br /><sqlMap namespace="EventActions"><br /><br /><resultMap id="eventActionsResult" class="com.vbose.domain.EventActions"><br /> <result column="ACTION_ID" property="actionId" jdbcType="INTEGER" /><br /> <result column="ACTION_DESC" property="actionDesc" jdbcType="VARCHAR" /><br /> <result column="SUSP_ID" property="suspensionId" jdbcType="INTEGER" /><br /></resultMap><br /><br /><select id="findEventActionsByActionId" resultMap="eventActionsResult"><br /> SELECT ea.ACTION_ID,<br /> ea.ACTION_DESC,<br /> ea.SUSP_ID<br /> FROM SS_EVENT_ACTIONS ea<br /> WHERE ea.ACTION_ID = #value#<br /> WITH UR<br /></select><br /><br /></sqlMap><br /><br /></code><br /><br /><span style="font-style: italic;">EventActions.java</span> (Domain Object)<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><br />/**<br />* Created on : Dec 31, 2008<br />* File : EventActions.java<br />* $ Revision : $<br />* Copyright © Vigil Bose<br />* All Rights Reserved<br />* This is unpublished proprietary source code.<br />* The copyright notice above does not evidence any actual or<br />* intended publication of such source code.<br />*/<br />package com.vbose.domain;<br /><br />import java.io.Serializable;<br /><br />/**<br />* EventActions.java : A class that represents a row in<br />* the 'EVENT_ACTIONS' table.<br />* @author Vigil Bose<br />*/<br />public class EventActions implements Serializable {<br /><br /> private static final long serialVersionUID = 1L;<br /> /** The cached hash code value for this instance. Settting to 0 triggers re-calculation. */<br /> private int hashValue = 0;<br /><br /> private Integer actionId;<br /> private String actionDesc;<br /> private Integer suspensionId;<br /><br />/**<br /> * Simple constructor of EventActions instances.<br /> */<br /> public EventActions() {<br /><br /> }<br /> /**<br /> * Constructor of EventActions instances given a simple primary key.<br /> * @param eventId<br /> */<br /> public EventActions(Integer actionId) {<br /> this.actionId = actionId;<br /> }<br /> /**<br /> * @return the actionId<br /> */<br /> public Integer getActionId() {<br /> return actionId;<br /> }<br /> /**<br /> * @param actionId the actionId to set<br /> */<br /> public void setActionId(Integer actionId) {<br /> this.hashValue = 0;<br /> this.actionId = actionId;<br /> }<br /> /**<br /> * @return the actionDesc<br /> */<br /> public String getActionDesc() {<br /> return actionDesc;<br /> }<br /> /**<br /> * @param actionDesc the actionDesc to set<br /> */<br /> public void setActionDesc(String actionDesc) {<br /> this.actionDesc = actionDesc;<br /> }<br /> /**<br /> * @return the suspensionId<br /> */<br /> public Integer getSuspensionId() {<br /> return suspensionId;<br /> }<br /> /**<br /> * @param suspensionId the suspensionId to set<br /> */<br /> public void setSuspensionId(Integer suspensionId) {<br /> this.suspensionId = suspensionId;<br /> }<br /><br /> /**<br /> * Implementation of the equals comparison on the basis of equality of the primary key values.<br /> * @param rhs<br /> * @return boolean<br /> */<br /> public boolean equals(Object rhs){<br /> if (rhs == null){<br /> return false;<br /> }<br /> if (! (rhs instanceof EventActions)){<br /> return false;<br /> }<br /> EventActions that = (EventActions) rhs;<br /> if (this.getActionId() == null || that.getActionId() == null){<br /> return false;<br /> }<br /> return (this.getActionId().equals(that.getActionId()));<br /> }<br /><br /> /**<br /> * Implementation of the hashCode method conforming to the Bloch pattern with<br /> * the exception of array properties (these are very unlikely primary key types).<br /> * @return int<br /> */<br /> public int hashCode() {<br /> if (this.hashValue == 0) {<br /> int result = 17;<br /> int actionIdValue = this.getActionId() == null ? 0 :<br /> this.getActionId().hashCode();<br /> result = result * 37 + actionIdValue;<br /> this.hashValue = result;<br /> }<br /> return this.hashValue;<br /> }<br />}<br /><br /><br /></code><br />Now, wire the JDBC infrastructure and the data access object in the Spring application context. See below.<br /><br /><span style="font-style: italic;">Spring Application Context</span><br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><br /><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans"<br />xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns:jee="http://www.springframework.org/schema/jee"<br />xmlns:tx="http://www.springframework.org/schema/tx"<br />xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"<br />xsi:schemaLocation="<br />http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br />http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd<br />http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd<br />http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"><br /><br /><jee:jndi-lookup id="sampleDS" jndi-name="jdbc/SampleDS" proxyInterface="javax.sql.DataSource" resourceRef="true"/><br /><br /><context:annotation-config><br /><br /><tx:annotation-driven order="2"/><br /><br /><!--JTA appserver managed distributed transaction manager reference--><br /><tx:jta-transaction-manager /><br /><br /><!-- SqlMap setup for iBATIS Database Layer --><br /><bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"><br /> <property name="configLocation" value="classpath:/com/vbose/domain/ibatis/maps/sql-map-config.xml"/><br /> <property name="dataSource" ref="sampleDS"/><br /></bean><br /><br /><bean id="lookUpServiceIBatisDao" class="com.vbose.bus.dao.impl.LookUpServiceIBatisDaoImpl"><br /> <property name="sqlMapClient" ref="sqlMapClient"/><br /></bean><br /><br /><br /></beans><br /><br /></code><br /><span style="font-weight: bold;font-size:100%;" >RAR Deployment</span><br /><p>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.<br /></p> <p>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.</p><p><span style="font-weight: bold;">Access DB2 Connection locally using Apache DBCP</span><span style="font-size:100%;"><br /></span></p>Now, I will show how the application code can access DB2 connection locally using Apache DBCP connection pool mechanism. The application code remains unchanged and all I have to do is use a local connection in the Spring application context instead of JNDI connection and JTA transaction manager. This set up is handy when the application is not running under IBM Websphere or any appserver environment.<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><br /><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans"<br />xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns:jee="http://www.springframework.org/schema/jee"<br />xmlns:tx="http://www.springframework.org/schema/tx"<br />xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"<br />xsi:schemaLocation="<br />http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br />http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd<br />http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd<br />http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"><br /><br /><!-- Transaction manager for a single JDBC DataSource (alternative to JTA) --><br /><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"<br />p:dataSource-ref="sampleDS"/><br /><br /><bean id="sampleDS" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"<br /> p:driverClassName="com.ibm.db2.jcc.DB2Driver"<br /> p:url="jdbc:db2://os19.in.vbose.com:4763/DSNQ:currentFunctionPath=SAMPLE;IGNORE_DONE_IN_PROC=true;currentSchema=SAMPLE;"<br /> p:username="xxxxxx"<br /> p:password="xxxxxxx"<br /> p:maxActive="3"<br /> p:maxIdle="3"<br /> p:validationQuery="SELECT DTS FROM DT_TM_TS WITH UR"<br /> p:testWhileIdle="true"<br /> p:timeBetweenEvictionRunsMillis="1800000"<br />/><br /><br /><br /><context:annotation-config><br /><br /><tx:annotation-driven order="2"/><br /><br /><br /><!-- SqlMap setup for iBATIS Database Layer --><br /><bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"><br /> <property name="configLocation" value="classpath:/com/vbose/domain/ibatis/maps/sql-map-config.xml"/><br /> <property name="dataSource" ref="sampleDS"/><br /></bean><br /><br /><bean id="lookUpServiceIBatisDao" class="com.vbose.bus.dao.impl.LookUpServiceIBatisDaoImpl"><br /> <property name="sqlMapClient" ref="sqlMapClient"/><br /></bean><br /><br /><br /></beans><br /><br /><br /></code><br />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.<br /><br /><p style="font-weight: bold;"><span style="font-size:100%;">References</span></p><ol><li>Spring Framework 2.5.6 Reference Document</li><li>IBM Websphere RedBooks</li><li>iBatis 2.3.4 Reference Document<br /></li></ol><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);"><span><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;font-size:100%;" >About The Author</span><span style="font-weight: bold;"><br /><br />Vigil Bose </span>works as Principal System Architect (Java/J2EE) at OCTO, </span></span></span></span></span><span style=";font-family:Arial,Helvetica,Geneva;font-size:85%;" > </span><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);"><span><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);">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.</span></span></span></span></span>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com15tag:blogger.com,1999:blog-3710815942271269136.post-38724779365623384972008-08-19T07:48:00.017-07:002008-08-19T11:57:47.496-07:00Integrating DWR 2.0.5 with Spring 2.5.5 and web flow 2.0.3<span style="font-weight: bold;">Overview<br /></span>DWR is an open source Remote Procedure Call (RPC) library that makes it easy to call Java functions from JavaScript and to call JavaScript functions from Java via Reverse Ajax functionality that is introduced in DWR 2.0 version. This article is limited to explaining as to how to configure DWR 2.0.5 using XML namespace support available in Spring 2.0 version and above.<br /><br /><span style="font-weight: bold;">Detailed Steps<br /></span><ul><li>Step 1 - Add dwr to web.xml file</li></ul><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><?xml version="1.0" encoding="UTF-8"?><br /><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"<br />xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"<br />id="WebApp_ID" version="2.5"><br /><br />......<br /><br /><!-- DWR 2.0.5 Integration --><br /><servlet><br /><servlet-name>dwr-invoker</servlet-name><br /><servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class><br /><br /><!-- Turn debug to false in production--><br /><init-param><br /><param-name>debug</param-name><br /><param-value>false</param-value><br /></init-param><br /><br /><load-on-startup>2</load-on-startup><br /></servlet><br /><servlet-mapping><br /><servlet-name>dwr-invoker</servlet-name><br /><url-pattern>/dwr/*</url-pattern><br /></servlet-mapping><br /><br /></web-app><br /><br /></code><ul><li>Step 2 - Add the dwr namespace and schema to your spring configuration file. The namespace is xmlns:dwr=”http://www.directwebremoting.org/schema/spring-dwr” The schemaLocation is http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd. Also map engine.js, util.js, call, dwr and interface request URIS to dwrcontroller (see example below)<br /></li></ul>Example: Sample Spring MVC configuraton (webmvc-config.xml)<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;"><br /><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans"<br />xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"<br />xsi:schemaLocation=" http://www.springframework.org/schema/beans<br /> http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br /> http://www.directwebremoting.org/schema/spring-dwr<br /> http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd"><br /><br /><!-- Maps request URIs to controllers --><br /><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><br /><property name="mappings"><br /> <value><br /> /engine.js=dwrController<br /> /util.js=dwrController<br /> /call/**=dwrController<br /> /dwr/**"=dwrController<br /> /interface/**=dwrController<br /> </value><br /></property><br /><property name="defaultHandler"><br /> <!-- Selects view names to render based on the request URI: e.g. /main selects "main" --><br /> <bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" /><br /></property><br /><property name="order" value="0"/><br /></bean><br /><br />.....<br /><br /><!-- Enable DWR AJAX functionality --><br /><dwr:configuration><br /><dwr:create javascript="TestData" type="spring" class="com.web.ajax.TestData"/><br /><dwr:convert type="bean" class="com.data.ClassLoadingData" /><br /></dwr:configuration><br /><br /><dwr:controller id="dwrController" debug="true" /><br /><br /><!-- configure spring creators --><br /><bean id="testData" class="com.web.ajax.TestData"><br /><dwr:remote javascript="TestData"><br /> <dwr:include method="refreshClassLoadingData" /><br /></dwr:remote><br /><property name="jvmDataManager" ref="jvmDataManager"/><br /></bean><br /><br /><bean id="jvmDataManager" class="com.web.jvm.impl.JvmDataManagerImpl/><br /><br /></code><br /><br /><ul><li>Step 3 Configure Spring creators - In the above configuration, we expose it directly as spring beans (e.g. testData ).<br /><p>The dwr:remote element is the element that will expose the bean to dwr. This is the best approach as it allows you to wire your dependencies like any other spring object.</p> Secondly you can configure them in a dwr:configuration much in the same as the standard dwr.xml file works.</li></ul><br /><ul><li>Step 4 Configure Spring converters - The spring converters must be configured inside of a dwr:configuration element in spring. Please refer the configuration above.</li></ul><br /><ul><li> Other important elements to know:</li></ul><ol><li> dwr:include : Used to include specific methods. Can be used with dwr:convert, dwr:create, or dwr:remote element</li><li> dwr:exclude : Used to exclude specific methods. Can be used with dwr:convert, dwr:create, or dwr:remote element</li><li> dwr:init : Optional element that will allow you to specify custom creator types and converter types.</li><li> dwr:converter : Specifies a custom converter type, must be used within dwr:init.</li><li> dwr:create : Specifies a custom creator type, must be used within a dwr:init.</li><li> dwr:signature : Used to specify signatures much like the element in the standard dwr.xml.</li></ol><br />NOTE: Please make sure you source TestData.js in the page as in the example below.<br /><br /><script language='JavaScript' type='text/javascript' src='<root-context><root-context>/dwr/interface/TestData.js'/><br /><br />Replace <root-context> with your app's root context.<br /><br />Example: AJAX Javascript function refreshClassLoadingData()<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;">function refreshClassLoadingData(){<br />TestData.refreshClassLoadingData(function(data){<br /> if (data != null){<br /> DWRUtil.setValue('currentLoadedClasses', data.loadedClassCount);<br /> }<br /> });<br />}<br />//Please note the "data" represent the ClassLoadingData returned from AJAX function. So<br />//it is possible to access the variables of ClassLoadingData object in Javascript since<br />//it is converted as a bean in Javascript.<br /></code><br />Example: TestData.java<br /><br /><code style="border-style: solid; border-color: rgb(238, 238, 238) rgb(238, 238, 238) rgb(238, 238, 238) rgb(204, 204, 204); border-width: 1px 1px 1px 6px; padding: 8px 10px; background: rgb(255, 255, 255) none repeat scroll 0% 50%; width: 900px; line-height: 1.6em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(102, 102, 102); white-space: pre; margin-bottom: 12px; display: block;">public class TestData{<br />@Autowired<br />@Qualifier("jvmDataManager")<br />private IjvmDataManager jvmDataManager;<br /><br />/**<br /> * This is the AJAX function that can be called from UI via DWR AJAX<br /> */<br /> public ClassLoadingData refreshClassLoadingData(){<br /> return this.jvmDataManager.getClassLoadingData();<br /> }<br />}<br /><br /></code><span style="font-weight: bold;"><br />Conclusion<br /></span>The DWR namespace support in spring configuration eliminates the need of having dwr.xml file placed inside WEB-INF folder. The sample configuration shown above is sufficient enough to get the DWR working with Spring 2.5.5 and spring webflow 2.0.3. Please note the TestData, ClassLoadingData shown above are all plain old java objects.<br /><br />More Information on DWR is available <a href="http://directwebremoting.org/dwr/overview/dwr">here.</a></root-context>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com15tag:blogger.com,1999:blog-3710815942271269136.post-23980299039713893322008-07-22T13:38:00.003-07:002008-07-22T14:00:39.799-07:00Eclipse 3.4, Trac 0.11 and MylynI have been working on setting up the configuration management environment at work place. I chose BUILDIX 2.1 from Thoughworks as the tool of our choice since it comes free of cost. The buildix distribution comes with Trac 0.10, CruiseControl , Subversion and Mingle integration bundled with Ubuntu Linux VMWARE image.<br /><br />However the issue tracker Trac 0.10 that comes with Buildix 2.1 does not support the advanced ticket work flows. So I decided to upgrade it to 0.11. The upgrade went very well. Meantime, I upgraded our eclipse environment to 3.4 as the IDE of our choice. The Mylyn task based UI plugin of eclipse works so great and the eclipse 3.4 version of Mylyn comes with JIRA, BugZilla and Trac connectors. However, by default Mylyn only supports Trac 0.9.2 Trac 0.10.x versions.<br /><br />So basically we lost connectivity from Eclipse to our issue tracker with the upgrade. Then this <a href="http://nil.checksite.co.uk/post.cfm/trac-0-11-and-mylyn"> </a>article about <a href="http://nil.checksite.co.uk/post.cfm/trac-0-11-and-mylyn">Trac 0.11 and Mylyn</a> becomes handy that provide simple instructions to make Eclipse 3.4 Mylyn talk to Trac 0.11.<br /><br />I had to install TracXMLRPC 1.0.0 plugin from the Trac SVN repository and enable the plugin via Trac web admin module. I then re-started the apache web server as per the instructions given at the article I mentioned above The eclipse 3.4 Mylyn can now talk to Trac 0.11 issue tracker and I can see all the tickets.<br /><br />Hope this blog helps other users who encountered issues in integrating Eclipse 3.4, Mylyn and Trac 0.11.<br /><h3 style="cursor: pointer;"><a href="https://10.128.103.44/trac/jscheduler/admin/general/plugin#no8"><br /></a></h3> <input name="plugin_filename" value="TracXMLRPC-1.0.0-py2.5.egg" type="hidden"><span style="font-weight: bold;"></span>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com4tag:blogger.com,1999:blog-3710815942271269136.post-19536928468801659572008-06-16T10:42:00.005-07:002008-06-16T12:59:28.759-07:00Integrating Spring Security with JSF/Facelets using acegi-jsf<span style="font-weight: bold;">Abstract<br /><br /></span>Spring Security is the security framework which is a part of Spring framework technology stack. It is a mature, powerful and flexible security solution for enterprise applications. Earlier, it was widely known as Acegi Security and now it is called Spring Security. Recently I have been working on a product of mine and I currently use JSF/Facelets and Spring Webflow /Spring Security and JPA technologies to build the product. Spring webflow out of the box integrates with Spring Security and provides access to implicit expression language ( EL) variable called currentUser to get access to the authenticated principal name. I wanted more than this in other pages that are not part of Spring webflow related.<br /><br /><span style="font-weight: bold;">Authentication Tag Libraries<br /><br /></span>Spring Security out of the box provides the following tag support to get the authenticated principal in JSP fragments.<br /><br /><pre><br /> <security:authentication property="principal.username"/><br /></pre><br />However, Spring Security does not provide any support of using similar tags in JSF/Facelets view technology. I did some research and found the following <a href="http://cagataycivici.wordpress.com/2006/01/19/acegi_jsf_components_hit_the/">weblog</a><br /><br />My big thanks to Çağatay Çivici who showed us a way to use "acegijsf" tag in JSF/Facelets. However, the website need some more fine grained details as to how to wire everything together to make use of his library. So it is my humble attempt at explaining as to how to use his library in a less invasive way. I hope this will help any novice JSF/Facelets developer to make use of tag support in JSF/Facelets view technology.<br /><br /><span style="font-weight: bold;">Detailed Steps<br /><br /></span><ul><li>Download <a href="http://jexcellente.googlepages.com/acegi-jsf-1.1.3.jar">acegi-jsf-1.1.3.jar<br /></a></li></ul>NOTE: The above said jar is customized to use Spring Security 2.0.2 instead of Acegi Security. I also added acegijsf.taglib.xml inside META-INF folder of the jar. The one you download from <a href="http://sourceforge.net/project/showfiles.php?group_id=137466">Sourceforge.net</a> does not have any of these customizations.<br /><br /><ul><li>Place the above said jar in WEB-INF/lib of your JSF/Facelets web application.</li><li>Please add the following xml fragments into your faces-config.xml located under WEB-INF of your web application.</li></ul> <pre><br /><component><br /> <component-type>net.sf.jsfcomp.acegijsf.Authorize</component-type><br /> <component-class>net.sf.jsfcomp.acegijsf.Authorize</component-class><br /></component> <br /><component><br /> <component-type>net.sf.jsfcomp.acegijsf.Authentication</component-type><br /> <component-class>net.sf.jsfcomp.acegijsf.Authentication</component-class><br /></component><br /></pre>Now, you have to add the following namespace to your facelet .XHTML<br /><ul><li> e.g. xmlns:acegijsf="http://sourceforge.net/projects/jsf-comp/acegijsf"</li><li>Thats it. Now you can utilize the following tags inside your XHTML.</li></ul><pre> <acegijsf:authorize ifAllGranted="ROLE_ADMIN"><br /> <span style="color: rgb(51, 51, 255);"> Add the components that are only visible to the users that satisfy the requirements here.</span><br /></acegijsf:authorize><br /></pre>The attribute names are same both in jsp tag and the jsf component. You just give a role list seperated with a comma(Whitespaces omitted). All of these attributes can be bound to a value using EL. <p><span style="color: rgb(51, 51, 255);">ifAllGranted </span>= User must be in all of the roles<br /><span style="color: rgb(51, 51, 255);">ifAnyGranted</span> = User must be in any of the roles<br /><span style="color: rgb(51, 51, 255);">ifNotGranted</span> = None of the roles must be granted for the user<span style="font-weight: bold;"></span></p> This component does not render the secured children components if the user does not satisfy the granting requirements given with the attributes.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com57tag:blogger.com,1999:blog-3710815942271269136.post-73714936413489125382008-05-02T09:43:00.006-07:002008-08-01T14:40:33.966-07:00Install jManage Application Management Platform as a service<span style="font-weight: bold;">Overview<br /><br /></span> jManage 2.0 is an open source application management platform, which provides a centralized console for managing application clusters and distributed-application environments. jManage platform provides advanced features like Dashboards, Alerts, Graphs, Connectors, Security, SNMP support and more.<br /><br />jManage is a web based application and is used for managing applications in Development, QA, Staging and Production environments. It has a single point, web-based access to all your resources. It is possible to access any server or other 'managed' application in your network, make adjustments or invoke actions, all from single point web based console.<br /><br />More details about jManage is available at <a href="http://www.jmanage.org/">jManage's web site</a>.<br /><br /><span style="font-weight: bold;">Install jManage as a Service</span><br /><br />Out of the box, jManage comes with an embedded jetty servlet engine। When the application is started using the available batch commands in Windows environment, it starts in a console mode.<br /><br />I will add detailed steps here to enable jManage as a service in Windows and Unix/Linux environments. Make sure you should have JDK 1.5 to run jManage 2.0<br /><br />Windows Environment:<br /><br />1. Download jManage Application from jManage web site and unzip it into a folder of your choice.<br />2. Download the tarfile to a temp directory and untar the contents. Please click <a href="http://jexcellente.googlepages.com/jmanage-service.zip">here </a>to download the tar file<br /><br />Tar File Contents:<br /><br /><fieldset style=""><br />1. jmanage (Unix/Linux based .sh file)<br />2. libwrapper.so<br />3. wrapper.conf<br />4. wrapper.dll<br />5. wrapper.exe<br />6. wrapper.jar<br />7. JManage.bat<br />8. InstallJManage-NT.bat<br />9. UninstallJManage-NT.bat<br />10.wrapper<br /></fieldset><br /><br /><span style="font-weight: bold;">Where to place the above mentioned Files?<br /><br /></span><fieldset style=""><br /><ol><li>Place jmanage (.sh file), JManage.bat, InstallJManage-NT.bat, UninstallJManage-NT.bat and wrapper.exe and wrapper in the bin directory of JManage installation.</li><li>Place wrapper.conf in the config folder of JManage installation</li><li>Place wrapper.dll, libwrapper.so and wrapper.jar in the lib folder of<br />JManage installation<br /></li></ol> Thats it.<br /><br /></fieldset><br /><br /><span style="font-weight: bold;"> Instructions to Install and Running in Windows NT based Environment:<br /><br /></span> The JManage.bat will help run the application in console mode. You can<br />test the app using this batch file. You may use InstallJManage-NT.bat to<br />install it as a service in Windows NT based environment.<br /><br />The UninstallJManage-NT.bat can be used to uninstall the service.<br /><br />To see the application listed as service, please use Control Panel> Administrative Tools > Services option and locate JManage application in the list. Right click and then start the<br />application. The application is configured in such a way that it will start automatically when the operating system boots up.<br /><br /><span style="font-weight: bold;"> Instructions to Install and start the application in UNIX/</span><span style="font-weight: bold;">Linux</span><span style="font-weight: bold;"> environment:<br /><br /></span>In UNIX/Linux Environments, you will be using the .sh file we placed in the bin directory of JManage installation. The file name is JManage without the .sh extension.<br /><br />e.g. Assuming JManage is installed in /usr/app<br /><br />CONSOLE MODE:<br /><br />/usr/app/JManage/bin/JManage console<br /><br />The above command will run the application in console mode.<br /><br />The application can be terminated by hitting CTRL-C in the command window. This will cause the Wrapper to shut down the application cleanly. This is same in Windows environment as well.<br /><br />DAEMON PROCESS:<br /><br />The application can be run as a detatched daemon process by executing the script using the start command.<br /><br />/usr/app/JManage/bin/JManage start<br />Running My Application...<br /><br />To Stop<br />/usr/app/JManage/bin/JManage stop<br />Stopping JManage Application...<br />Stopped JManage Application.<br /><br />However, there is one caveat to this approach. jManage out of the box requires the users to supply a password when the application starts up. I have to hard code this password as one of the parameters in the wrapper.conf file.<br /><br />Please note the following lines in wrapper.conf file<br /><br />wrapper.app.parameter.3=123456<br />wrapper.app.parameter.7=123456<br /><br />If you are planning to generate a new password and if you want to use a new password, then you will have to modify the above said line to reflect the new password.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com27tag:blogger.com,1999:blog-3710815942271269136.post-34091838872380984842007-12-20T01:00:00.000-08:002008-01-01T11:17:42.876-08:00Aspect J and Spring Framework - A case study<span style="font-weight: bold;"><span style="color: rgb(0, 0, 0);">Introduction</span><br /><br /></span><span style="color: rgb(0, 0, 0);">I have been working on several projects now and I have observed one common requirement in all the web application projects I have worked so far. The requirement is that the application need to track the changes especially when the update happens to a record in the database. The application also need to track who updates and when the update happens on the record. Tracking changes is not a big deal as this can be easily implemented using database triggers. When the record gets updated in the database, the old record can be moved into a history table using database triggers. Let us see the big picture.<br /><br /><span style="font-weight: bold;">The Big Picture<br /><br /></span>I have often come across developers writing umpteen number of lines of code in the presentation layer of the web application just to compare the changes made to the domain data against the data retrieved from the database. One of the things that compelled them to implement the track changes logic in the presentation layer is to avoid invoking the business service layer unless there is a genuine change in the data.<br /><br />Things can </span><span style="color: rgb(0, 0, 0);">get </span><span style="color: rgb(0, 0, 0);">unwieldy to implement the above mentioned track changes functionality in the presentation layer if the application demands tracking changes to a large number of objects. We also do not want to implement such functionality in the domain object either. So let us take a different approach in implementing such functionality that will scale to a very large number of objects in a less invasive way.<br /><br /><span style="font-weight: bold;">Use Case Requirement<br /><br /></span>Let us take Online User Management web application as an example where we will implement the track changes functionality with the help of AspectJ, Spring framework and Hibernate. The use case mandates whenever a user updates the profile, the system tracks the changes to the properties of the domain object and records the user who updates and the date on which the update happens in the database table.<br /><br /><span style="font-weight: bold;">Technologies Used<br /><br /></span></span><ol><li><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><span style="color: rgb(0, 0, 0);"> AOP : </span></span><span style="color: rgb(0, 0, 0);">Aspect Oriented Programming a.k.a. AOP </span>is a way of modularizing crosscutting concerns much like object-oriented programming is a way of modularizing common concerns.</span></li><li><span style="font-weight: bold; color: rgb(0, 0, 0);"> AspectJ:</span><span style="color: rgb(0, 0, 0);"> AspectJ is an implementation of aspect-oriented programming for Java. AspectJ adds to Java just one new concept, a join point -- and that's really just a name for an existing Java concept. It adds to Java only a few new constructs: pointcuts, advice, inter-type declarations and aspects. Pointcuts and advice dynamically affect program flow, inter-type declarations statically affects a program's class hierarchy, and aspects encapsulate these new constructs. For more details, please refer the </span><a style="color: rgb(0, 0, 0);" href="http://www.eclipse.org/aspectj/doc/released/progguide/index.html">AspectJ Programming Guide</a><span style="color: rgb(0, 0, 0);">.</span></li><li><span style="font-weight: bold; color: rgb(0, 0, 0);">Spring Framework</span><span style="color: rgb(0, 0, 0);"> - It is the leading open source J2EE application framework .</span></li><li><span style="font-weight: bold; color: rgb(0, 0, 0);">Hibernate</span><span style="color: rgb(0, 0, 0);"> - It is one of the leading Object Relational Mapping tools. Hibernate is a powerful, high performance object/relational persistence and query service.</span></li></ol><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><br />Technical Design<br /><br /></span>We will first design our domain objects we are going to use as an example to track the changes to their properties. A typical online user management application contains a minimum of Users, Contacts & Address domain objects. Let us now verify the structure of these objects.<br /><br /><br /></span><br /><div style="text-align: center;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKNbrakxYf5gIlckc8Pg4UR2KaVUWmeDBUXlHTbSw1TfxYKLhTWcNnxTR7SZVss1ryippsytLWTWzARJjsrV20auyVQVdpvNqodx_0ss3Ej0oERiQVeTs5P-0Yjwe4MkZEIft80VSGMQTN/s1600-h/UsersSchemaClassDiagram.PNG"><img style="cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKNbrakxYf5gIlckc8Pg4UR2KaVUWmeDBUXlHTbSw1TfxYKLhTWcNnxTR7SZVss1ryippsytLWTWzARJjsrV20auyVQVdpvNqodx_0ss3Ej0oERiQVeTs5P-0Yjwe4MkZEIft80VSGMQTN/s400/UsersSchemaClassDiagram.PNG" alt="" id="BLOGGER_PHOTO_ID_5141651956326252018" border="0" /></a><br /></div><span style="color: rgb(0, 0, 0);"><br /></span><div style="text-align: center;"><span style="color: rgb(0, 0, 0);">Figure 1. UML diagram of Domain objects<br /><br /></span><div style="text-align: left;">From the diagram, it is evident that Users may have one or more Contacts and each Contact may have one or more address either physical or mailing address.<br /></div></div><br /><span style="font-style: italic;">Example: Users.java</span><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; color: rgb(0, 0, 0); font-family: courier new; font-size: 12px; background-color: lightgray;"><br /><blockquote><pre><br />package com.vbose.domain;<br /><br />import java.io.Serializable;<br />import java.util.HashSet;<br /><br />/**<br />* Users.java - A class that represents a row in the 'USERS' table.<br />* This class may be customized as it is never re-generated<br />* after being created.<br />* @author Vigil Bose<br />*/<br />public class Users implements Serializable<br />{<br /><blockquote>private static final long serialVersionUID = 1L;<br /><br />/** The cached hash code value for this instance.<br />Settting to 0 triggers re-calculation. */<br />private int hashValue = 0;<br /><br />/** The composite primary key value. */<br />private java.lang.String username;<br /><br />/** The value of the luStatusReasonCodes association. */<br />private LuStatusReasonCodes luStatusReasonCodes;<br /><br />/** The value of the luUserStatusCodes association. */<br />private LuUserStatusCodes luUserStatusCodes;<br /><br />/** The value of the contactsSet one-to-many association. */<br />private java.util.Set contactsSet = new HashSet();<br /><br />/** The value of the simple password property. */<br />private java.lang.String password;<br /><br />/** The value of the simple lockedTime property. */<br />private java.util.Date lockedTime;<br /><br />/** The value of the simple secretQuestion property. */<br />private java.lang.String secretQuestion;<br /><br />/** The value of the simple secretAnswer property. */<br />private java.lang.String secretAnswer;<br /><br />/** The value of the simple createdDate property. */<br />private java.util.Date createdDate;<br /><br />/** The value of the simple createdName property. */<br />private java.lang.String createdName;<br /><br />/** The value of the simple updatedDate property. */<br />private java.util.Date updatedDate;<br /><br />/** The value of the simple updatedName property. */<br />private java.lang.String updatedName;<br /><br />/** The value of the simple passwordExpiration property. */<br />private java.util.Date passwordExpiration;<br /><br />/** The value of the simple lastLogin property. */<br />private java.util.Date lastLogin;<br /><br />/** The value of the non-persistent property used only in Updates **/<br />private Boolean trackChanges = new Boolean(false);<br /><br />/** The value of the non-persistent property used only in Updates **/<br />private Boolean propertyChanged = new Boolean(false);<br /><br />/**<br />* Simple constructor of Users instances.<br />*/<br />public Users(){<br />}<br /><br />/**<br />* Constructor of Users instances given a simple primary key.<br />* @param username<br />*/<br />public Users(java.lang.String username){<br /> this.setUsername(username);<br />}<br /><br />/**<br />* Return the simple primary key value that identifies this object.<br />* @return java.lang.String<br />*/<br />public java.lang.String getUsername(){<br /> return username;<br />}<br /><br />/**<br />* Set the simple primary key value that identifies this object.<br />* @param username<br />*/<br />public void setUsername(java.lang.String username){<br /> this.hashValue = 0;<br /> this.username = username;<br />}<br /><br />/**<br />* Return the value of the PASSWORD column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getPassword(){<br /> return this.password;<br />}<br /><br />/**<br />* Set the value of the PASSWORD column.<br />* @param password<br />*/<br />public void setPassword(java.lang.String password){<br /> this.password = password;<br />}<br /><br />/**<br />* Return the value of the LOCKED_TIME column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getLockedTime(){<br /> return this.lockedTime;<br />}<br /><br />/**<br />* Set the value of the LOCKED_TIME column.<br />* @param lockedTime<br />*/<br />public void setLockedTime(java.util.Date lockedTime){<br /> this.lockedTime = lockedTime;<br />}<br /><br />/**<br />* Return the value of the SECRET_QUESTION column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getSecretQuestion(){<br /> return this.secretQuestion;<br />}<br /><br />/**<br />* Set the value of the SECRET_QUESTION column.<br />* @param secretQuestion<br />*/<br />public void setSecretQuestion(java.lang.String secretQuestion){<br /> this.secretQuestion = secretQuestion;<br />}<br /><br />/**<br />* Return the value of the SECRET_ANSWER column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getSecretAnswer(){<br /> return this.secretAnswer;<br />}<br /><br />/**<br />* Set the value of the SECRET_ANSWER column.<br />* @param secretAnswer<br />*/<br />public void setSecretAnswer(java.lang.String secretAnswer){<br /> this.secretAnswer = secretAnswer;<br />}<br /><br />/**<br />* Return the value of the CREATED_DATE column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getCreatedDate(){<br /> return this.createdDate;<br />}<br /><br />/**<br />* Set the value of the CREATED_DATE column.<br />* @param createdDate<br />*/<br />public void setCreatedDate(java.util.Date createdDate){<br /> this.createdDate = createdDate;<br />}<br /><br />/**<br />* Return the value of the CREATED_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getCreatedName(){<br /> return this.createdName;<br />}<br /><br />/**<br />* Set the value of the CREATED_NAME column.<br />* @param createdName<br />*/<br />public void setCreatedName(java.lang.String createdName){<br /> this.createdName = createdName;<br />}<br /><br />/**<br />* Return the value of the UPDATED_DATE column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getUpdatedDate(){<br /> return this.updatedDate;<br />}<br /><br />/**<br />* Set the value of the UPDATED_DATE column.<br />* @param updatedDate<br />*/<br />public void setUpdatedDate(java.util.Date updatedDate){<br /> this.updatedDate = updatedDate;<br />}<br /><br />/**<br />* Return the value of the UPDATED_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getUpdatedName(){<br /> return this.updatedName;<br />}<br /><br />/**<br />* Set the value of the UPDATED_NAME column.<br />* @param updatedName<br />*/<br />public void setUpdatedName(java.lang.String updatedName){<br /> this.updatedName = updatedName;<br />}<br /><br />/**<br />* Return the value of the PASSWORD_EXPIRATION column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getPasswordExpiration(){<br /> return this.passwordExpiration;<br />}<br /><br />/**<br />* Set the value of the PASSWORD_EXPIRATION column.<br />* @param passwordExpiration<br />*/<br />public void setPasswordExpiration(java.util.Date passwordExpiration){<br /> this.passwordExpiration = passwordExpiration;<br />}<br /><br />/**<br />* Return the value of the LAST_LOGIN column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getLastLogin(){<br /> return this.lastLogin;<br />}<br /><br />/**<br />* Set the value of the LAST_LOGIN column.<br />* @param lastLogin<br />*/<br />public void setLastLogin(java.util.Date lastLogin){<br /> this.lastLogin = lastLogin;<br />}<br /><br />/**<br />* Return the value of the STATUS_REASON_CODE column.<br />* @return LuStatusReasonCodes<br />*/<br />public LuStatusReasonCodes getLuStatusReasonCodes(){<br /> return this.luStatusReasonCodes;<br />}<br /><br />/**<br />* Set the value of the STATUS_REASON_CODE column.<br />* @param luStatusReasonCodes<br />*/<br />public void setLuStatusReasonCodes(LuStatusReasonCodes luStatusReasonCodes){<br /> this.luStatusReasonCodes = luStatusReasonCodes;<br />}<br /><br />/**<br />* Return the value of the USER_STATUS_CODE column.<br />* @return LuUserStatusCodes<br />*/<br />public LuUserStatusCodes getLuUserStatusCodes(){<br /> return this.luUserStatusCodes;<br />}<br /><br />/**<br />* Set the value of the USER_STATUS_CODE column.<br />* @param luUserStatusCodes<br />*/<br />public void setLuUserStatusCodes(LuUserStatusCodes luUserStatusCodes){<br /> this.luUserStatusCodes = luUserStatusCodes;<br />}<br /><br />/**<br />* Return the value of the USERNAME collection.<br />* @return Contacts<br />*/<br />public java.util.Set getContactsSet(){<br /> return this.contactsSet;<br />}<br /><br />/**<br />* Set the value of the USERNAME collection.<br />* @param contactsSet<br />*/<br />public void setContactsSet(java.util.Set contactsSet){<br /> this.contactsSet = contactsSet;<br />}<br /><br />/**<br />* The API addContacts() not only reduces the lines of code when<br />* dealing with "Users" objects, but also enforces the cardinality<br />* of the association.Errors that arise from leaving out one of<br />* the two required actions are avoided.<br />* Whenever an association is created between a parent Users and<br />* a child Contacts, two actions are required.<br />* 1) The parent Users of the child must be set, effectively breaking<br />* the association between the child and its old parent (there can<br />* be only one parent for any child)<br />* 2) The child must be added to the "contactsSet" collection of the<br />* new parent "Users"<br />*<br />* This is a convenience method to the Users class that groups these<br />* operations, allowing reuse and helping ensure correctness<br />* @param contacts<br />*/<br />public void addContacts(Contacts contacts){<br /> if (contacts == null)<br /> throw new IllegalArgumentException("Null contacts Object!");<br /> if (contacts.getUsers() != null){<br /> contacts.getUsers().getContactsSet().remove(contacts);<br /> }<br /> contacts.setUsers(this);<br /> this.contactsSet.add(contacts);<br />}<br /><br />/**<br />* @return the trackChanges<br />*/<br />public Boolean getTrackChanges() {<br /> return trackChanges;<br />}<br /><br />/**<br />* @param trackChanges the trackChanges to set<br />*/<br />public void setTrackChanges(Boolean trackChanges) {<br /> this.trackChanges = trackChanges;<br />}<br /><br />/**<br />* Return the non-persistent property<br />* @return the propertyChanged<br />*/<br />public Boolean getPropertyChanged() {<br /> return propertyChanged;<br />}<br /><br />/**<br />* Sets the non-persistent property<br />* @param propertyChanged the propertyChanged to set<br />*/<br />public void setPropertyChanged(Boolean propertyChanged) {<br /> this.propertyChanged = propertyChanged;<br />}<br /><br />/**<br />* Implementation of the equals comparison on the basis of equality of the<br />* primary key values.<br />* @param rhs<br />* @return boolean<br />*/<br />public boolean equals(Object rhs){<br /> if (rhs == null)<br /> return false;<br /> if (! (rhs instanceof Users))<br /> return false;<br /> Users that = (Users) rhs;<br /> if (this.getUsername() == null || that.getUsername() == null)<br /> return false;<br /> return (this.getUsername().equals(that.getUsername()));<br />}<br /><br />/**<br />* Implementation of the hashCode method conforming to the Bloch pattern with<br />* the exception of array properties (these are very unlikely primary key<br />* types).<br />* @return int<br />*/<br />public int hashCode(){<br /> if (this.hashValue == 0){<br /> int result = 17;<br /> int usernameValue = this.getUsername() == null ? 0<br /> : this.getUsername().hashCode();<br /> result = result * 37 + usernameValue;<br /> this.hashValue = result;<br /> }<br /> return this.hashValue;<br />}</blockquote><br />}<br /></pre></blockquote><br /><br /></div><br /><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><br /></span></span><pre><span style="font-style: italic;">Example: Contacts.java</span></pre><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; color: rgb(0, 0, 0); font-family: courier new; font-size: 12px; background-color: lightgray;"><br /><blockquote><pre><br />package com.vbose.domain;<br /><br />import java.io.Serializable;<br />import java.util.HashSet;<br /><br />/**<br />* Contacts.java - A class that represents a row in the 'CONTACTS' table.<br />* This class may be customized as it is never re-generated<br />* after being created.<br />* @author Vigil Bose<br />*/<br />public class Contacts implements Serializable<br />{<br /><br /><blockquote>private static final long serialVersionUID = 1L;<br /><br />/** The cached hash code value for this instance.<br />Settting to 0 triggers re-calculation. */<br />private int hashValue = 0;<br /><br />/** The composite primary key value. */<br />private java.lang.Integer contactId;<br /><br />/** The value of the luContactTypes association. */<br />private LuContactTypes luContactTypes;<br /><br />/** The value of the users association. */<br />private Users users;<br /><br />/** The value of the simple firstName property. */<br />private java.lang.String firstName;<br /><br />/** The value of the simple middleInitial property. */<br />private java.lang.String middleInitial;<br /><br />/** The value of the simple lastName property. */<br />private java.lang.String lastName;<br /><br />/** The value of the simple firmName property. */<br />private java.lang.String firmName;<br /><br />/** The value of the simple phoneNumber property. */<br />private java.lang.String phoneNumber;<br /><br />/** The value of the simple faxNumber property. */<br />private java.lang.String faxNumber;<br /><br />/** The value of the simple emailAddress property. */<br />private java.lang.String emailAddress;<br /><br />/** The value of the simple createdDate property. */<br />private java.util.Date createdDate;<br /><br />/** The value of the simple createdName property. */<br />private java.lang.String createdName;<br /><br />/** The value of the simple updatedDate property. */<br />private java.util.Date updatedDate;<br /><br />/** The value of the simple updatedName property. */<br />private java.lang.String updatedName;<br /><br />/** The value of the simple title property. */<br />private java.lang.String title;<br /><br />/** The value of the simple status property. */<br />private java.lang.String status;<br /><br />/** The value of the geographicAddressesSet one-to-many association. */<br />private java.util.Set geographicAddressesSet = new HashSet();<br /><br />/** The value of the non-persistent property used only in Updates **/<br />private Boolean trackChanges = new Boolean(false);<br /><br />/** The value of the non-persistent property used only in Updates **/<br />private Boolean propertyChanged = new Boolean(false);<br /><br />/**<br />* Simple constructor of Contacts instances.<br />*/<br />public Contacts(){<br />}<br /><br />/**<br />* Constructor of Contacts instances given a simple primary key.<br />* @param contactId<br />*/<br />public Contacts(java.lang.Integer contactId){<br /> this.setContactId(contactId);<br />}<br /><br />/**<br />* Return the simple primary key value that identifies this object.<br />* @return java.lang.Integer<br />*/<br />public java.lang.Integer getContactId(){<br /> return contactId;<br />}<br /><br />/**<br />* Set the simple primary key value that identifies this object.<br />* @param contactId<br />*/<br />public void setContactId(java.lang.Integer contactId){<br /> this.hashValue = 0;<br /> this.contactId = contactId;<br />}<br /><br />/**<br />* Return the value of the USERNAME column.<br />* @return Users<br />*/<br />public Users getUsers(){<br /> return this.users;<br />}<br /><br />/**<br />* Set the value of the USERNAME column.<br />* @param users<br />*/<br />public void setUsers(Users users){<br /> this.users = users;<br />}<br /><br />/**<br />* Return the value of the CONTACT_TYPE_CODE column.<br />* @return LuContactTypes<br />*/<br />public LuContactTypes getLuContactTypes(){<br /> return this.luContactTypes;<br />}<br /><br />/**<br />* Set the value of the CONTACT_TYPE_CODE column.<br />* @param luContactTypes<br />*/<br />public void setLuContactTypes(LuContactTypes luContactTypes){<br /> this.luContactTypes = luContactTypes;<br />}<br /><br />/**<br />* Return the value of the FIRST_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getFirstName(){<br /> return this.firstName;<br />}<br /><br />/**<br />* Set the value of the FIRST_NAME column.<br />* @param firstName<br />*/<br />public void setFirstName(java.lang.String firstName){<br /> this.firstName = firstName;<br />}<br /><br />/**<br />* Return the value of the MIDDLE_INITIAL column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getMiddleInitial(){<br /> return this.middleInitial;<br />}<br /><br />/**<br />* Set the value of the MIDDLE_INITIAL column.<br />* @param middleInitial<br />*/<br />public void setMiddleInitial(java.lang.String middleInitial){<br /> this.middleInitial = middleInitial;<br />}<br /><br />/**<br />* Return the value of the LAST_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getLastName(){<br /> return this.lastName;<br />}<br /><br />/**<br />* Set the value of the LAST_NAME column.<br />* @param lastName<br />*/<br />public void setLastName(java.lang.String lastName){<br /> this.lastName = lastName;<br />}<br /><br />/**<br />* Return the value of the FIRM_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getFirmName(){<br /> return this.firmName;<br />}<br /><br />/**<br />* Set the value of the FIRM_NAME column.<br />* @param firmName<br />*/<br />public void setFirmName(java.lang.String firmName){<br /> this.firmName = firmName;<br />}<br /><br />/**<br />* Return the value of the PHONE_NUMBER column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getPhoneNumber(){<br /> return this.phoneNumber;<br />}<br /><br />/**<br />* Set the value of the PHONE_NUMBER column.<br />* @param phoneNumber<br />*/<br />public void setPhoneNumber(java.lang.String phoneNumber){<br /> this.phoneNumber = phoneNumber;<br />}<br /><br />/**<br />* Return the value of the FAX_NUMBER column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getFaxNumber(){<br /> return this.faxNumber;<br />}<br /><br />/**<br />* Set the value of the FAX_NUMBER column.<br />* @param faxNumber<br />*/<br />public void setFaxNumber(java.lang.String faxNumber){<br /> this.faxNumber = faxNumber;<br />}<br /><br />/**<br />* Return the value of the EMAIL_ADDRESS column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getEmailAddress(){<br /> return this.emailAddress;<br />}<br /><br />/**<br />* Set the value of the EMAIL_ADDRESS column.<br />* @param emailAddress<br />*/<br />public void setEmailAddress(java.lang.String emailAddress){<br /> this.emailAddress = emailAddress;<br />}<br /><br />/**<br />* Return the value of the CREATED_DATE column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getCreatedDate(){<br /> return this.createdDate;<br />}<br /><br />/**<br />* Set the value of the CREATED_DATE column.<br />* @param createdDate<br />*/<br />public void setCreatedDate(java.util.Date createdDate){<br /> this.createdDate = createdDate;<br />}<br /><br />/**<br />* Return the value of the CREATED_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getCreatedName(){<br /> return this.createdName;<br />}<br /><br />/**<br />* Set the value of the CREATED_NAME column.<br />* @param createdName<br />*/<br />public void setCreatedName(java.lang.String createdName){<br /> this.createdName = createdName;<br />}<br /><br />/**<br />* Return the value of the UPDATED_DATE column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getUpdatedDate(){<br /> return this.updatedDate;<br />}<br /><br />/**<br />* Set the value of the UPDATED_DATE column.<br />* @param updatedDate<br />*/<br />public void setUpdatedDate(java.util.Date updatedDate){<br /> this.updatedDate = updatedDate;<br />}<br /><br />/**<br />* Return the value of the UPDATED_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getUpdatedName(){<br /> return this.updatedName;<br />}<br /><br />/**<br />* Set the value of the UPDATED_NAME column.<br />* @param updatedName<br />*/<br />public void setUpdatedName(java.lang.String updatedName){<br /> this.updatedName = updatedName;<br />}<br /><br />/**<br />* Return the value of the TITLE column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getTitle(){<br /> return this.title;<br />}<br /><br />/**<br />* Set the value of the TITLE column.<br />* @param title<br />*/<br />public void setTitle(java.lang.String title){<br /> this.title = title;<br />}<br /><br />/**<br />* Return the value of the STATUS column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getStatus(){<br /> return this.status;<br />}<br /><br />/**<br />* Set the value of the STATUS column.<br />* @param status<br />*/<br />public void setStatus(java.lang.String status){<br /> this.status = status;<br />}<br /><br />/**<br />* Return the value of the CONTACT_ID Collection.<br />* @return the geographicAddressesSet<br />*/<br />public java.util.Set getGeographicAddressesSet(){<br /> return geographicAddressesSet;<br />}<br /><br />/**<br />* Set the value of the CONTACT_ID collection.<br />* @param geographicAddressesSet the geographicAddressesSet to set<br />*/<br />private void setGeographicAddressesSet(java.util.Set geographicAddressesSet) {<br /> this.geographicAddressesSet = geographicAddressesSet;<br />}<br /><br />/**<br />* The API addGeographicAddresses() not only reduces the lines of code<br />* when dealing with "Contacts" objects, but also enforces the cardinality<br />* of the association.Errors that arise from leaving out one of the two<br />* required actions are avoided. Whenever an association is created between<br />* a parent Contacts and a child GeographicAddresses, two actions are<br />* required.<br />* 1) The parent Users of the child must be set, effectively breaking the<br />* association between the child and its old parent (there can be only<br />* one parent for any child)<br />* 2) The child must be added to the "geographicAddressesSet" collection<br />* of the new parent "Contacts"<br />*<br />* This is a convenience method to the Contacts class that groups these<br />* operations, allowing reuse and helping ensure correctness<br />* @param geographicAddresses<br />*/<br />public void addGeographicAddresses(GeographicAddresses geographicAddresses){<br /><br /> if (geographicAddresses == null)<br /> throw new IllegalArgumentException("Null geographicAddresses Object!");<br /> if (geographicAddresses.getContacts() != null){<br /> geographicAddresses.getContacts().getGeographicAddressesSet().<br /> remove(geographicAddresses);<br /> }<br /> geographicAddresses.setContacts(this);<br /> this.geographicAddressesSet.add(geographicAddresses);<br />}<br /><br />/**<br />* @return the trackChanges<br />*/<br />public Boolean getTrackChanges(){<br /> return trackChanges;<br />}<br /><br />/**<br />* @param trackChanges the trackChanges to set<br />*/<br />public void setTrackChanges(Boolean trackChanges) {<br /> this.trackChanges = trackChanges;<br />}<br /><br />/**<br />* Return the non-persistent property<br />* @return the propertyChanged<br />*/<br />public Boolean getPropertyChanged() {<br /> return propertyChanged;<br />}<br /><br />/**<br />* Sets the non-persistent property<br />* @param propertyChanged the propertyChanged to set<br />*/<br />public void setPropertyChanged(Boolean propertyChanged) {<br /> this.propertyChanged = propertyChanged;<br />}<br /><br />/**<br />* Implementation of the equals comparison on the basis of<br />* equality of the primary key values.<br />* @param rhs<br />* @return boolean<br />*/<br />public boolean equals(Object rhs){<br /> if (rhs == null)<br /> return false;<br /> if (! (rhs instanceof Contacts))<br /> return false;<br /> Contacts that = (Contacts) rhs;<br /> if (this.getUsers() != null && that.getUsers() != null){<br /> if (this.getUsers().getUsername() != null &&<br /> that.getUsers().getUsername() != null){<br /> if (!this.getUsers().getUsername().<br /> equals(that.getUsers().getUsername())){<br /> return false;<br /> }<br /> }<br /> }<br /> if (this.getLuContactTypes() != null && that.getLuContactTypes() != null){<br /> if (this.getLuContactTypes().getContactTypeCode() != null &&<br /> that.getLuContactTypes().getContactTypeCode() != null){<br /> if (!this.getLuContactTypes().getContactTypeCode().<br /> equals(that.getLuContactTypes().getContactTypeCode())){<br /> return false;<br /> }<br /> }<br /> }<br /> return true;<br />}<br /><br />/**<br />* Implementation of the hashCode method conforming to the Bloch pattern with<br />* the exception of array properties (these are very unlikely primary key<br />* types).<br />* @return int<br />*/<br />public int hashCode(){<br /> if (this.hashValue == 0){<br /> int result = 17;<br /> int usernameValue = this.getUsers() == null ? 0 :<br /> this.getUsers().getUsername().hashCode();<br /> result = result * 37 + usernameValue;<br /> int contactTypeCodeValue = this.getLuContactTypes() == null ? 0 :<br /> this.getLuContactTypes().getContactTypeCode().hashCode();<br /> result = result * 37 + contactTypeCodeValue;<br /> this.hashValue = result;<br /> }<br /> return this.hashValue;<br />}</blockquote><br />}<br /></pre></blockquote><br /><br /></div><br /><br /><span style="font-style: italic;">Example: GeographicAddresses.java</span><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; color: rgb(0, 0, 0); font-family: courier new; font-size: 12px; background-color: lightgray;"><br /><blockquote><pre><br />package com.vbose.domain;<br /><br />import java.io.Serializable;<br /><br />/**<br />* GeographicAddresses.java - A class that represents a<br />* row in the 'GEOGRAPHIC_ADDRESSES' table.<br />* This class may be customized as it is never re-generated<br />* after being created.<br />* @author Vigil Bose<br />*/<br />public class GeographicAddresses implements Serializable<br />{<br /><br /><blockquote>private static final long serialVersionUID = 1L;<br /><br />/** The cached hash code value for this instance.<br />Settting to 0 triggers re-calculation. */<br />private int hashValue = 0;<br /><br />/** The composite primary key value. */<br />private java.lang.Integer addressId;<br /><br />/** The value of the luCountyCodes association. */<br />private LuCountyCodes luCountyCodes;<br /><br />/** The value of the contacts association. */<br />private Contacts contacts;<br /><br />/** The value of the simple addressLine1 property. */<br />private java.lang.String addressLine1;<br /><br />/** The value of the simple addressLine2 property. */<br />private java.lang.String addressLine2;<br /><br />/** The value of the simple city property. */<br />private java.lang.String city;<br /><br />/** The value of the simple stateCode property. */<br />private java.lang.String stateCode;<br /><br />/** The value of the simple postalCode property. */<br />private java.lang.String postalCode;<br /><br />/** The value of the simple stateProvince property. */<br />private java.lang.String stateProvince;<br /><br />/** The value of the simple isoCountryCode property. */<br />private java.lang.String isoCountryCode;<br /><br />/** The value of the simple createdDate property. */<br />private java.util.Date createdDate;<br /><br />/** The value of the simple createdName property. */<br />private java.lang.String createdName;<br /><br />/** The value of the simple updatedDate property. */<br />private java.util.Date updatedDate;<br /><br />/** The value of the simple updatedName property. */<br />private java.lang.String updatedName;<br /><br />/** The value of the simple routingNumber property. */<br />private java.lang.String routingNumber;<br /><br />/** The value of the simple addressType property. */<br />private java.lang.String addressType;<br /><br />/** The value of the non-persistent property used only in Updates **/<br />private Boolean trackChanges = new Boolean(false);<br /><br />/** The value of the non-persistent property used only in Updates **/<br />private Boolean propertyChanged = new Boolean(false);<br /><br />/**<br />* Simple constructor of GeographicAddresses instances.<br />*/<br />public GeographicAddresses(){<br />}<br /><br />/**<br />* Constructor of GeographicAddresses instances given a<br />* simple primary key.<br />* @param addressId<br />*/<br />public GeographicAddresses(java.lang.Integer addressId){<br /> this.setAddressId(addressId);<br />}<br /><br />/**<br />* Return the simple primary key value that identifies this<br />* object.<br />* @return java.lang.Integer<br />*/<br />public java.lang.Integer getAddressId(){<br /> return addressId;<br />}<br /><br />/**<br />* Set the simple primary key value that identifies this<br />* object.<br />* @param addressId<br />*/<br />public void setAddressId(java.lang.Integer addressId){<br /> this.hashValue = 0;<br /> this.addressId = addressId;<br />}<br /><br />/**<br />* Return the value of the CONTACT_ID association column.<br />* @return contacts<br />*/<br />public Contacts getContacts(){<br /> return this.contacts;<br />}<br /><br />/**<br />* Set the value of the CONTACT_ID association column.<br />* @param contacts<br />*/<br />public void setContacts(Contacts contacts){<br /> this.contacts = contacts;<br />}<br /><br />/**<br />* Return the value of the ADDRESS_LINE1 column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getAddressLine1(){<br /> return this.addressLine1;<br />}<br /><br />/**<br />* Set the value of the ADDRESS_LINE1 column.<br />* @param addressLine1<br />*/<br />public void setAddressLine1(java.lang.String addressLine1){<br /> this.addressLine1 = addressLine1;<br />}<br /><br />/**<br />* Return the value of the ADDRESS_LINE2 column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getAddressLine2(){<br /> return this.addressLine2;<br />}<br /><br />/**<br />* Set the value of the ADDRESS_LINE2 column.<br />* @param addressLine2<br />*/<br />public void setAddressLine2(java.lang.String addressLine2){<br /> this.addressLine2 = addressLine2;<br />}<br /><br />/**<br />* Return the value of the CITY column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getCity(){<br /> return this.city;<br />}<br /><br />/**<br />* Set the value of the CITY column.<br />* @param city<br />*/<br />public void setCity(java.lang.String city){<br /> this.city = city;<br />}<br /><br />/**<br />* Return the value of the COUNTY_CODE column.<br />* @return LuCountyCodes<br />*/<br />public LuCountyCodes getLuCountyCodes(){<br /> return this.luCountyCodes;<br />}<br /><br />/**<br />* Set the value of the COUNTY_CODE column.<br />* @param luCountyCodes<br />*/<br />public void setLuCountyCodes(LuCountyCodes luCountyCodes){<br /> this.luCountyCodes = luCountyCodes;<br />}<br /><br />/**<br />* Return the value of the STATE_CODE column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getStateCode(){<br /> return this.stateCode;<br />}<br /><br />/**<br />* Set the value of the STATE_CODE column.<br />* @param stateCode<br />*/<br />public void setStateCode(java.lang.String stateCode){<br /> this.stateCode = stateCode;<br />}<br /><br />/**<br />* Return the value of the POSTAL_CODE column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getPostalCode(){<br /> return this.postalCode;<br />}<br /><br />/**<br />* Set the value of the POSTAL_CODE column.<br />* @param postalCode<br />*/<br />public void setPostalCode(java.lang.String postalCode){<br /> this.postalCode = postalCode;<br />}<br /><br />/**<br />* Return the value of the STATE_PROVINCE column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getStateProvince(){<br /> return this.stateProvince;<br />}<br /><br />/**<br />* Set the value of the STATE_PROVINCE column.<br />* @param stateProvince<br />*/<br />public void setStateProvince(java.lang.String stateProvince){<br /> this.stateProvince = stateProvince;<br />}<br /><br />/**<br />* Return the value of the ISO_COUNTRY_CODE column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getIsoCountryCode(){<br /> return this.isoCountryCode;<br />}<br /><br />/**<br />* Set the value of the ISO_COUNTRY_CODE column.<br />* @param isoCountryCode<br />*/<br />public void setIsoCountryCode(java.lang.String isoCountryCode){<br /> this.isoCountryCode = isoCountryCode;<br />}<br /><br />/**<br />* Return the value of the CREATED_DATE column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getCreatedDate(){<br /> return this.createdDate;<br />}<br /><br />/**<br />* Set the value of the CREATED_DATE column.<br />* @param createdDate<br />*/<br />public void setCreatedDate(java.util.Date createdDate){<br /> this.createdDate = createdDate;<br />}<br /><br />/**<br />* Return the value of the CREATED_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getCreatedName(){<br /> return this.createdName;<br />}<br /><br />/**<br />* Set the value of the CREATED_NAME column.<br />* @param createdName<br />*/<br />public void setCreatedName(java.lang.String createdName){<br /> this.createdName = createdName;<br />}<br /><br />/**<br />* Return the value of the UPDATED_DATE column.<br />* @return java.util.Date<br />*/<br />public java.util.Date getUpdatedDate(){<br /> return this.updatedDate;<br />}<br /><br />/**<br />* Set the value of the UPDATED_DATE column.<br />* @param updatedDate<br />*/<br />public void setUpdatedDate(java.util.Date updatedDate){<br /> this.updatedDate = updatedDate;<br />}<br /><br />/**<br />* Return the value of the UPDATED_NAME column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getUpdatedName(){<br /> return this.updatedName;<br />}<br /><br />/**<br />* Set the value of the UPDATED_NAME column.<br />* @param updatedName<br />*/<br />public void setUpdatedName(java.lang.String updatedName){<br /> this.updatedName = updatedName;<br />}<br /><br />/**<br />* Return the value of the ROUTING_NUMBER column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getRoutingNumber(){<br /> return this.routingNumber;<br />}<br /><br />/**<br />* Set the value of the ROUTING_NUMBER column.<br />* @param routingNumber<br />*/<br />public void setRoutingNumber(java.lang.String routingNumber){<br /> this.routingNumber = routingNumber;<br />}<br /><br />/**<br />* Return the value of the ADDRESS_TYPE column.<br />* @return java.lang.String<br />*/<br />public java.lang.String getAddressType(){<br /> return this.addressType;<br />}<br /><br />/**<br />* Set the value of the ADDRESS_TYPE column.<br />* @param addressType<br />*/<br />public void setAddressType(java.lang.String addressType){<br /> this.addressType = addressType;<br />}<br /><br />/**<br />* @return the trackChanges<br />*/<br />public Boolean getTrackChanges(){<br /> return trackChanges;<br />}<br /><br />/**<br />* @param trackChanges the trackChanges to set<br />*/<br />public void setTrackChanges(Boolean trackChanges){<br /> this.trackChanges = trackChanges;<br />}<br /><br />/**<br />* Return the non-persistent property<br />* @return the propertyChanged<br />*/<br />public Boolean getPropertyChanged() {<br /> return propertyChanged;<br />}<br /><br />/**<br />* Sets the non-persistent property<br />* @param propertyChanged the propertyChanged to set<br />*/<br />public void setPropertyChanged(Boolean propertyChanged) {<br /> this.propertyChanged = propertyChanged;<br />}<br /><br />/**<br />* Implementation of the equals comparison on the basis of<br />* equality of the primary key values.<br />* @param rhs<br />* @return boolean<br />*/<br />public boolean equals(Object rhs){<br /> if (rhs == null)<br /> return false;<br /> if (! (rhs instanceof GeographicAddresses))<br /> return false;<br /> GeographicAddresses that = (GeographicAddresses) rhs;<br /><br /> if (this.getAddressType() != null && that.getAddressType() != null){<br /> if (!this.getAddressType().equals(that.getAddressType())){<br /> return false;<br /> }<br /> }<br /> return true;<br />}<br /><br />/**<br />* Implementation of the hashCode method conforming to the Bloch<br />* pattern with the exception of array properties (these are<br />* very unlikely primary key types).<br />* @return int<br />*/<br />public int hashCode(){<br /> if (this.hashValue == 0){<br /> int result = 17;<br /> int addressTypeValue = this.getAddressType() == null ? 0 :<br /> this.getAddressType().hashCode();<br /> result = result * 37 + addressTypeValue;<br /> this.hashValue = result;<br /> }<br /> return this.hashValue;<br />}</blockquote><br /><br />}<br /></pre></blockquote><br /><br /></div><br /><br /><span style="color: rgb(0, 0, 0);">Now we have identified the domain objects whose properties need to be tracked whenever they get updated by the user.</span><br /><br /><span style="color: rgb(0, 0, 0);">Our crosscutting concern is the notification of changes to Java bean properties. JavaBeans can have bound properties. This means we can register listeners to get notification when the value of the property changes. The java.beans package contains the classes and interfaces required to implement this functionality. The registered listener can implement the methods to record who updated the record and when the record is updated before saving the updated bean information in the database. We are going to use AspectJ, the leading AOP (Aspect Oriented Programming) implementation to address the above mentioned crosscutting concern.</span><br /><br /><span style="color: rgb(0, 0, 0);">Aspect-oriented programming complements object-oriented programming in many ways.</span><br /><span style="color: rgb(0, 0, 0);">One interesting complementary feature is behavior composability. This means it should be possible to compose a class by adding behavior from different classes. OO uses inheritance and many patterns to add behavior to existing classes. AOP allows us to use mixins without changing the class inheritance hierarchy or otherwise changing the code.</span><br /><br /><span style="font-style: italic; color: rgb(0, 0, 0);">Example: BeanTrackChangesAspect.aj</span><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; color: rgb(0, 0, 0); font-family: courier new; font-size: 12px; background-color: lightgray;"><br /><blockquote><pre><br />package com.vbose.aop;<br /><br />import java.beans.PropertyChangeEvent;<br />import java.beans.PropertyChangeListener;<br />import java.beans.PropertyChangeSupport;<br />import java.lang.reflect.Method;<br /><br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />import com.vbose.domain.Contacts;<br />import com.vbose.domain.GeographicAddresses;<br />import com.vbose.domain.Users;<br /><br />/**<br />* BeanTrackChangesAspect.aj - This aspect is used to addresses the cross-cutting<br />* concern of the notification of changes to the Java bean properties.<br />* @author Vigil Bose<br />*/<br />public aspect BeanTrackChangesAspect {<br /><br /><blockquote>private final Log logger = LogFactory.getLog(getClass());<br /><br />/**Introduces a new data member variable called support **/<br />PropertyChangeSupport PropertySupport.support = new<br /> PropertyChangeSupport(this);<br />/**<br />* In this mixin implementation BeanTrackChangesAspect,<br />* the behavior that is to be composed with the JavaBean is<br />* declared as an interface in our aspect.<br />*/<br />public interface PropertySupport{<br /><br />/**<br />* Interface API addPropertyChangeListener() is used to<br />* add a PropertyChangeListener to the listener list.<br />* @param listener - The PropertyChangeListener<br />*/<br />public void addPropertyChangeListener(PropertyChangeListener listener);<br /><br />/**<br />* Interface API addPropertyChangeListener() is used to<br />* add a PropertyChangeListener for a specific property.<br />* @param propertyName - The property of the bean<br />* @param listener - The PropertyChangeListener<br />*/<br />public void addPropertyChangeListener(String propertyName,<br /> PropertyChangeListener listener);<br /><br />/**<br />* Interface API removePropertyChangeListener() is used to<br />* remove a PropertyChangeListener for a specific property.<br />* @param propertyName - The property of the bean<br />* @param listener - The PropertyChangeListener<br />*/<br />public void removePropertyChangeListener(String propertyName,<br /> PropertyChangeListener listener);<br /><br />/**<br />* Interface API removePropertyChangeListener() is used to<br />* remove a PropertyChangeListener from the listener list.<br />* @param listener - The PropertyChangeListener<br />*/<br />public void removePropertyChangeListener(PropertyChangeListener listener);<br /><br />/**<br />* Interface API hasListeners() is used to check if there<br />* are any listeners for a specific property.<br />* @param propertyName - The property of the bean<br />*/<br />public void hasListeners(String propertyName);<br /><br />/**<br />* Interface API firePropertyChange() is used to report<br />* a bound property update to any registered listeners.<br />* @param source - The source bean whose property has been changed<br />* @param property - The property of the bean<br />* @param oldval - The old value of the property<br />* @param newval - The new value of the property<br />*/<br />public void firePropertyChange(Object source,<br /> String property,<br /> Object oldval,<br /> Object newval );<br />}<br /><br />/**<br />* In the following code, we are introducing a super-interface<br />* that our beans Users domain object implements<br />*/<br />declare parents: Users implements PropertySupport;<br /><br />/**<br />* In the following code, we are introducing a super-interface<br />* that our beans Contacts domain object implements<br />*/<br />declare parents: Contacts implements PropertySupport;<br /><br />/**<br />* In the following code, we are introducing a super-interface<br />* that our beans GeographicAddresses domain object implements<br />*/<br />declare parents: GeographicAddresses implements PropertySupport;<br /><br />/**<br />* Add a PropertyChangeListener to the listener list.<br />* @param listener - The PropertyChangeListener<br />*/<br />public void PropertySupport.addPropertyChangeListener<br /> (PropertyChangeListener listener){<br /><br /> support.addPropertyChangeListener(listener);<br />}<br /><br />/**<br />* Add a PropertyChangeListener for a specific property.<br />* @param propertyName - The property of the bean<br />* @param listener - The PropertyChangeListener<br />*/<br />public void PropertySupport.addPropertyChangeListener<br /> ( String propertyName, PropertyChangeListener listener){<br /><br /> support.addPropertyChangeListener( propertyName,listener);<br />}<br /><br />/**<br />* Remove a PropertyChangeListener for a specific property.<br />* @param propertyName - The property of the bean<br />* @param listener - The PropertyChangeListener<br />*/<br />public void PropertySupport.removePropertyChangeListener<br /> ( String propertyName,PropertyChangeListener listener){<br /><br /> support.removePropertyChangeListener( propertyName,listener);<br />}<br /><br />/**<br />* Remove a PropertyChangeListener from the listener list.<br />* @param listener - The PropertyChangeListener<br />*/<br />public void PropertySupport.removePropertyChangeListener<br /> (PropertyChangeListener listener) {<br /><br /> support.removePropertyChangeListener(listener);<br />}<br /><br />/**<br />* Check if there are any listeners for a specific property.<br />* @param propertyName - The property of the bean<br />*/<br />public void PropertySupport.hasListeners(String propertyName){<br /><br /> support.hasListeners(propertyName);<br />}<br /><br />/**<br />* Report a bound property update to any registered listeners.<br />* @param source - The source bean whose property has been changed<br />* @param property - The property of the bean<br />* @param oldval - The old value of the property<br />* @param newval - The new value of the property<br />*/<br />public void PropertySupport.firePropertyChange(Object source,<br /> String property,<br /> Object oldval,<br /> Object newval) {<br /><br />PropertyChangeEvent propertyChangeEvent =<br /> new PropertyChangeEvent(users, property,<br /> ( oldval == null ? oldval : oldval.toString()),<br /> (newval == null ? newval : newval.toString()));<br /><br /> support.firePropertyChange(propertyChangeEvent);<br />}<br /><br />/**<br />* Named Point cut usersSetter. A named pointcut declaration means<br />* that in the around advice that follows, we can use the name of<br />* the pointcut and we need not repeat the pointcut definition.<br />* The pointcut definition call( public * *..Users.set*(*) )&&<br />* target( users ) picks out any call to all setter methods<br />* regardless of the arguments passed to the setter.<br />* We see that this named pointcut also takes a parameter of the<br />* type Users, which means that every join point picked out by this<br />* makes available an object of this type. This is also called the<br />* exposed context. This parameter is available inside of any advice<br />* that uses this pointcut, as we can see in the code.<br />* The target( users ) means that the pointcut definition applies if<br />* the target of the method call joinpoint is a Users. It should be<br />* noted that users on the right side matches the parameter type<br />* Users on the left side. This point cut also restricts the advice<br />* from acting on the join point by a conditional expression and a<br />* bunch of setters that are omitted.<br />* The assigned value can be exposed with an args pointcut<br />*/<br />pointcut usersSetter(Users users):<br /> if (users.getTrackChanges().booleanValue()) &&<br /> call(public * *..Users.set*(*)) &&<br /> !call(public * *..Users.setPropertyChanged(*)) &&<br /> !call(public * *..Users.setUsername(*)) &&<br /> !call(public * *..Users.setCreatedDate(*)) &&<br /> !call(public * *..Users.setCreatedName(*)) &&<br /> !call(public * *..Users.setUpdatedName(*)) &&<br /> !call(public * *..Users.setUpdatedDate(*)) &&<br /> !call(public * *..Users.setContactsSet(*)) &&<br /> target(users);<br /><br /><br />/**<br />* Named Point cut contactsSetter. A named pointcut declaration<br />* means that in the around advice that follows, we can use the<br />* name of the pointcut and we need not repeat the pointcut<br />* definition. The pointcut definition<br />* call( public * *..Contacts.set*(*) )&& target( contacts )<br />* picks out any call to all setter methods regardless of the<br />* arguments passed to the setter.<br />*/<br />pointcut contactsSetter(Contacts contacts):<br />if (contacts.getTrackChanges().booleanValue()) &&<br /> call(public * *..Contacts.set*(*)) &&<br /> !call(public * *..Contacts.setPropertyChanged(*)) &&<br /> !call(public * *..Contacts.setCreatedDate(*)) &&<br /> !call(public * *..Contacts.setCreatedName(*)) &&<br /> !call(public * *..Contacts.setUpdatedName(*)) &&<br /> !call(public * *..Contacts.setUpdatedDate(*)) &&<br /> !call(public * *..Contacts.setGeographicAddressesSet(*)) &&<br /> target(contacts);<br /><br />/**<br />* Named Point cut geogrpahicAddressesSetter. A named pointcut<br />* declaration means that in the around advice that follows,<br />* we can use the name of the pointcut and we need not repeat<br />* the pointcut definition. The pointcut definition<br />* call( public * *..GeographicAddresses.set*(*) )&&<br />* target( geographicAddresses ) picks out any call to<br />* all setter methods regardless of the arguments passed<br />* to the setter.<br />*/<br />pointcut geogrpahicAddressesSetter(GeographicAddresses geographicAddresses):<br /> if (geographicAddresses.getTrackChanges().booleanValue()) &&<br /> call(public * *..GeographicAddresses.set*(*)) &&<br /> !call(public * *..GeographicAddresses.setPropertyChanged(*)) &&<br /> !call(public * *..GeographicAddresses.setCreatedDate(*)) &&<br /> !call(public * *..GeographicAddresses.setCreatedName(*)) &&<br /> !call(public * *..GeographicAddresses.setUpdatedName(*)) &&<br /> !call(public * *..GeographicAddresses.setUpdatedDate(*)) &&<br /> target(geographicAddresses);<br /><br />/**<br />* Around advice runs in place of the join point it operates<br />* over, rather than before or after it. Because around is allowed<br />* to return a value, it must be declared with a return type,<br />* like a method. Even though our around advice substitutes our<br />* join point, we can still call the original functionality by<br />* using the proceed method Around advice.<br />* The main point here is that every time the setter method is<br />* called, our advice takes a copy of the value of the property,<br />* lets the original method proceed, and, after the new value is<br />* set, calls the firePropertyChange method. Now we see that the<br />* code to be introduced to our beans has been separated cleanly<br />* and is now reusable.<br />* @param users - The Users domain<br />*/<br />void around(Users users): usersSetter(users) {<br /><br /> String propertyName = thisJoinPointStaticPart.getSignature().<br /> getName().substring("set".length());<br /> String getMethodName = "get"+propertyName;<br /><br /> Method method = null;<br /> try{<br /><br /> method = Users.class.getMethod(getMethodName, null);<br /> Object oldValue = method.invoke(users, null);<br /><br /> proceed(users);<br /><br /> Object newValue = method.invoke(users, null);<br /> users.firePropertyChange(users,<br /> propertyName,<br /> oldValue,<br /> newValue);<br /><br /><br /> }catch (Exception e){<br /> logger.error("An exception occured while getting the method" +<br /> " name of the property :"+propertyName, e);<br /> e.printStackTrace();<br /> }<br />}<br /><br />/**<br />* Around advice runs in place of the join point it operates over,<br />* rather than before or after it. Because around is allowed<br />* to return a value, it must be declared with a return type, like<br />* a method. Even though our around advice substitutes our<br />* join point, we can still call the original functionality by<br />* using the proceed method Around advice.<br />* The main point here is that every time the setter method is<br />* called, our advice takes a copy of the value of the property,<br />* lets the original method proceed, and, after the new value is<br />* set, calls the firePropertyChange method. Now we see that the<br />* code to be introduced to our beans has been separated cleanly<br />* and is now reusable.<br />* @param contacts - The Contacts domain<br />*/<br />void around(Contacts contacts): contactsSetter(contacts) {<br /><br /> String propertyName = thisJoinPointStaticPart.getSignature().<br /> getName().substring("set".length());<br /> String ge tMethodName = "get"+propertyName;<br /><br /> Method method = null;<br /> try{<br /><br /> method = Contacts.class.getMethod(getMethodName, null);<br /> Object oldValue = method.invoke(contacts, null);<br /><br /> proceed(contacts);<br /><br /> Object newValue = method.invoke(contacts, null);<br /> contacts.firePropertyChange(contacts,<br /> propertyName,<br /> oldValue,<br /> newValue);<br /><br /><br /> }catch (Exception e){<br /> logger.error("An exception occured while getting the method " +<br /> "name of the property :"+propertyName, e);<br /> e.printStackTrace();<br /> }<br />}<br /><br />/**<br />* Around advice runs in place of the join point it operates over,<br />* rather than before or after it. Because around is allowed<br />* to return a value, it must be declared with a return type, like<br />* a method. Even though our around advice substitutes our<br />* join point, we can still call the original functionality by<br />* using the proceed method Around advice.<br />* The main point here is that every time the setter method is<br />* called, our advice takes a copy of the value of the property,<br />* lets the original method proceed, and, after the new value is<br />* set, calls the firePropertyChange method. Now we see that the<br />* code to be introduced to our beans has been separated cleanly<br />* and is now reusable.<br />* @param geographicAddresses - The GeographicAddresses domain<br />*/<br />void around(GeographicAddresses geographicAddresses):<br /> geogrpahicAddressesSetter(geographicAddresses) {<br /><br /> String propertyName = thisJoinPointStaticPart.getSignature().<br /> getName().substring("set".length());<br /> String getMethodName = "get"+propertyName;<br /><br /> Method method = null;<br /> try{<br /><br /> method = GeographicAddresses.class.getMethod(getMethodName, null);<br /> Object oldValue = method.invoke(geographicAddresses, null);<br /><br /> proceed(geographicAddresses);<br /><br /> Object newValue = method.invoke(geographicAddresses, null);<br /> geographicAddresses.firePropertyChange(geographicAddresses,<br /> propertyName,<br /> oldValue,<br /> newValue);<br /><br /><br /> }catch (Exception e){<br /> logger.error("An exception occured while getting the method " +<br /> "name of the property :"+propertyName, e);<br /> e.printStackTrace();<br /> }<br />}</blockquote><br />}<br /></pre></blockquote><br /><br /></div><br /><br /><span style="color: rgb(0, 0, 0);">The BeanTrackChangesAspect.aj file is self explanatory as it contains a lot of comments. This one AOP aspect adds behavior and additional methods to our Java Beans (domain objects). AOP language is invaluable in solving many problems. Let us analyze the internals of BeanTrackChangesAspect.aj file. It has references to the following properties.<br /><br /></span><ul style="color: rgb(0, 0, 0);"><li><span style="color: rgb(0, 0, 0);">PropertyChangeSupport - A </span> utility class that can be used by beans that support bound properties. You can use an instance of this class as a member field of your bean and delegate various work to it. This class is serializable.</li></ul><ul style="color: rgb(0, 0, 0);"><li><span style="color: rgb(0, 0, 0);">PropertySupport - This is the inter-type declaration. The behavior that needs to be composed in each of the domain object is declared as an interface. </span>Declaring additional methods or fields on behalf of a type is called "Introductions". It is also known as an inter-type declaration in the AspectJ community.</li></ul><ul style="color: rgb(0, 0, 0);"><li><span style="color: rgb(0, 0, 0);">declare parents: Users implements PropertySupport - This "declare parents" applies the PropertySupport interface to Users domain object. In other words, it makes the Users domain object implement the PropertySupport interface.</span><span style="color: rgb(0, 0, 0);"> The other declare statements works the same way for other respective domain objects. The PropertySupport methods are implemented in the </span>BeanTrackChangesAspect.aj files for each domain object.</li></ul><ul style="color: rgb(0, 0, 0);"><li><span style="color: rgb(0, 0, 0);">Join Point - </span>a point during the execution of a program, such as the execution of a method or the handling of an exception.</li></ul><ul style="color: rgb(0, 0, 0);"><li><span style="color: rgb(0, 0, 0);">Pointcut - </span>a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP</li></ul><ul style="color: rgb(0, 0, 0);"><li><span style="color: rgb(0, 0, 0);">Around Advice - </span>Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its own return value or throwing an exception.</li></ul><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);">In the around advice, the AOP aspect keep track of old value and new value of the bean properties and fire an existing PropertyChangeEvent to any registered listeners. No event is fired if the given event's old and new values are equal and non-null.<br /><br />The AOP pointcut implementation shown above uses a conditional expression to check whether <span style="font-weight: bold;">"trackChanges"</span> property is set prior to let the advice execute the joinpoint. The "trackChanges" property is set by our unit test prior to call the update on the respective domain object. This way we can control the behavior of the advice.<br /></span><br />Now, let us look at the listener implementation that gets notified of the property changes.<br /><br /><span style="font-style: italic;">Example: BeanTrackChangesListener.java</span><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray; color: rgb(0, 0, 0);"><br /><blockquote><pre><br />package com.vbose.listener;<br /><br />import java.beans.PropertyChangeEvent;<br />import java.beans.PropertyChangeListener;<br /><br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />import com.vbose.domain.Contacts;<br />import com.vbose.domain.GeographicAddresses;<br />import com.vbose.domain.Users;<br /><br />/**<br />* BeanTrackChangesListener.java - An implementation of PropertyChangeListener<br />* interface. A "PropertyChange" event gets fired whenever a bean changes a<br />* "bound" property. You can register a PropertyChangeListener with a source<br />* bean so as to be notified of any bound property updates.<br />* @author Vigil Bose<br />*/<br />public class BeanTrackChangesListener implements PropertyChangeListener {<br /><br /><blockquote>private final Log logger = LogFactory.getLog(getClass());<br /><br />/**<br />* The API propertyChange() is triggered when the listener<br />* detects changes to the properties of the bean.<br />*/<br />public void propertyChange(PropertyChangeEvent evt) {<br /><br /> Object object = evt.getSource();<br /> if (evt.getOldValue() != null || evt.getNewValue() != null){<br /> if (object instanceof Users){<br /><br /> Users users = (Users)object;<br /> users.setPropertyChanged(new Boolean(true));<br /> users.setUpdatedName("vbose");<br /> users.setUpdatedDate(new java.util.Date());<br /><br /> printPropertyChanges(evt);<br /><br /> }<br /> if (object instanceof Contacts){<br /><br /> Contacts contacts = (Contacts)object;<br /> contacts.setPropertyChanged(new Boolean(true));<br /> contacts.setUpdatedName("vbose");<br /> contacts.setUpdatedDate(new java.util.Date());<br /><br /> printPropertyChanges(evt);<br /><br /> }<br /> if (object instanceof GeographicAddresses){<br /><br /> GeographicAddresses geographicAddresses = (GeographicAddresses)object;<br /> geographicAddresses.setPropertyChanged(new Boolean(true));<br /> geographicAddresses.setUpdatedName("vbose");<br /> geographicAddresses.setUpdatedDate(new java.util.Date());<br /><br /> printPropertyChanges(evt);<br /><br /> }<br /> }<br />}<br /><br />/**<br />* The printPropertyChanges() is used to print the property<br />* changes in the log file configured.<br />* @param evt - The PropertyChangeEvent.<br />*/<br />private void printPropertyChanges(PropertyChangeEvent evt) {<br /><br /> logger.info("Property [" +<br /> evt.getPropertyName() +<br /> "] changed from {" +<br /> evt.getOldValue() + "} to {" +<br /> evt.getNewValue() +"}");<br /> }</blockquote><br />}<br /></pre></blockquote><br /></div><br /><br /><span style="color: rgb(0, 0, 0);">In the listener implementation, the updated by and updated date properties are set. In the example shown above, the updated by property is hard coded. In reality, this value should come from the currently logged in user who modifies the record. Such information can be obtained from the SecurityContext once the user is authenticated. The listener sets the <span style="font-weight: bold;">"propertyChanged"</span> property on the respective domain object in addition to the updated by and updated date properties. This provides a hook to the service layer to further control the subsystem processing when the properties of the domain object are changed. This may even include notifying other systems about the change in the properties of the respective domain object.<br /><br />Now, let us look at what Spring framework and Hibernate does in completing the use case and help us execute the unit tests.</span><br /><br /><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;">Spring Framework</span> - Spring is a lightweight application framework. Spring helps structure the whole application in a consistent and productive manner. The inversion of control container enables sophisticated configuration management of POJOs (Plain Old Java Objects). Some of the benefits of using Spring framework are :</span><br /><ol style="color: rgb(0, 0, 0);"><li>Spring focuses around providing a way to manage the business objects.<br /></li><li>Spring is an ideal framework for test driven projects.<br /></li><li>Spring provides a consistent framework for data access, whether using JDBC or an O/R mapping product such as TopLink, Hibernate or a JDO implementation</li><li>Spring 2.0 provides tighter integration with AspectJ AOP language.</li><li>.....<br /></li></ol></span><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);">In this use case example, I have primarily used a business service and a data access service to support the integration test that are configured in Spring application context file.</span></span><br /><span style="color: rgb(0, 0, 0);"><br /><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;">Hibernate</span> - Spring framework provides first class integration with Hibernate like any other ORM tools. Hibernate is used in this use case example for data persistence. Spring provides abstract templates that deals with the low level plumbing of ORM tools. However, in this use case example, I will show the usage of template less data access strategy using Hibernate.</span><br /><br /><pre style="color: rgb(0, 0, 0);"><span style="font-style: italic;">Example: IUsersService.java</span></pre><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray; color: rgb(0, 0, 0);"><br /><blockquote><pre><br />package com.vbose.bus;<br /><br />import com.vbose.domain.Users;<br /><br />/**<br />* A simple java business service interface that exposes<br />* the service APIs to create and update the user information.<br />* @author Vigil Bose<br />*/<br />public interface IUsersService {<br /><blockquote><br />/**<br />* The API createUser() is used to create the user<br />* information in the database<br />* @param users - The users domain object<br />*/<br />public void createUser(Users users);<br /><br />/**<br />* The API updateUser() is used to update the user profile<br />* information in the database<br />* @param users - The users domain object<br />*/<br />public void updateUser(Users users);<br /></blockquote><br />}<br /></pre></blockquote><br /></div><br /><br />The unit test will invoke the createUser in IUsersService interface API to create the user. The test also invokes the updateUser API to update the user information.<br /><pre><span style="font-style: italic; color: rgb(0, 0, 0);">Example: UsersServiceImpl.java</span></pre><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray; color: rgb(0, 0, 0);"><br /><blockquote><pre><br />package com.vbose.bus.impl;<br /><br />import com.vbose.bus.IUsersService;<br />import com.vbose.bus.dao.IUsersServiceDao;<br />import com.vbose.domain.Users;<br /><br />/**<br />* UsersServiceImpl.java - The java service implementation that<br />* implements the APIs to create and update the user information<br />* @author Vigil Bose<br />*/<br />public class UsersServiceImpl implements IUsersService {<br /><br /><blockquote>private IUsersServiceDao usersServiceDao;<br /><br />/**<br />* A setter method of dependency injection<br />* @param usersServiceDao the usersServiceDao to set<br />*/<br />public void setUsersServiceDao(IUsersServiceDao usersServiceDao) {<br /> this.usersServiceDao = usersServiceDao;<br />}<br /><br />/**<br />* The API createUser() is used to create the user<br />* information in the database<br />* @param users - The users domain object<br />* @see com.vbose.bus.IUsersService#createUser(com.vbose.domain.Users)<br />*/<br />public void createUser(Users users) {<br /> this.usersServiceDao.createUser(users);<br />}<br /><br />/**<br />* The API updateUser() is used to update the user profile<br />* information in the database<br />* @param users - The users domain object<br />* @see com.vbose.bus.IUsersService#updateUser(com.vbose.domain.Users)<br />*/<br />public void updateUser(Users users) {<br /> this.usersServiceDao.updateProfile(users);<br />}</blockquote><br /><br />}<br /></pre></blockquote><br /></div><br />The usersServiceImpl delegates the call to the collaborating data access object whose dependency is injected by Spring.<br /><br /><pre><span style="font-style: italic; color: rgb(0, 0, 0);">Example: IUsersServiceDao.java</span></pre><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray; color: rgb(0, 0, 0);"><br /><blockquote><pre><br />package com.vbose.bus.dao;<br /><br />import org.springframework.dao.DataAccessException;<br />import com.vbose.domain.Users;<br /><br />/**<br />* IUsersServiceDao.java - The data access strategy interface that exposes API's<br />* to create and update user information in the database<br />* @author Vigil Bose<br />*/<br />public interface IUsersServiceDao {<br /><blockquote><br />/**<br />* The data access API createUser() is used to create user information<br />* in the database<br />* @param users - The users domain instance<br />* @throws DataAccessException<br />*/<br />public void createUser(Users users) throws DataAccessException;<br /><br />/**<br />* The data access API updateProfile() is used to update the user profile<br />* in the database<br />* @param users - The users domain instance<br />* @throws DataAccessException<br />*/<br />public void updateProfile(Users users) throws DataAccessException;<br /><br />/**<br />* The API findUsersByUserName() is used to retrieve the Users<br />* information for the given username<br />* @param username - The unique identifier of the Users domain instance<br />* @return - An instance of Users domain instance.<br />* @throws DataAccessException<br />*/<br />public Users findUsersByUserName(String username) throws DataAccessException;<br /></blockquote><br />}<br /></pre></blockquote><br /></div><br /><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><br /></span></span></span><span style="color: rgb(0, 0, 0);">The finder API defined in the data access interface is used to fetch the user information from the database. Let us now see the implementation of IUsersServiceDao interface below.</span><br /><br /><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 0);"><span><pre><span style="font-weight: bold;"></span><pre><span style="font-style: italic; color: rgb(0, 0, 0);">Example: UsersServiceDaoImpl.java</span></pre><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray; color: rgb(0, 0, 0);"><br /><blockquote><pre><br />package com.vbose.bus.dao.impl;<br /><br />import java.util.List;<br /><br />import org.hibernate.Query;<br />import org.hibernate.SessionFactory;<br />import org.springframework.dao.DataAccessException;<br /><br />import com.vbose.bus.dao.IUsersServiceDao;<br />import com.vbose.domain.Users;<br /><br />/**<br />* UsersServiceDaoImpl.java - The Hibernate data access strategy<br />* implementation that implements the APIs to create and update<br />* the user information in the database.<br />* @author Vigil Bose<br />*/<br />public class UsersServiceDaoImpl implements IUsersServiceDao {<br /><br /><blockquote>private SessionFactory fatcory;<br /><br />/**<br />* A constructor dependency injection<br />*/<br />public UsersServiceDaoImpl(SessionFactory factory){<br /> this.fatcory = factory;<br />}<br /><br />/**<br />* The data access API createUser() is used to create<br />* user information in the database<br />* @param users - The users domain instance<br />* @throws DataAccessException<br />*/<br />public void createUser(Users users) throws DataAccessException {<br /> this.fatcory.getCurrentSession().save(users);<br />}<br /><br />/**<br />* The data access API updateProfile() is used to<br />* update the user profile in the database<br />* @param users - The users domain instance<br />* @throws DataAccessException<br />*/<br />public void updateProfile(Users users) throws DataAccessException {<br /> this.fatcory.getCurrentSession().saveOrUpdate(users);<br />}<br /><br />/**<br />* The API findUsersByUserName() is used to retrieve the<br />* Users information for the given username<br />* @param username - The unique identifier of the Users domain instance<br />* @return - An instance of Users domain instance.<br />* @throws DataAccessException<br />*/<br />public Users findUsersByUserName(String username) throws DataAccessException {<br /><br /> Query query = this.fatcory.getCurrentSession().<br /> getNamedQuery("com.vbose.domain.Users.findUsersByUserName")<br /> .setParameter("username", username);<br /><br /> List list = query.list();<br /> return (list != null && list.size()> 0 ? (Users)list.get(0) : null);<br />}</blockquote><br /><br />}<br /></pre></blockquote></div></pre><br /><b style="color: rgb(0, 0, 0);">Resource management</b><br /><br /><span style="color: rgb(0, 0, 0);">With Hibernate 3.0.1, Spring is able to manage Hibernate Session without having to go through the Hibernate Session. Spring is able to manage the underlying resource without using templates that are available for those technologies. This is true for JPA (Java Persistence API) as well. What this means is that even if we use the Hibernate API directly (SessionFactory.getCurrentSession()), we will still be using a Spring managed Hibernate Session. This is true for EntityManager obtained through a JPA EntityManagerFactory as well.</span><br /><br /><span style="color: rgb(0, 0, 0);">The one thing that was missing was the exception translation. However we can still enjoy automatic exception translation using AOP, if using Hibernate in an environment where annotations are not available (example: J2sdk 1.4.x) by first declare an exception translator and then declare a piece of AOP configuration, like so in the following way:</span><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray; color: rgb(0, 0, 0);"><br /><blockquote><pre><br /><bean id="persistenceExceptionInterceptor"<br />class="org.springframework.dao.support.PersistenceExceptionTranslationInterceptor"/><br /><br /><aop:config><br /><aop:advisor pointcut="execution(public * *..IUsersServiceDao.*(..))"<br /> advice-ref="persistenceExceptionInterceptor"/><br /></aop:config><br /><br />In Java 5 where we can use annotations, use the following bean instead...<br /><br /><bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/><br /></pre><br /></blockquote><br /></div><br /><br /><span style="font-weight: bold;"><span style="color: rgb(0, 0, 0);">Putting Things Together</span><br /><br /></span><span style="color: rgb(0, 0, 0);">Let us now wire everything in the Spring application context file such that we can run the tests to track the Bean changes.<br /><br /></span><pre><span style="font-style: italic; color: rgb(0, 0, 0);">Example: bean-track-context.xml</span></pre><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray; color: rgb(0, 0, 0);"><br /><blockquote><pre><br /><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans"<br />xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xmlns:aop="http://www.springframework.org/schema/aop"<br />xmlns:tx="http://www.springframework.org/schema/tx"<br />xmlns:util="http://www.springframework.org/schema/util"<br />xsi:schemaLocation="http://www.springframework.org/schema/beans<br />http://www.springframework.org/schema/beans/spring-beans-2.0.xsd<br />http://www.springframework.org/schema/aop<br />http://www.springframework.org/schema/aop/spring-aop-2.1.xsd<br />http://www.springframework.org/schema/tx<br />http://www.springframework.org/schema/tx/spring-tx-2.1.xsd<br />http://www.springframework.org/schema/util<br />http://www.springframework.org/schema/util/spring-util-2.0.xsd"><br /><br /><bean id="propertyConfigurer"<br />class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><br /><property name="locations"><br /> <list><br /> <value>jdbc.properties</value><br /> </list><br /></property><br /></bean><br /><br /><bean id="usersService" class="com.vbose.bus.impl.UsersServiceImpl"><br /> <property name="usersServiceDao" ref="usersServiceDao"/><br /></bean><br /><br /><bean id="usersServiceDao" class="com.vbose.bus.dao.impl.UsersServiceDaoImpl"><br /> <constructor-arg ref="sessionFactory"/><br /></bean><br /><br /><bean id="dataSource"<br /> class="org.springframework.jdbc.datasource.DriverManagerDataSource"><br /> <property name="driverClassName" value="${jdbc.driverClassName}"/><br /> <property name="url" value="${jdbc.url}"/><br /> <property name="username" value="${jdbc.username}"/><br /> <property name="password" value="${jdbc.password}"/><br /></bean><br /><br /><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><br /> <property name="dataSource" ref="dataSource"/><br /></bean><br /><br /><!--<br />Transaction advice definition, based on method name patterns.<br />Defaults to PROPAGATION_REQUIRED for all methods whose name<br />starts with "create" ,"update" etc. By default, the transaction<br />is rolled back for runtime exceptions including DataAccessException.<br />It will not roll back during checked exceptions unless specified<br />in the declaration.<br />--><br /><tx:advice id="usersServiceTransactionAdvice"><br /><tx:attributes><br /> <tx:method name="*" /><br /></tx:attributes><br /></tx:advice><br /><br /><bean id="sessionFactory"<br /> class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><br /><property name="dataSource" ref="dataSource"/><br /><property name="hibernateProperties"><br /><props><br /><prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop><br /> <prop key="hibernate.connection.pool_size">3</prop><br /> <prop key="hibernate.show_sql">false</prop><br /> <prop key="hibernate.max_fetch_depth">3</prop><br /></props><br /></property><br /><property name="mappingResources"><br /><list><br /> <value>com/vbose/domain/Users.hbm.xml</value><br /> <value>com/vbose/domain/LuUserStatusCodes.hbm.xml</value><br /> <value>com/vbose/domain/LuStatusReasonCodes.hbm.xml</value><br /> <value>com/vbose/domain/Contacts.hbm.xml</value7gt;<br /> <value>com/vbose/domain/LuContactTypes.hbm.xml</value><br /> <value>com/vbose/domain/GeographicAddresses.hbm.xml</value><br /> <value>com/vbose/domain/LuCountyCodes.hbm.xml</value><br /> <value>com/vbose/domain/LuCountryCodes.hbm.xml</value><br /></list><br /></property><br /></bean><br /><br /><bean id="transactionManager"<br /> class="org.springframework.orm.hibernate3.HibernateTransactionManager"><br /><property name="sessionFactory" ref="sessionFactory" /><br /></bean><br /><br /><bean id="persistenceExceptionInterceptor"<br />class="org.springframework.dao.support.PersistenceExceptionTranslationInterceptor"/><br /><br /><!--<br />Because of a small change in Hibernate 3.0.1, Spring is able to<br />manage the Hibernate session for you,without you having to go through<br />the Hibernate session. The one thing that was missing was the exception<br />translation. To also get that going, you can still enjoy automatic<br />exception translation; using AOP, if using Hibernate in an<br />environment where annotations are not available (pre Java5)<br />by first declare an exception translator and then declare a<br />piece of AOP configuration, like so in the following way.<br />However, the following configuration can be replaced by<br /><br /><bean class="org.springframework.dao.annotation.<br /> PersistenceExceptionTranslationPostProcessor"/><br /><br />if using annotations. --><br /><br /><aop:config><br /><aop:pointcut id="usersServicePointcut"<br /> expression="execution(public * *..IUsersService.*(..))"/><br /><aop:advisor pointcut-ref="usersServicePointcut"<br /> advice-ref="usersServiceTransactionAdvice" order="1"/><br /><br /><aop:advisor pointcut="execution(public * *..IUsersServiceDao.*(..))"<br /> advice-ref="persistenceExceptionInterceptor"/><br /></aop:config><br /><br /><bean id="beanTrackChangesAspect"<br /> class="com.vbose.aop.BeanTrackChangesAspect" factory-method="aspectOf"/><br /><br /><bean id="beanTrackChangeListener"<br /> class="com.vbose.listener.BeanTrackChangesListener"/><br /></beans><br /><br /></pre></blockquote><br /><br /></div><br /><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><br /></span><span><span style="color: rgb(0, 0, 0);">The following figure is the Spring configuration of the managed beans declared in bean-track-context.xml file.</span><br /><br /></span></span><div style="text-align: center;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3GTJ9PQZEFwEqYplwSnPoR38R5jD9WtocnJB6tdMizFyas8TIUfOre-PPIrrP9bB2lXwhRyLJkgXbgfUXk7_CI-HFr-eRcwbVfmRgo5rZrNlW0LxHRr8YaIL32n0MxZlihOwpItbxo5SZ/s1600-h/bean-track-context.PNG"><img style="cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3GTJ9PQZEFwEqYplwSnPoR38R5jD9WtocnJB6tdMizFyas8TIUfOre-PPIrrP9bB2lXwhRyLJkgXbgfUXk7_CI-HFr-eRcwbVfmRgo5rZrNlW0LxHRr8YaIL32n0MxZlihOwpItbxo5SZ/s400/bean-track-context.PNG" alt="" id="BLOGGER_PHOTO_ID_5141886633339305506" border="0" /></a><span style="color: rgb(0, 0, 0);"><br /><span>Figure 2. Spring Application Context<br /><br /></span></span><div style="text-align: left;"><span style="font-weight: bold;"><span style="color: rgb(0, 0, 0);">Testing</span><br /><br /></span><span style="color: rgb(0, 0, 0);">Let us now run the unit test and analyze the results. Spring Mock provides first class abstract templates that facilitates the dependency injection features and can run the tests in transaction. </span><br /><br /><span style="color: rgb(0, 0, 0);">Some of the Spring Mock Tests available from spring-mock.jar are given below:</span><br /><br /><p><span style="font-size:100%;"><strong>Spring Mock Test Classes</strong></span><span style="font-style: italic;"><br /></span></p><p><span style="font-style: italic; font-weight: bold;font-size:85%;" >AbstractDependencyInjectionSpringContextTests</span><span style="font-style: italic; font-weight: bold;font-family:mon;font-size:85%;" >:</span><span style="font-family:monospace;"><br /></span></p><p style="text-align: justify;"><span style=";font-family:monospace;font-size:85%;" > T</span><span style="font-size:85%;">his test class injects test dependencies so we don't need to specifically perform the Spring application context lookups. It also automatically locates the corresponding object in the set of configuration files specified in the <strong>getConfigLocations()</strong> method.</span></p><span style="font-style: italic; font-weight: bold;"><span style="font-size:85%;">AbstractTransactionalDataSourceSpringContextTests: </span></span><span style="font-style: italic;"><br /><br /></span><span style="font-size:85%;">This test class is used to test the code that runs inside a transaction. It creates and rolls back a transaction for each test case. We write code with the assumption that there is a transaction present. It provides the fields such as a <span style="font-weight: bold;">JdbcTemplate</span> that can be used to verify database state after test operations, or verify the results of queries performed by application code. An <span style="font-weight: bold;">ApplicationContext</span> is also inheited, and can be used for explicit lookup if necessary.</span><span style="font-style: italic;"><br /></span><span style="font-style: italic;"><br /><span style="font-weight: bold;font-size:85%;" >AbstractJpaTests: </span><br /><br /></span><span style="font-size:85%;">This test class is used for testing JPA functionality. It provides an <span style="font-weight: bold;">EntityManager</span> instance that we can use to call JPA methods.</span><span style="font-style: italic;"><br /><br /><span style="font-weight: bold;font-size:85%;" >AbstractAspectjJpaTests: </span><br /><br /></span><span style="font-size:85%;">This </span><span><span style="font-size:85%;">class extends from <span style="font-weight: bold;">AbstractJpaTests</span> and it is used for load-time weaving (LTW) purposes using AspectJ. We override the method <span style="font-weight: bold;">getActualAopXmlLocation()</span> to specify the location of AspectJ's configuration xml file. </span><br /><br /><span style="font-style: italic;"><span style="font-weight: bold;font-size:85%;" >AbstractModelAndViewTests:</span><br /><br /></span><span style="font-size:85%;">This is a convenient base class for testing the presentation and controller layers using Sping MVC in the application.<br /><br /><span style="font-size:100%;"><span style="font-size:100%;">We</span><span style="font-size:100%;"> use</span><span style="font-weight: bold;font-size:100%;" > AbstractTransactionalDataSourceSpringContextTests </span>from the above list such that our tests can run within a transaction and provides dependency injection features. The following is the result of executing two JUnit Tests. Since the tests are run within a transaction, the data that is used to populate the domain object prior to the insert and after the update do not affect the state of the database since the transaction is rolled back after the test execution is completed.<br /></span></span><span style="font-style: italic;"><span style="font-style: italic;"></span></span></span><br />1. testPropertyChange()<br /><br /><div style="text-align: center;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr1mAWV8hGY4jgVBXa3m3n4k3hFxNkqBUz04qvJYk6zBQQOhhhCnY-PgojMEGVPtrRhq85Yt_w510kn3jfzcytjYqPWWDftsI6d-NdJx1LkHtYhhsjdXv6FKiFsueJW_QVIwAgVM_YvrZE/s1600-h/bean-track-test.PNG"><img style="cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr1mAWV8hGY4jgVBXa3m3n4k3hFxNkqBUz04qvJYk6zBQQOhhhCnY-PgojMEGVPtrRhq85Yt_w510kn3jfzcytjYqPWWDftsI6d-NdJx1LkHtYhhsjdXv6FKiFsueJW_QVIwAgVM_YvrZE/s400/bean-track-test.PNG" alt="" id="BLOGGER_PHOTO_ID_5141895042885271090" border="0" /></a><br /></div><div style="text-align: center;">Figure 3. Unit Test 1<br /></div></div></div><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><br /><br /></span><span>The red rectangular box in the Figure 3 above indicate the log of the bean properties that are changed and picked up properly by the listener. The blue rectangular box in the figure above indicate the log of the updated by and updated date properties of the beans.<br /><br /><p style="font-style: italic;"><span style="font-size:85%;"> <strong>A snippet of the Unit Test Log of the Listener</strong></span></p><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray;"><br /><blockquote><pre><br />[BeanTrackChangesListener] - <Property [SecretQuestion] changed from {What is your favorite color?} to<br />{What is your favorite dish?}><br />[BeanTrackChangesListener] - <Property [SecretAnswer] changed from {White} to {Seafood}><br />[BeanTrackChangesListener] - <Property [EmailAddress] changed from {vbose@vbose.com} to {vbose@test.com}><br />[BeanTrackChangesListener] - <Property [Title] changed from {Systems Architect} to {Architect}><br />[BeanTrackChangesListener] - <Property [AddressLine1] changed from {Address Line 1} to {1400 GNSI Plaza}><br />[BeanTrackChangesListener] - <Property [City] changed from {City} to {GnsiCity}><br /></pre></blockquote><br /><br /></div><br /><br /><p style="font-style: italic;"><span style="font-size:85%;"> <strong>A snippet of the Unit Test Log After the Updates:</strong></span></p><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray;"><br /><blockquote><pre><br />[BeanTrackChangesListenerTest] - <Updated by in Users : vbose><br />[BeanTrackChangesListenerTest] - <Updated Date in Users : Sun Dec 09 01:35:19 EST 2007><br />[BeanTrackChangesListenerTest] - <Updated by in Contacts : vbose><br />[BeanTrackChangesListenerTest] - <Updated Date in Contacts : Sun Dec 09 01:35:19 EST 2007><br />[BeanTrackChangesListenerTest] - <Updated by in GeographicAddresses : vbose><br />[BeanTrackChangesListenerTest] - <Updated Date in GeographicAddresses : Sun Dec 09 01:35:19 EST 2007><br /></pre></blockquote><br /><br /></div><br /><br /></span><span>2. testPropertyChangeWithoutChanges()<br /><br /><br /></span></span><div style="text-align: center;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggo1olV961pawiC4wtNBwAQsrg0nvxvSvthQ9rLa4aZvrkQU7t8mUQsYvY8aPVyxC9lrTmDyYCSWqS-FyWFk7iFOG6Dvh-6DwUrugpuNzex1woLEtI7RIMsE2XJICcL89-DMKgAwI4vQkt/s1600-h/bean-track-neg-test.PNG"><img style="cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggo1olV961pawiC4wtNBwAQsrg0nvxvSvthQ9rLa4aZvrkQU7t8mUQsYvY8aPVyxC9lrTmDyYCSWqS-FyWFk7iFOG6Dvh-6DwUrugpuNzex1woLEtI7RIMsE2XJICcL89-DMKgAwI4vQkt/s400/bean-track-neg-test.PNG" alt="" id="BLOGGER_PHOTO_ID_5141897082994736722" border="0" /></a><br /></div><div style="text-align: center;">Figure 4. Unit Test 2<br /></div><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><br /><br /></span><span>When the second test is run, the listener did not pick any changes as there are no changes in the bean properties. See the log snippet of the updated by and updated date bean properties.<br /><br /><p style="font-weight: bold; font-style: italic;"><span style="font-size:85%;"> A snippet of the <span style="font-weight: normal;"><strong>Unit Test Log without updating the data:</strong></span></span></p><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px; font-family: courier new; font-size: 12px; background-color: lightgray;"><br /><blockquote><pre><br />[BeanTrackChangesListenerTest] - <Updated by in Users : Null><br />[BeanTrackChangesListenerTest] - <Updated Date in Users : Null><br />[BeanTrackChangesListenerTest] - <Updated by in Contacts : Null><br />[BeanTrackChangesListenerTest] - <Updated Date in Contacts : Null><br />[BeanTrackChangesListenerTest] - <Updated by in GeographicAddresses : Null><br />[BeanTrackChangesListenerTest] - <Updated Date in GeographicAddresses : Null><br /></pre></blockquote><br /><br /></div><br /></span><br /><br /><span style="font-weight: bold;">AspectJ Compiler</span><span style="font-weight: bold;"></span><br /><br /><span style="color: rgb(0, 0, 0);">AspectJ programs can be compiled using ajc (command line compiler) that comes with the AspectJ distribution. The AspectJ Development Tools (AJDT) project provides Eclipse platform based tool support for AOSD with AspectJ. I have used AJDT 1.5 for Eclipse 3.3 released as part of Europa!</span><br /><br /><span style="font-weight: bold;"><span style="color: rgb(0, 0, 0);">Conclusion<br /><br /></span></span><span style="color: rgb(0, 0, 0);">Concerns that crosscut a class which is the fundamental manipulation in Java could be isolated so that such code is not spread out across the codebase. Aspect Oriented Programming makes this possible to separate such crosscutting concerns. This makes the modification easier. It also helps to add a concern without changing the code in a less invasive way. </span><br /><span style="color: rgb(0, 0, 0);"><span style="font-weight: bold;"><br />References</span></span><span style="color: rgb(0, 0, 0);"><br /><br />1. <a href="http://www.eclipse.org/aspectj/doc/released/adk15notebook/index.html">The AspectJ Development Kit</a><br />2. <a href="http://static.springframework.org/spring/docs/2.5.x/reference/index.html">Spring framework Reference Document</a><br />3. <a href="http://www.eclipse.org/aspectj/doc/released/progguide/index.html">The AspectJ Programming Guide</a><br />4. <a href="http://java.sun.com/docs/books/tutorial/javabeans/properties/bound.html">Bound Properties</a><br />5. <a href="http://today.java.net/pub/a/today/2005/12/15/writing-mixins-with-aop.html?page=1">AOP mixin Implementation</a><br /><br /><span style="font-weight: bold;">About The Author</span><span style="font-weight: bold;"><br /><br />Vigil Bose </span>is a Technical and Application Integration Architect at GlobalNet Services Inc, an application and infrastructure solutions provider to US Federal Government and other commercial clients. He primarily focuses on light-weight architectures and open source frameworks to build J2EE solutions for his clients. He 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.</span></span></span></span></span>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com10tag:blogger.com,1999:blog-3710815942271269136.post-91423978044333449092007-12-12T07:54:00.001-08:002008-12-22T19:41:04.735-08:00Installation Procedure of PMD for Eclipse1. Start Eclipse.<br /><br />2. Start the installation procedure : select the Help>Software Updates>Find and Install... menu item.<br /><br />3. Select "Search for new features to install" option and click Next.<br /><br />4. Click New Remote Site...<br /><br />5. Give a name (i.e. PMD Eclipse), enter the URL<br />http://pmd.sourceforge.net/eclipse and hit OK<br /><br />6. Select ‘PMD Eclipse’ in the Sites to include in search list and click Finish.<br /><br />7. Check box before PMD Eclipse in the "Select the features to install" list.<br /><br />8. Expand the PMD Eclipse by clicking on the + sign before it,<br /><br />9. Uncheck the box before the text “Show the latest version of a feature only”<br /><br />10. Check the box with the current Eclipse version, uncheck any other box and click Next.<br /><br />11. Accept the terms of the license agreements and click Next.<br /><br />12. Verify that the install location is your Eclipse installation directory, otherwise select the correct one, click Finish.<br /><br />13. A warning appear telling the feature is not signed. Ignore and click Install to continue.<br /><br />14. Accept to restart the workbench to load PMD into the workbench.<br /><br />URL for usage: <a href="http://www.jacoozi.com/index.php?option=com_content&task=view&id=121&Itemid=134&PHPSESSID=451c384e093fd6430526a5f796f7d750#howtoinstall">Click Here</a>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com5tag:blogger.com,1999:blog-3710815942271269136.post-60980335464411840512007-12-02T17:07:00.001-08:002007-12-02T17:20:16.535-08:00Hibernate Performance tuning Tips - Second-Level and Query CachesI have read an interesting article regarding the Second Level and Query Caches of Hibernate Object Relational Mapping tool.<br /><br />One of the important things that concerns Architects, Technical Leads and Developers is the performance of the mappings between the Database and Java Applications.<br /><br />For those who do would like to know more about the performance-enhancing changes to particular queries and retrievals, please read the following article on <a href="http://www.javalobby.org/java/forums/t48846.html">Hibernate Second Level and Query Cache</a> <a href="http://www.javalobby.org/java/forums/t48846.html"></a>by R. J. Lorimer.<a href="http://www.javalobby.org/forums/profile.jspa?userID=58312" class="author"><br /></a><h4> </h4>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com6tag:blogger.com,1999:blog-3710815942271269136.post-34780378906164238062007-08-15T21:52:00.000-07:002007-08-15T23:05:16.565-07:00EJB3, Spring & Hibernate : A Comparative Study by Reza RehmanI attended a NOVAJUG presentation on EJB3, Spring & Hibernate comparative analysis by <a href="http://www.rahmannet.net/blog/">Reza Rehman</a> who is the co-author of EJB3 In Action by Manning publications . I have used EJB 2.1 in the past and now a heavy user of Spring technologies in all my current projects.<br /><br />The presentation was really helpful and Reza showed a comparative analysis of EJB3, Spring & Hibernate technologies.<br /><br />EJB3 embraces POJO (Plain Old Java Object) programming through annotation. In EJB3, the xml descriptor is made optional. The Object Relational mapping and object queries have been completely defined instead of being left up to the vendors to figure out.<br /><br />EJB 3 makes heavy use of the so called "Intelligent Defaulting" whenever possible which is similar to convention over configuration concept used in Ruby on Rails.<br /><br />Some of the comparative analysis shown by Reza are given below.<br /><br />Use EJB3 if :<br /><br />1. Your application uses annotations and dislike XML configuration.<br />2. Your application is stateful.<br />3. Standardization is an important consideration.<br />4. You use Java Server Faces and are considering using JBoss SEAM framework.<br /><br />Use Spring if:<br /><br />1. Your application requires fine grained control at the container level.<br />2. Your application requires a lot of configuration beyond gluing together components and resources.<br />3. Your application need to build non-standard but powerful solution stack like iBatis, Quartz or Spring Security.<br />4. Your application need advanced Aspect Oriented Programming features.<br /><br />Use Hibernate if:<br /><br />1. You like Hibernate API better than JPA.<br />2. You are unlikely to switch between persistence engines.<br /><br />There is also another good article by Rod Coffin on Side-by-Side Comparison of Spring and EJB 3.0. The article is available <a href="http://www.devx.com/Java/Article/32314/0/page/1">at devx.com.<br /></a>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com5tag:blogger.com,1999:blog-3710815942271269136.post-51488638414175838012007-07-17T09:04:00.000-07:002007-07-17T10:01:49.906-07:00XA Transactions with SpringI have read an interesting article about XA transactions using Spring. This article gives step by step instructions to implement XA transactions using <span style="font-weight: bold;">Atomikos's JTA implementation </span>and <span style="font-weight: bold;">Bitronix's JTA implementation</span>.<br /><br />To learn more about XA, <em>Principles of Transaction Processing</em> is a very good book, which covers the 2PC failure conditions and optimizations in great detail. Also, <a href="http://corfield.org/blog/index.cfm/do/blog.entry/entry/Mike_Spille_on_IoC_Containers__a_lesson_for_all_framework_authors">Mike Spille's blog</a> (see Resources section) is another good resource, which focuses on XA within the JTA context and provides wealth of information, especially on failures during 2PC and helps understand more about XA transactions.<br /><br />Please click <a href="http://www.javaworld.com/javaworld/jw-04-2007/jw-04-xa.html?page=3">XA transactions using Spring</a> to read more about it.<br /><a href="http://www.javaworld.com/javaworld/jw-04-2007/jw-04-xa.html?page=3"><span style="font-weight: bold;"><br /></span></a>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com3tag:blogger.com,1999:blog-3710815942271269136.post-91715659502703134782007-06-26T18:56:00.000-07:002007-06-27T06:50:51.707-07:00Template-less Data Access using SpringAlef Arendsen from Interface21 blogged about the usage of HibernateTemplate/JpaTemplate. In his blog he demonstrates an alternate approach by using the Hibernate Session API directly in the data access code without the need of templates. The recommended approach is also documented in <a href="http://www.springframework.org/docs/api/org/springframework/orm/hibernate3/HibernateTemplate.html">HibernateTemplate </a> and <a href="http://www.springframework.org/docs/api/org/springframework/orm/jpa/JpaTemplate.html">JpaTemplate </a>Javadocs.<br /><br />To access Alef's blog, please click <a href="http://blog.interface21.com/main/2007/06/26/so-should-you-still-use-springs-hibernatetemplate-andor-jpatemplate/">here.</a>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com26tag:blogger.com,1999:blog-3710815942271269136.post-20744131091858507092007-06-24T20:39:00.000-07:002007-06-25T08:34:06.920-07:00Lean Software DevelopmentThe main idea behind Lean is to avoid over production because over production is not only wasteful it prevents rapid response to changing customer demand.<br /><br />The lean initiative in the product development primarily revolves around the concept of eliminating waste and getting quality right the first time. Lean product development is a new concept. This concept is first developed and tested in Toyota's Motor Company design studios and it is a very successful approach that Toyota uses to design new car models. Toyota’s success caused their methods to be studied and imitated by people in many diverse industries, including software development.<br /><br /><span style="font-weight: bold; color: rgb(51, 102, 255);">Lean Software Development Principles</span><br /><br />Lean principles are very important for organization that continuously improve its process. Let's look at the basic principles and practices of Lean, as applied to software development.<br /><br /><span style="color: rgb(51, 102, 255); font-weight: bold;">Eliminate Waste</span><br /><span style=""><span style="font-size:100%;">The three biggest wastes in software development are:</span></span><i><span style=""><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><br /><span style="font-weight: bold;">Extra Features</span><br />We need a process which allows us to develop just those 20% of the features that give 80% of the value.<br /><br /><span style="font-weight: bold;">Churn</span><br />If you have requirements churn, you are specifying too early. If you have test and fix cycles, you are testing too late.<br /><br /><span style="font-weight: bold;">Crossing Boundaries</span><br />Organizational boundaries typically increase cost by over 25%, creating buffers that slow down response time and interfere with communication.<br /><br /></div></span></i><br /><span style="color: rgb(51, 102, 255); font-weight: bold;">Focus On Learning</span></span><i><span style=""><br /></span></i>Planning is useful. Learning is essential.<br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><br /><span style="font-style:italic;"><span style="font-weight:bold;">Use the Scientific method</span><br />Teach teams to: establish hypotheses, conduct many rapid experiments, create concise documentation, and implement the best alternative.</span><br /><br /><span style="font-style:italic;"><span style="font-weight: bold;">Standards Exist to be Challenged and Improved</span><br />Embody the current best known practice in standards that everyone follows, while actively encouraging everyone to challenge and change the standards.</span><br /><br /><span style="font-style:italic;"><span style="font-weight: bold;">Predictable Performance is Driven by Feedback</span><br />A predictable organization does not guess about the future and call it a plan; it develops the capacity to rapidly respond to the future as it unfolds.</span><br /><br /></div><br /><span style="color: rgb(51, 102, 255); font-weight: bold;">Build Quality In</span><br /><span style=""><span style="font-size:100%;">If you routinely find defects in your verification process, your process is defective.</span></span><i><span style=""><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><br /><span style="font-weight: bold;">Mistake-Proof Code with Test-Driven Development</span><br />Write executable specifications instead of requirements.<br /><br /><span style="font-weight: bold;">Stop Building Legacy Code</span><br />Legacy code is code that lacks automated unit and acceptance tests.<br /><br /><span style="font-weight: bold;">The Big Bang is Obsolete</span><br />Use continuous integration and nested synchronization<br /><br /></div><br /></span></i><span style=""><span style="color: rgb(51, 102, 255); font-weight: bold;">Defer Commitment</span><br /><span style=""><span style="font-size:100%;">Abolish the idea that it is a good idea to start development with a complete specification.</span></span></span><i><span style=""><i><span style=""><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><br /><span style="font-weight: bold;">Break Dependencies</span><br />System architecture should support the addition of any feature at any time.<br /><br /><span style="font-weight: bold;">Maintain Options</span><br />Think of code as an experiment – make it change-tolerant.<br /><br /><span style="font-weight: bold;">Schedule Irreversible Decisions at the Last Responsible Moment</span><br />Learn as much as possible before making irreversible decisions.<br /><br /></div><br /></span></i></span></i><span style=""><span style=""><span style="color: rgb(51, 102, 255); font-weight: bold;">Deliver Fast</span><br /><span style=""><span style="font-size:100%;">Lists and queues are buffers between organizations that simply slow things down.</span></span></span></span><i><span style=""><i><span style=""><i><span style=""><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><br /><span style="font-weight: bold;">Rapid Delivery, High Quality, and Low Cost are Fully Compatible</span><br />Companies that compete on the basis of speed have a big cost advantage, deliver superior quality, and are more attuned to their customers' needs.<br /><br /><span style="font-weight: bold;">Queuing Theory Applies to Development, not Just Servers</span><br />Focusing on utilization creates a traffic jams that actually reduces utilization. Drive down cycle time with small batches and fewer things-in-process.<br /><br /><span style="font-weight: bold;">Limit Work to Capacity</span><br />Establish a reliable, repeatable velocity with iterative development. Aggressively limit the size of lists and queues to your capacity to deliver.<br /><br /></div><br /></span></i></span></i></span></i><span style=""><span style=""><span style=""><span style="color: rgb(51, 102, 255); font-weight: bold;">Respect People</span><br /><span style=""><span style="font-size:100%;">Engaged, thinking people provide the most sustainable competitive advantage.</span></span></span></span></span><i><span style=""><i><span style=""><i><span style=""><i><span style=""><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><br /><span style="font-weight: bold;">Teams Thrive on Pride, Commitment, Trust, and Applause</span><br />What makes a team? Members are mutually committed to achieve a common goal.<br /><br /><span style="font-weight: bold;">Provide Effective Leadership</span><br />Effective teams have effective leaders who bring out the best in the team.<br /><br /><span style="font-weight: bold;">Respect Partners</span><br />Allegiance to the joint venture must never create a conflict of interest.<br /><br /></div><br /></span></i></span></i></span></i></span></i><span style=""><span style=""><span style=""><span style=""><span style="color: rgb(51, 102, 255); font-weight: bold;">Optimize the Whole</span></span></span></span></span><i><span style=""><i><span style=""><i><span style=""><i><span style=""><br /></span></i></span></i></span></i></span></i><span style=""><span style=""><span style=""><span style=""><span style=""><span style="font-size:100%;">Brilliant products emerge from a unique combination of opportunity and technology.</span></span></span></span></span></span><i><span style=""><i><span style=""><i><span style=""><i><span style=""><i><span style=""><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><span style="font-weight: bold;">Focus on the Entire Value Stream</span><br />– from concept to cash.<br />– from customer request to deployed software.<br /><br /><span style="font-weight: bold;">Deliver a Complete Product</span><br />Develop a complete product, not just software. Complete products are built by complete teams.<br /><br /><span style="font-weight: bold;">Measure UP</span><br />Measure process capability with cycle time. Measure team performance with delivered business value. Measure customer satisfaction with a net promoter score.<br /><br /></div></span></i></span></i></span></i></span></i></span></i><br />Now, let's look at the agile principles from the agile manifest.<br /><br /><span style="color: rgb(51, 102, 255); font-weight: bold;">Agile Principles</span><br /><br /><div style="border: 1px solid gray; padding: 5px 2px 5px 3px;font-family:courier new;font-size:12px;color:black;"><br />. Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.<br /><br />· Welcome changing requirements, even late in development. Agile processes harness change for the customer's competitive advantage.<br /><br />· Deliver working software frequently, from a couple of weeks to a couple of months, with a preference to the shorter timescale.<br /><br />· Business people and developers must work together daily throughout the project.<br /><br />· Build projects around motivated individuals. Give them the environment and support they need, and trust them to get the job done.<br /><br />· The most efficient and effective method of conveying information to and within a development team is face-to-face conversation.<br /><br />· Working software is the primary measure of progress.<br /><br />· Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely.<br /><br />· Continuous attention to technical excellence and good design enhances agility.<br /><br />· Simplicity--the art of maximizing the amount of work not done--is essential.<br /><br />· The best architectures, requirements, and designs emerge from self-organizing teams.<br /><br />· At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.<br /></div><br />The non-agile world values Process whereas the Agile world values People. Documentation and Traceability are key objectives in the non-agile world and Working Software is the main objective of Agility.<br /><br />The executives lean towards Lean Product Development more readily that they do Agile. This is partly because Agility is expressed in the language of developers, not managers. Lean, on the other hand generally makes sense at all levels from developers up through executive officers. Lean speaks the language of "production" without much regard to what is being produced.<br /><br /><span style="font-weight:bold;">References</span><br /><br />1. http://www.poppendieck.com/Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com0tag:blogger.com,1999:blog-3710815942271269136.post-651568484448906662007-06-16T16:54:00.000-07:002007-06-26T16:03:52.275-07:00Dynamic Routing Using Spring framework and AOPThis article is published in InfoQ.com under exclusive content. So all the readers are requested to visit the following link.<br /><a href="http://www.infoq.com/articles/dynamic-routing-using-spring"><br />http://www.infoq.com/articles/dynamic-routing-using-spring</a>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com82tag:blogger.com,1999:blog-3710815942271269136.post-72762782559934940902007-06-08T07:31:00.000-07:002007-06-10T17:48:35.311-07:00JIRA, BAMBOO And Confluence Wiki - A well thought out tools for the enterprise<span class="blsp-spelling-error" id="SPELLING_ERROR_0">JIRA</span>, Bamboo and Confluence are tools created and supported by <a href="http://www.atlassian.com/" title="http://www.atlassian.com/"><span class="blsp-spelling-error" id="SPELLING_ERROR_1">Atlassian</span></a>. This whole set of tools would cost $4800 company wide, which is the same as the price for 1 floating <span class="blsp-spelling-error" id="SPELLING_ERROR_2">Clearquest</span> license from IBM.<br /><br /><span class="blsp-spelling-error" id="SPELLING_ERROR_3">JIRA</span> is integrated with the popular open source development environment (Eclipse) for an additional $250. Cruise Control is the leading open source continuous integration tool which is not integrated with the development environment. But Bamboo can be integrated with the development environment.<br /><span style=";font-family:Arial;font-size:11;" ></span><br />The <span class="blsp-spelling-error" id="SPELLING_ERROR_4">Atlassian</span> tool set is scalable up to 500 users, the tools are web-based and they will greatly aid the company in collecting software development life-cycle (<span class="blsp-spelling-error" id="SPELLING_ERROR_5">SDLC</span>) metrics to support those who are pursuing <span class="blsp-spelling-error" id="SPELLING_ERROR_6">CMMI</span> certification. Even otherwise these integrated tools will greatly enhance the quality of the software product.<br /><br /><div style="text-align: left;">Bamboo can also be integrated with <a href="http://cobertura.sourceforge.net/">Cobertura</a>. It can also be integrated with <a href="http://pmd.sourceforge.net/">PMD</a>.<span style="text-decoration: underline;"></span><br /><br />The following links gives an idea about how to integrate Cobertura and PMD with Bamboo.<br /><br />Bamboo with PMD: <a href="http://confluence.atlassian.com/display/BAMEXT/PMD+plugin">http://confluence.atlassian.com/display/BAMEXT/PMD+plugin</a><br /><br />Bamboo with Cobertura: <a href="http://confluence.atlassian.com/display/BAMEXT/Cobertura+plugin">http://confluence.atlassian.com/display/BAMEXT/Cobertura+plugin</a><br /><br />Cobertura is a free Java tool that calculates the percentage of code accessed by tests. It can be used to identify which parts of your Java program are lacking test coverage. It is based on jcoverage.<br /></div><br />PMD scans Java source code and looks for potential problems like: <ul><li>Possible bugs - empty try/catch/finally/switch statements</li><li>Dead code - unused local variables, parameters and private methods</li><li>Suboptimal code - wasteful String/StringBuffer usage</li><li>Overcomplicated expressions - unnecessary if statements, for loops that could be while loops</li><li>Duplicate code - copied/pasted code means copied/pasted bugs</li></ul><span class="blsp-spelling-error" id="SPELLING_ERROR_7">JIRA</span> is a bug tracking, issue tracking, and project management application developed to make this process easier for the team. <span class="blsp-spelling-error" id="SPELLING_ERROR_8">JIRA</span> has been designed with a focus on task achievement, is instantly usable and is flexible to work with.<br /><br />Confluence is an enterprise <a href="http://www.atlassian.com/software/confluence/wiki.jsp" title="What is a wiki?">wiki</a> that makes it easy for the team to collaborate and share knowledge.<br /><br />Continuous integration (CI) automates the process of compiling and testing source code, saving time as well as identifying build problems as soon as they occur. Bamboo is the continuous integration server provided by <span class="blsp-spelling-error" id="SPELLING_ERROR_9">Atlassian</span>.<br /><br />Click <a href="http://www.atlassian.com/software/bamboo/videos/project-plan-tests/project-plan-tests.jsp">here</a> to see Bamboo in action.<br /><br />Capability Maturity Model Integration (<span class="blsp-spelling-error" id="SPELLING_ERROR_10">CMMI</span>) is a process improvement approach that provides organizations with the essential elements of effective processes. It can be used to guide process improvement across a project, a division, or an entire organization. <span class="blsp-spelling-error" id="SPELLING_ERROR_11">CMMI</span> helps integrate traditionally separate organizational functions, set process improvement goals and priorities, provide guidance for quality processes, and provide a point of reference for appraising current processes.<br /><span style=";font-family:Arial;font-size:11;" ></span>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com10tag:blogger.com,1999:blog-3710815942271269136.post-90597949112472382452007-06-07T21:32:00.001-07:002007-06-08T09:59:07.173-07:00Oracle 10g release 2 XML parser hacks and Spring framework<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgrY3EhukmR-3fGB6_0hmd8LcN0By_uq9afbPgvfQ55q3mcxoz4Stb1INWNmzydZzs12k4Ha1eLzEjkZotQUKineIpwqzlaBiUjMhXishF1MLc1rpf62qPGm4gTlqEq69QTzZQYu8m_b6_/s1600-h/oracle10g+-+release2-hacks.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgrY3EhukmR-3fGB6_0hmd8LcN0By_uq9afbPgvfQ55q3mcxoz4Stb1INWNmzydZzs12k4Ha1eLzEjkZotQUKineIpwqzlaBiUjMhXishF1MLc1rpf62qPGm4gTlqEq69QTzZQYu8m_b6_/s400/oracle10g+-+release2-hacks.jpg" alt="" id="BLOGGER_PHOTO_ID_5073560176001049186" border="0" /></a><br />The Oracle 10g release 2 supports only <span class="blsp-spelling-error" id="SPELLING_ERROR_0">JDK</span> 1.4.x and both Oracle XML Parser and Sun's parser have issues in loading Spring framework 2.0 application context <span class="blsp-spelling-error" id="SPELLING_ERROR_1">xml</span> files particularly Spring <span class="blsp-spelling-error" id="SPELLING_ERROR_2">Webflow</span> 1.0.3.<br /><br />The exception that arises out of buggy XML parser is given below:<br /><br />oracle.xml.parser.schema.XSDException: Duplicated definition for: '<span class="blsp-spelling-error" id="SPELLING_ERROR_3">identifiedType</span>'<br /><br />The configuration change in <span class="blsp-spelling-error" id="SPELLING_ERROR_4">opmn</span>.<span class="blsp-spelling-error" id="SPELLING_ERROR_5">xml</span> in the diagram shown above seems to work just fine. The example <span class="blsp-spelling-error" id="SPELLING_ERROR_6">OC</span>4J application component instance shown is app1.<br /><br />Sourcing xerces-2.6.2.jar and <span class="blsp-spelling-error" id="SPELLING_ERROR_7">xml</span>-<span class="blsp-spelling-error" id="SPELLING_ERROR_8">apis</span>.jar in the application's <span class="blsp-spelling-error" id="SPELLING_ERROR_9">bootclasspath</span> level overrides the Oracle's buggy XML parser while starting the application component instance.<br /><br />Alternate way to circumvent the Oracle XML parser issue is by putting xerces-2.6.2.jar and <span class="blsp-spelling-error" id="SPELLING_ERROR_10">xml</span>-<span class="blsp-spelling-error" id="SPELLING_ERROR_11">apis</span>.jar in $ORACLE_HOME/<span class="blsp-spelling-error" id="SPELLING_ERROR_12">jdk</span>/<span class="blsp-spelling-error" id="SPELLING_ERROR_13">jre</span>/lib/ext. However this may void Oracle's application server support if the enterprise has purchased support from Oracle since they do not support their clients to hack Oracle controlled JDK environment.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com0tag:blogger.com,1999:blog-3710815942271269136.post-14170263016598985362007-06-07T09:09:00.000-07:002007-06-09T21:33:06.180-07:00Run a Java program without the main methodHere is an example of how to run a java program without the main method ...<br /><pre>public class HelloWorld{<br /> static{<br /> System.out.println("Hello World!");<br /> System.exit(0);<br /> }<br />}</pre><br />Display: Hello World!<br /><br />Now let us test the program without System.exit(0). The program will terminate complaining that there is no main method.<br /><br /><pre>public class HelloWorld{<br /> static{<br /> System.out.println("Hello World!");<br /> //System.exit(0);<br /> }<br />}</pre><br />Display: Hello World!<br />Exception in thread "main" java.lang.NoSuchMethodError: mainVigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com0tag:blogger.com,1999:blog-3710815942271269136.post-35635525079774013912007-06-06T15:31:00.000-07:002007-06-06T15:50:04.467-07:00The benefits of Virtualization Without Performance PenaltyToday, virtualization is emerging as the fastest way to help businesses with scalability, security and management of their global IT infrastructure. Virtualization is a set of technologies that helps IT run more applications on a given set of servers, can dramatically increase utilization of existing capacity and could enable businesses to leverage their current hardware to meet their needs for years to come. This facilitates IT to make immediate, incremental changes to capacity to meet dynamic business needs without incurring new costs. But performance penalty is an inevitable result of the traditional approach to implementing virtualization.<br /><br />I have read an interesting white paper on virtualization and its benefits in avoiding the performance penalty from BEA. The white paper is available at the following link.<br /><br /><a href="http://dev2dev.bea.com/2007/05/BEA_Virtualization_wp.pdf">http://dev2dev.bea.com/2007/05/BEA_Virtualization_wp.pdf</a>Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com0tag:blogger.com,1999:blog-3710815942271269136.post-86450205847351102982007-06-06T07:25:00.001-07:002007-06-08T10:30:46.823-07:00My first experience with Spring frameworkThis happened when I was hired by a local company in Maryland back in early 2003 to design and implement an enterprise solution to one of the US Federal government agencies. The higher ups have already decided to use the Enterprise Java Bean solution for the project. This is when I came across one of the best selling books I have ever read is Expert One-on-One J2EE Design and Development by none other than the father of Spring framework Mr. Rod Johnson. I fell in love with the book immediately simply because of the practical things outlined in it.<br /><br />I went to the management and talked about what I learned from the book and I decided to give it a try on some of the things mentioned in the book. I downloaded first set of interface21 libraries published with Expert One-on-One J2EE Design and Development and started applying in the prototype I was working on then. A few months down the road these libraries became one of the most popular Java/J2EE frameworks now in the Java/J2EE development community which is the <a href="http://www.springframework.org/">Spring framework</a>.<br /><br />Since 2003 I have designed several big enterprise applications using the Spring framework/Spring web flow stack.Vigil Bosehttp://www.blogger.com/profile/08471230906517374691noreply@blogger.com5