Sunday, October 23, 2005

Finally no more clob-clipping: Oracle 10g supports standard JDBC CLOB-handling

The new enhancements in Oracle JDBC 10g promises to simplify the insertion and retrieval techniques for the CLOBs using the standard APIs.

Handling Clobs in Oracle 10g

Just discovered the above link after trying to use Oracle's thin JDBC-Driver with Hibernate to save CLOB-data ... This automatically and silently nullifies the CLOB-field when you try to save more then 4k to it which you are likely to do -- after all it's called a cLob.

Now, finally this seems to be fixed in the 10g-JDBC driver. Up to now, it seems to work fine with our somewhat dated 8i installation. Keep my fingers crossed that it stays that way. I'd hate having to resort to the fat oci-driver ...

Wednesday, October 19, 2005

Apache DBCP - never forget maxWait

Had some not so cozy hours debugging a productive app on Tomcat. The thing would spontaneously hang about once a day (The whole of Tomcat, apart from JMX was completely hung). It hung in an infinite wait in the Database-Pool. Funnily the default of the maxWait-Param is "-1", i.e. infinitely. Now, after I fixed this it runs nicely.
But it's still not clear to me, where the total deadlock came from... Maybe some thread which would not release it's connection before it got another one (to a different DB).

Wednesday, October 05, 2005

The Scattered State-Machine - An Antipattern for Web-Controllers

Like a lot of popular anti-patterns the scattered controller stems from the naive implementation of a seemingly obvious abstraction. The reasoning goes like this: Web-Apps show some html-page, each user event (http-request) triggers an action which, in turn, results in an event determining the next state which is either an action or a an html-page transferred back to the user's browser. So, use the old recipe for desaster: Make each noun of your problem description a class, let the resulting "state-machine" be "declaratively" defined using obscure tables or, more fashionable, xml (ok, luckily, xml is not that fashionable anymore). - And voila, you did it. You've polluted your whole controller with a verbose, scattered "state-machine", the internal workings of which are distributed across a host of artifacts: page-template, action-classes, state-machine-spec, events. And most of the time, all you want to do is: Just call a method and display the results ...

Struts apps are particularly notorious for this Anti-Pattern. If you want to know just how complicated you can make the good old library-search scattering your event-urls not only throughout jsp, java-code and struts-config but also through a spring context, see this ibm-dev-works article

Tuesday, September 27, 2005

Now on the hivemind-wiki: Hivemind support for Hibernate Long-Session-Pattern

Handling Hibernate-Sessions is a recurrent topic on the Tapestry users mailing list. Still, long sessions seem to be surprisingly unknown, once one considers the fact that Gavin King advocates its use in "Hibernate in Action".
So, I've posted some code implementing the Long-Session-Pattern in Hivemind on the Hivemind-Wiki.
I'd be curious to hear whether it worked for anyone (or why it didn't) ...

Friday, September 09, 2005

Bye, bye BEA: From Weblogic/EJB/CMP to Tomcat/Hivemind/Hibernate

... and loosing some 1700 loc on the way (counting only Java, disregarding evil xml-deployment-descriptors). Our first non-trivial App on Hivemind/Hibernate is now productive for 5 weeks. No technical problems so far, just the usual buggies associated with cleaning up only part of a design-mess. The whole thing was never really performance-critical (only some 2000 transactions per workday), but only reducing db-hits dramatically using hibernates 2nd level cache made it at all possible to move the app some 400 km away from its underlying database.

Friday, July 29, 2005

Java AWK - parsing csv-files in Java can be fun

Ever parsed text-files, writing loops and calling indexOf / substr just to get some boring job done? I confess, I did. Today, instead, I sat back and browsed the jdk-JavaDocs. Thinking what it would take to bring some of the simplicity of AWK to Java - and it'really simple - just a few lines of code and you can write things like this:

public class JawkSample extends JawkProgram {

protected void registerRules() {
addRules( new Rule[] {

new Rule( "^Q\\d",
new Command(){ protected void execute() {
print( "\nName: " + f(3));
}} ),

new Rule( "^P",
new Command(){ protected void execute() {
print("\n ignoring line "+ line() );
}} ),

});

}

public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("test1.txt");
JawkSample prog = new JawkSample();

prog.process( in, System.out );

}
}

Ok, anonymous classes are not nearly as nice and pretty as closures a la Ruby and Python. But it does the job, cleanly and nicely. Here is the base class - it just needs rt.jar - nothing else. I never noticed how much Regexp-support improved from 1.3 to 1.4. So it is possible to easily create small domain-specific languages in Java.

