Search This Blog

Tuesday, August 26, 2008

To Service or Not to Service..thats the question!

Service Oriented Architecture or SOA as the acronym has been discussed, defined, re-defined,argued, incorporated and touted. In this blog, I hope to share some thoughts on deciding whether code should be abstracted into a service or not. It is based of discussions with many of my esteemed colleagues over the years. Some of the discussions have also been with my 3+ year ole kids...;-)))) What the kids said, I take very very seriously lol!

During software development, I often have heard the term abstraction of common code or DRYing out common code. In other word, my architect or lead saying "This is business logic, it should not be intermixed with your UI code. You should move this to a business delegate so other callers can use it as well." or "This code looks like it can be re-used by other callers, it should be abstracted out to a common class or function." Highly valued and respected advice.

Abstraction of common code to place where it can be re-used time and again by different callers makes for a very strong logical argument. The "DRY" (Don't Repeat Yourself) principle.

As the developer, the follow up question is often "So where exactly should I move it to?" A method in the same class? A different class? A service?

As this point, IMHO, interrogation of the scope or breadth of the abstraction is required in order to determine where to extract the common piece of functionality to. In other words, at this point the question "Who will be the consumers of this piece of code?" is the question of most importance IMO.

If the common piece of functionality is strongly tied to the application using it and callers from any other application would NOT benefit from the abstraction, then the answer becomes as simple as having the common piece of functionality defined in a Class or Function within the application so that it may be re-used.

Now if the benefits of the common code can be reaped by callers from different applications then this piece of code needs to be distributable or shareable so that callers from different applications can readily use it.

One way that the distribution and sharing can be achieved is to place the common code in a software library. For the J2EE developer, I am talking about a jar, for a C developer, a lib file. This software library is then be made accessible to callers and the callers would not need to repeat the common code.

The above approach works well when the library will not suffer much "FLUX". Flux in the code would mean distributing the changes to all consumers. Which applications do I need to distribute the jar/library to? In addition, what if we require two versions of the code to be available? There is a coordination penalty to be suffered here. The solution might work in the number of consumers are of a very low number. In addition, this piece of code is specific to Java consumers. What if this code would be beneficial to consumers written in different languages?

Using a distributed computing approach one can centralize the solution and also make it available to consumers with different languages (via Corba, REST, SOAP) . This eliminates the problem of having to distribute the jar/code to all consumers. Multiple versions of the same piece of software can be simultaneously supported using separate end points, for example, "/orderservice/v1", "/orderservice/v2".

We are moving away from a local to a global way, losing control. What I mean is when the library was self contained and distributed to only a handful of applications, things were simple and more controlled. With exposing as a distributed service, we are opening the code up to more wider audience and thus more exposure.

In deciding that a service will be distributed, one will quite likely find themselves addressing some non-functional requirements:

Semantics (Inter operability with different Consumers):

What languages will the consumers of the distributed code be in? For example, C, C++, Java or maybe only Java! This is one of the most difficult questions to answer. One would at this time pose the question "Why not just design the distributed code to simply be semantic agnostic?". For one, the native features and structures provided are often unusable and wrappers or translations are required. Translation to provide for cross language consumption has a price that to be paid. For example, with an RMI service on can depend on a total java solution and reap the benefits of the structures and semantics therein.

Quality of Service (QOS):

How much will the service be loaded, i.e., frequency of request? What is the acceptable failure rate? Are there maintenance windows that can be defined? What is the acceptable response time? How large is the payload exchanged? Scalability, fail over are some of the major players. These are some of the QOS requirements that need to be addressed.

Security:

Unlike the library distribution where the consumers are known and potentially trusted, as the service has now become "public", security becomes a valid concern. Does a consumer require authentication? Can a consumer execute the operation (authorization)? Does the data transferred between client and server require encryption?

Transactions:

A process or code when abstracted might have been a participant in a more global transaction. Consider for example, there is initially an application that will book a hotel room, a car and flight reservation as part of one single transaction. If we abstract out the flight booking to a service in light of other applications wanting to book flights, what do we do about our original process that requires all to work or have no booking at all?

Synchronicity:
Some processes are synchronous while others do not have to be. For example, when the wife commands to vacuum the house, it had better be done immediately. If the kids ask for a new toy, it can be provided later on. When designing the code, one needs to determine if the process has to be done synchronously or not? I guess this would apply equally to the library routine present in a jar.

Volatility:
It is arguable that this requirement falls under the functional requirement umbrella. Questions such as "Will the service undergo much flux?", "Do changes need to be backward compatible?", "How can separate versions of the service co-exist?", "Transition strategies from version a to version b of the service."

Discovery:

How will the shared piece of code be discovered to be usable by consumers? Registry, fixed URIs? Again security is coexistent with this requirement.

Having distributed code involves considerable thought. It is almost impossible to provide canned answers to the above as the requirement variance is large from company to company, use case to use case.

I will express some opinions based of the above:

Prophets are a rare commodity. Even if they exist, their reliability is often questionable. I feel it is often best to adopt a direction that is sound at given moment of time and space (space accounts for effort ;-)) Trying to sound smart here ;-).

If there is going to be very limited amount of semantically equivalent consumers of a duplicated piece of functionality, it is better to lean toward localization of the same. Following the direction of a shared function or library would be preferred.

If the functionality has the prospects (put on prophetic hat here) of being used by different semantics consider a service. Note that even different semantics can be achieved without a service, for example Java Native Interface or JNI.

If the functionality will be consumed by different consumers using the same semantics and one expects the number of consumers to be large, consider a distributed environment whose semantics satisfy the majority of the consumers. Thinking RMI, EJB here for Java consumers. For example, if in a total Java shop, if RMI services can be accommodated, why think of CORBA or SOAP?

If the functionality will be consumed by different consumers using different semantics, consider a language neutral implementation of the service such as COBRA, SOAP, POX, JMS etc.

Design consumers for change and flexibility. If consumers of a service or piece of functionality are developed so that they can easily adapt to change, we have a win-win situation.

To illustrate the same, consider a client that needs information about products, product identifiers, name and description in order to function.

If the code were designed as follows:





public interface ProductDAO {
public Product getProduct(Integer id);
}




with an initial implementation as shown below:



public class ProductDAOImpl implements ProductDAO {
public Product getProduct(Integer id) {
ProductModel prod = getProduct(id);
Product prod = mapToClient(prod);
return prod;
}
}




Then if the code was abstracted to a web service, the client would only need to provide a different implementation as shown below:



public class ProductSoapDaoImpl implements ProductDAO {
public Product getProduct(Integer id) {
ProductDTO dto = makeSoapCall(id);
Product prod = mapProduct(dto);

return prod;
}

private ProductDTO makeSoapCall(Integer id) {
....
}
}





The point to note is that we have an "Agile" client, i.e, a client that has been designed to adopt to change. The Product class used is still a product as far as the Client application is concerned. How its obtained is immaterial. Deciding where a client needs to be agile is again a Prophetic task! I hope to point out with the above that if "change or re-use" is anticipated, develop for the same, regardless of which layer of the architecture you are a part of.

Because we have SOA enviroment, not every piece of re-usable code needs to be a distributed Service. Put on your best prophetic hat when thinking semantics of a service. Remember securing is enduring.

Chris Angel is just freaking awesome!

Wednesday, August 20, 2008

Easy Mock Class Extensions: Byte code enhancement, Interface elimination, Mocking final classes/methods

Today, I had a very constructive discussion with some colleagues. One of the primary purposes served by interfaces has been to support "Mocking" of tests, especially in cases where there is at most one implementation in a span of time. After thinking of Easy Mock class Extensions, where one could mock a class, I raised the question of the value of the interface in such a case as one could easily mock an implementation which started a very interesting discussion.

Now, with Mock frameworks like JMock or EasyMock, mocking of Classes is possible but they explicitly declare that classes that are declared final or methods that are declared final cannot be mocked. I thought at the time of how the instrumentation api could be leveraged to assist in mocking the final class or a class with final methods.

One typical case, where we propagate the pattern of an interface and implementation pattern is in the DAO layer. If an API is designed as an external API, i.e., others will use the developed API and/or the API will be deployed in unknown environments where specific implementatio might be in use, then the separation of the DAO interface and implementation is justified. In a standard/isolated case, i.e., a case where one has decided on their database provider,the O/R mapping strategy, the value of the overhead of implementing interfaces is diminished as at any real given time, there would typically be only one concrete implementation. So it begs the question as to why the DAO interface is even required?

One argument that I have heard as the case for interfaces has been testability. For example:

Service service = new ServiceImpl();
service.setDAO(new DAOMockImpl()));
service.executeServiceMethod();

