22 July 2008

Spring, Annotations and JPA web project

I struggled to set up the latest version of Spring (2.5.4) with JPA using annotations as much as possible for a web project (not using spring MVC). I could find much documentation and the documentation I found was lacking and not specific to the setup I was trying. So here is how I did it for those who need to know.

Project Setup

I'm using Netbeans, but it shouldn't matter what you are using - I'll keep the IDE out of the description and use external libraries.

You will need a JPA provider (I'm using hibernate 3.2), Spring libraries and a database (I'm using PostgreSQL). I am also using JUnit4.4, which makes testing with spring a lot easier, I have to edit the testing libraries manually on Netbeans 6.1, as it comes standard with JUnit4.1.

So, create a web project.

Setting up JPA

Create a database first, I created one called 'deleteme' with user 'deleteme' and password 'deleteme', so that I will remember to delete it. At some stage.
with your IDE and create a database.

Next, create a 'persistance.xml' file in the 'WEB-INF/classes/META-INF' directory, this is what myne looks like:


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="deleteme" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    </properties>
  </persistence-unit>
</persistence>


Note: The database details are not in the persitance config file, they will be in the spring config file (more on that later). The only thing you need change is the persistence-unit name which in my case is, 'deleteme'.

Setting up Spring

Create a new file 'spring.xml' (for example) and add the basic configurations:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
          
    <context:annotation-config/>
    <context:component-scan base-package="com.gamatam.example" />
   
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.postgresql.Driver"/>
        <property name="url" value="jdbc:postgresql://localhost/deleteme"/>
        <property name="username" value="deleteme"/>
        <property name="password" value="deleteme"/>
    </bean>
   
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    </bean>
   
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
   
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
   
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
   
    <tx:annotation-driven />
</beans>


Note: I setup the datasource in the spring configuration, as the configuration is more or less in one place and it makes unit testing easier (rather than using a datasource from the J2EE container).

The different namespaces needed tripped me up the first time I set this up, its a great idea, but does create more confusion to new users.

Basically, I setup a datasource for the database and an EntityManagerFactoryBean, which will find the persistance configuration. Then add the exception translation and transaction management and specify that the config is annotation driven. Thats it!

First Test

Now you can create your first test to see that the configuration files are being loaded OK etc.. Here is myne:

package com.gamatam.example;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;