package com.bmw.jawk;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Instanzen der Klasse JawkProgram "J-AWK-Programme", AWK-artige
* Programme zur Verarbeitung von Text-Streams in Java.
*
* @author schultma
*/
public abstract class JawkProgram {
protected String fieldSeparator = ";";
protected Pattern splitPattern;

private List /*of Rule*/ rules = new ArrayList();

private BufferedReader input;
private BufferedWriter output;

private class Line {
private String content;
private String[] fields;

public Line ( String content ) {
this.content = content;
}

public String getContent(){
return content;
}

public String field( int i ) {
if (fields==null)
fields = splitPattern.split( content );
return fields[i];
}

public void process() {
for ( Iterator ruleIterator = rules.iterator(); ruleIterator.hasNext(); ) {
Rule curRule = (Rule) ruleIterator.next();
curRule.applyTo( this );
}
}
}

protected abstract class Command {
private Line line;

protected void print( String s ) {
try {
output.write( s );
} catch ( IOException e ) {
throw new RuntimeException(e);
}
}

protected String f(int i) {
return line.field(i);
}

protected String line() {
return line.getContent();
}

public final void executeOn( Line l ) {
line = l;
execute();
}
abstract protected void execute();
}

protected class Rule {
private Matcher matchPattern;
private Command command;

public Rule( String pattern, Command command ) {
this.matchPattern = Pattern.compile( pattern ).matcher("");
this.command = command;
}

public void applyTo( Line line ) {
matchPattern.reset( line.getContent() );
if ( matchPattern.find() ) {
if ( command==null ) {
command.print( line.getContent() );
} else {
command.executeOn( line );
}
}
}
}

protected void addRule( Rule rule ) {
rules.add( rule );
}

protected void addRules( Rule[] r ) {
rules.addAll( Arrays.asList(r) );
}

protected abstract void registerRules();

public JawkProgram () {
registerRules();
}

public void process( InputStream in, OutputStream out ) {
input = new BufferedReader( new InputStreamReader(in) );
output = new BufferedWriter( new OutputStreamWriter(out) );

splitPattern = Pattern.compile( fieldSeparator );

try {

String currentLine;
while ( (currentLine = input.readLine()) != null ) {
Line l = new Line(currentLine);
l.process();
}
output.flush();

} catch ( IOException e ) {
throw new RuntimeException(e);
}
}


}

Thursday, July 28, 2005

Unified service lifecyle-interface for different service-models