In the above example, the DAO is mocked with an implementation of the DAO interface.

The same could easily acheived by mocking the DAOImplementation class itself.

Anyway, I wanted to see if anyone has in fact handled the case of using byte code enhancement to handle the final problem with mocks. I did find an excellent example of the same in Xzajo's Weblog. In the example, present in the Blog, a very descriptive method of how byte code enhancement is utilized to allow proxying of final classes/methods is described. Very very nice! My example, shown below demonstrates how the same can be achieved in a Maven/Easy mock environment and utilizes the code from Xzajo's blog.

One change that I have is that we probably do not want all loaded classes to be devoid of their "final" keyword. For this reason, I propose a method of specifying the packages one would like to be enhanced.

The instrumentation class utilizes the The Byte Code Engineering Library (BCEL) . We could easily change the same to use some other library if required. I have defined a class called FinalizerRemover which implements ClassFileTransformer and the implementation details are shown below:



1 public byte[] transform(ClassLoader loader, String className, Class redefiningClass,

2 ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {

3 byte returnedBytes[] = bytes;
4

5 try {
6 ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), className);

7 JavaClass clazz = parser.parse();
8 if (instrument(clazz.getPackageName())) {

9 if (clazz.isFinal()) {
10 System.out.println("Changing final modifier of class:" + clazz);

11 clazz.setAccessFlags(clazz.getAccessFlags() & (~Constants.ACC_FINAL));

12 }
13 Method[] methods = clazz.getMethods();

14 for (Method m : methods) {
15 if (m.isPublic() && m.isFinal()) {

16 System.out.println("Transforming Method:" + m);
17 m.setAccessFlags(m.getAccessFlags() & (~Constants.ACC_FINAL));

18 System.out.println("Transformed Method:" + m);
19 }

20 }
21 }
22 returnedBytes = clazz.getBytes();

23
24 }
25 catch (Exception e) {

26 e.printStackTrace();
27 }
28
29 return returnedBytes;

30 }





In the above example, I have method check to see whether the class requires transformation or not. I use an argument to the VM -Dtpackages, a comma separated list of packages requiring transformation.

The code is present in a maven project called Finalizer remover producing a jar file called finalizerremover.jar.

A test maven module (FinalizeOverrideProject) is defined that contains DAO's which are final classes. A service layer class refers to the DAO as shown below:




1 public class ProductServiceImpl {

2 private ProductDAOImpl productDAO;
3
4 public final void setProductDAO(ProductDAOImpl productDAO) {

5 this.productDAO = productDAO;
6 }

7
8 public Product getProduct(Integer id) {

9 return productDAO.getProduct(id);
10 }

11 }





The ProductDAO mentioned above is an actual implementation and not an interface.
The test code for the ProductServiceImpl is as follows:



1 private ProductDAOImpl productDAOMock;

2 @Before
3 public void setUp() {

4 productDAOMock = EasyMock.createMock(ProductDAOImpl.class);

5 }
6 @Test
7 public void testGetProduct() {

8 ProductServiceImpl impl = new ProductServiceImpl();
9 impl.setProductDAO(productDAOMock);

10
11 Integer id = 123;
12 Product p = new Product(id, "Porsche Boxster");

13
14 EasyMock.expect(productDAOMock.getProduct(id)).andReturn(p);

15 EasyMock.replay(productDAOMock);
16 Product result = impl.getProduct(id);

17 assertNotNull(result);
18 EasyMock.verify(productDAOMock);

19 }





If run without the byte code enhancement, the above test would not work as it would not be possible for EasyMock to "mock" the final DAO class. However, as the DAO class is
enhanced to strip out the final methods, mocking is possible.

To enable the instrumentation to work when we run a "mvn test", the following changes are affected to the maven pom to specify the intrumented jar and the packages to be instrumented:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

<version>2.4.2</version>
<configuration>
<argLine>-Dtpackages="com.welflex" -javaagent:${settings.localRepository}/com/welflex/finalizeRemover/finalizeremover/1.0-SNAPSHOT/finalizeremover-1.0-SNAPSHOT.jar</argLine>
<useSystemClassLoader>true</useSystemClassLoader>

</configuration>
</plugin>

Maven's surefire plugin is configured to run with the instrumentation jar. The intrumentation jar is obtained from the local maven repo.

The example is run on a Maven 2.0.9, Java 1.6.X environment. In order to run the example issue a
"mvn install" from the FinalizeRemover project. The operation will result in the deployment of
the intrumentation library in a local repository. Execute a "mvn test" on the FinalizeOverrideProject to test and view the example.

Conclusion:

Think more about redundant interfaces, orthogonality has a price. More later...

Downloads: The code for the example can be obtained from HERE!

Sunday, August 17, 2008

Whats in a name?

I have often had discussions with people regarding which is the better way to represent Acronyms in Java. Should a class that represents a Billing Telephone Number be represented as BTN or Btn?
I often fall back to the Java language classes for reference. URL, UUID, URI seem to support the full uppercase naming convention. But is that the correct way? It has to be more than a matter of convention and style to sway one way or another.

I have been reading this excellent book by Gafter and Bloch called "Java Puzzlers" and find it to be an excellent book that often makes me think "WTF?" when reading parts of it. I only walk away humbled regarding my understanding of the java language. I truly recommend this book as a read for any java enthusiast. Just, please, don't use the examples for interview questions. Some hapless bloke like me wouldn't stand a chance :-)

Anyway, back to the naming conventions. Consider the following example:

1 public class Naming {

2 public static void main(String args[]) {

3 System.out.println(A.BTN.NUMBER);

4 }
5 }
6
7 class A {

8 static class BTN {
9 static Integer NUMBER = 9789999;

10 }
11
12 static Btn BTN = new Btn();

13 }
14
15 class Btn {
16 Integer NUMBER = 12345678;

17 }


Will it even compile considering Class A has a static variable called BTN and a class called BTN ?
For the sake of discussion, lets say the class does compile, what then will be the run time output? Will it print out 9789999 from the inner static class of A or will it print out 12345678 from the instance of class Btn?

If you surmised the answer to be the latter you are right, the code does infact print out 12345678. Now why is that?

The Java Language Specifications (JLS 6.5.2) states that when a variable and a type have the sam me name, the variable takes precedence. In other words, the variable name tends to obscure the type name.

Based of the above, if the program mentioned above had used the java naming conventions, i.e., the static inner class of B had been named Btn, the problem would not have surfaced.

With the same said, following the conventions regarding naming of java classes, packages, variables is quite essential.

Lessons Learned:

1. Use Camel case starting with a capital letter for Class Names
2. For static constants use ALL CAPITALS.
3. Package names in all lower case.
4. Avoid top level package or domain names for variable names. For example, don't name classes String, Object; or don't name variable as java, net, org etc. Read the book for more.

The book is really nice, some example's seem to indicate warped cases which the normal developer would not even tread. Regardless it is worth a read. Let me leave you with some other pit falls, maybe convince you to want a read ;-).


1 public static void main(String args[]) {

2 System.out.println(2.00 - 1.10);
3 System.out.println('A' + 'B');

4 }



What gets printed? Enjoy!

Friday, August 8, 2008

JAXRS, JBoss RestEasy, Maven, Spring...rock on!

I'm drowning my audience with Rest related code. What can I do, the hunger is biting me bad! JSR 311/JAXRS is an API. Different providers provide their own implementations of the same. I have already explored RESTLET's version of the implementation and how it applies to my SpringRestlet example. Note the common theme running here..I need a framework to be able to provide a Spring Hook otherwise, I turn my head the other way :-). Yeah, a Spring fan (those who remember the movie "Swim fan" feel my obsession)!

That said, we move on to the example. RestEasy is a JBoss project that allows one to build RESTful webservices. I like their philosophy where they say, the goal is to build an easy way to speak REST.

As of this blog, Rest Easy JAXRS is at : 1.0 BETA 5. Some of the things I liked about the implementation right away:

1. Support for a Client API to talk to Restful Webservice
2. Easy Spring Integration
3. Maven Support
4. Decent Documentation
5. Easy to get going with a Starter Webservice
6. JBoss Backing..we have Hibernate after all ;-)
7. Last but not the least led by a member of the JSR

In my previous blog with the RESTLET framework support for JAXRS and Spring I had developed my own custom Servlet. With Rest Easy, I did not have to do the same. My webapp's web.xml has exactly the same configuration as mentioned in the RestEasy documentation. One major issue that I encountered is that I could not get auto discovery of Spring managed Resources and Providers (as advertised by the framework) without annotating the corresponding classes with the Spring @Component annotation. Maybe there is something I am missing. Regardless, I have filed a bug report with the RestEasy jira, lets see what surfaces from the same.

