Here’s some statistical analysis as to popularity of recent web technologies in Java. By comparing the searches performed between Struts 2, JSF, Spring MVC and JBoss Seam using Google Trends, it appears that Struts 2 is gaining traction among Java developers while JSF started to lose ground since mid-2007. Searches for Spring MVC and JBoss Seam are increasing but at a slow pace.

On the other hand, jQuery is becoming popular amount Ajax Frameworks. YUI, Dojo and Prototype are roughly equal and jQuery has dramatically surpassed all other frameworks since early this year.

If you’re interested how the graph were generated, try the links below:

Struts 2 vs. JSF vs. JBoss Seam vs. Spring MVC

YUI vs. Prototype vs. JQuery vs. Dojo


UPDATE [2008-09-13]

Here’s an updated graph on Java technologies as commented below.

Spring transactions After two days of debugging our codes on transaction handling, I’m writing this post to share my experience so others don’t have to undergo the same pain and torture. However, this post assumes that you’ve setup your Spring transactions - either via AOP or annotations. If you haven’t done so, here are some good references:

  1. Spring Framework - Transaction Management
  2. On Java - Wire Hibernate Transactions in Spring

So, once you’ve setup or tried to setup transactions and failed - here are some tips how to debug your transaction management.

Enable logging. In log4j.properties, add log4j.logger.org.springframework.orm.jpa=DEBUG to enable logging of JPA transactions. This will allow you to trace the activities behind the Spring transaction processes. The logs provide detailed information about new, reused and active transactions, transaction modes, transaction commits and more. This is the best way to understand how transaction behaves on your application and gives you an insight how to fix your transactional problems.

Check your database and dialect. Dialects affect transaction handling so be sure to use the appropriate dialect for your database. Note that there are 2 dialects to define - JPA Dialect and Hibernate Dialect. JPA dialect is defined in the EntityManagerFactory while Hibernate is defined in Hibernate properties.

JPADialect is defined in EntityManagerFactory as shown below:


<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
<property name="persistenceUnitName">
<value>hibernateConfig</value>
</property>
</bean>

While Hibernate Dialect is defined via persistence.xml.

Watch out for listeners, they could mess up your transactions. A couple of examples about listeners (especially ApplicationListener) found online doesn’t consider transaction handling. Most of them performs data updates within the listener. This should not be the case because in doing so, you could be creating a transaction on the listener which forces all other operations to reuse that transaction. The better way of doing it is to call a service or business layer to perform transactional operations. This way, transaction is created only when the service is invoked.

Declare your transaction as readOnly whenever possible. Read-only transactions run faster so enable this on non-writing functions - (e.g. load, read, find, etc). Also, this avoid transaction commits on binded-data. One specific scenario is when Spring validation throws an error and data is still saved despite the validation error, this means that the data was loaded on a non-readOnly transaction and Spring transaction is committing it.

Reduce your transactional method calls. Put all your business logic function calls in one method marked with @Transactional and avoid calling other methods with their own transaction declarations. For example, if your transactions are declared on service layer, avoid calling another service method because this will trigger transactional checks which unnecessarily slows down the system. Call the DAO method directly instead. This way all your operation are contained in a single transaction declaration.

Understand propagation. Transaction propagation is hard to understand because the effects cannot be easily seen in your application… until you start performance tuning or having problems on saved data. Take note that if your transaction propagation is default, it will try to reuse existing transactions. This means that you could lose your transaction settings (e.g. readOnly), because new transaction was not created instead an existing was reused.

audit security A common requirement in developing enterprise applications is to ensure audit logs are available for data security and traceability–who made the changes, when they were made, and what files or sections were changed. This requirement is not only dictated by corporate IT policies, but also required by government laws. Considering that most enterprise applications have at least 50 domain objects, implementing audit logs on each of them can be time-consuming. So, a generic solution must be established to minimize coding when creating audit logs.

The Solution

  • Use Hibernate interceptors to trigger change events.
  • Use Java reflections to retrieve old and new data.
  • Create an interface to switch logging on or off for every data object.
In summary, here are the steps needed to be performed to accomplish this.
  1. Create an Auditable interface as a marker on the data that needs to be audited. Any data object that needs to be audited must implement this Auditable interface.
  2. Create an AuditLog to store log information. This contains the date (when), user (who), class name, object id and the audit message (what).
  3. Create an AuditLogInterceptor that will keep track of all data change events and store all the  changes performed.
  4. Create a utility that can retrieve object values using Java reflections to process generic data retrieval.
  5. Create sample usage of auditing.
