Skip navigation

Monthly Archives: February 2009

If you are looking for a simple, easy to use and configure web framework for Java, Grails is the way to go.  I spent a ton of time looking around for Java web frameworks and I landed on Grails.  I am in the process of rebuilding my company’s public facing website as well as their intranet.  Because the two sites need access to the same data, I decided to build a common class library which handles all data access.  Although Grails is meant to handle all mapping and data acess for you, it was pretty easy to work in my existing data access project.

The first thing I would like to note about Grails is that there is virtually no configuration.  You will have to edit one or two configuration files if you want to customize certain aspects of the application, but unlike other frameworks, there is ZERO xml configuration.  I have run into a number of challenges as my website, like all websites, has a bunch of unique features.  Due to the excellent documentation for Grails I have had little to no trouble overcoming these challenges.

Because my application uses it’s own set of class factories, I was not able to simply drop my hibernate.xml.cfg and mapping files into grails.  I need to have complete control over how the objects are loaded and saved to the database.  This meant I would need something similar to the OpenSessionInViewFilter.  The problem with adding a fitler is that I didn’t want to open up sessions for every request, just requests that needed acess to the data.  After reading through the documentation I found that Grails has support for controller filters, here is a simple way to open up and close sessions for Hibernate in a grails filter.  Drop a file named HibernateFilters.groovy into the grails-app/conf directory:

public class HibernateFilters {
def filters = {
ensureSession(controller:’*’, action:’*’) {
before = {
HibernateUtil.getCurrentSession().beginTransaction();
}

afterView = {
HibernateUtil.getCurrentSession().getTransaction().commit();
}
}
}
}

Between tag libraries, templates and layouts, building UI in a Grails application is a breeze.  The UI code is so clean because of the way the rendering engine works.  There is no need for server side code in the views (although it is possible to put it there).

AJAX support is excellent in Grails.  It solves the common problem of rendering of UI on the server side as well as the client side.  It is simple to render a template or view and return it in an AJAX call.  This is huge, becuase you won’t find yourself writing the same UI code twice.  In my experience with .NET this was one of the most frustrating parts of building AJAX applications.  Also, Grails makes it really simple to render JSON and XML.  You can simply use “as JSON” or “as XML” in your render calls.

All in all, Grails is a quick and easy to use framework that provides all the tools a web developer needs to build a rich and dynamic web application with minimal headaches.  Out of the frameworks I’ve used (ASP.NET, CakePHP, Wicket, Tapestry), Grails is definitely at the top of the list (followed closely by CakePHP).

Check out the official grails website.

Introduction

I’ve been working dilligently lately on a new internal web application.  I made the decision long ago that the app would be a full blown AJAX application.  After deciding to go with DWR, Java and Hibernate running on Tomcat, I quickly noticed that my situation was pretty rare.  It seems as though everyone out there also uses Spring in combination with DWR and Hibernate.  I briefly went through the spring documentation and could not find a reason why I would need to use it for our application.

Along the way I’ve run into a few issues specifically with DWR and Hibernate and I’d like to share the experience for anyone else out there looking to do the same.

OpenSessionInViewFilter

I kept hearing about this magical filter for Spring that handles all of your Hibernate session management inside of AJAX application woes.  I was having all kinds of issues with sessions being closed, lazy loaded collections throwing exceptions etc.  The solution was this servlet filter:

