Hi mavericjr,
now I was able to make the servlet sucessfully run under tomcat (version 6) with hibernate using JTA.
This time I used a custom local JNDI-implementation, so I need no any jboss library anymore
and I get rid of all serialization problems.
I also tested the commit and rollback functionality and it works correctly (the servlet test this).
See here the sources:
The servlet JTAHibernateServlet.java :
Code:
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import javax.naming.spi.InitialContextFactoryBuilder;
import javax.naming.spi.NamingManager;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.enhydra.jdbc.standard.StandardXADataSource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.transaction.JOTMTransactionManagerLookup;
import org.objectweb.jotm.Jotm;
import org.objectweb.transaction.jta.TMService;
public class JTAHibernateServlet extends HttpServlet implements InitialContextFactoryBuilder {
static JOTMTransactionManagerLookup _ml = new JOTMTransactionManagerLookup();
static LocalContext _localCtx = null;
public static class ExtendedXADataSource extends StandardXADataSource { // XAPOOL
@Override
public Connection getConnection() throws SQLException {
// Accoding to Enhydra doku, here we must return the connection of
// our XAConnection
// see
// http://cvs.forge.objectweb.org/cgi-bin/viewcvs.cgi/xapool/xapool/examples/xapooldatasource/DatabaseHelper.java?sortby=rev
return super.getXAConnection().getConnection();
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out
.println("<h1>Hello world, here a hibernate jta example servlet!</h1>");
try {
Properties props = new Properties();
if (!NamingManager.hasInitialContextFactoryBuilder())
NamingManager.setInitialContextFactoryBuilder(this);
InitialContext jndiCtx = new InitialContext(props);
/* startup JOTM */
TMService jotm = new Jotm(true, false);
jotm.getUserTransaction().setTransactionTimeout(36000);
// XAPOOL
ExtendedXADataSource xads = new ExtendedXADataSource();
xads.setDriverName("org.hsqldb.jdbcDriver");
//xads.setDriverName("com.p6spy.engine.spy.P6SpyDriver");
xads.setUrl("jdbc:hsqldb:hsql://localhost");
xads.setTransactionManager(jotm.getTransactionManager());
jndiCtx.bind("java:/MyDatasource", xads);
jndiCtx
.bind("java:comp/UserTransaction", jotm.getUserTransaction()); // this is needed by hibernates JTATransactionFactory
HibernateEntityManagerFactory emf = (HibernateEntityManagerFactory) Persistence
.createEntityManagerFactory("helloworld");
UserTransaction userTransaction = jotm.getUserTransaction();
SessionFactory sf = emf.getSessionFactory();
userTransaction.begin();
EntityManager em = emf.createEntityManager();
Session session = (Session) em.getDelegate(); // sf.getCurrentSession();
A a = new A();
a.name= "firstvalue";
session.save(a);
session.flush();
Serializable id = session.getIdentifier(a);
out.println("<br>Created and flushed instance a with id : "
+ a.oid + " a.name set to:" + a.name);
out.println("<br>Calling userTransaction.commit() (Please check if the commit is effectively executed!)");
userTransaction.commit();
userTransaction.begin();
session = sf.openSession();
A a1 = (A) session.get(A.class, id);
out.print("<br>Should retrieve commited instance: " + a1.name);
a = new A();
a.name= "secondrecord";
session.save(a);
session.flush();
id = session.getIdentifier(a);
out.println("<br><br><br>Created and flushed instance a with id : "
+ a.oid + " a.name set to:" + a.name);
out.println("<br>Calling userTransaction.rollback()");
userTransaction.rollback();
userTransaction.begin();
session = sf.openSession();
A a2 = (A) session.get(A.class, id);
out.print("<br><br>Should not retrieve rollbacked instance (shall be null): " + a2);
userTransaction.rollback();
out.println("</body>");
out.println("</html>");
} catch (Exception r) {
r.printStackTrace();
}
}
@Override
public InitialContextFactory createInitialContextFactory(
Hashtable<?, ?> environment) throws NamingException {
return new InitialContextFactory() {
@Override
public Context getInitialContext(Hashtable<?, ?> environment)
throws NamingException {
if (_localCtx == null)
{
_localCtx = new LocalContext();
}
return _localCtx;
}
};
}
}
The custom local (scope = classloader) JNDI-Implementation
LocalContext.java:
Code:
import java.util.Hashtable;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.OperationNotSupportedException;
public class LocalContext implements Context {
static Hashtable<String,Object> string_object = new Hashtable<String,Object>();
@Override
public Object addToEnvironment(String propName, Object propVal)
throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public void bind(Name name, Object obj) throws NamingException {
string_object.put(name.toString(), obj);
}
@Override
public void bind(String name, Object obj) throws NamingException {
string_object.put(name, obj);
}
@Override
public void close() throws NamingException {
string_object.clear();
}
@Override
public Name composeName(Name name, Name prefix) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public String composeName(String name, String prefix)
throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public Context createSubcontext(Name name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public Context createSubcontext(String name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public void destroySubcontext(Name name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public void destroySubcontext(String name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public Hashtable<?, ?> getEnvironment() throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public String getNameInNamespace() throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public NameParser getNameParser(Name name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public NameParser getNameParser(String name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public NamingEnumeration<NameClassPair> list(Name name)
throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public NamingEnumeration<NameClassPair> list(String name)
throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public NamingEnumeration<Binding> listBindings(Name name)
throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public NamingEnumeration<Binding> listBindings(String name)
throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public Object lookup(Name name) throws NamingException {
return string_object.get(name.toString());
}
@Override
public Object lookup(String name) throws NamingException {
return string_object.get(name);
}
@Override
public Object lookupLink(Name name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public Object lookupLink(String name) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public void rebind(Name name, Object obj) throws NamingException {
string_object.put(name.toString(), obj);
}
@Override
public void rebind(String name, Object obj) throws NamingException {
string_object.put(name, obj);
}
@Override
public Object removeFromEnvironment(String propName) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public void rename(Name oldName, Name newName) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public void rename(String oldName, String newName) throws NamingException {
throw new OperationNotSupportedException();
}
@Override
public void unbind(Name name) throws NamingException {
string_object.remove(name.toString());
}
@Override
public void unbind(String name) throws NamingException {
string_object.remove(name);
}
}
My configuration (persistence.xml):
Code:
<persistence 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" version="1.0">
<persistence-unit name="helloworld" transaction-type="JTA">
<jta-data-source>java:/MyDatasource</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value = "create"/>
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.current_session_context_class" value="org.hibernate.context.JTASessionContext"/>
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JOTMTransactionManagerLookup"/>
</properties>
</persistence-unit>
</persistence>
My test persistent class A.java:
Code:
@Entity
public class A {
@Id @GeneratedValue(strategy = GenerationType.TABLE)
public long oid;
@Column
@NaturalId (mutable = false)
public String name;
}