The Implementation
The Auditable interface has 4 method declarations.
public interface Auditable {
	/**
	 * Retrieve the primary key
	 * @return
	 */
	public Long getId();

	/**
	 * Returns the list of fields that should be audited.
	 * @return
	 */
	public List getAuditableFields();

	/**
	 * Returns the field of the primary identifier (e.g. title).
	 * This field is used to uniquely identify the record.
	 * @return
	 */
	public String getPrimaryField();

	/**
	 * Returns customized audit log message. When empty, audit logging
	 * uses standard audit message.
	 * @return
	 */
	public String getAuditMessage();
}

The AuditLog entity must be able to store who, when, what:

package com.ideyatech.core.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.ideyatech.core.bean.user.BaseUser;
import com.ideyatech.core.persistence.listener.AuditLogListener;
import com.ideyatech.core.util.CrudUtil;

/**
 * This class is responsible for handling all audit functions
 * needed to be attached to the classes.
 *
 * @author allantan
 */
@Entity
@Table(name=”HISTORY_LOG”)
public class AuditLog implements Serializable {
	private static final long serialVersionUID = 269168041517643087L;
	@Column(name = “ENTITY_ID”,nullable=false,updatable=false)
	private Long entityId;
	@SuppressWarnings(”unchecked”)
	@Column(name = “ENTITY_CLASS”,nullable=false,updatable=false)
	private Class entityClass;
	@Column(name = “REFERENCE”)
	private String reference;
        @Column(name = “CREATE_DATE”)
        @Temporal(TemporalType.TIMESTAMP)
        private Date createDate;
	@Lob
	@Column(name = “MESSAGE”,nullable=false,updatable=false)
	private String message;
	@Column(name = “USER_ID”,nullable=false,updatable=false)
	private Long userId;
	@Transient
	private transient Object object;
	@Transient
	private transient BaseUser user;

	public AuditLog() {
	};
	@SuppressWarnings(”unchecked”)
	public AuditLog(String message, Long entityId, Class entityClass, Long userId) {
		this.message = message;
		this.entityId = entityId;
		this.entityClass = entityClass;
		this.userId = userId;
		this.setCreateDate(new Date());
	}

	/**
	 * @return the entityId
	 */
	public Long getEntityId() {
		return entityId;
	}

	/**
	 * @param entityId the entityId to set
	 */
	public final void setEntityId(Long entityId) {
		this.entityId = entityId;
	}

	/**
	 * @return the entityClass
	 */
	@SuppressWarnings(”unchecked”)
	public Class getEntityClass() {
		return entityClass;
	}

	/**
	 * @param entityClass the entityClass to set
	 */
	public final void setEntityClass(Class entityClass) {
		this.entityClass = entityClass;
	}

	/**
	 * @return the message
	 */
	public String getMessage() {
		return message;
	}

	/**
	 * @return the userId
	 */
	public Long getUserId() {
		return userId;
	}

	/**
	 * @param userId the userId to set
	 */
	public void setUserId(Long userId) {
		this.userId = userId;
	}

	/**
	 * @return the object
	 */
	public Object getObject() {
		return object;
	}

	/**
	 * @param object the object to set
	 */
	public void setObject(Object object) {
		this.object = object;
	}

	/**
	 * @return the user
	 */
	public BaseUser getUser() {
		return user;
	}

	/**
	 * @param user the user to set
	 */
	public void setUser(BaseUser user) {
		this.user = user;
	}
}

The AuditLogInterceptor is responsible in tracking the changes and creating necessary Audit logs. Notice that session is created from a separate HibernateUtils session so that the original(unchanged) data can be retrieved for comparison.

package com.ideyatech.core.persistence.interceptor;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.CallbackException;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Session;
import org.hibernate.type.Type;

import com.ideyatech.core.bean.Auditable;
import com.ideyatech.core.persistence.impl.AuditLogDAOImpl;
import com.ideyatech.core.util.CrudUtil;
import com.ideyatech.core.util.HibernateUtil;
import com.ideyatech.core.util.StringUtil;

/**
 * This is the interceptor responsible in tracking audit trails.
 * Source is patterned after the book “Java Persistence with Hibernate” - page 546 onwards
 * and merged with http://www.hibernate.org/318.html
 *
 * @author allantan
 */
public class AuditLogInterceptor extends EmptyInterceptor {
	private static final long serialVersionUID = 582549003254963262L;

