Monday, April 1, 2013

JMS and Spring: Small Things Sometimes Matter

JmsTemplate and DefaultMessageListenerContainer are Spring helpers for accessing JMS compatible MOM. Their main goal is to form a layer above the JMS API and deal with infrastructure such as transaction management/message acknowledgement and hiding some of the repetitive and clumsy parts of the JMS API (hang in there: JMS 2.0 is on its way!). To use either one of these helpers you have to supply them with (at least) a JMS ConnectionFactory and a valid JMS Destination.

When running your app on an application server, the ConnectionFactory will most likely be defined using the JEE architecture. This boils down adding the ConnectionFactory and its configuration parameters allowing them to be published in the directory service under a given alias (eg. jms/myConnectionFactory). Within your app you might for example use the "jndi-lookup" out of the JEE namespace or JndiTemplate/JndiObjectFactoryBean beans if more configuration is required for looking up the ConnectionFactory and pass it along to your JmsTemplate and/or DefaultMessageListenerContainer.

The latter, JMS destination, identifies a JMS Queue or Topic for which you want to produce messages to or consume mesages from. However, both JmsTemplate as DefaultMessageListenerContainer have two different properties for injecting the destination. There is a method taking the destination as String and one taking it as a JMS Destination type. This functionality is nothing invented by Spring, the JMS specification mentions both approaches:

4.4.4 Creating Destination Objects
Most clients will use Destinations that are JMS administered objects that they have looked up via JNDI. This is the most portable approach.
Some specialized clients may need to create Destinations by dynamically manufacturing one using a provider-specific destination name. 
Sessions provide a JMS provider-specific method for doing this.
If you pass along a destination as String then the helpers will hide the extra steps required to map them to a valid JMS Destination. In the end a createConsumer on a JMS Session expects you to pass along a Destination object to indicate where to consume messages from before returning a MessageConsumer.

When destinations are configured as String, the Destination is looked up by Spring using the JMS API itself. By default JmsTemplate and DefaultMessageListenerContainer have a reference to a DestinationResolver which is DynamicDestinationResolver by default (more on that later). The code below is an extract from DynamicDestinationResolver, the highlighted lines indicate the usage of the JMS API to transform the String to a Destination (in this example a Queue):

 protected Queue resolveQueue(Session session, String queueName) throws JMSException {
  if (session instanceof QueueSession) {
   // Cast to QueueSession: will work on both JMS 1.1 and 1.0.2
   return ((QueueSession) session).createQueue(queueName);
  }
  else {
   // Fall back to generic JMS Session: will only work on JMS 1.1
   return session.createQueue(queueName);
  }
 }
The other way mentioned by the spec (JNDI approach) is to configure Destinations as administrable objects on your application server. This follows the principle as with the ConnectionFactory; the destination is published in the applications servers directory and can be looked up by its JNDI name (eg. jms/myQueue). Again you can lookup the JMS Destination in your app and pass it along to JmsTemplate and/or DefaultMessageListenerContainer making use of the property taking the JMS Destination as parameter.

Now, why do we have those two options?

I always assumed that it was a matter of choice between convenience (dynamic approach) and environment transparancy/configurability (JNDI approach). For example: in some situations the name of the physical destination might be different depending on the environment where your application runs. If you configure your physical destination names inside your application you obviously loose this benefit as they cannot be altered without rebuilding your application. If you configured them as administered object on the other hand, it is merely a simple change in the application server configuration to alter the physical destination name.

Remember; having physical Destinations names configurable can make sense. Besides the Destination type, applications dealing with messaging are agnostic to its details. A messaging destination has no functional contract and none of its properties (physical destination, persistence, and so forth) are of importance for the code your write. The actual contract is inside the messages itself (the headers and the body). A database table on the other is an example of something that does expose a contract by itself and is tightly coupled with your code. In most cases renaming a database table does impact your code, hence making something like this configurable has normally no added value compared to a messaging Destination.

Recently I discovered that my understanding of this is not the entire truth. The specification (from "4.4.4 Creating Destination Objects" as pasted some paragraphs above) already gives a hint: "Most clients will use Destinations that are JMS administered objects that they have looked up via JNDI. This is the most portable approach." Basically this tells us that the other approach (the dynamic approach where we work with a destination as String) is "the least portable" way. This was never really clear to me as each provider is required to implement both methods, however "portable" has to be looked at in a broader context.

When configuring Destinations as String, Spring will by default transform them to JMS Desintations whenever it creates a new JMS Session. When using the DefaultMessageListenerContainer for consuming messages each message you process occurs in a transaction and by default the JMS session and consumer are not pooled, hence they are re-created for each receive operation. This results in transforming the String to a JMS Destination each time the container checks for new messages and/or receives a new message. The "non portable" aspect comes into play as it also means that the details and costs of this transformation depend entirely on your MOM's driver/implementation. In our case we experienced this with Oracle AQ as MOM provider. Each time a destination transformation happens the driver executes a specific query:

select   /*+ FIRST_ROWS */  t1.owner, t1.name, t1.queue_table, t1.queue_type, t1.max_retries, t1.retry_delay, t1.retention, t1.user_comment, t2. type , t2.object_type, t2.secure
from  all_queues t1, all_queue_tables t2
where  t1.owner=:1 and  t1.name=:2 and  t2.owner=:3 and  t1.queue_table=t2.queue_table
Forum entry can be found here.

Although this query was improved in the latest drivers (as mentioned by the bug report), it was still causing significant overhead on the database. The two options to solve this:

  • Do what the specification advices you to do: configure destinations as resources on the application server. The application server will hand out the same instance each time, so they are already cached there. Even though you will receive the same instance for every lookup, when using JndiTemplate (or JndiDestinationResolver, see below) it will also be chached application side, so even the lookup itself will only happen once.
  • Enable session/consumer caching on the DefaultMessageListenerContainer. When the caching is set to consumer, it indirectly also re-use the Destination as the consumer holds a reference to the Destination. This pooling is Spring added functionality and the JavaDoc says it safe when using resource local transaction and it "should" be safe when using XA transaction (except running on JBoss 4).