Hivemind sports a bunch of service-models (singleton, pooled, threaded). After adding "client-session" for my request-spanning, hibernate-sessions, I realised that it's rather unfortunate that each of the service models comes with its own lifecycle-interface (Discardable, PoolManageable,...). So if you want to be able to switch service-models via configuration in one place, your service has to implement all of these interfaces - and you might not be sure what "all" is, thanks to hivemind's ease of extensibility.
How about a unified lifecycle-interface for all service models? It should reflect the structure of possible client-service-interactions rather than the implementation of a service-model. I would call it, maybe, "Conversation" with the following methods:
  • begin() (a new client starts to talk to the service)
  • end() (current client is finished talking to the service, throw away client state)
  • pause() (client stop's talking to the service for now, but will resume later, so don't throw away client state, but free resources like db-connections.
  • resume() (previous client continues to talk to the service)
So when configured as a "pooled" service, just begin() and end() would be called, "threaded" would probably just use end(), "client-session" would employ all of them.

nifty toy = Tomcat + MX4J + hivemind.management + mc4j

Just brought up a managed version of Tomcat 5.5 on j2se 1.4 using mx4j and the hivemind.management module . There are just a few gotchas
  • put mx4j.jar and mx4j-remote.jar on tomcat's system classpath, along with bootstrap.jar
  • don't contribute services with performance interceptor to hivemind.management.MBeans
Everything else works cleanly out of the box. It's fun to watch your services drawing nice performance-graphs - just too cool.

Friday, June 03, 2005

Hivemind support for Hibernate Long-Session-Pattern

Finally I got around to dig into HiveMind's concept of service-models. Not much digging, actually it's amazingly simple and intuitive. I've implemented a new service-model called "stateful" which attaches service instances to a User-Session. "Stateful" actually is a bit of a misnomer since threaded and pooled services also hold state for the duration of one request.
Basically all one needs is
  • a persistence service I called ClientStateStorage, which can be provided with an http session for production. Otherwise it uses a simple Map for testing.
  • a service-model extending AbstractServiceModelImpl which works much like the PooledServiceModel
  • six (!) lines of xml to configure the stuff
And the best thing: Deployment by jar-dropping - I really love the way, HiveMind collects its config-data from all visible jars. I won't write another Springish application-context.xml.
Cluster-Failover-Safety is of course an issue because, as I understood it, HiveMind serialises services in a stateless manner (just writing its Id and, upon reading, creating a fresh instance with that id). For my Apps, however, that's not a big enough problem to trouble me much. Server-crashes happen so seldomly ...

Tuesday, May 31, 2005

Bugfix for Tapestry FCKeditor Component

There were bugs in tapfckconfig.js (absolute URL) and the Readme (missing servlet-mapping in web.xml) which prevented the filebrowser from working. The new version is (again) available here

Friday, May 27, 2005

Tapestry FCKeditor component

I've posted an FCKeditor component. It's a preliminary version - error handling support for File-Upload is still missing.
It consists of
  • a custom config-file tapfckconfig.js
  • the editor-component itself
  • a custom engine implementation mapping the filebrowser url's to the filebrowser service.
  • a filebrowser service which makes use of an ...
  • ... extension implementing the FileBrowser interface. This comes with a default implementation which just browses the filesystem of the server. It's easy to replace by a custom implementation supporting, e.g., a database.

Thursday, April 28, 2005

Stateful services in IoC Containers

Do HiveMind & Co. provide stateful services? I don't think so. Should they? As I'm growing increasingly fond of the Hibernate long-session-pattern, I do think so. You'd probably need some means of attaching/detaching some client-id to a thread (a servlet-filter, typically), so, after that the container could maintain same (service-id, client-id) to service-implementation map. In the servlet-case parallel request from the same client could be blocked (synchronised on) - actually this should be the general case - clients wanting to be served concurrently must provide thread id's instead of client ids.
HiveMind's pooled services should already be quite close, only, the pool needs to become aware of the client-id's -- I need to have a look at them.

Tuesday, April 26, 2005

Intercepting Exceptions in Tapestry Listeners

While I'm growing increasingly fond of Tapestry, there's one tiny advantage to Struts-like Action-classes over listener-methods. Namely, taking care of (non-technical) user exceptions by converting them to friendly messages. A common base-class for all pages overriding AbstractComponent's getListeners() method does the trick. I made it return a sub-class of the standard ListenerMap, which, in turn wraps each of the standard IActionListeners it returns into some custom IActionListener taking care of the standard user exceptions like "ObjectNotFound", "NoPermission", "OptimisticLockBroken" and the like by providing a nice message to a page property (or a delegate-bean).
Still, the way you have to unwrap your exception from the ApplicationRuntimeException is somewhat unsatisfactory. It's just too tight coupling to framework-internals. Maybe, there should be some hook in the framework to plug-in custom exception interceptors into listeners.
A nice way would be this: If the page implements an interface IListenerExceptionListener it would be called whenever a listener throws a suitable exception. Now, suitable could mean:
  • Any checked Exception (declared by the listener method)
  • contained in a list of classes (provided via the listener interface or some other means - could use a class to Listener Map instead, to avoid duplicate switching)
  • Any exception at all.

Wednesday, April 20, 2005

If you can't hide it below, hide it above

In one of the last projects, I was involved in, a Web-Controller accessed business logic through a service facade implemented as a Spring-bean hiding a hibernate-pesisted domain model. Transactions (and hibernate sessions) were controlled declaratively at the service facade. Sounds so nice and clean - nice layers not allowed to know certain things about fellow layers. Only, it didn't work out quite so nice.

  • First: Session/TA-state was, in fact, not hidden below the service facade, because domain objects (detached hibernate entities) were used in the service interface, resulting in plenty of LazyInitializationExceptions and duplicate objects. Tedious DTO's (see Fowler on local DTOs) would have avoided this, but at an unacceptably high price of cumbersome code-duplication.

  • Second: The "natural unit of work" in the application was handling one http request. So, the presentation code had to be careful not to call the service facade twice (or otherwise take over session/ta-control explicitly). So, after all, the presentation layer was, indeed coded, without any knowledge of the technical details below the service facade - sadly it had to know them to work properly.


In my current project, hibernate sessions and transactions are controlled almost entirely from a ServletFilter (See Gavin King's long-session-pattern) - and wow: no more LazyInitializationExceptions - nice "per-request-transactions". And the best of it: presentation and business layer are both freed from doing awkward things pertaining to hibernate persistence (re-attaching detached objects, explicitly setting ta-boundaries, pre-loading lazy collections before handing them back to someone who might need them). It's all hidden above. The only thing left to do is to request a fresh hibernate session at some sensible point (e.g. whenever the user is done with one set of "top-level-objects" and requests a new one).
Ah, yes, so Spring turned out to be rather useless in this particular case ...

Friday, February 18, 2005

Web Services with Axis

I'm currently thinking about using Web Services as a more robust (i.e. more tolerant to changes, compared to RMI) protocol for widely re-used services. Two days of fiddling with Axis 1.2 RC2 make me doubt whether that's a good idea. At least the jax-rpc stuff seems still quite brittle, especially on the client-side. Maybe, using WSDL2Java to generate stubs is not a good idea at all. One more attribute in a bean instantly breaks the client (the bean-deserializer complains about an illegal element). I'd rather like a more generic client - maybe a less picky bean-(de-)serializer will do ...

Wednesday, February 16, 2005

captatio benvolentiae

So now I'm starting my random notes with a completely pointless one, just to test it. Hoping, of course, that some of the seemingly interesting thoughts that made me start this thing might come back later.