	private static Logger _log = Logger.getLogger(AuditLogInterceptor.class);

    private Set inserts    = new HashSet();
    private Set updates    = new HashSet();
    private Set deletes    = new HashSet();
    private Map oldies     = new HashMap(); 

    @Override
    public boolean onSave(Object entity,
                          Serializable id,
                          Object[] state,
                          String[] propertyNames,
                          Type[] types)
            throws CallbackException {
        if (entity instanceof Auditable)
            inserts.add((Auditable)entity);
        return false;
    } 

	/* (non-Javadoc)
	 * @see org.hibernate.EmptyInterceptor#onDelete(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
	 */
	@Override
	public void onDelete(Object entity, Serializable id, Object[] state,
			String[] propertyNames, Type[] types) {
        if (entity instanceof Auditable)
            deletes.add((Auditable)entity);
	}

    @Override
    public boolean onFlushDirty(Object entity,
                                Serializable id,
                                Object[] currentState,
                                Object[] previousState,
                                String[] propertyNames,
                                Type[] types)
            throws CallbackException {
        if (entity instanceof Auditable) {
        	try {
	        	// Use the id and class to get the pre-update state from the database
	        	Session tempSession =
	                HibernateUtil.getSessionFactory().openSession();
	        	Auditable old = (Auditable) tempSession.get(entity.getClass(), ((Auditable) entity).getId());
	            oldies.put(old.getId(), old);
	        	updates.add((Auditable)entity);
        	} catch (Throwable e) {
        		_log.error(e,e);
        	}
        }
        return false;
    } 

    @Override
    public void postFlush(Iterator iterator)
                    throws CallbackException {
        try {
        	for (Auditable entity:inserts) {
        		if (!entity.skipAudit()) {
        			if (StringUtil.isEmpty(entity.getAuditMessage()))
        				AuditLogDAOImpl.logEvent(
        						CrudUtil.buildCreateMessage(entity), entity);
        			else
        				AuditLogDAOImpl.logEvent(
        						entity.getAuditMessage(), entity);
        		}
        	}
        	for (Auditable entity:deletes) {
        		if (!entity.skipAudit()) {
        			if (StringUtil.isEmpty(entity.getAuditMessage()))
        				AuditLogDAOImpl.logEvent(
        						CrudUtil.buildDeleteMessage(entity), entity);
        			else
        				AuditLogDAOImpl.logEvent(
        						entity.getAuditMessage(), entity);
        		}
        	}
        	for (Auditable entity:updates) {
        		if (!entity.skipAudit()) {
        			if (StringUtil.isEmpty(entity.getAuditMessage())) {
		        		Auditable old = oldies.get(entity.getId());
		        		AuditLogDAOImpl.logEvent(CrudUtil.buildUpdateMessage(old, entity), entity);
        			} else
        				AuditLogDAOImpl.logEvent(
        						entity.getAuditMessage(), entity);
        		}
        	}
        } catch (Throwable e) {
    		_log.error(e,e);
    	} finally {
            inserts.clear();
            updates.clear();
            deletes.clear();
            oldies.clear();
        }
    }
}



This is a continuation of the post “Audit Logging via Hibernate Interceptor“.

Other helper functions are shown below:

CrudUtil is the class responsible for retrieving object values using Java reflections:

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.ideyatech.core.InvalidImplementationException;
import com.ideyatech.core.bean.Auditable;
import com.ideyatech.core.bean.BaseCriteria;
import com.ideyatech.core.bean.BaseEntity;

/**
 * @author allanctan
 *
 */
public class CrudUtil {

    private static Logger _log = Logger.getLogger(CrudUtil.class);

	private static final String SQL_PARAM = “:([^\\s]+)”;
	private static final Pattern SQL_PARAM_PATTERN = Pattern.compile(
			SQL_PARAM, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);

    /**
     * Creates the logging message for new audit logs
     * @param obj
     * @return
     */
    public static String buildCreateMessage(Auditable obj) {
    	StringBuffer message = new StringBuffer(”Added “);
    	message.append(obj.getClass().getSimpleName())  // class name
    		.append(” “)
    		.append(obj.getPrimaryField())
    		.append(”:”);
    	Object value = retrieveObjectValue(obj, obj.getPrimaryField());
    	if (value!=null)
    		message.append(value.toString())
    		.append(” - “);
    	// loop through the fields list
		List auditFields = obj.getAuditableFields();
		int count = 0;
		for (String property:auditFields) {
			Object ret = retrieveObjectValue(obj, property);
			if (ret!=null && ret.toString().trim().length()>0) {
				if (count > 0)
					message.append(” and “);
				message.append(property)
					.append(”=”)
					.append(ret.toString());
				count++;
			}
		}

    	return message.toString();
    }

