Archive for the ‘hibernate’ Category

Migrating from tomcat to weblogic

Thursday, March 11th, 2010

Moving from tomcat to weblogic may sound crazy. In case you need to do it though (e.g for business reasons) here are a couple of things which may go wrong.

First of all the classloader hierarchy in weblogic do not do what you usually expect from other servers such as tomcat, resin, jetty and jboss. If your application uses hibernate (and implicitly ANTLR) you may get the following exception:

Caused by: java.lang.Throwable: Substituted for missing class org.hibernate.QueryException - ClassNotFoundException: org.hibernate.hql.ast.HqlToken [from com.example.model.Person order by id]
        at org.hibernate.hql.ast.HqlLexer.panic(HqlLexer.java:80)
        at antlr.CharScanner.setTokenObjectClass(CharScanner.java:340)
        at org.hibernate.hql.ast.HqlLexer.setTokenObjectClass(HqlLexer.java:54)
        at antlr.CharScanner.<init>(CharScanner.java:51)
        at antlr.CharScanner.<init>(CharScanner.java:60)
        at org.hibernate.hql.antlr.HqlBaseLexer.<init>(HqlBaseLexer.java:56)
...

As explained in the Hibernate3 Migration Guide Weblogic doesn’t seem to support proper class loader isolation, will not see the Hibernate classes in the application’s context and will try to use it’s own version of ANTLR.

In the same fashion you may get the following exception for commons lang:

java.lang.NoSuchMethodError: org.apache.commons.lang.exception.ExceptionUtils.getMessage(Ljava/lang/Throwable;)Ljava/lang/String;

because weblogic internally uses commons lang 2.1 and the one you use may have more API methods.

For both these problems the solution is to instruct weblogic to prefer the jars from the WEB-INF of your application. You need to create a weblogic specific file called weblogic.xml and place it under WEB-INF:

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app>
    <container-descriptor>
        <prefer-web-inf-classes>true</prefer-web-inf-classes>
    </container-descriptor>
</weblogic-web-app>

Another problem is that, like in resin, the default servlet is not named “default” so if you depend on it in web.xml, your application may throw the following at the deployment phase:

Caused by: weblogic.management.DeploymentException: [HTTP:101170]The servlet default is referenced in servlet-mapping *.avi, but not defined in web.xml.

This is because the default servlet is called FileServlet in the web.xml, so you’ll need to change all references in your web.xml from “default” to “FileServlet”.

Last, but not least, tomcat will automatically issue a 302 redirect from http://localhost:8080/context to http://localhost:8080/context/ before allowing your application to do any processing. So all instances of request.getServletPath() will never return an empty string, but will always start with “/”. Weblogic doesn’t do this so http://localhost:8080/context resolves and if your code contains something like:

request.getServletPath().substring(1)

you’ll get:

java.lang.StringIndexOutOfBoundsException: String index out of range: -1

so a safer way to trim this leading slash is by doing:

request.getServletPath().replaceFirst("^/", "")

Good luck, and remember. Every time you use a full blown application server for something that a simple web container would be enough, god kills a kitten.

fix hibernate+ehcache: miss for sql

Saturday, February 21st, 2009

If you are using an entity as a named parameter in a hibernate Query or Criteria which is cachable from ehcache then this entity needs to implement hashcode and equals using a business key. Otherwise the hibernate Query or Criteria may always “look different” to ehcache so it will be a constant cache miss.

DEBUG (MemoryStore.java:138) - query.FooBarCache: query.FooBarMemoryStore miss for sql: /* criteria query */ select this_.id as y0_ from foobars this_ where this_.state=?; parameters: LIVE; max rows: 1; transformer: org.hibernate.transform.PassThroughResultTransformer@294633f0
DEBUG (Cache.java:808) - query.FooBar cache - Miss

Singleton ehcache CacheManager warning fix

Thursday, February 12th, 2009

If you experience the following warning in your hibernate+ehcache application:

2008-11-20 13:02:42,937 WARN  (CacheManager.java:322) - 
  Creating a new instance of CacheManager using the diskStorePath 
  "D:\apache-tomcat-5.5.26\temp" which is already used by an 
  existing CacheManager.
The source of the configuration was classpath.
The diskStore path for this CacheManager will be set to 
  D:\apache-tomcat-5.5.26\temp\ehcache_auto_created_1227178962937.