public class OpenSessionInViewFilter implements Filter {

private static Log log = LogFactory.getLog(OpenSessionInViewFilter.class);

private SessionFactory sf;

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {

try {
log.debug(“Starting a database transaction”);
Factory.beginTransaction();

// Call the next filter (continue request processing)
chain.doFilter(request, response);

// Commit and cleanup
log.debug(“Committing the database transaction”);
Factory.commitTransaction();

} catch (StaleObjectStateException staleEx) {
log
.error(“This interceptor does not implement optimistic concurrency control!”);
log
.error(“Your application will not work until you add compensation actions!”);
// Rollback, close everything, possibly compensate for any permanent
// changes
// during the conversation, and finally restart business
// conversation. Maybe
// give the user of the application a chance to merge some of his
// work with
// fresh data… what you do here depends on your applications
// design.
throw staleEx;
} catch (Throwable ex) {
// Rollback only
ex.printStackTrace();

// log the error
log.error(“Error in application”, ex);

try {
if (sf.getCurrentSession().getTransaction().isActive()) {
log.debug(“Trying to rollback database transaction after exception”);
Factory.rollbackTransaction();
}
} catch (Throwable rbEx) {
log.error(“Could not rollback transaction after exception!”,
rbEx);
}

// Let others handle it… maybe another interceptor for exceptions?
throw new ServletException(ex);
}
}

public void init(FilterConfig filterConfig) throws ServletException {
log.debug(“Initializing filter…”);
log.debug(“Obtaining SessionFactory from static HibernateUtil singleton”);
sf = Factory.getFactory();
}
}

It is very simple, it just opens up a transaction for each incoming request and either commits or rolls it back when all is finished.  The fact that it is a filter seems to be a key, I wrote a similar servlet that did not have the same effect.

DWR Converters

DWR comes with a number of converters that work really nicely.  The most interesting one happens to be the Hibernate3 converter.  It does a decent job.  There is one major issue with the converter though for my unique situation.  I have a number of data objects with properties that I do not want passed to the client.  For instance, any password property (for obvious reasons), image / blob properties etc.  DWR has a nice feature that you can use to exclude properties so they are not delivered to the client.  To use this feature you simply add the following to your objects convert node in dwr.xml:

<param name=”exclude” value=”properties, to, exclude” />

The only issue with this feature is it also excludes the property when transmitting data UP to the server.  So if you need to update one of these fields it is ignored on the way in.  Also, when you send the object to the server, DWR’s Hibernate3 converter starts with a fresh object.  This means, your properties that are excluded will be wiped out.  These are pretty serious problems that were not very easy to solve. The solution was to come up with my own converter which I named the H3SmartBeanConverter. This was adapted from a combination of the H3BeanConverter and the BasicObjectConverter which are a part of DWR.  You can download it below.

The first thing I had to change was the way the excludes are handled.  If the converter is performing an inbound conversion, all properties are converted regardless of the exclude rules:

// Access rules mean we might not want to do this one
// only check exclude rules when creating an outbound object, if write is required, allow everything to go through
if (!isAllowedByIncludeExcludeRules(name) && !writeRequired) {
continue;
}

I also needed lazy loaded properties to be initialized and passed down to the client as long as the property is not excluded.  To accomplish this I modified the section of code dealing with hibernate lazy properties:

if (readRequired) {
// This might be a lazy-collection so we need to double check
Object retval = method.invoke(example, new Object[] {});
if (!Hibernate.isInitialized(retval)) {
Hibernate.initialize(retval);
}
}

The final piece of the converter was the piece that fixes the problem of excluded properties being wiped out.  In the convertInbound method of the converter, I check to see if the object being converted extends my data object class.  If it does I load the object from the database prior to loading properties:

// if the bean is a data object, first load it from the database.  This will prevent properties that are not passed to the client from being deleted.
if (DataObject.class.isAssignableFrom(beanType)) {
// get the id field
String rawID = (String)tokens.get(“id”);
String[] split = ParseUtil.splitInbound(rawID);
String splitValue = split[LocalUtil.INBOUND_INDEX_VALUE];
String splitType = split[LocalUtil.INBOUND_INDEX_TYPE];

InboundVariable nested = new InboundVariable(iv.getLookup(), null, splitType, splitValue);
TypeHintContext incc = createTypeHintContext(inctx, (Property)properties.get(“id”));
Integer id = (Integer)converterManager.convertInbound(((Property)properties.get(“id”)).getPropertyType(), nested, inctx, incc);

if (id > 0) {
bean = Factory.get(beanType, id);
}
}