The first is probably the best. However in our case all destinations are already defined inside the application (and there are plenty of them) and there is no need for having them configurable. Refactoring these merely for this technical reason is going to generate a lot of overhead with no other advantages. The second solution is the least preferred one as this would imply extra testing and investigation to make sure nothing breaks. Also, this seems to be doing more then needed, as there is no indication in our case that creating a Session or Consumer has measurable impact on performance. According to the JMS specification:
4.4 Session
A JMS Session is a single-threaded context* for producing and consuming
messages. Although it may allocate provider resources outside the Java virtual
machine, it is considered a lightweight JMS object.
Btw; this is also valid for MessageConsumers/Producers. Both of them are bound to a session, so if a Session is lightweight to open then these objects will be as well.

There is however a third solution; a custom DestinationResolver. The DestinationResolver is the abstraction that takes care of going from a String to a Destination. The default (DynamicDestinationResolver) uses the createConsumer(javax.jms.Destination) on the JMS Session to transform, but it does however not cache the resulting Destination. However, if your Destinations are configured on the application server as resources, you can (besides using Spring's JNDI support and injection the Destination directly) also use JndiDestinationResolver. This resolver will treat the supplied String as a JNDI location (instead of physical destination name) and perform a lookup for you. By default it will cache the resulting Destination, avoiding any subsequent JNDI lookups. Now, one can also configure JndiDestinationResolver as a caching decorator for the DynamicDestinationResolver. If you set fallback to true, it will first try to use the String as a location to lookup from JNDI, if that fails it will pass our String along to DynamicDestinationResolver using the JMS API to transform our String to a Destination. The resulting Destination is in both cases cached and thus a next request for the same Destination will be served from the cache. With this resolver there is a solution out of the box without having to write any code:

 <bean id="cachingDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
  <property name="cache" value="true"/>
  <property name="fallbackToDynamicDestination" value="true"/> 
 </bean>

 <bean id="infra.abstractMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" abstract="true">
  <property name="destinationResolver" ref="cachingDestinationResolver"/>
  ...
 </bean>
The JndiDestinationResolver is thread safe by internally using a ConcurrentHasmap to store the bindings. A JMS Destination is on itself thread safe according to the JMS 1.1 specification (2.8 Multithreading) and can safely be cached:

This is again a nice example on how simple things can sometimes have an important impact. This time the solution was straightforward thanks to Spring. It would however been a better idea to make the caching behaviour the default as this would decouple it from any provider specific quirks in looking up the destination. The reason this isn't the default is probably because the DefaultMessageListenerContainer supports changing the destination on the fly (using JMX for example):

Note: The destination may be replaced at runtime, with the listener container picking up the new destination immediately (works e.g. with DefaultMessageListenerContainer, as long as the cache level is less than CACHE_CONSUMER). However, this is considered advanced usage; use it with care!

Monday, March 4, 2013

Bulk fetching with Hibernate

If you need to process large database result sets from Java you can opt for JDBC to give you the low level control required. On the other hand if you are already using an ORM in your application falling back to JDBC might imply some extra pain. You would be losing features such as optimistic locking, caching, automatic fetching when navigating the domain model and so forth. Fortunately most ORMs, like Hibernate, have some options to help you with that. While these techniques are not new, there are a couple of possibilities to choose from.

A simplified example; let's assume we have a table (mapped to class "DemoEntity") with 100.000 records. Each record consists of a single column (mapped to the property "property" in DemoEntity) holding some random alphanumerical data of about ~2KB. The JVM is ran with -Xmx250m. Let's assume that 250MB is the overall maximum memory that can be assigned to the JVM on our system. Your job is to read all records currently in the table, doing some not further specified processing, and finally store the result. We'll assume that the entities resulting from our bulk operation are not modified. To start we'll try the obvious first, performing a query to simply retrieve all data:

new TransactionTemplate(txManager).execute(new TransactionCallback<Void>() {
 @Override
 public Void doInTransaction(TransactionStatus status) {
   Session session = sessionFactory.getCurrentSession();
   List<DemoEntity> demoEntitities = (List<DemoEntity>) session.createQuery("from DemoEntity").list();
   for(DemoEntity demoEntity : demoEntitities){
    //Process and write result
   }
   return null;
 }
});
After a couple of seconds:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded

Clearly this won't cut it. To fix this we will be switching to Hibernate scrollable result sets as probably most developers are aware of. The above example instructs hibernate to execute the query, map the entire results to entities and return them. When using scrollable result sets records are transformed to entities one at a time:

new TransactionTemplate(txManager).execute(new TransactionCallback<Void>() {
 @Override
 public Void doInTransaction(TransactionStatus status) {
  Session session = sessionFactory.getCurrentSession();
  ScrollableResults scrollableResults = session.createQuery("from DemoEntity").scroll(ScrollMode.FORWARD_ONLY);

  int count = 0;
  while (scrollableResults.next()) {
   if (++count > 0 && count % 100 == 0) {
    System.out.println("Fetched " + count + " entities");
   }
   DemoEntity demoEntity = (DemoEntity) scrollableResults.get()[0];
   //Process and write result
  }
 return null;
 }
});
After running this we get:

...
Fetched 49800 entities
Fetched 49900 entities
Fetched 50000 entities
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded

Although we are using a scrollable result set, every returned object is an attached object and becomes part of the persistence context (aka session). The result is actually the same as our first example in which we used "session.createQuery("from DemoEntity").list()". However, with that approach we had no control; everything happens behind the scenes and you get a list back with all the data if hibernate has done its job. using a scrollable result set on the other hand gives us a hook into the retrieval process and allows us to free memory up when needed. As we have seen it does not free up memory automatically, you have to instruct Hibernate to actually do it. Following options exist:

  • Evicting the object from the persistent context after processing it
  • Clearing the entire session every now and then
We will opt for the first. In the above example under line 13 (//Process and write result) we'll add:
session.evict(demoEntity);
Important:
  • If you were to perform any modification to the entity (or entities it has associations with that are cascade evicted alongside), make sure to flush the session PRIOR evicting or clearing, otherwise queries hold back because of Hibernate's write behind will not be sent to the database
  • Evicting or clearing does not remove the entities from second level cache. If you enabled second level cache and are using it and you want to remove them as well use the desired sessionFactory.getCache().evictXxx() method
  • From the moment you evict an entity it will be no longer attached (no longer associated with a session). Any modification done to the entity at that stage will no longer be reflected to the database automatically. If you are using lazy loading, accessing any property that was not loaded prior the eviction will yield the famous org.hibernate.LazyInitializationException. So basically, make sure the processing for that entity is done (or it is at least initialized for further needs) before you evict or clear
After we run the application again, we see that it now successfully executes:
...
Fetched 99800 entities
Fetched 99900 entities
Fetched 100000 entities

Btw; you can also set the query read-only allowing hibernate to perform some extra optimizations:

 ScrollableResults scrollableResults = session.createQuery("from DemoEntity").setReadOnly(true).scroll(ScrollMode.FORWARD_ONLY);
Doing this only gives a very marginal difference in memory usage, in this specific test setup it enabled us to read about 300 entities extra with the given amount of memory. Personally I would not use this feature merely for memory optimizations alone but only if it suits in your overall immutability strategy. With hibernate you have different options to make entities read-only: on the entity itself, the overall session read-only and so forth. Setting read only false on the query individually is probably the least preferred approach. (eg. entities loaded in the session before will remain unaffected, possibly modifiable. Lazy associations will be loaded modifiable even if the root objects returned by the query are read only).

Ok, we were able to process our 100.000 records, life is good. But as it turns out Hibernate has another another option for bulk operations: the stateless session. You can obtain a scrollable result set from a stateless session the same way as from a normal session. A stateless session lies directly above JDBC. Hibernate will run in nearly "all features disabled" mode. This means no persistent context, no 2nd level caching, no dirty detection, no lazy loading, basically no nothing. From the javadoc:

/**
 * A command-oriented API for performing bulk operations against a database.
 * A stateless session does not implement a first-level cache nor interact with any 
 * second-level cache, nor does it implement transactional write-behind or automatic 
 * dirty checking, nor do operations cascade to associated instances. Collections are 
 * ignored by a stateless session. Operations performed via a stateless session bypass 
 * Hibernate's event model and interceptors.  Stateless sessions are vulnerable to data 
 * aliasing effects, due to the lack of a first-level cache. For certain kinds of 
 * transactions, a stateless session may perform slightly faster than a stateful session.
 *
 * @author Gavin King
 */
The only thing it does is transforming records to objects. This might be an appealing alternative because it helps you getting rid of that manual evicting/flushing:
new TransactionTemplate(txManager).execute(new TransactionCallback<Void>() {
 @Override
 public Void doInTransaction(TransactionStatus status) {
  sessionFactory.getCurrentSession().doWork(new Work() {
   @Override
   public void execute(Connection connection) throws SQLException {
    StatelessSession statelessSession = sessionFactory.openStatelessSession(connection);
    try {
     ScrollableResults scrollableResults = statelessSession.createQuery("from DemoEntity").scroll(ScrollMode.FORWARD_ONLY);

     int count = 0;
     while (scrollableResults.next()) {
      if (++count > 0 && count % 100 == 0) {
       System.out.println("Fetched " + count + " entities");
      }
      DemoEntity demoEntity = (DemoEntity) scrollableResults.get()[0];
      //Process and write result 
     }
    } finally {
     statelessSession.close();
    }
   }
  });
  return null;
 }
});

Besides the fact that the stateless session has the most optimal memory usage, using the it has some side effects. You might have noticed that we are opening a stateless session and closing it explicitly: there is no sessionFactory.getCurrentStatelessSession() nor (at the time of writing) any Spring integration for managing the stateless session.Opening a stateless session allocates a new java.sql.Connection by default (if you use openStatelessSession()) to perform its work and therefore indirectly spawns a second transaction. You can mitigate these side effects by using the Hibernate work API as in the example which supplies the current Connection and pass it along to openStatelessSession(Connection connection). Closing the session in the finally has no impact on the physical connection since that is captured by the Spring infrastructure: only the logical connection handle is closed and a new logical connection handle was created when opening the stateless session.

Also note that you have to deal with closing the stateless session yourself and that the above example is only good for read-only operations. From the moment you are going to modify using the stateless session there are some more caveats. As said before, hibernate runs in "all feature disabled" mode and as a direct consequence entities are returned in detached state. For each entity you modify, you'll have to call: statelessSession.update(entity) explicitly. First I tried this for modifying an entity:

new TransactionTemplate(txManager).execute(new TransactionCallback<Void>() {
 @Override
 public Void doInTransaction(TransactionStatus status) {
  sessionFactory.getCurrentSession().doWork(new Work() {
   @Override
   public void execute(Connection connection) throws SQLException {
    StatelessSession statelessSession = sessionFactory.openStatelessSession(connection);
    try {
     DemoEntity demoEntity = (DemoEntity) statelessSession.createQuery("from DemoEntity where id = 1").uniqueResult();
     demoEntity.setProperty("test");
     statelessSession.update(demoEntity);
    } finally {
     statelessSession.close();
    }
   }
  });
  return null;
 }
});
The idea is that we open a stateless session with the existing database Connection. As the StatelessSession javadoc indicates that no write behind occurs, I was convinced that each statement performed by the stateless session would be sent directly to the database. Eventually when the transaction (started by the TransactionTemplate) would be committed the results would become visible in the database. However, hibernate does BATCH statements using a stateless session. I'm not 100% sure what the difference is between batching and write behind, but the result is the same and thus contra dictionary with the javadoc as statements are queued and flushed at a later time. So, if you don't do anything special, statements that are batched will not be flushed and this is what happened in my case: the "statelessSession.update(demoEntity);" was batched and never flushed. One way to force the flush is to use the hibernate transaction API:
StatelessSession statelessSession = sessionFactory.openStatelessSession();
statelessSession.beginTransaction();
...
statelessSession.getTransaction().commit();
...
While this works, you probably don't want to start controlling your transactions programatically just because you are using a stateless session. Also, doing this we are again running our stateless session work in a second transaction scenario since we didn't pass along our Connection and thus a new database connection will be acquired. The reason we can't pass along the outer Connection is because if we commit the inner transaction (the "stateless session transaction") and it would be using the same connection as the outer transaction (started by the TransactionTemplate) it would break the outer transaction atomicity as statements from the outer transaction sent to database would be committed along with the inner transaction. So not passing along the connections means opening a new connection and thus creating a second transaction. A better alternative would be just to trigger Hibernate to flush the stateless session. However, statelessSession has no "flush" method to manually trigger a flush. A solution here is to depend a bit on the Hibernate internal API. This solution makes the manual transaction handling and the second transaction obsolete: all statements become part of our (one and only) outer transaction:
StatelessSession statelessSession = sessionFactory.openStatelessSession(connection);
 try {
  DemoEntity demoEntity = (DemoEntity) statelessSession.createQuery("from DemoEntity where id = 1").uniqueResult();
  demoEntity.setProperty("test");
  statelessSession.update(demoEntity);
  ((TransactionContext) statelessSession).managedFlush();
 } finally {
  statelessSession.close();
}
Fortunately there is an even better solution very recently posted on the Spring jira: https://jira.springsource.org/browse/SPR-2495 This is not yet part of Spring, but the factory bean implementation is pretty straight forward: StatelessSessionFactoryBean.java when using this you could simple inject the StatelessSession:
@Autowired
private StatelessSession statelessSession;
It will inject a stateless session proxy which is equivalent to the way the normal "current" session works (with the minor difference that you inject a SessionFactory and need to obtain the currentSession each time). When the proxy is invoked it will lookup the stateless session bound to the running transaction. If none exists already it will create one with the same connection as the normal session (like we did in the example) and register a custom transaction synchronization for the stateless session. When the transaction is committed the stateless session is flushed thanks to the synchronization and finally closed. Using this you can inject the stateless session directly and use it as a current session (or the same way as you would inject a JPA PeristentContext for that matter). This relieves you from dealing with the opening and closing of the stateless session and having to deal with one way or the other to make it flush. The implementation is JPA aimed, but the JPA part is limited to obtaining the physical connection in obtainPhysicalConnection(). You can easily leave out the EntityManagerFactory and get the physical connection directly from the Hibernate session.

Very careful conclusion: it is clear that the best approach will depend on your situation. If you use the normal session you will have to deal with eviction yourself when reading or persisting entities. Besides the fact you have to do this manually, it might also impact further use of the session if you have a mixed transaction; you both perform 'bulk' and 'normal' operations in the same transaction. If you continue with the normal operations you will have detached entities in your session which might lead to unexpected results (as dirty detection will no longer work and so forth). On the other hand you will still have the major hibernate benefits (as long as the entity isn't evicted) such as lazy loading, caching, dirty detection and the likes. Using the stateless session at the time of writing requires some extra attention on managing it (opening, closing and flushing) which can also be error prone. In the assumption you can proceed with the proposed factory bean, you have a very bare bone session which is separately from your normal session but still participating in the same transaction. With this you have a powerful tool to perform bulk operations without having to think about memory management. The downside is that you don't have any other hibernate functionality available.

Monday, February 18, 2013

Unit (resource/frontend) testing template

Unit testing requires a lot of time and investment. One of the important things to safe keep this investment is building on good infrastructure. While we are all used to design production code, designing our tests and test infrastructure is in many cases forgotten or the time needed is simply not there. In many cases the requirements for the test set also grow (just like real requirements). Sometimes testing can even become a project inside the project. I have gathered some testing practices I've became used with over the years and put them in a small project, which you can find here: github unit-testing

It is a Spring/Spring MVC webapp using JPA (Hibernate as provider) for persistence and TestNG, Spring test support, selenium2 for testing. There are 3 types of test covered: basic unit test, unit resource test and front end test (unit resource tests with a flavor).

The basic unit tests give an idea how you can use Spring within your tests or use its MVC test extensions to test for example application controllers . The unit resources tests give a strategy for testing code that is depended on a resource, but cannot be fully tested without that resource (eg. dummies, mocks or stubs are not the best alternative). For example repositories depending on a RDBMS. In that case we work with an embedded database which allows to test our repositories very close to their production environment.

The front end tests require some extra features as they need to communicate with the database booted inside the deployed application. Also, to make it interesting I have put a repository that depends on an "not further specified" sub system for which no in memory equivalents exists. A stub is put into place in the deployed application which is remotely controllable from within the test. This allows you to have the data setup from the test for both resources (the one requiring a database and this one requiring the sub system) *in* the test. The data for both resources is setup and removed in scope of each test method (or tat least each test). Alternatives likes simulators have the data deployed together with the application which makes it brittle for changes. (eg. the data is automatically shared for all tests and packed together in one place)

The project is Maven enabled; importing it should be zero hassle. Surefire and failsafe (+cargo) are also configured, so all your tests (including the front end tests) are executed when performing a build with Maven. Since there are no dependencies whatsoever (besides the one defined in the pom) you can add this kind of project directly to your CI hassle-free.

There is also a PDF explaining some of the ideas, but it was put together in short time, so don't expect too much from it. Feel free to share your testing strategies!

Saturday, February 2, 2013

Thermal shutdown

While running a CPU intensive process last week my laptop decided to instantly power off on me. Since the battery was not installed I thought it was probably a power glitch, so I turned it back on and restarted the process. After a few minutes it powered off again, so far for the power glitch.

Thinking it might be temperature related I installed sensors and Computer Temperature Monitor for Ubuntu. As it turned out my CPU temperature was pretty high. When the process started it was around 90°C, slowly but steadily progressing towards 100°C. After that it was a matter of seconds before it powered off. Google confirmed my suspicion that 100°C is indeed very high for a laptop core. Running the same process on another comparable laptop ran a whopping 20°C cooler. It was now for sure that it was a thermal shutdown.

Eliminating the easiest thing first seemed a sane thing to do; for me this would be any influence imposed by software. First I booted Windows running the same process there again and gathering temperature readings using Sisoft Sandra. The temperature matched with those gathered in Ubuntu, powering of the laptop again after some minutes. My final attempt was to update the BIOS but again without any noticeable differences.

On a side note; the laptop was docked on a docking station when performing these tests. The docking station allows even more distance between the air-intake (located on the bottom side of the laptop) and the surface. Room temperature was normal and the (one and only) fan was also running and speeding up normally (as far as my audiovisual inspection powers could tell). Giving these standard conditions, and the fact that I was not even using everything (the GPU for example) a thermal shutdown was certainly not to be expected. Next I started out with the hardware. Again the easiest thing first: clean the air vents. Got myself a can with compressed air to clean the vents:

There was some dust, but not much. As expected this did not solve the heating problem. I repeated the same procedure, but this time with the keyboard and switch/led cover removed for easier access:

Next I emptied some air capsules used for inflating the tires of my MTB on the fan and vents. They produce a pretty high amount of air displacement:-)

After everything was defrosted again the vents were now clean for sure. But no improvements on the horizon for this skipper!

My next idea was to decided if the fan was behaving properly. Easier said then done, since I was unable to get any RPM readings. ACPI, closed BIOSes and the likes are apparently withholding me from getting that information. My 15 year old self build desktop had RPM readings of the CPU fan, GPU fan and every case fan. But as it seems, we no longer need health indication of our fans these days. The closest thing I was able to do was comparing the air displacement of the fan with the fan of my comparable laptop.

As it turned out, on top speed the air displacement was similar between the two laptops. This gave me a satisfactoriness indication that the fan/fan-controller were OK. All other inspections turned out to be OK as well; heat sinks were still fixed and heating up properly, so I was running out of ideas.

Getting annoyed I googled some more and stumbled across a blog about installing a custom heat sink for my model and the steps it involved. One of those steps is as most of you know applying thermal paste between the core and the heat sink. Thermal paste helps in pushing out remaining air between core and heat sink for optimal heat transfer. As a fan issue was now excluded, it could well be that the heat was perhaps not even properly being transfered to be vented out... I also realized that the temperature fluctuations of the CPU were indeed a bit strange. Idle it was around 40°C, but when the process started the temperature went up so fast that the fan lagged behind some seconds before shifting to top speed. When the fan finally reached its top speed the temperature increase was slowed down, but in the mean time the CPU had already ~90°C.

I decided to renew the thermal paste as a final act of desperation. Again easier said then done, at least for me, since the heat sink screws are torx, dammit! So, first to the home depot buying some torx equipment, and then to the computer shop getting some silver based thermal paste.

When I removed the heat sink I saw that they used ceramic based paste and that it was hardened out. A good indication I could be on to something since its not supposed to be hardened out, and certainly not on a only 1.5 year old laptop. Cleaned the paste of first:

Added new paste by putting a tiny drop in the middle on each IC surface. This is enough as when you install the heatsink it will (hopefully) spread evenly over its surface. To verify this I installed the heat sink, tightened the screws and then removed it again. In my case the surface is covered without the paste going over it, so that is what we want:

As it turned out I was lucky this time, after applying the new thermal paste the CPU temperature was now steady at around 80°C when on full load. Nice.

Monday, November 19, 2012

JavaFX 2 with Spring

I'm going to start this one with a bold statement: I always liked Java Swing, or applets for that matter. There, I said it. If I perform some self analysis, this admiration probably started when I got introduced to Java. Swing was (practically) the first thing I ever did with Java that gave some statisfactionary result and made me able to do something with the language at the time. When I was younger we build home-brew fat clients to manage our 3.5" floppy/CD collection (written in VB and before that in basic) this probably also played a role.

Anyway, enough about my personal rareness. Fact is that Swing has helped many build great applications but as we all know Swing has it drawbacks. For starters it hasn't been evolving since well, a long time. It also requires a lot of boiler plate code if you want to create high quality code. It comes shipped with some quirky design "flaws", lacks out of the box patterns such as MVC. Styling is a bit of a limitation since you have to fall back on the limited L&F architecture, I18N is not build in by default and so on. One could say that developing Swing these days is well, basically going back into time.

Fortunately Oracle tried to change this some years ago by Launching JavaFX. I recall getting introduced to JavaFX on Devoxx (or Javapolis as it was named back then). The nifty demo's looked very promising, so I was glad to see that a Swing successor was finally on its way. This changed from the moment I saw its internals. One of its major drawbacks was that it was based on a dark new syntax (called JavaFX script). In case you have never seen JavaFX script; it looks like a bizarre breed between Java, JSON and JavaScript. Although it is compiled to Java byte-code, and you could use the Java API's from it, integration with Java was never really good.

The language itself (although pretty powerful) required you to spend a lot of time understanding the details, for ending up with, well, again source code, but this time less manageable and supported then plain Java code. As it turned out, I wasn't the only one. A lot of people felt the same (for sure there were other reasons as well) and JavaFX never was a great success.

However, a while ago Oracle changed the tide by introducing JavaFX 2.
First of all they got rid of JavaFX script (which is no longer supported) and turned it into a real native Java SE API (JavaFX 2.2.3 is part of the Java 7 SE update 6) . The JavaFX API now looks more like the familiar Swing API, which is a good thing. It gives you layout managers lookalikes, event listeners, and all those other components you were so used to, but even better. So if you want you can code JavaFX like you did Swing you can, albeit with slightly different syntax and improved architecture. It is also possible now to intermix existing Java Swing applications with JavaFX.

But there is more. They introduced an XML based markup language that allows you to describe the view. This has some advantages, first of all coding in XML works faster then Java. XML can be more easily be generated then Java and the syntax for describing a view is simply more compact. It is also more intuitive to express a view using some kind of markup, especially if you ever did some web development before. So, one can have the view described in FXML (thats how its called), the application controllers separate from the view, both in Java, and your styling in CSS (yeah, so no more L&F, CSS support is standard). You can still embed Java (or other languages) directly in the FXML; but this is probably not what you want (scriptlet anti-pattern). Another nice thing is support for binding. You can bind each component in your view to the application controller by putting an fx:id attribute on the view component and an @FXML annotation on the instance variable in the application controller. The corresponding element will then be auto injected, so you can change its data or behavior from inside your application controller. It also turns out that with some lines of code you can painlessly integrate the DI framework of your choice, isn't that sweet?

And what about the tooling?
Well, first of all there is a plug-in for Eclipse (fxclipse) which will render you FXML on the fly. You can install it via Eclipse market place:


The plug-in will render any adjustment you make immediately:



Note that you need at least JDK7u6 for this plug-in to work. If your JDK is too old you'll get an empty pane in eclipse. Also, if you create a JavaFX project I needed to put the jfxrt.jar manually on my build classpath. You'll find this file in %JAVA_HOME%/jre/lib.

Up until know the plug-in doesn't help you visually (by drag& drop) but that there a separate IDE: scene builder. This builder is also integrated in Netbeans, for AFAIK there is no support for eclipse yet so you'll have to run it separately if you want to use it. The builder lets you develop FXML the visual way, using drag&drop. Nice detail; scene builder is in fact written in JavaFX. Then you also have a separate application called scenic view which does introspection on a running JavaFX application and shows how it is build up. You get a graph with the different nodes and their hierarchical structure. For each node you can see its properties and so forth:


Ok, so lets start with some code examples. The first thing I did was design my demo application in scene builder:


I did this graphically by d&d the containers/controlers on to the view. I also gave the controls that I want to bind to my view and fx:id, you can do that also via scene builder:


For the buttons in particular I also added an onAction (which is the method that should be executed on the controller once the button is clicked):


Next I added the controller manually in the source view in eclipse. There can only be one controller per FXML and it should be declared in the top level element. I made two FXML's, one that represents the main screen and one that acts as the menu bar. You probably want a division of your logic in multiple controllers, rather then stuffing to much in a single controller – single responsibility is a good design guideline here. The first FXML is “search.fxml” and represents the search criteria and result view:
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>

<StackPane id="StackPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" fx:controller="be.error.javafx.controller.SearchController">
  <children>
    <SplitPane dividerPositions="0.39195979899497485" focusTraversable="true" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0">
      <items>
        <GridPane fx:id="grid" prefHeight="91.0" prefWidth="598.0">
          <children>
     <fx:include source="/menu.fxml"/>
            <GridPane prefHeight="47.0" prefWidth="486.0" GridPane.columnIndex="1" GridPane.rowIndex="5">
              <children>
                <Button fx:id="clear" cancelButton="true" mnemonicParsing="false" onAction="#clear" text="Clear" GridPane.columnIndex="1" GridPane.rowIndex="1" />
                <Button fx:id="search" defaultButton="true" mnemonicParsing="false" onAction="#search" text="Search" GridPane.columnIndex="2" GridPane.rowIndex="1" />
              </children>
              <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" maxWidth="338.0" minWidth="10.0" prefWidth="338.0" />
                <ColumnConstraints hgrow="SOMETIMES" maxWidth="175.0" minWidth="0.0" prefWidth="67.0" />
                <ColumnConstraints hgrow="SOMETIMES" maxWidth="175.0" minWidth="10.0" prefWidth="81.0" />
              </columnConstraints>
              <rowConstraints>
                <RowConstraints maxHeight="110.0" minHeight="10.0" prefHeight="10.0" vgrow="SOMETIMES" />
                <RowConstraints maxHeight="72.0" minHeight="10.0" prefHeight="40.0" vgrow="SOMETIMES" />
              </rowConstraints>
            </GridPane>
            <Label alignment="CENTER_RIGHT" prefHeight="21.0" prefWidth="101.0" text="Product name:" GridPane.columnIndex="0" GridPane.rowIndex="1" />
            <TextField fx:id="productName" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
            <Label alignment="CENTER_RIGHT" prefWidth="101.0" text="Min price:" GridPane.columnIndex="0" GridPane.rowIndex="2" />
            <Label alignment="CENTER_RIGHT" prefWidth="101.0" text="Max price:" GridPane.columnIndex="0" GridPane.rowIndex="3" />
            <TextField fx:id="minPrice" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
            <TextField fx:id="maxPrice" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
          </children>
          <columnConstraints>
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="246.0" minWidth="10.0" prefWidth="116.0" />
            <ColumnConstraints fillWidth="false" hgrow="SOMETIMES" maxWidth="537.0" minWidth="10.0" prefWidth="482.0" />
          </columnConstraints>
          <rowConstraints>
            <RowConstraints maxHeight="64.0" minHeight="10.0" prefHeight="44.0" vgrow="SOMETIMES" />
            <RowConstraints maxHeight="68.0" minHeight="0.0" prefHeight="22.0" vgrow="SOMETIMES" />
            <RowConstraints maxHeight="68.0" minHeight="10.0" prefHeight="22.0" vgrow="SOMETIMES" />
            <RowConstraints maxHeight="68.0" minHeight="10.0" prefHeight="22.0" vgrow="SOMETIMES" />
            <RowConstraints maxHeight="167.0" minHeight="10.0" prefHeight="14.0" vgrow="SOMETIMES" />
            <RowConstraints maxHeight="167.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES" />
          </rowConstraints>
        </GridPane>
        <StackPane prefHeight="196.0" prefWidth="598.0">
          <children>
            <TableView fx:id="table" prefHeight="200.0" prefWidth="200.0">
              <columns>
                <TableColumn prefWidth="120.0" resizable="true" text="OrderId">
                  <cellValueFactory>
                    <PropertyValueFactory property="orderId" />
                  </cellValueFactory>
                </TableColumn>
                <TableColumn prefWidth="120.0" text="CustomerId">
                  <cellValueFactory>
                    <PropertyValueFactory property="customerId" />
                  </cellValueFactory>
                </TableColumn>
                <TableColumn prefWidth="120.0" text="#products">
                  <cellValueFactory>
                    <PropertyValueFactory property="productsCount" />
                  </cellValueFactory>
                </TableColumn>
                <TableColumn prefWidth="120.0" text="Delivered">
                  <cellValueFactory>
                    <PropertyValueFactory property="delivered" />
                  </cellValueFactory>
                </TableColumn>
                <TableColumn prefWidth="120.0" text="Delivery days">
                  <cellValueFactory>
                    <PropertyValueFactory property="deliveryDays" />
                  </cellValueFactory>
                </TableColumn>
                <TableColumn prefWidth="150.0" text="Total order price">
                  <cellValueFactory>
                    <PropertyValueFactory property="totalOrderPrice" />
                  </cellValueFactory>
                </TableColumn>
              </columns>
            </TableView>
          </children>
        </StackPane>
      </items>
    </SplitPane>
  </children>
</StackPane>
On line 11 you can see that I configured the application controller class that should be used with the view. On line 17 you can see the import of the separate menu.fxml which is shown here:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.MenuItem?>

<Pane prefHeight="465.0" prefWidth="660.0" xmlns:fx="http://javafx.com/fxml" fx:controller="be.error.javafx.controller.FileMenuController">
 <children>
  <MenuBar layoutX="0.0" layoutY="0.0">
   <menus>
    <Menu mnemonicParsing="false" text="File">
     <items>
      <MenuItem text="Exit" onAction="#exit" /> 
     </items>
    </Menu>
   </menus>
  </MenuBar>
 </children>
</Pane>
On line 7 you can see that it uses a different controller. In Eclipse, if you open the fxclipse view from the plug-in you will get the same rendered view as in scene builder. Its however convenient if you want to make small changes in the code to see them directly reflected: The code for launching the application is pretty standard:
package be.error.javafx;

import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class TestApplication extends Application {

 private static final SpringFxmlLoader loader = new SpringFxmlLoader();

 @Override
 public void start(Stage primaryStage) {
  Parent root = (Parent) loader.load("/search.fxml");
  Scene scene = new Scene(root, 768, 480);
  primaryStage.setScene(scene);
  primaryStage.setTitle("JavaFX demo");
  primaryStage.show();
 }

 public static void main(String[] args) {
  launch(args);
 }
}
The only special thing to note is that we extend from Application. This is a bit boiler plate code which will for example make sure that creating of the UI happens on the JavaFX application thread. You might remember such stories from Swing, where every UI interaction needs to occur on the event dispatcher thread (EDT), this is the same with JavaFX. You are by default on the “right thread” when you are called back by the application (in for example action listeners alike methods). But if you start the application or perform long running tasks in separate threads you need to make sure you start UI interaction on the right thread. For swing you would use SwingUtilities.invokeLater() for JavaFX: Platform.runLater().
More special is our SpringFxmlLoader:
package be.error.javafx;

import java.io.IOException;
import java.io.InputStream;

import javafx.fxml.FXMLLoader;
import javafx.util.Callback;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringFxmlLoader {

 private static final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringApplicationConfig.class);

 public Object load(String url) {
  try (InputStream fxmlStream = SpringFxmlLoader.class
    .getResourceAsStream(url)) {
   System.err.println(SpringFxmlLoader.class
    .getResourceAsStream(url));
   FXMLLoader loader = new FXMLLoader();
   loader.setControllerFactory(new Callback<Class<?>, Object>() {
    @Override
    public Object call(Class<?> clazz) {
     return applicationContext.getBean(clazz);
    }
   });
   return loader.load(fxmlStream);
  } catch (IOException ioException) {
   throw new RuntimeException(ioException);
  }
 }
}
The highlighted lines show the custom ControllerFactory. Without setting this JavaFX will simply instantiate the class you specified as controller in the FXML without anything special. In that case the class will not be Spring managed (unless you would be using CTW/LTW AOP). By specifying a custom factory we can define how the controller should be instantiated. In this case we lookup the bean from the application context. Finally we have our two controllers, the SearchController:
package be.error.javafx.controller;

import java.math.BigDecimal;
import java.net.URL;
import java.util.ResourceBundle;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import be.error.javafx.model.Order;
import be.error.javafx.model.OrderSearchCriteria;
import be.error.javafx.model.OrderService;

public class SearchController implements Initializable {

 @Autowired
 private OrderService orderService;
 @FXML
 private Button search;
 @FXML
 private TableView<Order> table;
 @FXML
 private TextField productName;
 @FXML
 private TextField minPrice;
 @FXML
 private TextField maxPrice;

 @Override
 public void initialize(URL location, ResourceBundle resources) {
  table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
 }

 public void search() {
  OrderSearchCriteria orderSearchCriteria = new OrderSearchCriteria();
  orderSearchCriteria.setProductName(productName.getText());
  orderSearchCriteria
    .setMaxPrice(StringUtils.isEmpty(minPrice.getText()) ? null:new BigDecimal(minPrice.getText()));
  orderSearchCriteria
    .setMinPrice(StringUtils.isEmpty(minPrice.getText()) ? null: new BigDecimal(minPrice.getText()));
  ObservableList<Order> rows = FXCollections.observableArrayList();
  rows.addAll(orderService.findOrders(orderSearchCriteria));
  table.setItems(rows);
 }

 public void clear() {
  table.setItems(null);
  productName.setText("");
  minPrice.setText("");
  maxPrice.setText("");
 }
}
The highlighted lines in respective order:
  • Auto injection by Spring, this is our Spring managed service which we will use to lookup data from
  • Auto injection by JavaFX, our controls that we need to manipulate or read from in our controller
  • Special init method to initialize our table so columns will auto resize when the view is enlarged
  • action listener style callback which is invoked when the search button is pressed
  • action listener style callback which is invoked when the clear button is pressed
Finally the FileMenuController which does nothing special besides closing our app:
package be.error.javafx.controller;

import javafx.application.Platform;
import javafx.event.ActionEvent;

public class FileMenuController {

 public void exit(ActionEvent actionEvent) {
  Platform.exit();
 }
}
And finally the (not so exciting) result:

After searching:


Making view wider, also stretches the columns:


The file menu allowing us the exit:


After playing a bit with JavaFX2 I was pretty impressed. There are also more and more controls coming (I believe there is already a browser control and such). So I think we are on the right track here.

Wednesday, September 12, 2012

Hibernate's Map behavior

Hibernate has a map construct which makes mapping key/value pairs rather elegant. Let's take a "car" as our example domain object. In our imagination we could store the options of a car as key/value pairs. The options could be things like: engine type, color and so forth.

The hibernate annotations that we would need to map this car entity are pretty straightforward:
@Entity
public class Car {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;

 @ElementCollection
 @CollectionTable(name = "options_map", joinColumns = @JoinColumn(name = "car_id"))
 private Map<String, String> options = new HashMap<String, String>();

 public Long getId() {
  return id;
 }

 public Map<String, String> getOptions() {
  return options;
 }
}
We created a "car" entity (and table) having a one-to-many relationship to our map storing the options as key/value pairs in map backed by a options_map table. Now, what will happen with entries having null as value?

You can argue that storing an entry with a null value does not make much sense in most scenarios. This is probably true as the only way you would do something like this is to keep an exhaustive list of possible key values. Even so, it would be a not so good solution since you would be duplicating your entire key set for each and every car. A better solution would be to map the key values to enumeration instead. Or, if the set of keys are also needed outside of your application, store them in a separate table for example.

Leaving this discussion behind, the thing I want to point out here is that whichever reason you have to store entries with null as their values, think again: hibernate ignores such entries completely.

Lets have a look at how hibernate handles this. In the first example we will create and store a car with three options; engine type, color and cupholder.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { InfrastructureContextConfiguration.class, TestDataContextConfiguration.class })
@Transactional
public class CarTest {