With the Resteasy version of my Spring/Restlet example , the webapp module has only 3 classes! An OrderNotFoundProvider class that translates all OrderNotFoundExceptions to meaningful REST responses, an OrderResource and a ProductsResource. I do not have any other JAVA artifacts in this module. A provider class for the Products that managed the marshalling specifics (
JSON marshalling/unmarshalling) has been moved to the common maven module to be shared among client and web modules. Regardless, look at my webapp module now, all we have is Resource and Exception management classes :-). Gone are the Application, Servlet, ApplicationConfig ...etc etc classes.

Unlike in the previous example of JAXRS that I had provided, in this example, I have changed the Client to use RestEasy's JAXRS Client support. I must admit, I am rather impressed by their effort with the same. So what are the changed in the client, the OrderClient has changed to:
@ConsumeMime("application/xml") 
public interface OrderClient {

/**
* Create an Order.
*
* @param orderDTO Order DTO
* @return OrderDTO with created id
* @throws IOException If an error occurs
*/

@POST
@Path("/order")
@ProduceMime("application/xml")
@ConsumeMime("application/xml")
public OrderDTO createOrder(OrderDTO orderDTO) throws IOException;

/**
* Updates an Order.
*
* @param orderDTO Order DTO
*/

@PUT
@Path("/order/{id}")
@ProduceMime("application/xml")
public void updateOrder(OrderDTO orderDTO, @PathParam ("id") Long id);

/**
* Retrieves an Order with the specified <code>orderId</code>.
*
* @param orderId Order Id
* @return OrderDTO
* @throws OrderNotFoundException if order is not found
* @throws IOException if an error occurs
*/

@GET
@Path("/order/{id}")
@ProduceMime("application/xml")
public OrderDTO getOrder(@PathParam("id") Long orderId) throws OrderNotFoundEx
ception, IOException;

/**
* Deletes an Order with the specified <code>orderId</code>
*
* @param orderId order Id
* @throws OrderException If an error occurs
*/

@DELETE
@Path("/order/{id}")
@ProduceMime("application/xml")
public void deleteOrder(@PathParam("id") Long orderId) throws OrderException;
}


Note the use of JAXRS annotations in the Order Client. Code is being shared, always a good thing :-). It is sufficient with the OrderClient defintion to talk to the webservice using Reseasy code. The same can be accomplished with the following lines from a consumer:

ResteasyProviderFactory.initializeInstance(); 
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

OrderClient client = ProxyFactory.create(OrderClient.class, "http://localhost:9090/IntegrationTest");

The first two lines initialize the Resteasy client code. The third line is where a Proxy is created for the OrderClient. In the spirit of my rest/spring example, I have decided to provide an abstraction where I delegate to the proxy mentioned above as shown below ;-) :
public class OrderClientImpl implements OrderClient { 
private final OrderClient delegate;

/**
* @param uri Server Uri
*/

public OrderClientImpl(String uri) {
delegate = ProxyFactory.create(OrderClient.class, uri);
}

public OrderDTO createOrder(OrderDTO orderDTO) throws IOException {
return delegate.createOrder(orderDTO);
}

public void deleteOrder(Long orderId) throws OrderException {
delegate.deleteOrder(orderId);
}

public OrderDTO getOrder(Long orderId) throws OrderNotFoundException, IOExcept
ion {
return delegate.getOrder(orderId);
}

public void updateOrder(OrderDTO orderDTO, Long id) {
delegate.updateOrder(orderDTO, id);
}

}

I choose to depend on my Integration test and/or consumer of the service to initialize the Resteasy framework via plugins/listener what have you.

Above said, the code just works nice. I feel with the Resteasy JAXRS implementation, I have reduced the amount of coding required to build REST web service that integrates with my favorite framework Spring. Onward and upward you Resteasy folks!

The Resteasy version of the JAXRS Spring/RestEasy/Maven/Dozer project can be downloaded from HERE!
The example was run using JDK 1.6.X and Apache maven 2.0.9 on Linux environment.
Enjoy! I am off to look at CXF from the apache foundation next..:-) ...

Wednesday, August 6, 2008

Singleton and Lazy Initialization

Instantiating a Singleton lazily has always been a challenge in pre JDK1.5.X days due to semantics of the volatile modifier and/or synchronization penalties. The double checked locking has been discussed quite a bit. I found this one technique of lazily loading a singleton that I thought I'd share. I must admit, I am late in realizing the same :-(. In lawers terms, if this has been "Asked and answered", too bad! There must be a few slow people like me out there...:-), hopefully ;-) The principle used is the "Lazy initialization holder class idiom", JLS 12.4.1.

The singleton class has a Holder class which creates the Singleton instance as shown below:

public class Singleton { 
static {
Watcher.singletonLoaded = true;
}

/**
* Prevent instantiation.
*/

private Singleton() {}

/**
* @return Lazily loaded instance.
*/

public static Singleton instance() {
return SingletonHolder.INSTANCE;
}

private static final class SingletonHolder {
static {
Watcher.singletonHolderLoaded = true;
}
public static final Singleton INSTANCE = new Singleton();
}
}


In the above code when Singleton.instance() is invoked for the first time, the side effect of loading the HolderClass and the creation of the Singleton INSTANCE occurs.

This is kinda nice as there is no synchronization and depends on the fact that class loading is serial, i.e., two threads will not load the same class twice with the same class loader at the same time.

The Watcher class shown above is only a simple way to track when the class has been loaded.

The following represent some unit test that demonstrate when the class is loaded and when the Singleton is obtained.
public class SingletonTest { 
@Test public void test() throws ClassNotFoundException {
Class.forName("Singleton");

assertTrue("Singleton class must have been loaded", Watcher.singletonLoaded);
assertFalse("Single Holder should not have been loaded", Watcher.singletonHolderLoaded);

Singleton.instance();

assertTrue("Singleton Holder must have been loaded", Watcher.singletonHolderLoaded);
}
}


The Watcher class shown above is a simple static class with booleans as indicators.

Monday, August 4, 2008

Restlet, JAXRS, JSR 311, Maven, Spring and more.

I have been wanting to alter my Restlet example that utilizes Spring, Restlet and Maven to use JAXRS or JSR 311 API. The Restlet project supports JAXRS.

For the sake of simplicity, I did not change the client code in anyway, i.e., preferring to use the Restlet API for invocations. In addition JAXRS does not provide for any Client API specifications ;-)

I changed the OrderResource as follows:
@Component @Path("/order")

public class OrderResource {
private static final Logger log = Logger.getLogger(OrderResource.class);

@Autowired private OrderService orderService;
@Autowired private MapperIF beanMapper;

public OrderResource() {
super();
}

private OrderDTO persistOrder(OrderDTO orderDTO) {
if (log.isDebugEnabled()) {
log.debug("Persisting order:" + orderDTO);
}

Order order = (Order) beanMapper.map(orderDTO, Order.class);

if (log.isDebugEnabled()) {
log.debug("Mapped Order" + order);
}

orderService.persist(order);

if (log.isDebugEnabled()) {
log.debug("Mapping persisted order to OrderDTO:" + order);
}
orderDTO = (OrderDTO) beanMapper.map(order, OrderDTO.class);

if (log.isDebugEnabled()) {
log.debug("Returning mapped order:" + orderDTO);
}

return orderDTO;
}

@Path("/{id}") @ConsumeMime("application/xml") @PUT public void updateOrder(
@PathParam("id") String id, OrderDTO orderDTO) {
if (log.isDebugEnabled()) {
log.debug("Enter Update Order, Id=" + id + ", Order DTO:" + orderDTO);
}
Long idLong = new Long(id);
orderDTO.setOrderId(idLong);
orderDTO = persistOrder(orderDTO);

if (log.isDebugEnabled()) {
log.debug("Order Persisted:" + orderDTO);
}
}

@ProduceMime("application/xml") @ConsumeMime("application/xml") @POST public OrderDTO storeOrder(
OrderDTO orderDTO) {
orderDTO = persistOrder(orderDTO);

return orderDTO;
}

@GET @Path("/{id}") @ProduceMime("application/xml") public OrderDTO getOrder(
@PathParam("id") String id) throws OrderNotFoundException {
Long orderId = new Long(id);

Order order = null;

try {
order = orderService.getOrder(orderId);
}
catch (OrderNotFoundException nfe) {
log.error("Order Not Found", nfe);
throw nfe;
}

log.info("Order found..");

OrderDTO orderDTO = (OrderDTO) beanMapper.map(order, OrderDTO.class);

return orderDTO;
}

@DELETE @Path("/{id}") public void deleteOrder(@PathParam("id") String id) {
Long orderId = new Long(id);
orderService.delete(orderId);
}

public void validate() {
Assert.notNull(orderService);
}
}