The Factory class is a basic wrapper for the Hibernate session object.  Factory.get calls Session.get under the covers.  Now, pre-loading the object from the database created yet another issue.  I was getting the error: “A collection with cascade=”alldeleteorphan” was no longer referenced by the owning entity.”  The problem here was once the object was loaded from the database, the collection properties were being overwritten with regular collection objects.  Hibernate uses specialized collection classes to handle persistence.  So, I had to add a bit of code to iterate through the collections instead of overwriting them:

// handle collections
if (Collection.class.isAssignableFrom(propType)) {
Collection collection = (Collection)property.getValue(bean);
collection.clear();

for (Object obj : (Collection)output) {
collection.add(obj);
}
} else if (Map.class.isAssignableFrom(propType)) {
Map map = (Map)property.getValue(bean);
map.clear();

for (Object obj : ((Map)output).entrySet()) {
Map.Entry mapEntry = (Map.Entry)obj;

map.put(mapEntry.getKey(), mapEntry.getValue());
}
} else {
property.setValue(bean, output);
}

Depending on which collections you are using you may need to add more code to handle them.  Finally, I had a working solution to my two biggest problems with DWR and Hibernate.  So far this solution has worked out really well, I have not run into any other issues.  If anyone has any suggestions as to how to do this in a simpler fashion, I’m all ears.

Download Java Classes:

H3SmartBeanConverter.java

OpenSessionInViewFilter.java

Recently I was tasked with building a pretty smiple CMS for my companie’s websites.  The major problem I ran into was picking a rich text editor that is easy enough to use with dojo.  There are a number of choices out there, but every single one has major problems.  These major problems include: cost, bugs, eas of use etc.  For instance, FCK is free, but it has a number of bugs.  TinyMCE is free as well, but it doesn’t play nicely with dojo.  Dojo has a built in rich text editor, but from what I understand building plugins for it is an absolute nightmare.  There are a ton of other free ones out there, but a lot of them seemed like they didn’t have very large user bases or very good support.

I decided to go with TinyMCE because it has a wide set of features and the plugins seem easy enough to develop.  The problem with TinyMCE at first glance was it didn’t look like it’d be easy to use with dojo.  The documentation is pretty poor in that it doesn’t have many examples.  I struggled for hours trying to find an example that would allow me to create a TinyMCE editor on the fly.  Finally (no thanks to the documentation), I came up with this:

dojo.provide("my.widgets.RichEditor");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.TextBox");

dojo.declare("my.widgets.RichEditor", [ dijit._Widget, dijit._Templated ], {
	templatePath :dojo.moduleUrl("my", "widgets/layout/RichEditor.htm"),
	templateString :"",
	widgetsInTemplate :true,
	width: 600,
	height: 400,
	editor: null,
	value: "",
	editorNode: null,
	initialized: false,

	postCreate : function() {
		this.inherited(arguments);

		var ed = new tinymce.Editor(this.editorNode.id, {
			theme: "advanced",
			plugins : "safari,spellchecker,pagebreak,style,layer,table,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,media,searchreplace,print,contextmenu,paste,directionality,noneditable,visualchars,nonbreaking,xhtmlxtras",
			theme_advanced_buttons1 : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect",
			theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
			theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen",
			theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,spellchecker,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,blockquote,pagebreak,|,insertfile,insertimage",
			theme_advanced_toolbar_location : "top",
			theme_advanced_toolbar_align : "left",
			theme_advanced_statusbar_location : "bottom",
			theme_advanced_resizing : true,
		});

		setTimeout(function() { ed.render(); }, 50);

		this.editor = ed;
		this.editor.onInit.add(dojo.hitch(this, function() {
			this.initialized = true;
			this.setValue(this.value);
		}));
	},

	setValue: function(value) {
		if (this.initialized) {
			this.editor.setContent(value);
		} else {
			this.value = value;
		}
	},

	getValue: function() {
		if (this.initialized) {
			return this.editor.getContent();
		} else {
			return this.value;
		}
	},

	destroy: function() {
		this.inherited(arguments);
		this.editor.destroy();
		tinyMCE.remove(this.editor);
	}
});

That is a dojo widget that allows you to use TinyMCE.  I haven’t been brave enough to try and load the TinyMCE js on the fly, I will have to try that one later on…