 @PersistenceContext
 private EntityManager entityManager;

 @Autowired
 private DataSource dataSource;

 @Test
 public void testWithNonNullValues() throws Exception {
  // Save 3 options with non-null value
  Car merc = new Car();
  merc.getOptions().put("AIRCO", "DUAL-AUTO");
  merc.getOptions().put("GEARBOX", "AUTO");
  merc.getOptions().put("CUPHOLDER", "YES");

  entityManager.persist(merc);
  entityManager.flush();
  entityManager.clear();

  merc = entityManager.find(Car.class, merc.getId());
  Assert.assertEquals(3, merc.getOptions().size());
 }
}
Nothing special happens when we run this test, the test passes: all ok.

Next, we choose to drop an option (the cupholder), but we want to keep all keys existent for each car. So we will again have 3 keys, but the cupholder will have a null value:
 public void testWithNullValue() throws Exception {
  // Save 3 properties, 2 with non-null value, 1 with null value
  Car bmw = new Car();
  bmw.getOptions().put("AIRCO", "DUAL-AUTO");
  bmw.getOptions().put("GEARBOX", "AUTO");
  bmw.getOptions().put("CUPHOLDER", null);

  entityManager.persist(bmw);
  entityManager.flush();
  entityManager.clear();

  bmw = entityManager.find(Car.class, bmw.getId());
  // FAIL: java.lang.AssertionError: expected:<2> but was:<3>
  Assert.assertEquals(3, bmw.getOptions().size());
 }