Notable Changes to the OrderResource:


  1. The @Path annotation on the OrderResource class tells the container that the OrderResource will handle calls of the context /order.
  2. The @Path annotation on some of the methods of the OrderResource denote specifics of the path.
  3. @ConsumeMime and @ProduceMime annotations indicate the mime types that will be consumed or produced by the method respectively.
  4. @POST, @GET, @PUT, @DELETE denote the different HTTP methods and a method annotated with one of these annotations will handle the request of the specific type.
  5. @PathParam denotes a parameter that will be available for the method.

In the above example, we have eliminated code that extends a Restlet Resource class. We have used annotations to specify what HTTP methods the Resource supports. We have also eliminated the Representation concept from the methods in favor of @ProduceMine and @ConsumeMine which help define what mime types can be produced and consumed by the method respectively. JAXRS introduces the concept of Providers that help in marshalling/unmarshalling different mime types. Providers are annotated with the @Provider annotation. In addition, in the case of Exceptions, Exception Providers also can be developed that determine the response to be provided to a client.

If a method is annotated with @ConsumeMime or @ProduceMime of type "application/xml" and the object part of the method argument or return type is a JAXB object, i.e., an object that has the annotation @XmlRootElement, automatic JAXB marshalling is accomplished. The OrderDTO is one such object.


From the example, we also had a ProductResource. The ProductResource from the earlier example only supported the MIME type of "application/jspon". The updated ProductResource is shown below:

@Component @Path("/products") public class ProductsResource {

private static final Logger log = Logger.getLogger(ProductsResource.class);

@Autowired private ProductService productService;
@Autowired private MapperIF beanMapper;

private Set map(Set products) {
Set productDTOs = new HashSet();

for (Product product : products) {
ProductDTO productDTO = (ProductDTO) beanMapper.map(product, ProductDTO.class);
productDTOs.add(productDTO);
}

return productDTOs;
}

/**
* Gets a {@link ProductListDTO} of Products that are supported.
*
* @return a List of Products
*/
@GET @ProduceMime( { "application/json" }) public ProductListDTO getProducts() {
log.debug("Enter getProducts()");

Set products = productService.getProducts();
Set productDTOs = map(products);

if (log.isDebugEnabled()) {
log.debug("Returning Products:" + productDTOs);
}

return new ProductListDTO(productDTOs);
}
}


Unlike in JAXB where the annotations determine the marshalling sematics, for the JSON marshalling, I had to do some customizationwhere we specifically detail how the marshalling should occur.

I have been discussing the operation with Jerome on the Restlet Discussion forum and maybe it will become easier to just specify the mime type and not have to worry about the conversion.

Until then, we can accomplish the conversion to JSON using a custom Provider as shown below:
@ProduceMime("application/json")

@Provider
public class ProductProvider implements
MessageBodyWriter {
private static final Logger log = Logger.getLogger(ProductProvider.class);

public long getSize(ProductListDTO t) {
return -1;
}

public boolean isWriteable(Class type, Type genericType, Annotation[] annotations) {
return true;
}

public void writeTo(ProductListDTO t, Class type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException,
WebApplicationException {

log.debug("Write To of ProductProvider invoked...");

JSONArray jsonArray = new JSONArray();

for (ProductDTO product : t.getProducts()) {
jsonArray.put(product.getProductId()).put(product.getName()).put(product.getDescription());
}

OutputStreamWriter writer = new OutputStreamWriter(entityStream);

try {
writer.write(jsonArray.toString());
writer.flush();
}
catch (IOException e) {
log.error("Error Writing JSON Array:", e);
throw e;
}

log.debug("Exit Write To of ProductProvider");
}
}



When an Order is not found, an OrderNotFoundException is thrown. The same is translated to a Response of HTTP code 404 to the consumer via the following Provider:





@Provider public class OrderNotFoundProvider implements ExceptionMapper {

public Response toResponse(OrderNotFoundException exception) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}




So how do all there components tie together. I have largely based the glue code on a very nice example from the Restlet WIKI about JAXRS Support. I have an OrderConfig class as shown below that indicates the supported MediaType mappings, the Resource Classes and the Custom Provider classes:





public class OrderConfig extends ApplicationConfig {

public Set> getResourceClasses() {
Set> rrcs = new HashSet>();

rrcs.add(OrderResource.class);
rrcs.add(ProductsResource.class);

return rrcs;
}

@Override public Map getMediaTypeMappings() {
Map map = new HashMap();

map.put("html", MediaType.TEXT_HTML_TYPE);
map.put("xml", MediaType.APPLICATION_XML_TYPE);
map.put("json", MediaType.APPLICATION_JSON_TYPE);

return map;
}

public Set>getProviderClasses() {
Set> rrcs = new HashSet>();
rrcs.add(ProductProvider.class);
rrcs.add(OrderNotFoundProvider.class);

return rrcs;
}
}


The Restlet OrderApplication class from my earlier example has now transformed to an instance of JaxRsApplication to which it attaches the above mentioned OrderConfig class:

public class OrderApplication extends JaxRsApplication {

/**
* Class Constructor. Attaches the {@link OrderConfig} class.
*
* @param context Restlet Context
*/
public OrderApplication(Context context) {
super(context);
attach(new OrderConfig());
}
}


One issue we need to address is how will resource classes, Mapper Beans, Services etc get Autowired and injected, i.e., where is the Spring Hook? The JaxRsApplication class supports the concept of Custom Resource creation factories. This hook is utilized by creating a Custom Spring ObjectFactory that instantiates and provides Spring Managed bean. Setting the hook into the JaxRsApplication is achieved using a Custom Restlet ServerServlet as shown below:


public class SpringServlet extends ServerServlet {


public Application createApplication(Context context) {
JaxRsApplication application = (JaxRsApplication) super.createApplication(context);

// Set the Object Factory to Spring Object Factory
application.setObjectFactory(new SpringObjectFactory(getWebApplicationContext()
.getAutowireCapableBeanFactory()));

return application;
}

private static class SpringObjectFactory implements ObjectFactory {
private final AutowireCapableBeanFactory beanFactory;

public SpringObjectFactory(AutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}

public T getInstance(Class jaxRsClass) throws InstantiateException {

@SuppressWarnings("unchecked")
T object = (T) beanFactory.createBean(jaxRsClass,
AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, false);

return object;
}
}

public WebApplicationContext getWebApplicationContext() {
return WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
}
}

I could not use the Restlet's SpringServerServlet for the implementation as it expects a RestletResource and Router etc.

Thoughts on JSR 311 and JAXRS and forward:

I quite like the JSR 311 method of creating the Web Service. I found the clean separation of Providers and Resources via annotations really helpful. The use of annotation makes reading the Resource code very simple and the Resource code itself is not working with Representation's like before. I would like to introduce WADL and WADL2JAVA into the example at some point. I also would like to see better JSON support. In addition, I am curious as how other implementations of JAXRS work and in particular provide for easy integration with my favorite framework Spring. One thing is the lack of a Client API from the specification that I regret.

Enviorment on which example was run:

OS - Windows Vista, JDK-1.6.X, Maven 2.0.8.

The JAXRS, Spring, Maven, Dozer example can be downloaded from HERE.

If you are unable to run the example, as always Ping me and I will be glad to help if I can :-)

Monday, July 21, 2008

Java Instrumentation, javaassist and a new hero Mr.Ted Neward

One of the most interesting sessions that I attended at NFJS was by Ted Neward called " The Busy Java Developer's Guide to Hacking (on) the JDK". I found Mr.Neward to be a very engaging speaker. One of the topics he covered during the session was how to agument java byte code dynamically and the use of the java instrumentation API. I have not directly had a chance to play/work with the same. Regarding byte code enhancement, asm does that and I have used libraries that utilize the same.

Mr.Neward introduced me to javassist, a neat tool to perform byte code augmentation at run time. Based of the same, I have below a simple Maven project that attempts to profile classes.

Keeping the scope simple, the example will only profile classes that are part of the package "com.welflex" and beyond. The code will point out when a method is entered and upon exit of the method and will also print out the time taken for the execution of the method.

The strategy used is that the original method is dynamically replaced with a method that the proxy will delegate to. The original method is named differently (with an impl) and the new proxy method takes the place of the original method and proxies to the new method.

