[seam-commits] Seam SVN: r13555 - in modules/persistence/trunk: impl and 3 other directories.
seam-commits at lists.jboss.org
seam-commits at lists.jboss.org
Thu Aug 5 06:07:06 EDT 2010
Author: swd847
Date: 2010-08-05 06:07:05 -0400 (Thu, 05 Aug 2010)
New Revision: 13555
Added:
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeManager.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeType.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContext.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java
Modified:
modules/persistence/trunk/impl/pom.xml
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/AbstractManagedPersistenceContextBeanLifecycle.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextExtension.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextProxyHandler.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContextProxyHandler.java
modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/transaction/EntityTransaction.java
modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionAttributeInterceptorTest.java
modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionInterceptorTest.java
modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionScopedTest.java
modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/UserTransactionTest.java
modules/persistence/trunk/pom.xml
Log:
port more stuff from seam 2, it compiles but needs to be tested
Modified: modules/persistence/trunk/impl/pom.xml
===================================================================
--- modules/persistence/trunk/impl/pom.xml 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/pom.xml 2010-08-05 10:07:05 UTC (rev 13555)
@@ -114,6 +114,13 @@
<artifactId>arquillian-junit</artifactId>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
</dependencies>
Modified: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/AbstractManagedPersistenceContextBeanLifecycle.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/AbstractManagedPersistenceContextBeanLifecycle.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/AbstractManagedPersistenceContextBeanLifecycle.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -44,7 +44,7 @@
public abstract class AbstractManagedPersistenceContextBeanLifecycle implements BeanLifecycle<EntityManager>
{
- static final Class<?> proxyClass = Proxy.getProxyClass(EntityManager.class.getClassLoader(), EntityManager.class, Serializable.class);
+ static final Class<?> proxyClass = Proxy.getProxyClass(PersistenceContext.class.getClassLoader(), EntityManager.class, Serializable.class, PersistenceContext.class);
static final Constructor<?> proxyConstructor;
@@ -76,7 +76,7 @@
{
EntityManagerFactory emf = getEntityManagerFactory();
EntityManager entityManager = emf.createEntityManager();
- ManagedPersistenceContextProxyHandler handler = new ManagedPersistenceContextProxyHandler(entityManager, manager);
+ ManagedPersistenceContextProxyHandler handler = new ManagedPersistenceContextProxyHandler(entityManager, manager, bean.getQualifiers());
EntityManager proxy = (EntityManager) proxyConstructor.newInstance(handler);
return proxy;
}
Added: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeManager.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeManager.java (rev 0)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeManager.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+
+import javax.enterprise.context.ApplicationScoped;
+
+/**
+ * Provides for programmatic configuration of the default flush mode.
+ *
+ * TODO: implement this
+ *
+ * @author Stuart Douglas
+ *
+ */
+ at ApplicationScoped
+public class FlushModeManager implements Serializable
+{
+ FlushModeType flushModeType = FlushModeType.AUTO;
+
+ public FlushModeType getFlushModeType()
+ {
+ return flushModeType;
+ }
+
+ public void setFlushModeType(FlushModeType flushModeType)
+ {
+ this.flushModeType = flushModeType;
+ }
+
+}
Added: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeType.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeType.java (rev 0)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/FlushModeType.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -0,0 +1,42 @@
+package org.jboss.seam.persistence;
+
+/**
+ * A full set of flush modes, including MANUAL,
+ * which is a glaring missing feature of the JPA
+ * spec.
+ *
+ * @author Gavin King
+ *
+ */
+public enum FlushModeType
+{
+
+ /**
+ * Flushing never occurs automatically, all changes are queued
+ * until the application calls flush() explicitly.
+ */
+ MANUAL,
+
+ /**
+ * Flushing occurs automatically at commit time and when necessary
+ * before query executions.
+ */
+ AUTO,
+
+ /**
+ * Flushing occurs automatically at transaction commit time.
+ */
+ COMMIT;
+
+ /**
+ * Does this flush mode keep unflushed changes past a
+ * transaction commit?
+ *
+ * @return false for all flush modes except for MANUAL
+ */
+ public boolean dirtyBetweenTransactions()
+ {
+ return this==MANUAL;
+ }
+
+}
Added: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java (rev 0)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -0,0 +1,289 @@
+package org.jboss.seam.persistence;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.persistence.EntityManager;
+import javax.transaction.Synchronization;
+
+import org.hibernate.EntityMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Session;
+import org.hibernate.StaleStateException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.type.VersionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Support for non-standardized features of Hibernate, when used as the JPA
+ * persistence provider.
+ *
+ * @author Gavin King
+ * @author Pete Muir
+ * @author Stuart Douglas
+ *
+ */
+public class HibernatePersistenceProvider extends PersistenceProvider
+{
+
+ @Inject
+ Instance<PersistenceContexts> persistenceContexts;
+
+ private static Logger log = LoggerFactory.getLogger(HibernatePersistenceProvider.class);
+ private static Class FULL_TEXT_SESSION_PROXY_CLASS;
+ private static Method FULL_TEXT_SESSION_CONSTRUCTOR;
+ private static Class FULL_TEXT_ENTITYMANAGER_PROXY_CLASS;
+ private static Method FULL_TEXT_ENTITYMANAGER_CONSTRUCTOR;
+ static
+ {
+ try
+ {
+ String version = null;
+ try
+ {
+ Class searchVersionClass = Class.forName("org.hibernate.search.Version");
+ Field versionField = searchVersionClass.getDeclaredField("VERSION");
+ version = (String) versionField.get(null);
+ }
+ catch (Exception e)
+ {
+ log.debug("no Hibernate Search, sorry :-(", e);
+ }
+ if (version != null)
+ {
+ Class searchClass = Class.forName("org.hibernate.search.Search");
+ try
+ {
+ FULL_TEXT_SESSION_CONSTRUCTOR = searchClass.getDeclaredMethod("getFullTextSession", Session.class);
+ }
+ catch (NoSuchMethodException noSuchMethod)
+ {
+ log.debug("org.hibernate.search.Search.getFullTextSession(Session) not found, trying deprecated method name createFullTextSession");
+ FULL_TEXT_SESSION_CONSTRUCTOR = searchClass.getDeclaredMethod("createFullTextSession", Session.class);
+ }
+ FULL_TEXT_SESSION_PROXY_CLASS = Class.forName("org.jboss.seam.persistence.FullTextHibernateSessionProxy");
+ Class jpaSearchClass = Class.forName("org.hibernate.search.jpa.Search");
+ try
+ {
+ FULL_TEXT_ENTITYMANAGER_CONSTRUCTOR = jpaSearchClass.getDeclaredMethod("getFullTextEntityManager", EntityManager.class);
+ }
+ catch (NoSuchMethodException noSuchMethod)
+ {
+ log.debug("org.hibernate.search.jpa.getFullTextSession(EntityManager) not found, trying deprecated method name createFullTextEntityManager");
+ FULL_TEXT_ENTITYMANAGER_CONSTRUCTOR = jpaSearchClass.getDeclaredMethod("createFullTextEntityManager", EntityManager.class);
+ }
+ FULL_TEXT_ENTITYMANAGER_PROXY_CLASS = Class.forName("org.jboss.seam.persistence.FullTextEntityManagerProxy");
+ log.debug("Hibernate Search is available :-)");
+ }
+ }
+ catch (Exception e)
+ {
+ log.debug("no Hibernate Search, sorry :-(", e);
+ }
+ }
+
+ @Inject
+ public void init()
+ {
+ featureSet.add(Feature.WILDCARD_AS_COUNT_QUERY_SUBJECT);
+ }
+
+ @Override
+ public void setFlushModeManual(EntityManager entityManager)
+ {
+ try
+ {
+ getSession(entityManager).setFlushMode(FlushMode.MANUAL);
+ }
+ catch (NotHibernateException nhe)
+ {
+ super.setFlushModeManual(entityManager);
+ }
+ }
+
+ @Override
+ public void setRenderFlushMode()
+ {
+ persistenceContexts.get().changeFlushMode(FlushModeType.MANUAL, true);
+ }
+
+ @Override
+ public boolean isDirty(EntityManager entityManager)
+ {
+ try
+ {
+ return getSession(entityManager).isDirty();
+ }
+ catch (NotHibernateException nhe)
+ {
+ return super.isDirty(entityManager);
+ }
+ }
+
+ @Override
+ public Object getId(Object bean, EntityManager entityManager)
+ {
+ try
+ {
+ return getSession(entityManager).getIdentifier(bean);
+ }
+ catch (NotHibernateException nhe)
+ {
+ return super.getId(bean, entityManager);
+ }
+ catch (TransientObjectException e)
+ {
+ if (bean instanceof HibernateProxy)
+ {
+ return super.getId(((HibernateProxy) bean).getHibernateLazyInitializer().getImplementation(), entityManager);
+ }
+ else
+ {
+ return super.getId(bean, entityManager);
+ }
+ }
+ }
+
+ @Override
+ public Object getVersion(Object bean, EntityManager entityManager)
+ {
+ try
+ {
+ return getVersion(bean, getSession(entityManager));
+ }
+ catch (NotHibernateException nhe)
+ {
+ return super.getVersion(bean, entityManager);
+ }
+ }
+
+ @Override
+ public void checkVersion(Object bean, EntityManager entityManager, Object oldVersion, Object version)
+ {
+ try
+ {
+ checkVersion(bean, getSession(entityManager), oldVersion, version);
+ }
+ catch (NotHibernateException nhe)
+ {
+ super.checkVersion(bean, entityManager, oldVersion, version);
+ }
+ }
+
+ @Override
+ public boolean registerSynchronization(Synchronization sync, EntityManager entityManager)
+ {
+ try
+ {
+ // TODO: just make sure that a Hibernate JPA EntityTransaction
+ // delegates to the Hibernate Session transaction
+ getSession(entityManager).getTransaction().registerSynchronization(sync);
+ return true;
+ }
+ catch (NotHibernateException nhe)
+ {
+ return super.registerSynchronization(sync, entityManager);
+ }
+
+ }
+
+ @Override
+ public String getName(Object bean, EntityManager entityManager) throws IllegalArgumentException
+ {
+ try
+ {
+ return getSession(entityManager).getEntityName(bean);
+ }
+ catch (NotHibernateException nhe)
+ {
+ return super.getName(bean, entityManager);
+ }
+ catch (TransientObjectException e)
+ {
+ return super.getName(bean, entityManager);
+ }
+ }
+
+ public static void checkVersion(Object value, Session session, Object oldVersion, Object version)
+ {
+ ClassMetadata classMetadata = getClassMetadata(value, session);
+ VersionType versionType = (VersionType) classMetadata.getPropertyTypes()[classMetadata.getVersionProperty()];
+ if (!versionType.isEqual(oldVersion, version))
+ {
+ throw new StaleStateException("current database version number does not match passivated version number");
+ }
+ }
+
+ public static Object getVersion(Object value, Session session)
+ {
+ ClassMetadata classMetadata = getClassMetadata(value, session);
+ return classMetadata != null && classMetadata.isVersioned() ? classMetadata.getVersion(value, EntityMode.POJO) : null;
+ }
+
+ private static ClassMetadata getClassMetadata(Object value, Session session)
+ {
+ Class entityClass = getEntityClass(value);
+ ClassMetadata classMetadata = null;
+ if (entityClass != null)
+ {
+ classMetadata = session.getSessionFactory().getClassMetadata(entityClass);
+ if (classMetadata == null)
+ {
+ throw new IllegalArgumentException("Could not find ClassMetadata object for entity class: " + entityClass.getName());
+ }
+ }
+ return classMetadata;
+ }
+
+ /**
+ * Returns the class of the specified Hibernate entity
+ */
+ @Override
+ public Class getBeanClass(Object bean)
+ {
+ return getEntityClass(bean);
+ }
+
+ public static Class getEntityClass(Object bean)
+ {
+ /*
+ * Class clazz = null; try { clazz = Entity.forBean(bean).getBeanClass();
+ * } catch (NotEntityException e) { // It's ok, try some other methods }
+ *
+ * if (clazz == null) { clazz = Hibernate.getClass(bean); }
+ *
+ * return clazz;
+ */
+ return null;
+ }
+
+ private Session getSession(EntityManager entityManager)
+ {
+ Object delegate = entityManager.getDelegate();
+ if (delegate instanceof Session)
+ {
+ return (Session) delegate;
+ }
+ else
+ {
+ throw new NotHibernateException();
+ }
+ }
+
+ /**
+ * Occurs when Hibernate is in the classpath, but this particular
+ * EntityManager is not from Hibernate
+ *
+ * @author Gavin King
+ *
+ */
+ static class NotHibernateException extends IllegalArgumentException
+ {
+ }
+
+}
Modified: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextExtension.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextExtension.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextExtension.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -117,6 +117,7 @@
BeanBuilder<EntityManager> builder = new BeanBuilder<EntityManager>(manager).defineBeanFromAnnotatedType(typeBuilder.create());
builder.setQualifiers(qualifiers);
builder.setScope(scope);
+ builder.getTypes().add(PersistenceContext.class);
builder.setBeanLifecycle(new ManagedPersistenceContextBeanLifecycle(qualifiers, manager));
beans.add(builder.create());
}
Modified: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextProxyHandler.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextProxyHandler.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContextProxyHandler.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -22,8 +22,12 @@
package org.jboss.seam.persistence;
import java.io.Serializable;
+import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.BeanManager;
@@ -54,15 +58,18 @@
private final Instance<SeamTransaction> userTransactionInstance;
+ private final Set<Annotation> qualifiers;
+
private transient boolean synchronizationRegistered;
static final Logger log = LoggerFactory.getLogger(ManagedPersistenceContextProxyHandler.class);
- public ManagedPersistenceContextProxyHandler(EntityManager delegate, BeanManager beanManager)
+ public ManagedPersistenceContextProxyHandler(EntityManager delegate, BeanManager beanManager, Set<Annotation> qualifiers)
{
super(delegate, beanManager);
this.delegate = delegate;
this.userTransactionInstance = InstanceResolver.getInstance(SeamTransaction.class, beanManager, DefaultTransactionLiteral.INSTANCE);
+ this.qualifiers = new HashSet<Annotation>(qualifiers);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
@@ -105,4 +112,9 @@
}
+ public Set<Annotation> getQualifiers()
+ {
+ return Collections.unmodifiableSet(qualifiers);
+ }
+
}
Added: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContext.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContext.java (rev 0)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContext.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.persistence;
+
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+/**
+ * Support for changing flushmodes for an existing persistence context.
+ *
+ * @author Gavin King
+ * @author Stuart Douglas
+ *
+ */
+public interface PersistenceContext
+{
+ public void changeFlushMode(FlushModeType flushMode);
+
+ public Set<Annotation> getQualifiers();
+
+ public Class<?> getBeanType();
+}
Modified: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContextProxyHandler.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContextProxyHandler.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContextProxyHandler.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -50,12 +50,15 @@
private final Instance<Expressions> expressionsInstance;
+ private final Instance<PersistenceProvider> persistenceProvider;
+
static final Logger log = LoggerFactory.getLogger(ManagedPersistenceContextProxyHandler.class);
public PersistenceContextProxyHandler(EntityManager delegate, BeanManager beanManager)
{
this.delegate = delegate;
expressionsInstance = InstanceResolver.getInstance(Expressions.class, beanManager);
+ persistenceProvider = InstanceResolver.getInstance(PersistenceProvider.class, beanManager);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
@@ -64,9 +67,23 @@
{
return handleCreateQueryWithString(method, args);
}
+ if ("changeFlushMode".equals(method.getName()) && method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(FlushModeType.class))
+ {
+ changeFushMode((FlushModeType) args[0]);
+ return null;
+ }
+ if ("getBeanType".equals(method.getName()) && method.getParameterTypes().length == 0)
+ {
+ return EntityManager.class;
+ }
return method.invoke(delegate, args);
}
+ private void changeFushMode(FlushModeType flushModeType)
+ {
+ persistenceProvider.get().setFlushMode(delegate, flushModeType);
+ }
+
protected Object handleCreateQueryWithString(Method method, Object[] args) throws Throwable
{
if (args[0] == null)
Added: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java (rev 0)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -0,0 +1,205 @@
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.enterprise.context.ConversationScoped;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Maintains the set of persistence contexts that have been touched in a
+ * conversation. Also controls the flush mode used by the persistence contexts
+ * during the render phase.
+ *
+ * @author Gavin King
+ */
+ at ConversationScoped
+public class PersistenceContexts implements Serializable
+{
+ private static final long serialVersionUID = -4897350516435283182L;
+ private static final Logger log = LoggerFactory.getLogger(PersistenceContexts.class);
+ /**
+ * persistences contexts are referenced by their qualifiers
+ */
+ private Set<PersistenceContextDefintition> set = new HashSet<PersistenceContextDefintition>();
+
+ private FlushModeType flushMode;
+
+ // the real flush mode is a backup of the flush mode when doing a temporary
+ // switch (such as during render)
+ private FlushModeType realFlushMode;
+
+ @Inject
+ BeanManager beanManager;
+
+ @Inject
+ @Any
+ Instance<PersistenceContext> persistenceContexts;
+
+ @Inject
+ Instance<PersistenceProvider> persistenceProvider;
+
+ @Inject
+ public void create(FlushModeManager manager)
+ {
+ FlushModeType defaultFlushMode = manager.getFlushModeType();
+ if (defaultFlushMode != null)
+ {
+ flushMode = defaultFlushMode;
+ }
+ else
+ {
+ flushMode = FlushModeType.AUTO;
+ }
+ }
+
+ public FlushModeType getFlushMode()
+ {
+ return flushMode;
+ }
+
+ public Set<PersistenceContextDefintition> getTouchedContexts()
+ {
+ return Collections.unmodifiableSet(set);
+ }
+
+ public void touch(PersistenceContext context)
+ {
+ set.add(new PersistenceContextDefintition(context.getQualifiers(), context.getBeanType()));
+ }
+
+ public void untouch(PersistenceContext context)
+ {
+ set.remove(new PersistenceContextDefintition(context.getQualifiers(), context.getBeanType()));
+ }
+
+ public void changeFlushMode(FlushModeType flushMode)
+ {
+ changeFlushMode(flushMode, false);
+ }
+
+ public void changeFlushMode(FlushModeType flushMode, boolean temporary)
+ {
+ if (temporary)
+ {
+ realFlushMode = this.flushMode;
+ }
+ this.flushMode = flushMode;
+ changeFlushModes();
+ }
+
+ /**
+ * Restore the previous flush mode if the current flush mode is marked as
+ * temporary.
+ */
+ public void restoreFlushMode()
+ {
+ if (realFlushMode != null && realFlushMode != flushMode)
+ {
+ flushMode = realFlushMode;
+ realFlushMode = null;
+ changeFlushModes();
+ }
+ }
+
+ private void changeFlushModes()
+ {
+
+ for (PersistenceContext context : persistenceContexts)
+ {
+ if (set.contains(new PersistenceContextDefintition(context.getQualifiers(), context.getBeanType())))
+ try
+ {
+ context.changeFlushMode(flushMode);
+ }
+ catch (UnsupportedOperationException uoe)
+ {
+ // we won't be nasty and throw and exception, but we'll log a
+ // warning to the developer
+ log.warn(uoe.getMessage());
+ }
+ }
+ }
+
+ public void beforeRender()
+ {
+ // some JPA providers may not support MANUAL flushing
+ // defer the decision to the provider manager component
+ persistenceProvider.get().setRenderFlushMode();
+ }
+
+ public void afterRender()
+ {
+ restoreFlushMode();
+ }
+
+ public static class PersistenceContextDefintition
+ {
+ private final Set<Annotation> qualifiers;
+ private final Class<?> type;
+
+ public PersistenceContextDefintition(Set<Annotation> qualifiers, Class<?> type)
+ {
+ this.qualifiers = new HashSet<Annotation>(qualifiers);
+ this.type = type;
+ }
+
+ public Set<Annotation> getQualifiers()
+ {
+ return qualifiers;
+ }
+
+ public Class<?> getType()
+ {
+ return type;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((qualifiers == null) ? 0 : qualifiers.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ PersistenceContextDefintition other = (PersistenceContextDefintition) obj;
+ if (qualifiers == null)
+ {
+ if (other.qualifiers != null)
+ return false;
+ }
+ else if (!qualifiers.equals(other.qualifiers))
+ return false;
+ if (type == null)
+ {
+ if (other.type != null)
+ return false;
+ }
+ else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+
+ }
+
+}
Added: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java (rev 0)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -0,0 +1,265 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.persistence;
+
+import java.lang.reflect.Method;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.OptimisticLockException;
+import javax.persistence.PersistenceContexts;
+import javax.transaction.Synchronization;
+
+/**
+ * Abstraction layer for persistence providers (JPA implementations). This class
+ * provides a working base implementation that can be optimized for performance
+ * and non-standardized features by extending and overriding the methods.
+ *
+ * The methods on this class are a great todo list for the next rev of the JPA
+ * spec ;-)
+ *
+ * @author Gavin King
+ * @author Pete Muir
+ * @author Stuart Douglas
+ *
+ */
+public class PersistenceProvider
+{
+ public enum Feature
+ {
+ /**
+ * Identifies whether this JPA provider supports using a wildcard as the
+ * subject of a count query.
+ *
+ * <p>
+ * Here's a count query that uses a wildcard as the subject.
+ * </p>
+ *
+ * <pre>
+ * select count(*) from Vehicle v
+ * </pre>
+ * <p>
+ * Per the JPA 1.0 spec, using a wildcard as a subject of a count query is
+ * not permitted. Instead, the subject must be the entity or the alias, as
+ * in this count query:
+ * </p>
+ *
+ * <pre>
+ * select count(v) from Vehicle v
+ * </pre>
+ * <p>
+ * Hibernate supports the wildcard syntax as an vendor extension.
+ * Furthermore, Hibernate produces an invalid SQL query when using the
+ * compliant subject if the entity has a composite primary key. Therefore,
+ * we prefer to use the wildcard syntax if it is supported.
+ * </p>
+ */
+ WILDCARD_AS_COUNT_QUERY_SUBJECT
+ }
+
+ protected Set<Feature> featureSet = new HashSet<Feature>();
+
+ /**
+ * Indicate whether this JPA provider supports the feature defined by the
+ * provided Feature enum value.
+ */
+ public boolean supportsFeature(Feature feature)
+ {
+ return featureSet.contains(feature);
+ }
+
+ /**
+ * sets the flush mode
+ */
+ public void setFlushMode(EntityManager entityManager, FlushModeType type)
+ {
+ switch (type)
+ {
+ case AUTO:
+ entityManager.setFlushMode(javax.persistence.FlushModeType.AUTO);
+ break;
+ case COMMIT:
+ entityManager.setFlushMode(javax.persistence.FlushModeType.COMMIT);
+ case MANUAL:
+ setFlushModeManual(entityManager);
+ default:
+ throw new RuntimeException("Unkown flush mode: " + type);
+ }
+ }
+
+ /**
+ * Set the flush mode to manual-only flushing. Called when an atomic
+ * persistence context is required.
+ */
+ public void setFlushModeManual(EntityManager entityManager)
+ {
+ throw new UnsupportedOperationException("Use of FlushMode.MANUAL requires Hibernate as the persistence provider. Please use Hibernate, a custom persistenceProvider, or remove the MANUAL flush mode setting.");
+ }
+
+ /**
+ * <p>
+ * Set the FlushMode the persistence contexts should use during rendering by
+ * calling {@link PersistenceContexts#changeFlushMode(FlushModeType, true)}.
+ * The actual changing of the flush mode is handled by the
+ * {@link PersistenceContexts} instance. The boolean argument should be true
+ * to indicate that this is a temporary change and that the old flush mode
+ * should be restored after render.
+ * </p>
+ * <p>
+ * Ideally, this should be MANUAL since changes should never flush to the
+ * database while in render response and the cost of a dirty check can be
+ * avoided. However, since the MANUAL mode is not officially part of the JPA
+ * specification, the default implementation will perform no operation.
+ * </p>
+ */
+ public void setRenderFlushMode()
+ {
+ // no-op in default implementation
+ }
+
+ /**
+ * Does the persistence context have unflushed changes? If it does not,
+ * persistence context replication can be optimized.
+ *
+ * @return true to indicate that there are unflushed changes
+ */
+ public boolean isDirty(EntityManager entityManager)
+ {
+ return true; // best we can do!
+ }
+
+ /**
+ * Get the value of the entity identifier attribute.
+ *
+ * @param bean a managed entity instance
+ */
+ public Object getId(Object bean, EntityManager entityManager)
+ {
+ // return Entity.forBean(bean).getIdentifier(bean);
+ return null;
+ }
+
+ /**
+ * Get the name of the entity
+ *
+ * @param bean
+ * @param entityManager
+ *
+ * @throws IllegalArgumentException if the passed object is not an entity
+ */
+ public String getName(Object bean, EntityManager entityManager) throws IllegalArgumentException
+ {
+ return null;
+ // return Entity.forBean(bean).getName();
+ }
+
+ /**
+ * Get the value of the entity version attribute.
+ *
+ * @param bean a managed entity instance
+ */
+ public Object getVersion(Object bean, EntityManager entityManager)
+ {
+ return null;
+ // return Entity.forBean(bean).getVersion(bean);
+ }
+
+ public void checkVersion(Object bean, EntityManager entityManager, Object oldVersion, Object version)
+ {
+ boolean equal;
+ if (oldVersion instanceof Date)
+ {
+ equal = ((Date) oldVersion).getTime() == ((Date) version).getTime();
+ }
+ else
+ {
+ equal = oldVersion.equals(version);
+ }
+ if (!equal)
+ {
+ throw new OptimisticLockException("Current database version number does not match passivated version number");
+ }
+ }
+
+ /**
+ * Enable a Filter. This is here just especially for Hibernate, since we well
+ * know that other products don't have such cool features.
+ *
+ * public void enableFilter(Filter filter, EntityManager entityManager) {
+ * throw new UnsupportedOperationException("Use of filters requires Hibernate as the persistence provider. Please use Hibernate or remove the filters configuration."
+ * ); }
+ */
+ /**
+ * Register a Synchronization with the current transaction.
+ */
+ public boolean registerSynchronization(Synchronization sync, EntityManager entityManager)
+ {
+ return false; // best we can do!
+ }
+
+ /**
+ * Wrap the delegate before returning it to the application
+ */
+ public Object proxyDelegate(Object delegate)
+ {
+ return delegate;
+ }
+
+ /**
+ * Returns the class of an entity bean instance
+ *
+ * @param bean The entity bean instance
+ * @return The class of the entity bean
+ */
+ public Class getBeanClass(Object bean)
+ {
+ return null;
+ // return Entity.forBean(bean).getBeanClass();
+ }
+
+ public Method getPostLoadMethod(Object bean, EntityManager entityManager)
+ {
+ return null;
+ // return Entity.forBean(bean).getPostLoadMethod();
+ }
+
+ public Method getPrePersistMethod(Object bean, EntityManager entityManager)
+ {
+ return null;
+ // return Entity.forBean(bean).getPrePersistMethod();
+ }
+
+ public Method getPreUpdateMethod(Object bean, EntityManager entityManager)
+ {
+ return null;
+ // return Entity.forBean(bean).getPreUpdateMethod();
+ }
+
+ public Method getPreRemoveMethod(Object bean, EntityManager entityManager)
+ {
+ return null;
+ // return Entity.forBean(bean).getPreRemoveMethod();
+ }
+
+}
Modified: modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/transaction/EntityTransaction.java
===================================================================
--- modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/transaction/EntityTransaction.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/main/java/org/jboss/seam/persistence/transaction/EntityTransaction.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -22,6 +22,7 @@
package org.jboss.seam.persistence.transaction;
import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.HeuristicMixedException;
@@ -32,6 +33,7 @@
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
+import org.jboss.seam.persistence.PersistenceProvider;
import org.jboss.weld.extensions.core.Veto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,8 +41,8 @@
/**
* Support for the JPA EntityTransaction API.
*
- * Adapts JPA transaction management to a Seam UserTransaction
- * interface.For use in non-JTA-capable environments.
+ * Adapts JPA transaction management to a Seam UserTransaction interface.For use
+ * in non-JTA-capable environments.
*
* @author Gavin King
*
@@ -50,12 +52,14 @@
public class EntityTransaction extends AbstractUserTransaction
{
private static final Logger log = LoggerFactory.getLogger(EntityTransaction.class);
-
+
@Inject
private EntityManager entityManager;
-
-
+
@Inject
+ private Instance<PersistenceProvider> persistenceProvider;
+
+ @Inject
public EntityTransaction(Synchronizations sync)
{
super(sync);
@@ -69,7 +73,7 @@
public void begin() throws NotSupportedException, SystemException
{
log.debug("beginning JPA resource-local transaction");
- //TODO: translate exceptions that occur into the correct JTA exception
+ // TODO: translate exceptions that occur into the correct JTA exception
try
{
getDelegate().begin();
@@ -81,15 +85,14 @@
}
}
- public void commit() throws RollbackException, HeuristicMixedException,
- HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
+ public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
{
log.debug("committing JPA resource-local transaction");
javax.persistence.EntityTransaction delegate = getDelegate();
boolean success = false;
try
{
- if ( delegate.getRollbackOnly() )
+ if (delegate.getRollbackOnly())
{
delegate.rollback();
throw new RollbackException();
@@ -110,7 +113,7 @@
public void rollback() throws IllegalStateException, SecurityException, SystemException
{
log.debug("rolling back JPA resource-local transaction");
- //TODO: translate exceptions that occur into the correct JTA exception
+ // TODO: translate exceptions that occur into the correct JTA exception
javax.persistence.EntityTransaction delegate = getDelegate();
try
{
@@ -152,18 +155,17 @@
@Override
public void registerSynchronization(Synchronization sync)
{
- if ( log.isDebugEnabled() )
+ if (log.isDebugEnabled())
{
log.debug("registering synchronization: " + sync);
}
- //try to register the synchronization directly with the
- //persistence provider, but if this fails, just hold
- //on to it myself
- // if ( !PersistenceProvider.instance().registerSynchronization(sync,
- // currentEntityManager) )
- // {
- // getSynchronizations().registerSynchronization(sync);
- // }
+ // try to register the synchronization directly with the
+ // persistence provider, but if this fails, just hold
+ // on to it myself
+ if (!persistenceProvider.get().registerSynchronization(sync, entityManager))
+ {
+ getSynchronizations().registerSynchronization(sync);
+ }
}
@Override
@@ -175,7 +177,7 @@
@Override
public void enlist(EntityManager entityManager)
{
- //no-op
+ // no-op
}
}
Modified: modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionAttributeInterceptorTest.java
===================================================================
--- modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionAttributeInterceptorTest.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionAttributeInterceptorTest.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -37,6 +37,7 @@
import org.jboss.arquillian.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.seam.persistence.PersistenceProvider;
import org.jboss.seam.persistence.transaction.DefaultTransaction;
import org.jboss.seam.persistence.transaction.SeamTransaction;
import org.jboss.seam.persistence.transaction.TransactionExtension;
@@ -74,6 +75,7 @@
war.addLibraries(MavenArtifactResolver.resolve(ArtifactNames.WELD_EXTENSIONS));
war.addLibraries(MavenArtifactResolver.resolve(ArtifactNames.SEAM_PERSISTENCE_API));
war.addPackage(TransactionExtension.class.getPackage());
+ war.addPackage(PersistenceProvider.class.getPackage());
war.addPackage(NamingUtils.class.getPackage());
war.addClasses(TransactionAttributeInterceptorTest.class, TransactionAttributeManagedBean.class, HelloService.class, Hotel.class, EntityManagerProvider.class, DontRollBackException.class);
war.addWebResource("META-INF/persistence.xml", "classes/META-INF/persistence.xml");
Modified: modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionInterceptorTest.java
===================================================================
--- modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionInterceptorTest.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionInterceptorTest.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -37,6 +37,7 @@
import org.jboss.arquillian.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.seam.persistence.PersistenceProvider;
import org.jboss.seam.persistence.transaction.DefaultTransaction;
import org.jboss.seam.persistence.transaction.SeamTransaction;
import org.jboss.seam.persistence.transaction.TransactionExtension;
@@ -75,6 +76,7 @@
war.addLibraries(MavenArtifactResolver.resolve(ArtifactNames.SEAM_PERSISTENCE_API));
war.addPackage(TransactionExtension.class.getPackage());
war.addPackage(NamingUtils.class.getPackage());
+ war.addPackage(PersistenceProvider.class.getPackage());
war.addClasses(TransactionInterceptorTest.class, TransactionManagedBean.class, HelloService.class, Hotel.class, EntityManagerProvider.class, DontRollBackException.class);
war.addWebResource("META-INF/persistence.xml", "classes/META-INF/persistence.xml");
war.addWebResource(new ByteArrayAsset(("<beans><interceptors><class>" + TransactionInterceptor.class.getName() + "</class></interceptors></beans>").getBytes()), "beans.xml");
Modified: modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionScopedTest.java
===================================================================
--- modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionScopedTest.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/TransactionScopedTest.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -13,6 +13,7 @@
import org.jboss.arquillian.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.seam.persistence.PersistenceProvider;
import org.jboss.seam.persistence.transaction.DefaultTransaction;
import org.jboss.seam.persistence.transaction.SeamTransaction;
import org.jboss.seam.persistence.transaction.TransactionExtension;
@@ -40,6 +41,7 @@
war.addLibraries(MavenArtifactResolver.resolve(ArtifactNames.SEAM_PERSISTENCE_API));
war.addPackage(TransactionExtension.class.getPackage());
war.addPackage(TransactionScopeExtension.class.getPackage());
+ war.addPackage(PersistenceProvider.class.getPackage());
war.addPackage(NamingUtils.class.getPackage());
war.addClasses(TransactionScopedTest.class, Hotel.class, HelloService.class, TransactionScopedObject.class);
war.addWebResource("META-INF/persistence.xml", "classes/META-INF/persistence.xml");
Modified: modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/UserTransactionTest.java
===================================================================
--- modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/UserTransactionTest.java 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/impl/src/test/java/org/jboss/seam/persistence/transactions/test/UserTransactionTest.java 2010-08-05 10:07:05 UTC (rev 13555)
@@ -5,6 +5,7 @@
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
+import javax.persistence.PersistenceException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
@@ -40,6 +41,7 @@
war.addLibraries(MavenArtifactResolver.resolve(ArtifactNames.WELD_EXTENSIONS));
war.addLibraries(MavenArtifactResolver.resolve(ArtifactNames.SEAM_PERSISTENCE_API));
war.addPackage(TransactionExtension.class.getPackage());
+ war.addPackage(PersistenceException.class.getPackage());
war.addClasses(UserTransactionTest.class, Hotel.class, HelloService.class);
war.addPackage(NamingUtils.class.getPackage());
war.addWebResource("META-INF/persistence.xml", "classes/META-INF/persistence.xml");
Modified: modules/persistence/trunk/pom.xml
===================================================================
--- modules/persistence/trunk/pom.xml 2010-08-04 17:40:14 UTC (rev 13554)
+++ modules/persistence/trunk/pom.xml 2010-08-05 10:07:05 UTC (rev 13555)
@@ -65,6 +65,12 @@
<artifactId>seam-persistence</artifactId>
<version>${project.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ <version>3.5.1-Final</version>
+ </dependency>
</dependencies>
</dependencyManagement>
More information about the seam-commits
mailing list