To avoid this warning consider using the CacheManager factory 
  methods to create a singleton CacheManager or specifying a 
  separate ehcache configuration (ehcache.xml) for each 
  CacheManager instance.

then you need to set the following in your hibernate.cfg.xml file:

<property name="hibernate.cache.provider_class">
  net.sf.ehcache.hibernate.SingletonEhCacheProvider
</property>

Ehcache Hibernate documentation

The * stupidest things I’ve done in my programming job

Saturday, February 7th, 2009

I’m not ashamed of those sins any more, so here you go :)

1. ORM

Stupidity
Building my own Object Relational Mapping framework.
Consequence
Project is a mess after 2 years of maintenance with hardcore hacks to bypass my own ORM and call custom SQL queries.
What should I have done
Use hibernate, iBATIS, Cayenne or something similar.

2. EAV

Stupidity
Using an Entity-Attribute-Value model database schema design.
Consequence
Non scalable solution and total impossibility to run any useful queries on the database level.
What should I have done
Use an ordinary normalized database schema design.

3. Database Access

Stupidity
Synchronize (serialize) database access using one shared connection.
Consequence
Zero scalability. Very slow response times when more than 10 users where using the application.
What should I have done
Don’t do that and use a connection pool such as c3p0 and use a “new” (reused) connection returned from the pool for every request/response cycle.

4. IDE

Stupidity
Avoided learning and using an Integrated development environment.
Consequence
Inability to build test and deploy the application quickly and generally do anything useful.
What should I have done
Get familiar with an IDE. NetBeans, eclipse etc.

5. Transactions

Stupidity
Not using them.
Consequence
Corrupt data in an application involving e-shop like functionality.
What should I have done
Use database transactions. When in MySQL use InnoDB.

6. Prepared Statements

Stupidity
Using Statements, string concatenation and naive character escaping to assemble my own “safe” queries.
Consequence
SQL Injections possible in my application. I managed to login using ‘or 1=1;delete from users;– and alter the database state in a very nasty way.
What should I have done
Use Prepared Statements which correctly assemble and escape the query properly depending on the JDBC driver used.

7. Business Logic

Stupidity
Doing it in the template (JSP).
Consequence
Messy non maintainable application.
What should I have done
Do it in an MVC style with servlets or with a Front Controller. Even better by using an existing open source MVC framework such as Struts, Spring MVC etc.

Of course, all the bad choices above have probably made me a better programmer.

Disabling foreign key generation in hbm2ddl

Monday, August 13th, 2007

When generating the database schema using the hbm2ddl tools, foreign keys are being created for every relation. You can enhance the schema by using the foreign-key attribute to specify your own name for a particular foreign key.

But, what happens when you don’t want a foreign key generated?

There is an undocumented behavior of the foreign-key attribute, and that is to specify foreign-key=”none”. hbm2ddl will not create an FK for a relation which has such an attribute. The hibernate documentation and the two bibles Hibernate in Action and Java Persistence with Hibernate state absolutely nothing about this feature. I found it after hardcore googling in the following hibernate changelog:

Changes in version 2.1.9 (xx.x.xxxx)
------------------------------------
* foreign-key="none" can be used to disable generation of a foreign key.

Later on, I found another blog mentioning this behavior: http://blog.xebia.com/2007/02/05/let-hibernate-connect-your-world/

The most logical question now is “why don’t you want an FK?”. That depends on the system you are building. Sometimes you might have a table in your application which will be CRUDed from another system, which you do not control. You may want to be able to keep references (ids) to entities which may be deleted. foreign-key=”none” together with not-found=”ignore” can solve these kind of problems.

Overcoming the MySQL BIT datatype problems with hibernate

Friday, June 15th, 2007

I’m fond of optimization. When I code or design my database schema I try to avoid waisting CPU cycles or storage space (at least without a good reason). So when my domain class has the following field:

private boolean active; // determines whether this Person is active

I will let hibernate and the MySQL5InnoDBDialect choose what is most appropriate:

<property name="active" not-null="true" />

In that case it will generate a BIT:

...
active bit not null,
...

The problem

So far so good…
…until you read the blog post called “Why you should not use BIT columns in MySQL” by Xaprb.
Another serious deficiency is the fact that a database dump will not export bit data as “0″ or “1″. Depending on the tool used to dump and the MySQL server version you may find one of the following:

INSERT INTO `person` VALUES (1,"foo","\\0");
INSERT INTO `person` VALUES (2,"bar","");

or

INSERT INTO `person` VALUES (1,"foo"," ");
INSERT INTO `person` VALUES (2,"bar"," ");

The third field is of datatype BIT. Row number 1 is false and row number 2 is true. The problem with that is that some MySQL client tools cannot import such things. It gives you an ERROR 1064 (42000) at line 23: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ” at line 1

Solution #1

Hand edit the sql script and change all false bits to 0 and all true bits to 1, the script can be imported like a charm.

Solution #2

Extend MySQL5InnoDBDialect and make all BITs rendered as TinyInt(1). The code is very simple:

package com.foo.hibernate;

import java.sql.Types;
import org.hibernate.dialect.MySQL5InnoDBDialect;

public class MySQL5InnoDBDialectBitFixed extends MySQL5InnoDBDialect {

  public MySQL5InnoDBDialectBitFixed() {
    super();
    registerColumnType(Types.BIT, "tinyint(1)");
  }
  
}

Now when using the MySQL5InnoDBDialectBitFixed dialect, hbm2ddl will generate:

...
active tinyint(1) not null,
...

Until we get better 5.x MySQL versions, with better BIT support, this plan should do the job nicely.

Good luck

Caching pages using ehcache

Monday, June 4th, 2007

When an http request to your /rss page needs 400 milliseconds to complete, it seems obvious that your website could benefit from some caching. Ehcache is a well known cache provider, which most of us know from hibernate. Since we are already “bound” to ehcache, lets see how we can benefit from caching some dynamically generated pages:

web.xml

<filter>
  <filter-name>SimplePageCachingFilter</filter-name>
  <filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>SimplePageCachingFilter</filter-name>
  <url-pattern>/rss</url-pattern>
</filter-mapping>

We set up the SimplePageCachingFilter in the web.xml of the web application and map it to one or more url patterns or servlets. All requests to /rss will be intercepted by the SimplePageCachingFilter.

ehcache.xml

<ehcache>
  <diskStore path="java.io.tmpdir" />
  <cache name="SimplePageCachingFilter"
         maxElementsInMemory="0"
         eternal="false"
         timeToIdleSeconds="600"
         timeToLiveSeconds="600"
         overflowToDisk="true"/>        
</ehcache>

We then configure the cache region for pages. We don’t want any elements kept in memory. Everything should be written to disk at the java.io.tmpdir location. The cache expires every 10 minutes.

Now hitting http://example.com/rss (our default rss page) results in a cache miss. The content is being generated from scratch but before returning to the client, the filter stores it locally. The second time we’ll get a cache hit. The content now is being fetched from the cache and its very fast. 10 minutes later this cache element will be invalidated. Note that the default implementation uses the URI together with the query string to calculate the cache key, so /rss?type=news and /rss?type=forum will result in two different cache elements.

SQL Server + hbm2ddl + unicode columns

Tuesday, May 1st, 2007

Hibernate offers org.hibernate.dialect.SQLServerDialect as the dialect for SQL Server. When generating the database schema, using hbm2ddl, the string type columns do not support native characters. So the following mapping:

<property name="title" length="128" />

will produce the following SQL:

...
title varchar(128) null,
...

By extending the org.hibernate.dialect.SQLServerDialect we can achieve the generation of NCHAR, NVARCHAR, and NTEXT columns instead of CHAR, VARCHAR and TEXT.

package com.foo.hibernate;

import java.sql.Types;
import org.hibernate.dialect.SQLServerDialect;

public class SQLServerNativeDialect extends SQLServerDialect{

  public SQLServerNativeDialect() {
    super();
    registerColumnType(Types.CHAR, "nchar(1)");
    registerColumnType(Types.VARCHAR, "nvarchar($l)");
    registerColumnType(Types.LONGVARCHAR, "nvarchar($l)");
    registerColumnType(Types.CLOB, "ntext");
  }

}

All we need to do now is plug this dialect in our hibernate configuration:

<property name="hibernate.dialect">
  com.foo.hibernate.SQLServerNativeDialect
</property>

Related hibernate forums thread: http://forum.hibernate.org/viewtopic.php?t=972518
Related API method: http://www.hibernate.org/hib_docs/v3/api/org/hibernate/dialect/Dialect.html