The example is based of maven multi-module project. There are two modules, the first being the actual profiler and the second is an example that will be profiled.
.
-- pom.xml
-- profiler-instrumentation
-- pom.xml
`-- src
`-- main
-- java
`-- welflex
`-- instrumentation
`-- ProfilerClassFileTransformer.java
`-- resources
`-- META-INF
`-- MANIFEST.MF
`-- profiler-target
-- pom.xml
`-- src
`-- main
`-- java
`-- com
`-- welflex
`-- profiletarget
-- Application.java
`-- Description.java



To start of, we define an implementation of the ClassFileTransformer called ProfilerClassTranformer whose core method shown below is responsible for replacing the byte code:
private void addProfilingInformation(CtClass clas, CtMethod mold) throws NotFoundException,
CannotCompileException {
// get the method information (throws exception if method with
// given name is not declared directly by this class, returns
// arbitrary choice if more than one with the given name)
String mname = mold.getName();
String longName = mold.getLongName();

// rename old method to synthetic name, then duplicate the
// method with original name for use as interceptor
String nname = mname + "$impl";

mold.setName(nname);
CtMethod mnew = CtNewMethod.copy(mold, mname, clas, null);

// start the body text generation by saving the start time
// to a local variable, then call the timed method; the
// actual code generated needs to depend on whether the
// timed method returns a value
String type = mold.getReturnType().getName();
StringBuffer body = new StringBuffer();
body.append("{\n");
body.append("int currentStackDepth = Thread.currentThread().getStackTrace().length;\n");
body.append("StringBuffer buf = new StringBuffer();");
body.append("for (int zs = 0; zs < currentStackDepth; zs++) {")
.append("buf.append(\" \");\n")
.append("}");

body.append(" System.out.println(buf.toString() + \"-> Enter Method:" + longName + "\");\n");
body.append(" long startTime = System.nanoTime();\n");
body.append("try {\n");

if (!"void".equals(type)) {
body.append(type + " result = ");
}

body.append(nname + "($$);\n");

if (!"void".equals(type)) {
body.append("return result;\n");
}

body.append("} finally {");
// finish body text generation with call to print the timing
// information, and return saved value (if not void)
body.append("long endTime = System.nanoTime();\n");
body.append("long delta = endTime - startTime;\n");

body.append("System.out.println(buf.toString() + \"<- Exit Method:" + longName +
" completed in \" + delta + \" nano secs\");\n");

body.append(" }\n");
body.append("}");

// replace the body of the interceptor method with generated
// code block and add it to class
mnew.setBody(body.toString());
clas.addMethod(mnew);
}
The code utilizes javassist in augmenting the original methods with profiling information. The target jar produced has a references to the javaassist.jar through the MANIFEST.MF (thanks to my boss for reminding Ted Neward of the same).

The above code should be rather simple to follow where the original method is being replaced by the "Aspect" like code. After downloading the project, issue a "mvn install" command to install the modules. I have additionally provided a ZIP file containing the resultant jars HERE.

In order to ensure that the profiler is applied on the code base, the following java command is executed from within a folder that contains the profiler-instrumentation, javaassist and profiler-target jars as shown below:
java -javaagent:./profiler-instrumentation-1.0-SNAPSHOT.jar -classpath .:profiler-target-1.0-SNAPSHOT.jar com.welflex.profiletarget.Application
-> Enter Method:com.welflex.profiletarget.Application.main(java.lang.String[])
-> Enter Method:com.welflex.profiletarget.Description.setDescription(java.lang.String)
<- Exit Method:com.welflex.profiletarget.Description.setDescription(java.lang.String) completed in 10415 nanosecs
-> Enter Method:com.welflex.profiletarget.Application.rest()
<- Exit Method:com.welflex.profiletarget.Application.rest() completed in 1000072374 nano secs
-> Enter Method:com.welflex.profiletarget.Application.rest(long)
<- Exit Method:com.welflex.profiletarget.Application.rest(long) completed in 3000058065 nano secs
-> Enter Method:com.welflex.profiletarget.Application.getDescription()
-> Enter Method:com.welflex.profiletarget.Description.getDescription()
<- Exit Method:com.welflex.profiletarget.Description.getDescription() completed in 5265 nano secs
<- Exit Method:com.welflex.profiletarget.Application.getDescription() completed in 207834 nano secs
Descripion of App:Simple App
<- Exit Method:com.welflex.profiletarget.Application.main(java.lang.String[]) completed in 4037331452 nano secsva

As seen above the key is to specify a "javaagent" via the "-javaagent" argument to the VM. As shown above that although the profiler-target code did not have any profiling information, we were able to instrument the same at run time using javaassist and the Java Instrumentation library. The above execution shows how long each method took to execute.

The MAVEN project for the profiler can be found HERE . I am running the example with JDK1.6.X and Maven 2.0.8.

The code is largely based of the following two fantastic blogs/articles:
Java Programming Dynamics, Part 4 by Dennis Sosnoski and
Add Logging at Class Load Time with Java Instrumentation
by Thorbjørn Ravn Andersen

If you have problems accessing the source or running the example..ping me. Thaks Mr.Neward..I have such a long way to go...the more I learn, there is still so much more to learn (please don't count the unlearn part) ! The "Force is infinite, I am not yet ready for the Jedi Council", I am still a Padwan! But...a Happy Padwan at that :-)))!

Friday, July 18, 2008

Attending a Symposium/Conference for the first time...

8+ years of Software development and this is the first time I am attending some sort of conference. I have previously not done the same as I did not want to pay the $$$ from my pocket. None of my previous employers have ever decided to shell out money for "my" growth :-)...Thankfully Overstock is so much different. They pay for any developer who wishes to attend a conference and infact encourage the same. Nice to be part of a company that invests back in their employees.

Anyway, I attended an interesting talk where I had my former boss and current boss in the same room. My former boss being a presenter and my current boss part of the audience along with me. I must admit, it is a bit intimidating thinking of the following fictional nightmarish conversation that might have ensued between them:

Former Boss: Can't believe you guys hired the moron..!
Current Boss: Yep! Me too, this is definitely not a case where the phrase, 'Your loss is our gain' is applicable.
Former Boss: He had his moments with us, I am curious as to what damage he has done to you?
Current Boss: Let me see...From the time he has landed, we have suffered quite a few disasters....I really have no way of linking the disasters to him, but I am leaning toward bad karma that most likely is following him.."
Former Boss: "I totally understand..ever since he left, our stock prices rose.."
Current Boss: "You know, since he came, our stock price actually rose, so maybe there is some redemption for him..but then again, our stock fell pretty bad today...I feel he is a time bomb..Any chances we can pay you to take him back?"
......
....more stuff...EEEP!

I hope the above is only part of my dreams ;-))....Lol !

Anyway, regarding NFJS..from what I attended not bad, I was not blown away or can say I enjoyed all the talks but one cannot hope to satisfy everyone.

...I think I might be able to do something like this, atleast that is the goal...Just need a good enough topic.."Sadness that there is no originality in me :-("....I need a good counsellor, and puhlease, I don't mean a shrink!

I liked the talk about base Java by Venkat Subramaniam...a very lively speaker, some topics were basic but the presentation was super, I must admit I learned stuff! I liked Ken Sipe's "Hacking, the Dark Arts"..nicely done with lot of examples, tips etc...

Got another day of NFJS tomorrow...can't wait to get there...I hope I can goto Java One one of these days..I just want to sight Gosling or Rod Johnson or Martin Fowler and that will be more memorable than the close encounter of the third kind I had the other day ;-)

Wednesday, July 16, 2008

More on the equals()/hashCode() Hack with Hibernate

The last blog I did not address Object Retrival. A reader of the blog mentioned the same. Prior to Hibernate 3, I beleive that custom collections could not be supported. However, as of Hibernate 3, they are. R.J.Lorimer's blog on how to implement the same is super!

The use of a the attribute "collection-type" when defining the mapping of the Set is the key to the solution.

So moving forward, for Hibernate, we define a custom CollectionType that factories the PropertyListenerHashSet as shown below:

  1 public class HibernatePropListenerHashSetType implements UserCollectionType {
2 public boolean contains(Object collection, Object entity) {
3 Set set = (Set) collection;
4 return set.contains(entity);
5 }
6
7 public Iterator getElementsIterator(Object collection) {
8 return ((Set) collection).iterator();
9 }
10
11 public Object indexOf(Object collection, Object entity) {
12 return null;
13 }
14
15 public Object instantiate(int anticipatedSize) {
16 return new PropertyListenerHashSet();
17 }
18
19 public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister) throws HibernateException {
20 return new PersistentSet(session);
21 }
22
23 @SuppressWarnings("unchecked") public Object replaceElements(Object original, Object target,
24 CollectionPersister persister, Object owner, Map copyCache, SessionImplementor session) throws HibernateException {
25 Set setA = (Set) original;
26 Set setB = (Set) target;
27 setB.clear();
28 setB.addAll(setA);
29
30 return null;
31 }
32
33 public PersistentCollection wrap(SessionImplementor session, Object collection) {
34 return new PersistentSet(session, (Set) collection);
35 }
36 }
Pretty simple...now the blocker!! Hibernate does not have an annotation that will support the custom collection-type, for example, something like @CollectionType (name=FooCollection.class). This hibernate forum entry describes the situation. It might be supported at a later date.