The test will fail (java.lang.AssertionError: expected:<2> but was:<3>). When we load our entity in an empty session it will only contain 2 options instead of 3. The cupholder option was removed (or simply not stored in database).

This can be a problem; during the lifetime of your transaction the map will continue to have a key 'CUPHOLDER' with a null value. Only after reading data from database again (which will for example happen in a new transaction) the car loaded from database will only have two properties left, since only the properties with a non-null value were stored.
Btw; in our test case we simulate a 'new transaction' by simply flushing and clearing the session; this forces hibernate to load the data freshly again from database as would be the behaviour in a new transaction.

Finally, hibernate also ignores existing records with a null value already in the database (which could be inserted by other users). In the example below we save two options (with non-null value) and then we sneakily add another option with a null value using a plain JDBC insert (we also perform a count directly afterwards to make 100% sure there are effectively three options in the database).
 public void testWithNullValueInsertedByOtherUser() throws Exception {
  // Save 2 options with non-null value
  Car audi = new Car();
  audi.getOptions().put("AIRCO", "DUAL-AUTO");
  audi.getOptions().put("GEARBOX", "AUTO");

  entityManager.persist(audi);
  entityManager.flush();
  entityManager.clear();

  JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
  // Add another option with null value bypassing hibernate (simulating other user)
  jdbcTemplate.update("insert into options_map (car_id, options_key, options) values (?, 'CUPHOLDER', null)",
    audi.getId());
  // Verify to make sure we now have 3 options in database
  Assert.assertEquals(3,
    jdbcTemplate.queryForInt("select count(*) from options_map where car_id = ?", audi.getId()));

  audi = entityManager.find(Car.class, audi.getId());
  // FAIL: java.lang.AssertionError: expected:<2> but was:<3>
  Assert.assertEquals(3, audi.getOptions().size());

 }