/**
 *
 * @author brians
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:web/WEB-INF/spring.xml" })
public class Basics {
   
    @Test
    public void first(){
       
    }
   
    public Basics() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

}


Note: With the 'RunWith' and 'ContextConfiguration' annotations, testing spring becomes a breeze, no more excuses :(

If that is working for you, you are past the worst part of your project and can go on to code.

Whats Next?

Well, next create an entity bean and test it, create a DAO for it and test it, create your business/service layer with transactinos and test it. That will be in part two..

This is what worked for me, you may not like it but comments on it anyway, I'd love to here from you.

Brian




18 June 2008

Plain ol' Servlets and JSP

I reached a realization after many years of working with web frameworks and creating a few back when there weren't any to be had: web frameworks don't always save you time and has everybody forgotten how to code with servlets JSPs and tag libraries?

What pushed me over the edge was trying to code in an agile way using JSF. JSF is a nice idea, at least it doesn't tie you to the framework too much (extending action classes etc), but it is so loosely coupled that a typo (and I make loads) can cause a half day loss of work tracking down the error and I haven't been through that kind of debugging since C/C++, um, and mobile device programming.

I also got tired of writing configuration data in multiple xml and property files: set up the framework in the web.xml file, then off to the frameworks action config file, then the mapping file etc.. yuck.

About 6 years ago I wrote a framework using XML and XSLT when it looked like XSLT was the best thing for view abstraction (hahaha). I had a nicely abstracted design, with a factory for choosing the action class, another for choosing the XSLT file and another for the SQL. This was all rather neat and worked well, though took a lot explaining to my colleagues, but as they weren't familiar with OOP architecture (architecture in general) I arrogantly thought once they saw the whole picture all would be forgiven...

A few years later there was call to use the same application and I took a look through the system again and realized that all the configuration could be done within the web.xml file: as all the logic was based around the request (it was a report based application), I could write a base servlet that handled the transforms and the configuration could be written into the servlet parameters and the mappings. It simplified the whole framework into a very manageable piece of code, I wouldn't say the same about the XSLT though..

The point of the diatribe is that we tend to go off and create a 'gatekeeper' servlet for handling all the requests and then a factory for mapping requests to actions, forgetting that a servlet is an action in itself. The other problem is the actions normally created are normally created, I suppose, to protect ourselves from all that HTTP request and response stuff, and then we end up passing it all through to the action ANYWAY, as its, um, pretty essential.

Since working on distributed applications servicing different types of clients I have used a clear business (or service) layer which means that the servlet becomes a translation layer only (getting parameters from the request etc..). Together with apache's beanutils there is really not much to do.

On the view side I again realized a flaw while using JSF: AJAX hit the scene but JSF or struts for that matter, had no support for it. So if you use these frameworks you are tied to whatever components they come up with including the javascript libraries and look and feel etc.

The other point is that HTML is already one language to learn, why bother with learning another (none-standard) way of doing it? Looking at the RFCs, HTML itself is going to become more complicated, why reinvent the wheel? I'd prefer to write my forms by hand and insert the values where needed, which brings me to my last point:

Why are more people not using tag libraries? They are easy to use and they do exactly what you need them to do. Together with EL and JSTL you can create some very clean and understandable views. There are some drawbacks and work arounds, but if more people were using them they would improve. Tool support is also a bit iffy: Netbeans has great support, but could be improved.

I've just brushed on the basics here and am not bashing frameworks completely, they have there place, but they don't have to be used everywhere in every situation.

I'd like to start not a framework, but rather a meme for using basic servlet/JSP for web development. If I get much interest from this blog, my next blog will be on the basics of using this meme.

28 January 2008

installing tomcat and apache on linux

This is mainly for my own record, I keep on having to do it from scratch and making it up on my way. The box I'm installing on is running redhat (or whatever it is called these days), not my choice - I prefer the debian / ubuntu setups, but I'm not fussed as they all work similarly.

Warning: This needs to be edited and formatted to make better sense and I may not get round to it..

Step One: Install Java
As java is so dead simple to install and manage on linux, I download and install it manually with little configuration

  1. Get the installer onto the box - I used lynx on the server to navigate from http://java.sun.com to the download area and download the installer, its not that clear using a text browser, but is possible (remember to press 'enter' on the agreement checkbox).
  2. Run the install (chmod +x to make it executable) in the directory you want it installed, which in my case was '/usr/local'.
  3. Create a symlink 'ln -s ..' to the jdk directory (/usr/local/java). My previous install I used the ./defaultjava ./currentjava etc, but I never needed it, so away it goes.

That is for java, I never create JAVA_HOME global environment variables as they can get overwritten when installing something else, it also makes it easier to swap java version and I've never had the need for it.

Step 2: Install tomcat
A bit more complicated, asd but mainly because I split out the tomcat directories (configuration, logging, web sites and working directories all go in linux freindly places (mostly).
  1. Download with wget: 'wget http://apache.is.co.za/tomcat/tomcat-6/v6.0.14/bin/apache-tomcat-6.0.14.tar.gz'. Check which version of tomcat you want first and replace the URL.
  2. Extract tomcat: I extract the application to '/java', because thats what makes sense to me. Some people would extract it to /usr/lib or ./bin or ./service or something.
  3. Configuration: move tomcat's conf directory to /etc/tomcat
  4. Compile the daemon: extract './bin/jsvc.tar.gz' and follow the instructions at http://tomcat.apache.org/tomcat-6.0-doc/setup.html
  5. edit ./native/Tomcat5.sh e.g:

# Adapt the following lines to your configuration
JAVA_HOME=/usr/local/java1.6
CATALINA_HOME=/java/tomcat
DAEMON_HOME=${CATALINA_HOME}/bin/jsvc-src
TOMCAT_USER=brians

# for multi instances adapt those lines.
TMP_DIR=/var/tmp
PID_FILE=/var/run/jsvc.pid
CATALINA_BASE=/etc/tomcat

#CATALINA_OPTS="-Djava.library.path=/home/jfclere/jakarta-tomcat-connectors/jni/native/.libs"
CLASSPATH=\
$JAVA_HOME/lib/tools.jar:\
$CATALINA_HOME/bin/commons-daemon.jar:\
$CATALINA_HOME/bin/bootstrap.jar
and change this line:
$DAEMON_HOME/src/native/unix/jsvc \
to:
$DAEMON_HOME/jsvc \


and -outfile /var/log/tomcat/stdout \
-errfile /var/log/tomcat/stderr \
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager \
-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties \

then chown tomcat.tomcat to /var/log/tomcat

test with (remember to create the user tomcat will run under first):
sudo sh ./native/Tomcat5.sh start
add to /etc/init.d

* change permissions on/etc/tomcat to tomcat and created directory /var/log/tomcat


Further Tomcat configuration:
Now to setup where the work folder is and setup the webapps.

mkdirs:

/var/www/html/webapps/hostname - these are for the manager installed apps and hot deploy WARs

/var/tomcat/work/hostname - these are for the tomcat generated files (jsp/servlet compiled)

/var/log/tomcat/ - for the log files

Then configure the server.xml:
host name="gamatam.com" appbase="/var/www/html/webapps/gamatam" workdir="/var/tomcat/work/gamatam" upackwars="true" autodelpoy="true" xmlvalidation="false" xmlnamespaceaware="false"
alias www.gamatam.com /alias
/host

It might be a good idea to make a backup of the server.xml file and then delete all the comments, makes it clearer.

Tomcat - Apache configuration:
Not as bad as you would think..

You need mod_jk installed (its a module for apache), you may be able to yum or apt-get it, I can't so i'm going to download it (rather than compile it). This might not work out..

Following the trail from http://tomcat.apache.org/connectors-doc/, download the right version for your linux and apache version (important)

And when all else fails, copy it from another location, more on this once the server's yum sources are set properly.

Add the following in the server.xml Engine:

listener classname="org.apache.jk.config.ApacheConfig" modjk="/etc/httpd/modules/mod_jk.so" confighome="/etc/tomcat" workersconfig="/etc/tomcat/conf/jk/workers.properties" jkworker="default" jklog="/var/log/tomcat/mod_jk.log" noroot="false"

you will need to create
/etc/tomcat/conf/jk/workers.properties and start with the default:

worker.list=default

worker.default.type=ajp13
worker.default.host=localhost
worker.default.port=8009

and then add the following to the apache config, which in centos/craphat is at /etc/httpd/conf/httpd.conf:

#TOMCAT#
Include /etc/tomcat/conf/auto/mod_jk.conf

That includes the tomcat related configuration and any virtual hosts etc and does the mapping.