Thursday, March 20, 2008

My Idiotic Move...

So I had encountered a bug during a data entry session. I had entered about 50 stamps from India, and then as I was completing the entries for India, needed to create a new country for the Indian feudal state of "Gwailor". Well, I added the new country, and closed my application. I just happened to forget, to add some other stamps I had purchased over the weekend and thus reopened my application. To my dismay, all the India stamps I had entered had become "Indian States - Gwailor"? This looked like a bug, but potentially not an obvious one. Why would creating and persisting 50 odd stamps with a reference to a country (India) which clearly had a unique identifier all of sudden become (Indian States - Gwailor). Well it turned out, that during my overzealous striving to minimize and re-use persistence setup code, I had made the EntityManager ThreadLocal. I also discovered I was not actually closing the EntityManager. Thus the entity manager was only being closed on application closure, which caused everything to be flushed from memory to the DB. Somehow (and I think this is TopLink bug, but would be hard to validate) the creation of the new country swapped out the persistent reference to the other country in the stamps. I had put a trace on this and was 100% sure it was not in my service code where this was happening. After much humming and hahhing, I decided on a little refactor. The first was to move the Transaction processing from the ServerFactory into a separate TransactionHandler. Each of my services maintained an instance of the TransactionHandler. The second thing I did is rather than imbedding the obtaining of the EntityManager within the transaction code, I added to each persistent method. Afterall, the creation of an EntityManager is lightweight (as long as you have a cached EntityFactory). I can then pass the EntityManager to the TransactionHandler and it can manage the inner/outer transaction context. While I could have simply have inner transactions, I only want to flush and send events from the top-most call. This means, if a method such as "setAsPrimary( CatalogueNumber catNum, Stamp s )" calls the save( ) for Stamp on the StampService, and this method calls the super.save( ) in PersistenceService, then I only want the save( ) in the StampService to emit the event and flush the EntityManager prior to commit. Either way, I now have the nice TransactionHandler which has a simple "begin( EntityManager em )" method. Only the first call to this method in the stack trace will actually start a transaction (tied to the first EntityManagers). Subsequent calls will merely return the inital calls EntityManager so operations within that transaction are called against same EntityManager. The API for this class is pretty simple: public EntityManager begin( EntityManager em ) throws PersistenceException; public void commit( ); public void rollback( ); public boolean isOuterTransaction( ); protected void validateThreadContext( ); The latter method is used on the begin to validate the the service instance is not being used in a non-thread safe way, and will throw an IllegalStateException if the TransitionHandler thread ID does not match the current thread ID. (While this shouldn't happen, I was concerned that I could have some older areas of code that was calling services in a non-thread safe manner. This ensures that is not happening). So far, this refactoring (while changing a lot of methods) actually went surprisingly clean, and was easy to verify its success with the unit tests I had. I actually was able to add some additional testing including a test that was validating this scenario I described above.

Saturday, March 8, 2008

EventBus handling

Often a simple order of operations can make a huge difference to the performance of your application. For example, in the StampJ application, many panels or models (for tables and/or trees) listen for a PersistenceEvent on the EventBus. This event might be a Delete, Update or Create operation. Now the way in which one listens to the event is key. Ideally, the listener will identify that the event is targetted toward a specific entity class relevant to the listener (for example a list of countries can ignore events raised by stamps). If the event is valid, then the actual event type can be determined and the appropriate action taken (such as updating the table, changing a value etc.) Ensuring only a single table model is present in the table is also a good idea. I uncovered a situation where I was creating a table model as part of the constructor of a StampListTable. Then within the StampResultPanel (which has a StampListTable) I was calling initialize( ) which just so happened to create a second StampListTableModel. While this looked beneign, what happened is since my StampListTableModel is listening for various persistent events, the model(s) were each processing the events, thus twice the secondary tasks were being executed. Of course, the way I discovered this was quite by accident. I happened to be trying to discovered why the reference catalogue numbers were sometimes out of wack with the persistence datastore. In debugging this I discovered that the event was being listened to twice.

Tuesday, March 4, 2008

Updated Photos

Since I made some recent UI updates, I decided to upload a few new pictures.
The first picture shows the main splitpane client, with the collection tree on the left. The new icons for the collections are present. As well, in the results table I now show an icon if the stamp has an image uploaded, color coded the Grade column and setup some default relative widths for the columns in the table. As well, the table headers now are using my owner table renderer which uses a gradient pattern from light to dark over the column name.

In the next picture I show the image popup which appears when you mouse over the thumbnail in the lower right corner. Simply moving off the thumbnail will hide the popup image.

QueryHint and TopLink Essentials

Since I am using TopLink Essentials (I tend to try and keep this updated - currently using version 2.1 build 22), I was finding a few query issues where I was getting some stale objects for certain queries from the cache. This seems possible, since I am performing a lot of queries in background tasks (executed as threads) using ThreadLocal entity managers, however all the entity managers should be using a shared EntityManagerFactory. I decided to send Query Hints with the query to force a refresh on called queries. Since I have provider information stored in the ServerFactory class, I added a new method createQuery( EntityManager em, String query ) to not only create the query, but also set the QueryHint and FlushMode. It turned out, I was setting the FlushMode on almost every query as it was, so this at least gives me some more control over this. The EntityManager is used to create the query, and also for getting the persistence provider. To force a refresh, I am using: query.setHint("toplink.refresh", "true"); when the provider is TopLink Essentials. Currently, for other providers I am not doing anything special. A great blog on this is posted by Wonseok Kim on Java.net: http://weblogs.java.net/blog/guruwons/archive/2006/09/understanding_t.html

Entity Deletion and Event Listening

Perhaps it was driven by the fact I spent the afternoon at work developing a service event listener for deletion of objects, but I decided to rewrite the way I handle deletion of objects. Earlier I learned, that I do not want to emit the deletion event with the object that I have deleted in it. This prevents the persistence manager from flushing the object out of the cache and leads to synchronization errors later. I am pretty sure this is because of the Strong Reference present within the thread preventing the Entity Manager from flushing. Instead I ended up sending the identity (a Long value) in the PersistenceEvent on the EventBus. The PersistableEvent.getEventClass() would return the class of the object deleted, however when there were a collection of objects (for example, from a multi-object delete) this would be difficult to discern. To this end, I created the class: org.javad.model.EntityReference which supports (currently) the setting of a reference class and an identity. I may eventually add additional status for information about the entity (like whether it is current etc.) however for the deletion case, this was sufficient.

Monday, March 3, 2008

StampJ Editor

The StampJ Editor is an application written in Java for the managing and inventorying my stamp collection. This tool combined my hobby (stamps) with my career (software development) and allows me to utilize a myriad of technologies to solve a practical problem. The application uses many of Java's emerging projects including:

Currently the database is stored in MySQL on my Linux Server, and is accessed using one of the EJB 3.0 JPA providers. Both Hibernate and Toplink Essentials have been tested, but Toplink Essentials is currently the provider of choice due to its smaller footprint (even though it has technical limitations related to join fetches). At some point I will post an article on this. Another interesting feature of the StampJ Editor (which is a Ruby on Rails concept) is automatic upgrade of the database schema and data migration. While some JPA providers like Hibernate can incorporate new columns, new indexes etc. automatically, Toplink Essentials for one does not support this. As well, I had a situation where one column in the database was split out into two separate columns (description became denomination and description). Therefore I plugged in a database migration/upgrade which will check the class registry in the database (I have a table for this) and if the class versions between the database and runtime do not match, it will run any configured migrators to migrate the data. This supports both SQL file updates and migrator classes. Below is an image of the Splash Screen of the application loading:

Currently the following functionality is available:

  • Ability to create/edit/delete Collections, Albums and Countries
  • Ability to create/edit/delete Stamps
  • Define reference Catalogue Numbers (beyond a primary catalogue number thus creating a cross-reference of catalogue information)
  • View image thumbnails and enlarged "full sized" images on mouse-over. Supports both local image loading and URL Connection loading (from a WebServer)
  • Obtain statistics on collection value, number of stamps.
  • Currency conversion between purchased currency, catalogue currency and current local currency.

Functionality planned includes:

  • Generating PDF reports of collection listings
  • A Web-portal for mobile "quick" search and catalogue lookup
  • Richer reports, statistics and better collection "valuation" based on conditions.
  • More META information such as printing method, paper types etc.Current Sample

Databases:

  • I currently use a database with 25,000 stamp entries as a performance benchmark.
  • The current "live" database has only ~ 800 stamps defined. But it is growing...

There is currently about 400 Junits written to test many sections of the code. Primarily, the Junits test the services behavior with the JPA. I have learned through experience that while writing JPA code is easy, writing JPA code to work in a swing application is not always so easy.

I am interested in collaborating with any interested developers or users of the application. If you are interested on information, contact me at drake_other@comcast.net