Sunday, December 18, 2005

J2EE Status Update

I haven't mentioned it on this blog, but my colleagues know I've been serious about learning J2EE and I'd just like to report to them here that it's going phenomenal. After just a few weeks I feel pretty comfortable that I know what's up in the land of Java and Enterprise development.

My new intermediate skills include (in order):
Cocoon component development
Hibernate
Profiling web applications w/ JMeter and Cocoon profiler
JUnit
Apache Ant
Apache Axis

The past weeks have been packed with learning goodness, and I'm pleased to say that the coming months should be equally fulfilling; especially now that I have a handle on the roles of the seemingly 100s of Java technologies.

Christmas is coming up, here are some great gift ideas: my amazon wishlist.

Saturday, December 17, 2005

The Power of SOAP

Note: This is only a draft

Simple Object Access Protocol, or SOAP, is an incredibly prominent buzzword lately, but does it really live up to the hype? They answer is a definitive yes. Like any tool, SOAP is not the answer to every question, but when a hybrid application calls for RPC it really shines.

So what exactly is it that makes SOAP so much better than any other RPC protocol? For one it is composed in XML and that's just fine. The killer is really the Web Service Definition Language, or WSDL, though. WSDL's power is derived from the fact that XML supports namespaces. A WSDL document is composed of the description of messages, bindings and data types; data types are described by an embedded or external XSD schema. That's right, the same format (Schema) you use to describe XML documents is used to describe input and return types of the SOAP methods your service exposes. There are primitives in the XSD namespace such as int, float, string, and boolean which all other simpleTypes and complexTypes are composed of. [This shifts the discussion to XSD].

If the ability to describe methods and data types isn't enough, most SOAP libraries take care of mapping transparently. For example PHP5's SOAP server implementation (good, but not great because the language lacks [complete/good] reflection and type hinting) allows you to return an arbitrary class and automatically maps fields to elements and attributes of same name described in your XSD. Apache Axis takes it one step farther and doesn't require you to write a line of WSDL; it takes care of it all for you using runtime reflection and a simple WSDD (which maps Java classes to XML elements) to generate the WSDL, Schema et. all.

Both languages are also blessed with tools to generate stub code from an existing WSDL document. This is important because it allows you to take an existing web-service implementation and clone it in another language without your consumer apps ever knowing a thing about it! The only thing that may change is the end point URL, but that doesn't even matter if the WSDL document is accessible from the same location; the end-point is defined within the WSDL!

Saturday, December 03, 2005

Hibernate Sessions In Flowscript

Note: This is only a draft, including code.

I ran into a problem with the solution Cocoon + Hibernate gives for closing sessions. It wasn't a fundamental problem, simply an inflexibility that needed to be addressed. The problem was that for flowscripts (CForms + Bean binding) I wanted to be able to 1) keep a hibernate session alive between user requests and 2) still take advantage of lazy initialization in the view using the ServletFilter solution given by the tutorial.

To achieve these goals I simply tweaked the doFilter function in the filter and created a HibernateSessionFacade:

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

// create an ArrayList to add disposable hibernate sessions to
ArrayList sessions = new ArrayList();
request.setAttribute( "DisposeHibernateSessions", sessions );

// Pass the request on to cocoon
chain.doFilter(request, response);

//List sessions = (List)request.getAttribute( "DisposeHibernateSessions" );

// After cocoon has finished processing, close the
// corresponding Hibernate sessions (see HibernateSessionFacade
if( sessions != null && sessions.size() > 0 )
{
Iterator it = sessions.iterator();

while( it.hasNext() ) {
Session hs = (Session)it.next();

if( hs != null && hs.isOpen() ) {

System.out.println("HibernateFilter: Closing Hibernate Session");

try{
hs.flush();
hs.connection().close();
hs.close();
}
catch( HibernateException e ){
System.out.println("HibernateFilter HibernateException: "+e.getMessage());
}
catch( SQLException e ){
System.out.println("HibernateFilter SQLException: "+e.getMessage());
}
}
}

}
}



function HibernateSessionFacade() {

}

HibernateSessionFacade.getSession = function( scheduleDisposal ) {
if( scheduleDisposal == undefined ) { scheduleDisposal = true; }

// Get new Session from PersistenceFactory
var factory = cocoon.getComponent( Packages.org.osspace.cocoon.hibernate.PersistenceFactory.ROLE );
var hs = factory.createSession();
if (hs == null) {
throw new Packages.org.apache.cocoon.ProcessingException( "Hibernate session is null" );
}

// Release PersistenceFactory
cocoon.releaseComponent(factory);

if( scheduleDisposal ) {
HibernateSessionFacade.scheduleDisposal( hs );
}

return hs;
}


HibernateSessionFacade.scheduleDisposal = function( hs ) {
// returns an ArrayList that was set by the HibernateFilter and adds the passed
// session to it. it will be removed at the end of the request
var sessions = cocoon.request.getAttribute( "DisposeHibernateSessions" );

if( sessions == null ) {
throw new Packages.org.apache.cocoon.ProcessingException("Could not schedule session for removal; the HibernateFilter did not create a list.");
}
sessions.add( hs );
}



This