The test will fail again: even though our car has 3 options in the database, hibernate will only retrieve the options with a non-null value. So instead of our expected 3 options we only get 2 options in our options map.

Conclusion: during the transaction the domain model will fully reflect the data we stored in it.
If we test for the key 'CUPHOLDER' to be present it would return true. However, in subsequent transactions, which might read the car and its options we saved before, we will only discover two options since an option with null value is not saved by hibernate and completely ignored. This would render our operation non-idempotent if we really depended on the cupholder key to be present.

To take this a bit further, if you are using Hibernate in combination with an Oracle databases you also need to be careful with empty string values. As you are probably aware Oracle transforms an empty string (a String of length equal to 0) to a null value. So if you would have a column of type varchar2 for example, inserting '' as value will be transformed to null.
So from the Java point of view, when using Oracle, you will also "lose" properties which do not only have a null value but also have a blank string value.

It is wise to think your null/empty string strategy well through, certainly when using Hibernate in combination with the map construct. The safest solution is probably to not depend on any entry with a blank or null value at all when using this construct.

Tuesday, July 17, 2012

Pro Spring MVC: with Web Flow

Today not a technical entry, but a small announcement.
The book I wrote together with Marten Deinum is finally out!
I got my copy yesterday and it looks rather good, if I say so myself:-)


My personal contributions are the chapters on :
  • Testing Spring MVC applications
  • Spring Web Flow
  • Building applications with Spring Web Flow
  • Advanced Spring Web Flow
  • Spring Security

I started writing on it around half December, the final touch (at least by us, authors) was made somewhere half June. I never expected that writing would be so difficult, it was quite a challenge. What I originally estimated as four weeks of work (two weeks full-time during vacation time and two weeks only evenings, after normal working hours) turned out to be almost five months! Writing good quality software is difficult, but writing content for a book is an even greater challenge.

At the end it was quite an interesting experience to go through the entire development cycle of a book. It was also a good learning path for the technology itself. Even though I have been working a long time with these technologies, it still took a lot of investigation to be able to write adequately about it.

Anyway, if you are doing front-end work with Spring MVC, Web Flow2 or are intrigued by these technologies, go take a look! The book is available on Amazon or directly from Apress.

Happy reading!