    /**
     * Creates the logging message for update audit logs
     * @param obj
     * @return
     */
    public static String buildUpdateMessage(Auditable oldObject, Auditable newObject) {

    	StringBuffer message = new StringBuffer(”Changed “);
    	message.append(oldObject.getClass().getSimpleName())  // class name
    		.append(” “)
    		.append(oldObject.getPrimaryField())
    		.append(”:”);
    	Object value = retrieveObjectValue(oldObject, oldObject.getPrimaryField());
    	if (value!=null)
    		message.append(value.toString())
    		.append(” - “);
    	// loop through the fields list
		List auditFields = oldObject.getAuditableFields();
		int count = 0;
		for (String property:auditFields) {
			Object oldValue = retrieveObjectValue(oldObject, property);
			Object newValue = retrieveObjectValue(newObject, property);
			if (oldValue == null) oldValue = new String(”");
			if (newValue == null) newValue = new String(”");
			if (!oldValue.equals(newValue)) {
				if (count > 0)
					message.append(” and “);
				message.append(property)
					.append(” from ‘”)
					.append(oldValue.toString())
					.append(”‘ to ‘”)
					.append(newValue.toString())
					.append(”‘”);
				count++;
			}
		}

    	return message.toString();
    }

    /**
     * Creates the logging message for new audit logs
     * @param obj
     * @return
     */
    public static String buildDeleteMessage(Auditable obj) {
    	StringBuffer message = new StringBuffer(”Deleted “);
    	message.append(obj.getClass().getSimpleName())  // class name
    		.append(” “)
    		.append(obj.getPrimaryField())
    		.append(”:”);
    	Object value = retrieveObjectValue(obj, obj.getPrimaryField());
    	if (value!=null)
    		message.append(value.toString());
    	return message.toString();
    }

    /**
     * Retrieves the property name for a method name.
     * (e.g. getName will return name)
     * @param methodName
     * @return
     */
    public static String getPropertyName(String methodName) {
    	if (StringUtil.isEmpty(methodName) || methodName.length()<=3)
    		return null;
    	if (methodName.startsWith(”get”) || methodName.startsWith(”set”)) {
    		String prop = methodName.substring(4);
    		char c = Character.toLowerCase(methodName.charAt(3));
    		return c+prop;
    	} else
    		return null;
    }
    /**
     * Retrieves the getter method name for a given property.
     * (e.g. name will return getName)
     * @param propertyName
     * @return
     */
    public static String getGetterMethodName(String propertyName) {
    	if (StringUtil.isEmpty(propertyName) || propertyName.length()<=0)
    		return null;
    	char c = Character.toUpperCase(propertyName.charAt(0));
    	return “get”+c+propertyName.substring(1);
    }

	/**
	 * This method retrieves the object value that corresponds to the property specified.
	 * This method can recurse inner classes until specified property is reached.
	 *
	 * For example:
	 * obj.firstName
	 * obj.address.Zipcode
	 *
	 * @param obj
	 * @param property
	 * @return
	 */
	public static Object retrieveObjectValue(Object obj, String property) {
		if (property.contains(”.”)) {
			// we need to recurse down to final object
			String props[] = property.split(”\\.”);
			try {
				Method method = obj.getClass().getMethod(getGetterMethodName(props[0]));
				Object ivalue = method.invoke(obj);
				if (ivalue==null)
					return null;
				return retrieveObjectValue(ivalue,property.substring(props[0].length()+1));
			} catch (Exception e) {
				_log.error(”Failed to retrieve value for “+property);
				throw new InvalidImplementationException(”CrudUtil”,”retrieveObjectValue”,null,”", e);
			}
		} else {
			// let’s get the object value directly
			try {
				Method method = obj.getClass().getMethod(getGetterMethodName(property));
				return method.invoke(obj);
			} catch (Exception e) {
				_log.error(”Failed to retrieve value for “+property);
				throw new InvalidImplementationException(”CrudUtil”,”retrieveObjectValue”,null,”", e);
			}
		}
	}

	/**
	 * This method retrieves the object type that corresponds to the property specified.
	 * This method can recurse inner classes until specified property is reached.
	 *
	 * For example:
	 * obj.firstName
	 * obj.address.Zipcode
	 *
	 * @param obj
	 * @param property
	 * @return
	 */
	public static Class retrieveObjectType(Object obj, String property) {
		if (property.contains(”.”)) {
			// we need to recurse down to final object
			String props[] = property.split(”\\.”);
			try {
				Method method = obj.getClass().getMethod(getGetterMethodName(props[0]));
				Object ivalue = method.invoke(obj);
				return retrieveObjectType(ivalue,property.substring(props[0].length()+1));
			} catch (Exception e) {
				_log.error(”Failed to retrieve value for “+property);
				throw new InvalidImplementationException(”CrudUtil”,”retrieveObjectValue”,null,”", e);
			}
		} else {
			// let’s get the object value directly
			try {
				Method method = obj.getClass().getMethod(getGetterMethodName(property));
				return method.getReturnType();
			} catch (Exception e) {
				_log.error(”Failed to retrieve value for “+property);
				throw new InvalidImplementationException(”CrudUtil”,”retrieveObjectValue”,null,”", e);
			}
		}
	}
}

HibernateUtil is a utility to retrieve hibernate session separate from the usual EntityManager.

import java.net.URL;
import java.util.Set;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.scannotation.AnnotationDB;
import org.scannotation.ClasspathUrlFinder;

/**
 * This utility allows creation of Hibernate session directly.
 * Used for logging purposes.
 *
 * @author allantan
 */
public class HibernateUtil {
    private static final SessionFactory sessionFactory;
    static {
        try {
        	URL[] urls = ClasspathUrlFinder.findResourceBases(”META-INF/persistence.xml”);
        	AnnotationDB db = new AnnotationDB();
        	db.scanArchives(urls);
        	Set entityClasses = db.getAnnotationIndex().get(javax.persistence.Entity.class.getName());
            // Create the SessionFactory
        	AnnotationConfiguration ac =  new AnnotationConfiguration();
            ac.setProperty(”hibernate.connection.datasource”, “java:comp/env/jdbc/ideyatech”);
            ac.setProperty(”hibernate.dialect”, “org.hibernate.dialect.MySQLDialect”);
            for (String clazz:entityClasses) {
            	ac.addAnnotatedClass(Class.forName(clazz));
            }
            sessionFactory = ac.buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println(”Initial SessionFactory creation failed.” + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

And finally, the sample implementation of an Auditable class:

public class InboundDocument implements Auditable {
	private static final long serialVersionUID = -7019861759834380358L;

	@Column(name = “DATE_RECEIVED”)
	@Field(index = Index.UN_TOKENIZED, store = Store.YES)
	@DateBridge(resolution = Resolution.DAY)
	private Date dateReceived;

	@Column(name = “NUMBER_OF_DAYS”)
	private Integer numberOfDays;

	@Column(name = “DATE_DUE”)
	@Field(index = Index.UN_TOKENIZED, store = Store.YES)
	@DateBridge(resolution = Resolution.DAY)
	private Date dateDue;

	@ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = “ACTION_NEEDED”)
	@Field(index = Index.TOKENIZED)
	@FieldBridge(impl = SystemCodesBridge.class)
	private SystemCodes actionNeeded;

        …
        …

	public List getAuditableFields() {
		List props = new ArrayList();
		props.add(”documentType”);
		props.add(”actionNeeded”);
		props.add(”dateReceived”);
		props.add(”dateDue”);
		props.add(”summary”);
		return props;
	}

	public String getPrimaryField() {
		return “barcodeNumber”;
	}
}

That’s it! Just implement all your auditable classes with Auditable interface. All the codes above are extracted from open-tides - an open-source web-foundation framework that can be used to quickly setup an enterprise project.



My team member has a requirement to implement JMS. I was able to dig up some stuff about JMS in my blog. I’m re-posting it here since it might be useful. For this example, I used IBM Websphere Community Edition(IBM WAS CE), which is synonymous to Geronimo(at least for the first version).

Here are the simple steps:

1. Run Geronimo or IBM WAS CE
2. Compile these two classes. Take note that you need the ff. jar files to compile and run these successfully. Here’s the list:

- geronimo-j2ee_1.4_spec.jar
- commons-logging-1.0.4.jar
- concurrent-1.3.4.jar

Note : Some jars might have new versions so be sure to use the latest one.

You’ll find it somewhere under the Geronimo or WAS CE installation directory.

3. Run the clients.

The receiver class

import java.util.logging.Logger;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.activemq.ActiveMQConnectionFactory;

public class JMSReceiver {
    protected Queue queue;

    protected String queueName = “SendReceiveQueue”;
    protected String url = “tcp://localhost:61616″;

    Logger logger = Logger.getAnonymousLogger();

    protected int ackMode = Session.AUTO_ACKNOWLEDGE;

    public static void main(String[] args) {
        JMSReceiver msgReceiver = new JMSReceiver();
        msgReceiver.run();
    }

    public void run() {
        QueueConnection connection;
        QueueSesion session;
        MessageConsumer consumer;
        try {
            ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
            onnection = (QueueConnection)connectionFactory.createConnection();
            connection.start();
            consumer = null;
            session = connection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
            queue = session.createQueue(queueName);
            consumer = session.createReceiver(queue);
            logger.info(”Waiting for message (max 5)”);
            for (int i = 0; i < 5; i++) {
                Message message = consumer.receive();
                processMessage(message);
            }
            logger.info(”Closing connection”);
            } catch (Exception e) {
                logger.error(”Caught: ”,e);
            } finally {
                consumer.close();
                session.close();
                connection.close();
            }
        }
    }
    public void processMessage(Message message) {
         try {
            TextMessage txtMsg = (TextMessage) message;
            logger.info(”Received a message: ” + txtMsg.getText());
         } catch (Exception e) {
            logger.error(”Caught: ” , e);
         }
    }
}

The sender class

import java.util.logging.Logger;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage

import org.activemq.ActiveMQConnectionFactory;

public class JMSSender {

    private Queue receiveQueue = null;
    protected String queueName = “SendReceiveQueue”;
    protected String url = “tcp://localhost:61616″;
    Logger logger = Logger.getAnonymousLogger();

    public static void main(String[] args) {
        JMSSender msgSender = new JMSSender();
        msgSender.run();
    }

    public void run() {
        QueueConnection queueConn = null;
        QueueSession queueSess = null;
        TextMessage myMessage = null;
        QueueSender queueSender = null;

        try {
            ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);

            queueConn = factory.createQueueConnection();
            queueSess = queueConn.createQueueSession(false,Session.AUTO_ACKNOWLEDGE)
            receiveQueue = queueSess.createQueue(queueName);
            queueSender = queueSess.createSender(receiveQueue);
            myMessage = queueSess.createTextMessage();

            myMessage.setText(”test from JMS client 2″);
            queueSender.send(myMessage);

        } catch (Exception e) {
            logger.info(”Caught: ”, e);
        } finally {
            queueSender.close();
            queueSess.close();
            queueConn.close();
        }
    }
}


Ivy Dependency Manager

Like most of us often hear, “its another framework or dependency management tool”. But what exactly differentiates Ivy from Maven?

Ivy is much easier to use. The library is simpler since it doesn’t do so much. It only focuses on dependency management and use the already famous and powerful ant to build the application. In short, ant and ivy is used side by side.

Why I Choose Ivy?

The main thing I like about Ivy is its simplicity. You can use Ivy with only ant installed on your system (and of course, java). This means that you don’t need to download any Ivy related libraries or when using eclipse, no plug-in is needed. You can run everything using ant, from installing the ivy library to downloading the dependencies.

Ivy is a dependency management tool that can use other repository such as maven repository.

Installing Ivy

Before continuing, I’ll assume that you are using ant version 1.7. You can choose to run the ant script in either console or from inside eclipse (It depends on your preference).

Here is a build.xml file that contains several targets that will be used in this post:

<?xml version="1.0" encoding="UTF-8"?>

<project name="ivytest" basedir="." default="usage" xmlns:ivy="antlib:org.apache.ivy.ant">

<property name="lib.dir" value="lib" />
<property name="build.dir" value="build" />
<property name="src.dir" value="src" />

<path id="lib.path.id">
<fileset dir="${lib.dir}" />
</path>

<path id="run.path.id">
<path refid="lib.path.id" />
<path location="${build.dir}" />
</path>

<property name="ivy.install.version" value="2.0.0-beta1" />
<property name="ivy.jar.dir" value="${basedir}/ivy" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />

<target name="usage" description="Displays the command used with this build script">
<echo message="Usage" />
<echo message="-------------------------------------------" />
<echo message="Available targets are:" />
<echo message="download-ivy --> Download ivy library" />
<echo message="install-ivy --> Install ivy library" />
<echo message="clean-libs --> Delete lib files" />
<echo message="clean-ivy --> Delete the ivy files" />
<echo message="resolve --> Resolve/Download ivy dependencies" />
</target>

<target name="download-ivy" unless="skip.download" description="Download ivy.jar">
<mkdir dir="${ivy.jar.dir}"/>
<echo message="installing ivy..."/>
<get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/ ${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}" usetimestamp="true"/>
</target>

<target name="install-ivy" depends="download-ivy" description="Install ivy library">
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
</target>

<target name="clean-libs" description="Delete all libraries/dependencies">
<echo message="Deleting ${lib.dir}" />
<delete dir="${lib.dir}" />
</target>

<target name="clean-ivy" depends="clean-libs" description="Delete the all folders/files that was generated by ivy">
<echo message="Deleting ${ivy.jar.dir}" />
<delete dir="${ivy.jar.dir}" />
</target>

<target name="resolve" depends="install-ivy" description="Resolve the dependencies">
<ivy:retrieve/>
</target>

<target name="run" depends="resolve" description="Compile and run the project">
<mkdir dir="${build.dir}" />
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="lib.path.id" />
<java classpathref="run.path.id" classname="Main"/>
</target>

</project>

Invoke “ant install-ivy” and the ivy jars will be downloaded. A new folder named “ivy” will be created with the ivy.jar in it.

Dowloading Dependencies

By default ivy uses maven 2 repository but you can certainly define other repository (It will be covered on later post).

The build.xml above contains a target named “resolve”. Running the target will cause the Ivy to download defined dependencies on ivy.xml (ivy.xml is needed since all the dependencies are defined on that file). Here is an example of ivy.xml:

<?xml version="1.0" encoding="UTF-8"?>

<ivy-module version="2.0">
<info organisation="ideyatech" module="ivytest"/>
<dependencies>
<dependency org="log4j" name="log4j" rev="1.2.8"/>
</dependencies>
</ivy-module>

The code above downloads the log4j and its dependencies from the defined repository (in our case, maven repo). I chose to use log4j because in the next section, I’ll be demonstrating to compile a simple java class that uses a Ivy managed library. Invoke “ant resolve” now and you will see a message saying that the library is being downloaded.

Compiling The Application

Main.java:

import org.apache.log4j.Logger;
public class Main {
    private static final Logger log = Logger.getLogger(Main.class);
    public static void main(String[] args) {
        System.out.println(”Printed using system.out.println”);
        log.info(”Printed using log4j logger”);
     }
}

The sample java file won’t really print the message being logged. The purpose of this example is to test compiling the application with the Ivy libraries being referenced. The idea is to simply add the “lib” dir to the classpath on compilation.

Try invoking “ant run” and the application will be compiled and executed. Note that invoking the “ant clean-libs” and removing the “resolve” dependency on run target will cause the compilation to throw some error.

References:

http://ant.apache.org/ivy/index.html

Note:

  • Ivy logo is property of Apache Ivy and is not connected with Ideyatech.



We’ve been using Continuum for quite some time now. While Continuum does seem to do a good job managing our builds, its limited support for JUnit Test reports made us evaluate an alternative, Hudson. Hudson is the new guy on the block, aside from cool icons and more intuitive interface, this tool seems to be quite competitive and feature-packed.

So, I’m listing down a head-to-head comparison between Continuum and Hudson as we’ve used them and based on features we are looking for:

Build Management:

Continuum seems to perform better in this area. It allows multiple jobs/script configured on a single project. Projects can also be logically grouped. Hudson only supports one job per workspace, which I find very limiting. This means that if we need 3 jobs (e.g. build-war, deploy, run-test), each job needs its own workspace, which doesn’t make sense because all these job share the same source code.

User Management:

I prefer Hudson a little over Continuum because I like simplicity over flexibility. Considering our small team size, there is no point of grouping people with several permissions across multiple projects. All we need is the ability to restrict the developer’s access within their projects. Hudson has a simple, easy-to-use permission system–I was able to setup user access rights within 30 minutes. Continuum seems to be a little over-complicated on this. Continuum also has a strict password policy which makes it more difficult to manage.

Scheduling:

Once again, Hudson is better due to its simplicity. To configure a schedule, simply add “@daily” on schedule option and you’re all set. While Continuum’s scheduling isn’t complex, there’s more clicking involved. Again, Simplicity over Flexibility.

Email Alerts/Notification:

Although both tools provide email support, Hudson has a more detailed email report. Hudson allows the tracking of JUnit test reports for every test, while Continuum only provides notifications on failed or successful builds.

In the end, we decided to switch to Hudson because it is easier to use and it includes the Junit test reporting feature.

Note: The Continuum and Hudson logos are properties of Apache Continuum and Hudson, respectively.

As recommended by Yahoo on YSlow - tip #1: Make fewer HTTP request and tip #10: Minify javascript- we aim to implement these tips on all our projects with minimal head-ache. While these recommendations are truly useful, implementing them can be quite tedious and challenging. Consider having to maintain multiple min versions of the javascript and the files that links to them! So to alleviate the problem, we created a tool called low-tides (as part of open-tides) that helps automate the merging and minification of css and js files.

So what is the rationale behind the the tool?

  • Maintenance of minified js and css is a nightmare. Keeping separate js and css files for development and production can be very confusing. Some developers might change the production version without syncing with the development version. So eventually, changes to different files becomes a mess — Which one has the latest code?
  • Maintenance of html files that links to proper javascript and css is another problem. Since minified versions are likely to have different filename (e.g. basic-min.js), html codes that reference the scripts need to be changed. This leads to having multiple copies of html files… again.
  • Versioning of html, css, and js files introduce a whole new set of configuration items. Imagine bullets #1 and #2 getting multiplied across a number of version releases!
  • At the time of this writing, there are no tools available that can merge multiple javascripts. The development version of javascript needs to be logically separated while the production version needs to be merged (for lesser http request). Moreover, merging javascript is not straightforward. Some javascripts need to be pre-loaded while others can be postponed.

I suppose by now you get the picture. The solution we propose to this configuration problem is simple:  Always change from the development version and have a deployment script automatically create the production version. As such, files are always maintained from the development version - but the key to this approach is to ensure that the script for creating production versions is quick and easy-to-use.

Now here comes Low-tides. Low-tides is a Java-based program that automatically analyzes html files for javascript and css includes. It will merge includes that are in sequence into a single file and minify it. In summary, it automatically solves all the problems mentioned above.

You can download it here: http://code.google.com/p/open-tides/downloads/list

Usage instructions are available here: http://code.google.com/p/open-tides/wiki/LowTides

Has anyone ever tried looking at OSWorkflow recently? It is unfortunate that this OpenSymphony project has been shelved. However, I found value in this lightweight workflow tool — for one, being lightweight makes it simple and easy to work with, plus, integration with Spring and Hibernate is readily available.

However, since OSWorkflow stopped development, there had been no support for JPA-based applications anymore. Fortunate for those interested in making JPA work on OSWorkflow via Spring, I was able to tweak some of the OSWorkflow classes and integrate it with JPA Session.

The primary problem in integrating OSWorkflow with JPA is the Session. The original session used by OSWorkflow (SpringHibernateOSWorkflowStore) is a sessionFactory injected via Spring. Since JPA uses EntityManager, the sessionFactory and EntityManager are on different transactions.

The solution is to extend AbstractHibernateWorkflowStore and use session from EntityManager. Here’s the code:

public class JPAHibernateWorkflowStore extends AbstractHibernateWorkflowStore {
    @PersistenceContext
    private EntityManager em;

	@Override
	protected Object execute(InternalCallback action) throws StoreException {
        try {
    		return action.doInHibernate((Session)em.getDelegate());
        } catch (StoreException e) {
            throw new RuntimeException(e);
        }
	}

	public void init(Map arg0) throws StoreException {
		// TODO Auto-generated method stub
	}

	/**
	 * @param em the em to set
	 */
	public void setEntityManager(EntityManager em) {
		this.em = em;
	}
}

Afterwards, use JPAHibernateWorkflowStore instead of SpringHibernateWorkflowStore as your workflow store. You will also need to copy HibernateCurrentStep.hbm.xml, HibernateHistoryStep.hbm.xml and HibernateWorkflowEntry.hbm.xml (under com.opensymphony.workflow.spi.hibernate3) to META-INF (along with persistence.xml). This will ensure that hbm mappings are recognized by the EntityManager.

Well, that’s basically it. If you are having a hard time following my instructions, try getting the standard SpringHibernateWorkflowStore to work first. Afterwards, change implementation to JPA-based approach.

Ciao!



I created this basic DWR training and uploaded to Youtube. This video discuss about the basic setup of DWR and the sample is to perform an Ajax based validation.