28th August 2008
Spring / Toplink / MySQL set up
Spring is an amazing framework in Java. However, the set up pain was really huge for a Tomcat / Toplink / MySQL set up. Here's how I finally managed to do it.
According the Spring documentation, here's how you're supposed to do it.
<?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:p="http://www.springframework.org/schema/p"
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.0.xsd" >
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/><bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<bean id="dataSource"
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="databasePlatform" value="oracle.toplink.essentials.platform.database.MySQL4Platform"/> </bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver"/>
</property>
</bean>
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
<property name="username" value="myuser"/>
<property name="password" value="mypass"/>
</bean><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean></beans>
The advantage of using the Spring set up is that you can use Spring to inject an entityManager into your data access objects. Unfortunately, although I fiddled and tried many times, it just didn't work over Tomcat. I got it working fine for my unit tests so I ended up having a seperate Spring/Toplink config file.
First I established a javax.sql.DataSource datasource connection in Tomcat. I did this by sticking it in the /META-INF/context.xml file
<Resource
auth="Container"
name="jdbc/mycon"
type="javax.sql.DataSource"
password="mypass"
driverClassName="com.mysql.jdbc.Driver"
maxIdle="2"
maxWait="5000"
username="myuser"
url="jdbc:mysql://localhost:3306/mydatabase?characterEncoding=UTF-8"
maxActive="4"/>
The characterEncoding proved necessary as I've outlined here
Next, I set up a persistence file in /WEB-INF/classes/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<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="mypersistence" transaction-type="RESOURCE_LOCAL"> <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<non-jta-data-source>java:comp/env/jdbc/mycon</non-jta-data-source> <class>com.yourclass</class><properties>
<property name="toplink.weaving" value="true"/>
<property name="toplink.cache.type.default" value="Full"/>
<property name="toplink.cache.size.default" value="1"/> <property name="toplink.logging.level" value="FINE"/>
<property name="toplink.session.customizer" value="classes.ToplinkSessionCustomiser"/>
</properties></persistence-unit>
</persistence>
To get Toplink to pick up the DataSource, I had to use the toplink.session.customizer property. Here's the class
import oracle.toplink.essentials.tools.sessionconfiguration.SessionCustomizer;
import oracle.toplink.essentials.sessions.Session;
import oracle.toplink.essentials.jndi.JNDIConnector;/**
* This is what is needed to get a JNDI database connection
* http://forums.oracle.com/forums/thread.jspa?threadID=519351&tstart=105
*/
public class ToplinkSessionCustomiser implements SessionCustomizer {
public ToplinkSessionCustomiser() { }public void customize(Session session) throws Exception {
JNDIConnector connector = (JNDIConnector) session.getLogin().getConnector();
connector.setLookupType(JNDIConnector.STRING_LOOKUP);}
}
Next I put together an EntityManager
import javax.persistence.Persistence;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;public class PersistenceUtil {
private static EntityManagerFactory emf;
private static String entity_name = "mypersistence";
private PersistenceUtil() { }public static EntityManagerFactory getEMF() {
return getEMF();
}public static EntityManager getManager() {
return getEMF().createEntityManager();
}
public static EntityManagerFactory getEMF() {
if (emf == null) {
emf = Persistence.createEntityManagerFactory(entity_name);
}
return emf;
}}
I had to put spring-tomcat-weaver.jar into my /tomcat/common/lib folder
Finally, I was able to write some code to stuff to and from the database
import javax.persistence.Query;
/**
* @author Kevin Saunders, saunderswebsolutions.com
*/@NamedQuery(
name = "userById",
query = "SELECT t FROM MyUserClass t WHERE t.userid = :userid"
)
public class EmailService {
private EntityManager em;public final EntityManager getEntityManager() {
if (em == null) {
return em = PersistenceUtil.getManager();
}
return em;
}public MyUserClass getEmail(Integer userid) {
Query query = getEntityManager().createNamedQuery("userById");
query.setParameter("userid", userid);
return query.getSingleResult();
}
}
I hope this helps someone to cut down on the set up time needed to get Spring working with Tomcat.
If you are having problems getting MySQL to maintain a connection to Toplink, click here