zaterdag 28 juli 2007

my jstl frustrations

the in-container jstl interpreter functionality is great. And where there are greats things there are also less great things. Some of my frustrations on jstl:

no way to cast objects. In some cases this would be very welcome. For example when you have a superclass Item and some extending, more specifiek objects like AnITem and AnotherItem. In code you would be working with Item objects in general. In your view you need to have them casted towards a specifiek one. No way to do this in jstl so you need to cast in the controller which is not cool when you're working with a collection that could contain multiple kind of items.

Another one is the way you can't use numbers as a key for map collections. Need to provide another getter returing a string for that.

zondag 15 juli 2007

maven and jetty for quick dev deploy (2)

See previous post for more on general maven-jetty-plugin info. This time I'll explain how to get all this to work in eclipse. Wouldn't it be very easy to be able to execute this all from within eclipse? Follow these steps:

in Eclipse hit Run > External Tools > External Tools... to get the following popup:



First dubbelclick on Program on the left to create a new configuration. Then on the right complete information on the Main tab. Location is the path to your maven bin directory, Working Directory is your maven project and the arguments maven needs is
jetty:run


Next on the Environment tab add a New variable with name MAVEN_OPTS and value :
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=n




And you're good to go. Launch the External tool you just configured which will start the jetty container. When you whish to debug you can create a new Run > Debug ... > Remote Java Application. All you need to set is the portnumber yout entered for the jetty arguments (4000 in my example).

sources:
o jetty documentation
o more on maven + eclipse

zaterdag 14 juli 2007

maven and tiger

By default the maven compiler plugin assumes you're working with 1.3 compatible sources. So tiger (java 1.5) sources will throw an UnsupportedClassVersionError.

The solution is to configure the maven-compiler plugin in your pom file to generate 1.5 sources like this:

<?xml version="1.0"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>be.cappelleh.test</groupId>
<artifactId>test</artifactId>
<name>test</name>
<version>1.0-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- dependencies here -->
</dependencies>
</project>


source
o http://maven.apache.org/plugins/maven-compiler-plugin/

maven and jetty for quick dev deploy

Jetty is a java powered lightweight servlet container. It can be used as an embedded container bringing webapps closer to desktop applications. But that's another story. Here I will quickly explain how you can even quicker deploy your webapp on a jetty container using the maven jetty plugin.

All you need to do is add some configuration for the jetty plugin in you pom file. Like this basic config:

<?xml version="1.0"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>be.cappelleh.test</groupId>
<artifactId>test</artifactId>
<name>test</name>
<version>1.0-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<useTestClasspath>true</useTestClasspath>
<scanIntervalSeconds>10</scanIntervalSeconds>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- dependencies here -->
</dependencies>
</project>


Next you can run your application using the following goal

mvn jetty:run


First time will take a bit longer because of the dependencies that need to be downloaded. Once up and running you'll see

[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.


And that means your application is waiting for you at (replace yourContext with your project context)

http://localhost:8080/yourContext


sources:
o jetty project homepage
o maven jetty plugin config
o maven jetty plugin goals
o more on jetty

woensdag 11 juli 2007

how to tell browser not to cache documents

I had to find a way to make sure the browser doesn't cache PDF documents on the local file system. IE for instance downloads a copy towards C:/Documents and Settings/userDirectory/Local Settings/Temporary Internet Files/ (which is the default, can be changed through Tools > Internet Options > Tab General and click Settings on panel Temprary Internet Files).

The solution was actually very easy, add the following HTTP headers to your response, that's it.

response.setHeader("Cache-Control","no-cache"); // for HTTP 1.1
response.setHeader("Pragma","no-cache"); //for HTTP 1.0
response.setDateHeader ("Expires", 0); //for proxy server
response.setHeader("Cache-Control","no-store"); //HTTP 1.1


source:
http://java.ittoolbox.com/groups/technical-functional/java-l/how-to-avoid-caching-of-pages-in-temporary-internet-files-folder-721490

hibernate: once set up you'll love it

Hibernate is lovely... it needs a little more attention to set up but once that's done no other persistence framework will beat it. So let's go over the setup steps here. I know there is a lot of information (good job on that from hibernate, springs lacks this at the moment) on this topic online, still it would be nice to have an overview (so I can get back to this summary myself).

dependencies

Let it be clear that using hibernate means you'll need to add some dependencies, jar files, to your project. If you use maven to manage these depencies this can't be hard.

your model

You'll need some POJO's or Plain Old Java Objects you want to store. These are simple Java objects with a ctor, some private properties and public setters and getters, also called JavaBeans.

mapping

Next you need to let hibernate know how these POJO's need to be stored in whatever JDBC enabled db you want to use. Therefore create a mapping file for all your POJO's. I use the following one as a reference, it comes from the hibernate reference documentation (see sources). Also make sure you check the mapping cheat sheet (sources) for more advanced mapping files.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="eg">

<class name="Cat"
table="cats"
discriminator-value="C">

<id name="id">
<generator class="native"/>
</id>

<discriminator column="subclass"
type="character"/>

<property name="weight"/>

<property name="birthdate"
type="date"
not-null="true"
update="false"/>

<property name="color"
type="eg.types.ColorUserType"
not-null="true"
update="false"/>

<property name="sex"
not-null="true"
update="false"/>

<property name="litterId"
column="litterId"
update="false"/>

<many-to-one name="mother"
column="mother_id"
update="false"/>

<set name="kittens"
inverse="true"
order-by="litter_id">
<key column="mother_id"/>
<one-to-many class="Cat"/>
</set>

<subclass name="DomesticCat"
discriminator-value="D">

<property name="name"
type="string"/>

</subclass>

</class>

<class name="Dog">
<!-- mapping for Dog could go here -->
</class>

</hibernate-mapping>


configuration

Then you can already configure hibernate. Create an xml file called hibernat.cfg.xml in your project resources folder and copy the following, adjusted for your needs, into it.

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<mapping resource="events/Event.hbm.xml"/>

</session-factory>

</hibernate-configuration>


Check the hibernate reference documentation (sources) for more information on this config. Good to know is that the jdbc driver and sql dialect depend on the database you are using. Als the mapping resources at the bottom here need to point towards your mapping files you created earlier.

some util

You can use the following util code to access the hibernate session.


package util;

import org.hibernate.*;
import org.hibernate.cfg.*;

public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}

}


hit it

Now you can start writing your services. In these services you retrieve the hibernate session, begin and commit transactions and in between this you'll saveOrUpdate, load, delete, list, ... your POJO's. For more specific queries you'll need to get into hql.

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId);

// The getEmailAddresses() might trigger a lazy load of the collection
aPerson.getEmailAddresses().add(emailAddress);

session.getTransaction().commit();



sources:
o hibernate reference documentation
o hibernate mapping cheat sheet
o hibernate tutorial, quick start

dinsdag 3 juli 2007

Spring Interceptors

Interceptors are very useful to intercept changes in your web application. Think of switching language, changing user id, ... Before Spring you would probably implement this using a filter.

Spring has a default interceptor for the language called LocaleChangeInterceptor. Look at the source of this one to see what you can do with interceptors.

It implements the HandlerInterceptor interface with the following methods (read api for more info):

void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

Callback after completion of request processing, that is, after rendering the view.

void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

Intercept the execution of a handler.

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

Intercept the execution of a handler.

To ease implementing only those you really need to implement there is the HandlerInterceptorAdapter.

Another example of using interceptors is to detect caching rules according to annotations


work out an example