In the meanwhile, we can still achieve the custom collection type using hbm mappings :-). So reverting to XML mapping, we defined the Organization object's mapping to use our custom collections as follows:

  1 <set name="applications"  inverse="true" cascade="all-delete-orphan"
2 collection-type="com.welflex.collection.HibernatePropListenerHashSetType">
3 <key column="ORG_ID" not-null="true"/>
4 <one-to-many class="com.welflex.model.SmartApplication" />
5 </set>


The unit test has been augmented to test for the same:

  1     try {
2 session = HibernateUtil.getSessionFactory().getCurrentSession();
3 tx = session.beginTransaction();
4 Organization org = (Organization) session.load(Organization.class, orgId);
5 org.addApplication(app);
6 assertTrue(org.getApplications().contains(app));
7
8 // Lets add a new App to the set
9 SmartApplication otherApp = new SmartApplication();
10 otherApp.setName("Foo Bar");
11 org.addApplication(otherApp);
12 assertEquals(2, org.getApplications().size());
13
14 session.update(org);
15 session.flush();
16
17 // Upon Saving if our collection's contains matches up, our code woiked!
18 assertTrue(otherApp.getId() != null);
19 assertTrue("More acid test", org.getApplications().contains(otherApp));
20 tx.commit();
21 }
A Maven example of the above is available HERE.  Enjoy!!!





Tuesday, July 8, 2008

Java - equals(), hashCode(), Object Identity, A HACK solution....

Introduction:
Time to provide a note to myself again. I am using this blog to log stuff that act as notes for me. I hate searching for some stuff on the Internet. There are times when I am involved with re-learning and this is one of those times :-).

Wise men of java say, "When you override the equals() method in java, you must also override hashCode()"..Why is that so? I found an nice blog/article on the same to explain better than I ever can.

In short, whenever an object is added to a HashSet, its hashCode() method is interrogated. The value obtained there is used in a computation to determine in which bucket to place the object in. Many objects could hash to the same bucket. The way an object is found in the HashSet is to first hash to the bucket and then run through the elements in the bucket with a comparison of identity or equals. I hope I am right on this ;-)

What I am hoping to explore is equals and hashCode from a persistence perspective, i.e., when using persistent/persistable entities.

Exploration of Problem:

Let us consider a problem domain for the sake of discussion. Our problem domains involves Organizations and Applications there in. Every Organization has one or more Applications. In our domain, an Application is unique by virtue of its name. The underlying data model will not allow two applications with the same name. Additionally, as an Organization, we choose to use surrogate id's and not natural ids for primary keys. In other words, the name attribute of an Application object will not be the pk but an alternate key. Additionally, the name of a persisted application could be changed over time.




public class Application {
private Integer id;
private String name;

public Application() {}

public Integer getId() { return id; }

public void setId(Integer id) { this.id = id;}

public String getName() { return name; }

public void setName(String name) { this.name = name; }
}


The above implementation does not override equals() or hashCode(). The following are some unit-tests against the above class.




  1  @Test public void testIdentity() throws Exception {
2 HashSet<Application> appSet = new HashSet<Application>();
3
4 Application app = new Application();
5 Application appOther = new Application();
6
7 appSet.add(app);
8
9 assertTrue("Set must contain inserted application", appSet.contains(app));
10 assertFalse("Set must not contain other app as it should be using identity for equals", appSet
11 .contains(appOther));
12 assertFalse("Should not be equal", app.equals(appOther));
13 assertFalse("Should not have the same hashcodes as different objects",
14 app.hashCode() == appOther.hashCode());
15
16 app.setId(new Integer(2));
17 appOther.setId(new Integer(2));
18
19 assertTrue("Object should still be obtainable from the due to identity", appSet.contains(app));
20 assertFalse("Set must not contain other app as it should be using identity for equals", appSet
21 .contains(appOther));
22 }


From the above example, two objects are neither equal nor share the same hashCode even though they appear to be the same, i.e., don't have any properties set. Even if the properties are set, they still appear un-equal as equals() and hashCode() are different.

