Author: bleny Date: 2013-05-24 17:48:17 +0200 (Fri, 24 May 2013) New Revision: 621 Url: http://nuiton.org/projects/sandbox/repository/revisions/621 Log: introduce classes in nuiton-jpa-api and nuiton-jpa-junit Added: nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/ nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/AbstractJpaDao.java nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaDao.java nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaEntity.java nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/hibernate/ nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/hibernate/HibernateUtil.java nuiton-jpa/nuiton-jpa-junit/src/main/java/org/nuiton/jpa/junit/ nuiton-jpa/nuiton-jpa-junit/src/main/java/org/nuiton/jpa/junit/JpaEntityManagerRule.java Modified: nuiton-jpa/nuiton-jpa-api/pom.xml nuiton-jpa/nuiton-jpa-junit/pom.xml nuiton-jpa/pom.xml Modified: nuiton-jpa/nuiton-jpa-api/pom.xml =================================================================== --- nuiton-jpa/nuiton-jpa-api/pom.xml 2013-05-24 15:21:33 UTC (rev 620) +++ nuiton-jpa/nuiton-jpa-api/pom.xml 2013-05-24 15:48:17 UTC (rev 621) @@ -13,6 +13,40 @@ <groupId>org.nuiton.jpa</groupId> <artifactId>nuiton-jpa-api</artifactId> + <dependencies> + + <dependency> + <groupId>org.hibernate.javax.persistence</groupId> + <artifactId>hibernate-jpa-2.0-api</artifactId> + </dependency> + + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-core</artifactId> + </dependency> + + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-entitymanager</artifactId> + </dependency> + + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </dependency> + + </dependencies> + <build> Added: nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/AbstractJpaDao.java =================================================================== --- nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/AbstractJpaDao.java (rev 0) +++ nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/AbstractJpaDao.java 2013-05-24 15:48:17 UTC (rev 621) @@ -0,0 +1,132 @@ +package org.nuiton.jpa.api; + +/* + * #%L + * MagaLiE :: Persistence + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2013 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import java.util.List; + +/** + * This abstract class gather all code which is common to all daos for all entities. + * + * Code included is common implementations of {@link JpaDao} interface and there is + * also commun helpers methods for implementation business-specific operations + * exposed as protected. + * + * @author bleny, tchemit + * @since 0.1 + */ +public abstract class AbstractJpaDao<E extends JpaEntity> implements JpaDao<E> { + + protected EntityManager entityManager; + + public AbstractJpaDao(EntityManager entityManager) { + this.entityManager = entityManager; + } + + protected abstract Class<E> getEntityClass(); + + @Override + public E findById(String id) { + E entity = entityManager.find(getEntityClass(), id); + return entity; + } + + @Override + public List<E> findAll() { + String simpleName = getEntityClass().getSimpleName(); + TypedQuery<E> query = entityManager.createQuery("from " + simpleName, getEntityClass()); + return query.getResultList(); + } + + @Override + public void persist(E entity) { + entityManager.persist(entity); + } + + @Override + public E merge(E entity) { + E merge = entityManager.merge(entity); + return merge; + } + + @Override + public void remove(E entity) { + entityManager.remove(entity); + } + + @Override + public boolean contains(E entity) { + return entityManager.contains(entity); + } + + @Override + public E newInstance() { + E newInstance; + try { + newInstance = getEntityClass().newInstance(); + // TODO brendan 24/05/13 proper exception management + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + return newInstance; + } + + protected TypedQuery<E> createQuery(String hql) { + TypedQuery<E> query = entityManager.createQuery(hql, getEntityClass()); + return query; + } + + protected List<E> findAll(TypedQuery<E> query) { + return query.getResultList(); + } + + protected E findUnique(TypedQuery<E> query) { + return query.getSingleResult(); + } + + protected E findAnyOrNull(TypedQuery<E> query) { + List<E> all = findAll(query); + E onlyElement = null; + if ( ! all.isEmpty()) { + onlyElement = all.get(0); + } + return onlyElement; + } + + protected E findUniqueOrNull(TypedQuery<E> query) { + List<E> all = findAll(query); + E onlyElement = null; + if ( ! all.isEmpty()) { + if (all.size() > 1) { + throw new IllegalStateException("multiple results " + all); + } + onlyElement = all.get(0); + } + return onlyElement; + } + +} Added: nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaDao.java =================================================================== --- nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaDao.java (rev 0) +++ nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaDao.java 2013-05-24 15:48:17 UTC (rev 621) @@ -0,0 +1,52 @@ +package org.nuiton.jpa.api; + +/* + * #%L + * MagaLiE :: Persistence + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2013 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import java.util.List; + +/** + * Represents de common operation we can do using JPA + * + * @param <E> is the type of the entity manipulated with this DAO + * + * @author bleny, tchemit + * @since 0.1 + */ +public interface JpaDao<E extends JpaEntity> { + + E findById(String id); + + List<E> findAll(); + + void persist(E entity); + + E merge(E entity); + + void remove(E entity); + + boolean contains(E entity); + + E newInstance(); + +} Added: nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaEntity.java =================================================================== --- nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaEntity.java (rev 0) +++ nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/JpaEntity.java 2013-05-24 15:48:17 UTC (rev 621) @@ -0,0 +1,59 @@ +package org.nuiton.jpa.api; + +/* + * #%L + * MagaLiE :: Persistence + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2013 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +/** + * A JpaEntity must have a technical id. + * + * Also equals() is defined for compliance with JPA expectations. + * + * @author bleny, tchemit + * @since 0.1 + */ +public abstract class JpaEntity { + + public abstract String getId(); + + @Override + public boolean equals(Object other) { + String id = getId(); + if (other instanceof JpaEntity) { + JpaEntity that = (JpaEntity) other; + return id != null && that.getId() != null && id.equals(that.getId()); + } + return false; + } + + @Override + public int hashCode() { + String id = getId(); + return id == null ? 0 : id.hashCode(); + } + + @Override + public String toString() { + return "JpaEntity{id=" + getId() + "}"; + } + +} Added: nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/hibernate/HibernateUtil.java =================================================================== --- nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/hibernate/HibernateUtil.java (rev 0) +++ nuiton-jpa/nuiton-jpa-api/src/main/java/org/nuiton/jpa/api/hibernate/HibernateUtil.java 2013-05-24 15:48:17 UTC (rev 621) @@ -0,0 +1,132 @@ +package org.nuiton.jpa.api.hibernate; + +import org.apache.commons.lang3.SystemUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.ejb.AvailableSettings; +import org.hibernate.ejb.EntityManagerFactoryImpl; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.service.internal.SessionFactoryServiceRegistryImpl; +import org.hibernate.tool.hbm2ddl.SchemaExport; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import java.io.File; +import java.lang.reflect.Field; +import java.sql.Driver; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class HibernateUtil { + + private static final Log log = LogFactory.getLog(HibernateUtil.class); + + protected static final Map<String, String> HIBERNATE_H2_CONFIG; + + public static final String HBM2DDL_AUTO_VALIDATE = "validate"; + + public static final String HBM2DDL_AUTO_CREATE_DROP = "create-drop"; + + public static final String HBM2DDL_AUTO_CREATE = "create"; + + public static final String HBM2DDL_AUTO_UPDATE = "update"; + + static { + + Map<String, String> hibernateH2Config = new HashMap<String, String>(); + + hibernateH2Config.put(AvailableSettings.JDBC_DRIVER, Driver.class.getName()); + hibernateH2Config.put(AvailableSettings.JDBC_USER, "sa"); + hibernateH2Config.put(AvailableSettings.JDBC_PASSWORD, ""); + hibernateH2Config.put(Environment.DIALECT, org.hibernate.dialect.H2Dialect.class.getName()); + hibernateH2Config.put(Environment.HBM2DDL_AUTO, HBM2DDL_AUTO_CREATE); + + HIBERNATE_H2_CONFIG = Collections.unmodifiableMap(hibernateH2Config); + + } + + private HibernateUtil() {} + + public static EntityManagerFactory createTempEntityManagerFactory(String persistenceUnitName, String context) { + + EntityManagerFactory tempEntityManagerFactory = + createTempEntityManagerFactory( + persistenceUnitName, + context, Collections.<String, String>emptyMap()); + + return tempEntityManagerFactory; + + } + + public static EntityManagerFactory createTempEntityManagerFactory(String persistenceUnitName, String context, Map<String, String> jpaParameters) { + + Map<String, String> allJpaParameters = new HashMap<String, String>(); + + allJpaParameters.putAll(jpaParameters); + + allJpaParameters.putAll(HIBERNATE_H2_CONFIG); + + File tempDirFile = SystemUtils.getJavaIoTmpDir(); + + File databaseFile = new File(tempDirFile, context); + + String h2dataPath = databaseFile.getAbsolutePath() + File.separator + "h2data"; + + String jdbcUrl = "jdbc:h2:file:" + h2dataPath; + + allJpaParameters.put(AvailableSettings.JDBC_URL, jdbcUrl); + + if (log.isTraceEnabled()) { + log.trace("will store H2 data in " + h2dataPath); + log.trace("jdbc url is\n" + jdbcUrl); + log.trace("allJpaParameters = " + allJpaParameters); + } + + EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName, allJpaParameters); + + return entityManagerFactory; + + } + + public static void cleanDatabase(EntityManager entityManager) { + + if (log.isInfoEnabled()) { + log.info("will clean database"); + } + + ServiceRegistry serviceRegistry = + ((EntityManagerFactoryImpl) entityManager.getEntityManagerFactory()) + .getSessionFactory().getServiceRegistry(); + + Configuration configuration = null; + try { + Field configurationField = SessionFactoryServiceRegistryImpl.class.getDeclaredField("configuration"); + configurationField.setAccessible(true); + configuration = (Configuration) configurationField.get(serviceRegistry); + } catch (IllegalAccessException e) { + if (log.isErrorEnabled()) { + log.error("should not occur", e); + } + } catch (NoSuchFieldException e) { + if (log.isErrorEnabled()) { + log.error("should not occur", e); + } + } + + SchemaExport schemaExport= new SchemaExport(serviceRegistry, configuration); + + schemaExport.setHaltOnError(true); + + // drop + schemaExport.execute(true, true, true, false); + + // create + schemaExport.execute(true, true, false, true); + + } + +} \ No newline at end of file Modified: nuiton-jpa/nuiton-jpa-junit/pom.xml =================================================================== --- nuiton-jpa/nuiton-jpa-junit/pom.xml 2013-05-24 15:21:33 UTC (rev 620) +++ nuiton-jpa/nuiton-jpa-junit/pom.xml 2013-05-24 15:48:17 UTC (rev 621) @@ -14,6 +14,7 @@ <artifactId>nuiton-jpa-junit</artifactId> <dependencies> + <dependency> <groupId>${project.groupId}</groupId> <artifactId>nuiton-jpa-api</artifactId> @@ -25,7 +26,9 @@ <artifactId>junit</artifactId> <scope>provided</scope> </dependency> + </dependencies> + <build> Added: nuiton-jpa/nuiton-jpa-junit/src/main/java/org/nuiton/jpa/junit/JpaEntityManagerRule.java =================================================================== --- nuiton-jpa/nuiton-jpa-junit/src/main/java/org/nuiton/jpa/junit/JpaEntityManagerRule.java (rev 0) +++ nuiton-jpa/nuiton-jpa-junit/src/main/java/org/nuiton/jpa/junit/JpaEntityManagerRule.java 2013-05-24 15:48:17 UTC (rev 621) @@ -0,0 +1,127 @@ +package org.nuiton.jpa.junit; + +/* + * #%L + * MagaLiE :: Services + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2013 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.nuiton.jpa.api.hibernate.HibernateUtil; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import java.util.Date; +import java.util.Map; + +public class JpaEntityManagerRule implements TestRule { + + private static final Log log = LogFactory.getLog(JpaEntityManagerRule.class); + + protected String persistenceUnitName; + + protected String timestamp = String.valueOf(new Date().getTime()); + + protected EntityManager entityManager; + + protected boolean open = false; + + protected Map<String, String> jpaParameters; + + public JpaEntityManagerRule(String persistenceUnitName, Map<String, String> jpaParameters) { + this.persistenceUnitName = persistenceUnitName; + this.jpaParameters = jpaParameters; + } + + @Override + public Statement apply(final Statement base, Description description) { + + final String testClassName = description.getClassName(); + + final String testMethodName = description.getMethodName(); + + if (log.isDebugEnabled()) { + log.debug("will create entityManager for test class " + + testClassName + " and method " + testMethodName); + } + + return new Statement() { + @Override + public void evaluate() throws Throwable { + createEntityManager(testClassName, testMethodName); + try { + base.evaluate(); + } finally { + closeEntityManager(); + } + } + }; + } + + protected void createEntityManager(String testClassName, String testMethodName) { + + String context = testClassName + + '_' + testMethodName + + '_' + timestamp; + + EntityManagerFactory entityManagerFactory = + HibernateUtil.createTempEntityManagerFactory( + persistenceUnitName, context, jpaParameters); + + entityManager = entityManagerFactory.createEntityManager(); + + if (log.isDebugEnabled()) { + log.debug("created entityManager " + entityManager); + } + + open = true; + + } + + public EntityManager getEntityManager() { + + if ( ! open) { + throw new IllegalStateException("entity manager is not yet opened"); + } + + return entityManager; + + } + + /** + * Override to tear down your specific external resource. + */ + protected void closeEntityManager() { + + if (log.isDebugEnabled()) { + log.debug("close entityManager " + entityManager); + } + + open = false; + + entityManager.close(); + + } + +} Modified: nuiton-jpa/pom.xml =================================================================== --- nuiton-jpa/pom.xml 2013-05-24 15:21:33 UTC (rev 620) +++ nuiton-jpa/pom.xml 2013-05-24 15:48:17 UTC (rev 621) @@ -35,6 +35,8 @@ <eugeneVersion>2.6.2</eugeneVersion> <nuitonUtilsVersion>2.6.12</nuitonUtilsVersion> <processorPluginVersion>1.3</processorPluginVersion> + <h2Version>1.3.170</h2Version> + <hibernateVersion>4.1.9.Final</hibernateVersion> </properties> @@ -85,7 +87,26 @@ <version>1.0.1.Final</version> </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-core</artifactId> + <version>${hibernateVersion}</version> + </dependency> + + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-entitymanager</artifactId> + <version>${hibernateVersion}</version> + </dependency> + + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>${h2Version}</version> + </dependency> + </dependencies> + </dependencyManagement> <!-- ************************************************************* -->