Lets now look at a similar class where equals() has been overridden using the object's id property but the hashCode() method has not been overridden.




  1   @Override public boolean equals(Object otherApp) {
2 if (!(otherApp instanceof AppWithEqualsImpl)) { return false;
3
4 if (this == otherApp) { return true; }
5
6 if (this.getClass() != otherApp.getClass()) { return false;}
7
8 AppWithEqualsImpl other = (AppWithEqualsImpl) otherApp;
9
10 if (id == null) {
11 if (other.id != null)
12 return false;
13 }
14 else if (!id.equals(other.id))
15 return false;
16
17 return true;
18 }


Some tests with class:



  1   @Test public void testOnlyEqualsImpl() throws Exception {
2 HashSet<AppWithEqualsImpl> appSet = new HashSet<AppWithEqualsImpl>();
3
4 AppWithEqualsImpl app = new AppWithEqualsImpl();
5 AppWithEqualsImpl appOther = new AppWithEqualsImpl();
6
7 appSet.add(app);
8
9 assertTrue("App and other App are equal", app.equals(appOther));
10 assertTrue("App and other App don't have same hashcode", app.hashCode() != appOther.hashCode());
11 assertTrue("Set must contain inserted application", appSet.contains(app));
12 assertFalse(
13 "Set will not contain other instance as although equal, they have different hashCodes",
14 appSet.contains(appOther));
15
16 app.setId(new Integer(10));
17 assertTrue("Set should contain app as equals has changed but not hashcode", appSet
18 .contains(app));
19
20 appOther.setId(new Integer(10));
21 assertFalse(
22 "Set will not contain other instance as although equal in Id, they still have different hashCodes",
23 appSet.contains(appOther));
24 }


The above example demonstrates, that although both the objects are identical, as they have different hash Codes, the "appOther" object will fail the contains() test on the HashSet. The object added to the set is located as it matched both on identity and hashCode. After changing the "app" objects, Id field, it can still be found in the HashSet as the hashCode of the object has not altered and is still hashing to the same bucket. However, the problem to note here is that although "otherApp" is equal to the app in the Set, the Set considers "appOther" as a totally different object, thus breaking set semantics (i.e., duplicates) if "appOther" is inserted.

So we need to implement hashCode so that both "app" and "appOther" hash to the same bucket. Lets take a look at a variant that does exactly that:




  1 @Override public int hashCode() {
2 final int prime = 31;
3 int result = 1;
4 result = prime * result + ((id == null)
5 ? 0
6 : id.hashCode());
7 return result;
8 }
9
10 @Override public boolean equals(Object obj) {
11 if (!(obj instanceof AppWithEqualsHashCodeImpl)) { return false;}
12
13 if (this == obj) { return true;}
14
15 if (this.getClass() != obj.getClass()) { return false;}
16
17 final AppWithEqualsHashCodeImpl other = (AppWithEqualsHashCodeImpl) obj;
18 if (id == null) {
19 if (other.id != null)
20 return false;
21 }
22 else if (!id.equals(other.id))
23 return false;
24
25 return true;
26 }


A few tests based of the above class:




  1 @Test public void testEqualsAndHashCodeImpl() {
2 HashSet<AppWithEqualsHashCodeImpl> appSet = new HashSet<AppWithEqualsHashCodeImpl>();
3
4 AppWithEqualsHashCodeImpl app = new AppWithEqualsHashCodeImpl();
5 AppWithEqualsHashCodeImpl appOther = new AppWithEqualsHashCodeImpl();
6
7 appSet.add(app);
8
9 assertTrue("Set must contain inserted application", appSet.contains(app));
10 assertTrue("Set must return a match for contains of appOther as equals/hashCode are same now",
11 appSet.contains(appOther));
12
13 app.setId(new Integer(10));
14
15 assertEquals(app, appSet.iterator().next());
16 assertTrue(app.hashCode() == appSet.iterator().next().hashCode());
17
18 // Note the below
19 assertFalse(
20 "Set contains() should return false when checked for inserted app as hashcode has now changed."
21 + "Contains will check agaisnt a new bucket based of the new hashcode.", appSet
22 .contains(app)); // This means adding app back to the collection will have two elements.
23
24 appSet.add(app);
25 assertEquals(2, appSet.size());
26 }


In the above tests, as the object override's equal and hashCode, when "appOther" is considered the same object by the Set, thus preserving Set semantics. All good, however, look at the lines from 13-25 where we change a property that is participating in the hashCode. When the original added object is checked agaisnt the collection to see if the collection contains it, the collection reports back as false. Whatever is happening???

The problem is that as we changed a property of the object that participates in the hashCode calculation, we have effectively changed the hashCode of the object. When contains() is invoked, it tries to locate the object using the new hashCode. However, the object is present in the Set based of the old hash code and therefore cannot be located. What a pain? The first question we ask is can't we say appSet.rehash() so that the inserted object's hashCode is re-invoked and placed in the correct bucket? The API does not support RE-hashing. And probabaly rightfully so.

Is there anyway, we can overcome this problem? There are multiple solutions. One common path is to not include mutable properties as part of the hashCode() implementation and instead use a an alternate key or business key of the object for the same. In our domain, we know that an Application is uniquely identified by its name, so we can use that for the hashCode computation as shown below:




  1 public class AppWithBizKeyEquals {
2 private Integer id;
3
4 // This is a part of the business Key
5 private final String name;
6
7 public AppWithBizKeyEquals(String name) {
8 this.name = name;
9 }
10 // No setter for name. However there are setter's for id
11 .....
12 .....
13 @Override public int hashCode() {
14 final int prime = 31;
15 int result = 1;
16 result = prime * result + ((name == null)
17 ? 0
18 : name.hashCode());
19 return result;
20 }
21
22 @Override public boolean equals(Object obj) {
23 if (this == obj) return true;
24 if (obj == null) return false;
25 if (getClass() != obj.getClass()) return false;
26 final AppWithBizKeyEquals other = (AppWithBizKeyEquals) obj;
27 if (name == null) {
28 if (other.name != null)
29 return false;
30 }
31 else if (!name.equals(other.name))
32 return false;
33 return true;
34 }


In the above class, the name field is what constituted the business key and is set as immutable. One cannot change the value of the name after object creation. We are still able to alter the "id" property of the object after creation. Lets take a look at some tests:




  1 @Test public void testBusinessKeyEqualHashCode() {
2 HashSet<AppWithBizKeyEquals> appSet = new HashSet<AppWithBizKeyEquals>();
3
4 AppWithBizKeyEquals app = new AppWithBizKeyEquals("Foo");
5 AppWithBizKeyEquals appOther = new AppWithBizKeyEquals("Foo");
6
7 appSet.add(app);
8
9 assertTrue("Both instances must be equal", app.equals(appOther));
10 assertTrue("Both instances must have same hashcode", app.hashCode() == appOther.hashCode());
11
12 assertTrue("Set must contain inserted application", appSet.contains(app));
13 assertTrue("Set must return a match for contains of appOther as equals/hashCode are same now",
14 appSet.contains(appOther));
15
16 app.setId(new Integer(10));
17
18 assertTrue("Both instances are still equal as Id is not part of biz equality", app
19 .equals(appOther));
20 assertTrue(
21 "Both instances must still have same hashcode as Id should not have changed hashCode", app
22 .hashCode() == appOther.hashCode());
23
24 assertTrue("Set must contain inserted application", appSet.contains(app));
25 assertTrue(
26 "Set must return a match for contains of appOther as equals/hashCode are unaffected by id change",
27 appSet.contains(appOther));
28 }


In the above example, notice that both "app" and "appOther" are constructed by providing the name of the application. Both their hashCode() and equals() match. Changing the "id" property of the "app" object has no effect on locating the object in the Set as the "id" property does not participate in the hashCode() calculation.

This works great. However, has some deficiencies:

a. We need to find a business key always. Sometimes, it might be the entire object.
b. Business key becomes immutable

In our example, we could identify the name of the Application as the business key. However, as per our requirement, the name of an Application can be changed. The works agains't the immutability constraints that we have imposed on our object. There are work around to the same but clearly this not ideal.

So, can we overcome this problem where changing of a property that participates in the hashCode calculation of an object still allows us to locate the object by querying the HashSet?

One direction we could have hoped to take is that before the "id" of the object is set, we remove the object from the Set and after the Id is set we re-insert it back. That would work. However, what if the object was part of another object like an Organization and saving the Organization object would implicitly save the children Application objects thus providing "id" for them? How can we intercept the same?




  1 Organization org = new Organization("Foo Org");
2 Application app = new Application();
3 app.setName("Foo");
4 org.getApplications().add(app);
5 persister.save(app);
6
7 assertTrue(org.getApplications().contains(app));


Clearly the above code would fail the validation based of the previous mentioned examples.

So is there no way we can accomplish this???

Well, there may be others. I however, thought of one really bad hack that would make this work. It requires some deviations but acheives the results. The solution is neither performant, not safe, not anything else and I am not patenting the same here!!! There go the $$$$ :-))))

So what is the hack? What if we could acheive the removal and addition of the Object into the Set implicitly thereby simulating a rehash of the object?

To assist with the hack, enter the design patterns such as Observer (Listener).

The Hack:
To aid with the hack, we start with an Annotation. The annotation, HashCodeParticipator, will be applied to any field in a model object that will participate in the calculation of the hashCode().



  1 @Retention(RetentionPolicy.RUNTIME) public @interface HashcodeParticipator {}

We will be utilizing the PropertyChange support of Java Beans. To aid with our solution, we define an event class that is an extension of java.beans.PropertyChangeEvent. This event will be fired when a Property that participates in the hashCode() is:

a. About to be changed
b. Changed




  1 public class HashCodeElementChangeEvent extends PropertyChangeEvent {
2 public static final int HASH_PARTICIPANT_WILL_CHANGE = 0;
3 public static final int HASH_PARTICIPANT_CHANGED = 1;
4
5 private final int eventType;
6
7 public HashCodeElementChangeEvent(Object source, String propertyName, int eventType) {
8 super(source, propertyName, null, null);
9 if (eventType != HASH_PARTICIPANT_CHANGED && eventType != HASH_PARTICIPANT_WILL_CHANGE) {
10 throw new IllegalArgumentException("Invalid Event Type");
11 }
12 this.eventType = eventType;
13 }
14
15 public boolean isChangingNotificationEvent() {
16 return eventType == HASH_PARTICIPANT_WILL_CHANGE;
17 }
18 }


We also define an interface called PropertyChangeNotifier, that implementing objects will utilize to notify listeners when a property that participates in the hashCode() computation is undergoing change.




  1 public interface PropertyChangeNotifier {
2 public void addHashCodePropertyChangeListener(PropertyChangeListener propertyChangeListener);
3 public void removeHashCodePropertyChangeListener(PropertyChangeListener propertyChangeListener);
4 }


Ok, so we now have a notifier. Show me the listener. We define an extension of a HashSet that is a listener of these events. The extended HashSet will receive two types of events. The first when a property that participates in the source object is about to be mutated and a second event after the mutation. Upon receipt of the pre-mutation event, the Set will remove the source object from its collection and upon receiving the post mutation event, it will re-insert the same into its collection of maintained objects. Lets take a look at the listener Set:




  1 public class PropertyListenerHashSet<E extends PropertyChangeNotifier> extends HashSet<E> implements
2 PropertyChangeListener {
3
4 public PropertyListenerHashSet() {
5 super();
6 }
7 // Other constructors..
8 ....
9
10 /**
11 * Addition to the set involves registering the Set as a Listener
12 * of the Object being added.
13 *
14 * @param o Object to add to the Set.
15 */

16 @Override public boolean add(E o) {
17 boolean retVal = super.add(o);
18 // Add Listener
19 ((PropertyChangeNotifier) o).addHashCodePropertyChangeListener(this);
20
21 return retVal;
22 }
23
24 /**
25 * Removes specified object from the set.
26 * Part of the removal operation involves de-registering the set
27 * as a listener of the object.
28 */

29 @Override public boolean remove(Object o) {
30 removeListener(o);
31 return super.remove(o);
32 }
33
34 /**
35 * On A PropertyChangeEvent, if the event is a notification that
36 * a HashCode participating attribute is altering, then the object
37 * is removed from the collection. A subsequent property change event
38 * will ensure the object is added back to the collection.
39 */

40 public void propertyChange(PropertyChangeEvent evt) {
41 if (! (evt instanceof HashCodeElementChangeEvent)) {
42 return;
43 }
44
45 HashCodeElementChangeEvent event = (HashCodeElementChangeEvent) evt;
46
47 if (event.isChangingNotificationEvent()) {
48 super.remove(event.getSource());
49 } else {
50 // Note that the object already has this Set as a listener
51 super.add((E) evt.getSource());
52 }
53 }
54
55 @Override
56 public void clear() {
57 for (E item : this) {
58 ((PropertyChangeNotifier) item).removeHashCodePropertyChangeListener(this);
59 }
60 super.clear();
61 }
62
63 private void removeListener(Object obj) {
64 for (Iterator<E> i = iterator(); i.hasNext();) {
65 E item = i.next();
66 if (item.equals(obj)) {
67 ((PropertyChangeNotifier) item).removeHashCodePropertyChangeListener(this);
68 break;
69 }
70 }
71 }
72 }
73


The items to note in the above class are; that whenever an element is added, the Set regsiter's as a listener of the object and when removed its the opposite. Also note the behavior when the PropertyChangeEvent is received, i.e., the addition and removal of the source object.

Now, lets look at an implementation of the PropertyChangeNotifier interface. For the sake of ease, we define a base class called BO (Business Object for short) as shown below:




  1 public class BO implements PropertyChangeNotifier {
2 protected transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
3 private final Set<String> hashCodeProperties = new TreeSet<String>();
4
5 @SuppressWarnings("unchecked") public BO() {
6 // Doing so we will not have to listener for all property changes.
7 Class child = this.getClass();
8 Field[] fields = child.getDeclaredFields();
9
10 for (Field field : fields) {
11 // If field is Participating in hashCode by virtue of annotation
12 if (field.getAnnotation(HashcodeParticipator.class) != null) {
13 hashCodeProperties.add(field.getName());
14 }
15 }
16 }
17 ....
18 ....
19 // Register only to be notified on properties that are hash code participants
20 public void addHashCodePropertyChangeListener(PropertyChangeListener propertyChangeListener) {
21 for (String hashCodeParticipant : annotatedProperties) {
22 propertyChangeSupport.addPropertyChangeListener(hashCodeParticipant, propertyChangeListener);
23 }
24 }
25 .....
26 .....
27
28 // Fire an event when a hash code participant property is about to change
29 public void fireHashCodeParticipantChangingEvent(String hashCodeParticipant) {
30 propertyChangeSupport.firePropertyChange(new HashCodeElementChangeEvent(this, hashCodeParticipant,
31 HashCodeElementChangeEvent.HASH_PARTICIPANT_WILL_CHANGE));
32 }
33
34 // Fire an event when the hash code participant property has been mutated.
35 public void fireHashCodeParticipantChangedEvent(String hashCodeParticipant) {
36 propertyChangeSupport.firePropertyChange(new HashCodeElementChangeEvent(this, hashCodeParticipant,
37 HashCodeElementChangeEvent.HASH_PARTICIPANT_CHANGED));
38 }
39 }
40


Lets look an implementation of our SmartApplication object that extends the BO. The object uses only the "id" property for equals() and hashCode() implementations. I am not showing the entire class but only the methods of interest below:




  1   /**
2 * Note this should probabaly be aspect handled. 1. beforeMethod - If method contains
3 * HashCodeParticipator annotation fireGoingtoChangeEvent 2. executeMethod 3. afterMethod - If
4 * method contains HashCodeParticipator fireChangedEvent
5 *
6 * @param id
7 */

8 public void setId(Integer id) {
9 fireHashCodeParticipantChangingEvent("id");
10 this.id = id;
11 fireHashCodeParticipantChangedEvent("id");
12 }
13
14 public String getName() {
15 return name;
16 }
17
18 public void setName(String name) {
19 String origName = this.name;
20 this.name = name;
21 propertyChangeSupport.firePropertyChange("name", origName, name);
22 }
23


In the above methods of the Smart Application class, the setId() method first fires an event to listeners that a hashCode property will be changed and after changing the property, fires another event stating the property has been mutated. Although not shown, the "id" property has an annotation of @HashCodeParticipant. Also note that when the "name" property is set, a simple property change event is fired.

Lets take a look at some unit tests that utilize the hacked framework:




  1 @Test public void testSmartApplication() throws Exception {
2 HashSet<SmartApplication> appSet = new PropertyListenerHashSet<SmartApplication>();
3
4 SmartApplication app = new SmartApplication();
5
6 appSet.add(app);
7 assertEquals("Should have only one listner, i.e., the Set", 1, app.getListenerCount());
8 assertTrue("Set must contain inserted application", appSet.contains(app));
9
10 // Mutate a hashCode participating propertt
11 app.setId(new Integer(10));
12
13 // The set now returns true for the contains due to hacked re-hash
14 assertTrue(appSet.contains(app));
15 assertEquals(1, app.getListenerCount());
16
17 // Remove from Set
18 assertTrue(appSet.remove(app));
19 assertEquals(0, app.getListenerCount());
20
21 assertFalse(appSet.contains(app));
22 assertEquals(0, appSet.size());
23
24 appSet.add(app);
25 assertEquals(1, appSet.size());
26 assertEquals(1, app.getListenerCount());
27
28 // Should not cause a property change event
29 app.setName("Foo");
30 appSet.clear();
31 assertEquals(0, appSet.size());
32 assertEquals(0, app.getListenerCount());
33 }


In the above example, even after the "id" property is changed, i.e., a property that participates in the hashCode() computation, the original object can still be located in the HashSet :-))) We managed to implement a transparent re-hash hack!

So what next???

Will this work with Hibernate?
The hibernate FAQ on equals/hashCode states the following:

"Will this work?
HashSet set = new HashSet();
User u = new User();
set.add(u);
session.save(u);
assert(set.contains(u));"

The answer is no, it will not work, for all the reasons discussed above. However, if we utilize the hack-framework mentioned above, it will.

To illustrate the solution, we introduce the Organization object. The Organization object contains an instance of our extended HashSet of Application objects like so:




  1   @OneToMany(mappedBy="organization",cascade=CascadeType.ALL, fetch=FetchType.EAGER)
2 @JoinColumn(name="ORG_ID")
3 @Fetch(value=FetchMode.JOIN)
4 private Set<SmartApplication> applications = new PropertyListenerHashSet<SmartApplication>();


One important thing to note is that Hibernate assigns the properties using "Reflection" by default. If our SmartApplication object's "id" property is assigned using Reflection, we cannot fire a property change. Therefore we need to ensure that the "id" property is set using the setter method. The same is accomplished using the annotation @AccessType (value="property") as shown below:




  1   @AccessType(value="property")
2 @HashcodeParticipator
3 private Integer id;


Now the unit test:




  1 @Test
2 public void testPersistence() {
3 Session session = HibernateUtil.getSessionFactory().getCurrentSession();
4 Transaction tx = null;
5 try {
6 tx = session.beginTransaction();
7 Organization org = new Organization();
8 org.setName("Foo Company");
9
10 SmartApplication app = new SmartApplication();
11 app.setName("Auditing");
12
13 org.addApplication(app);
14
15 session.save(org);
16
17 // This is the acid test....
18 assertTrue(org.getApplications().contains(app));
19 tx.commit();
20 } catch (Exception e) {
21 e.printStackTrace();
22 tx.rollBack();
23 }
24 }


The above test passes :-))))))))))))))))))))))

Conclusion:

The above mentioned solution is a hack!!! Please do not implement the same. I was only curious as to how one could overcome the problem and let my insane mind play. The code/article has not had any reading or advocation. There are issues such as performance, synchronization, Hibernate Read etc, etc, etc to be investigated.

I am a brooder by nature where someone's comment on a topic sends me over-analysing the same. My thinking does not necessarily equate to productivity or a good solution. The blog was meant more as an education to myself and a singular place to understand/refer to equals/hashCode. I only hope the above helps someone treading the same path as myself understand the esoteric world of Hashing better :-))). If I am in error, I would appreciate direction.

I have attached herewith a Maven project with the different scenarios. As a parting note, when implementing equals/hashCode

1. Attempt to find a business equals/hashCode when applicable
2. Ensure that you check for immediate object identity via this == other.
3. Check for class equality. This is specially important when a subtype fails to override equals/hashcode and a super-type evaluates as being the same as the sub-type which does not make sense. For example every Car is not a Porsche ;-)
4. Use a mutable property for hashCode judiciously. Watch for Id's specially.
5. Any finally, override equals and hashCode if the object in concern will ever be used as a Key of a HashMap or as an item in a HashSet.
6. GUID - This is a different blog.
7. Objects that are part of equals do not have to be part of hashCode
8. Attempt to contact more prominent brains such as Gosling, Gaving King or Rod Johnson for assistance....;-)..kidding.

G.N...what a Rant!!!! This must take the cake :-)))))