[seam-commits] Seam SVN: r10650 - in modules/trunk: persistence and 9 other directories.
seam-commits at lists.jboss.org
seam-commits at lists.jboss.org
Mon Apr 27 08:48:53 EDT 2009
Author: shane.bryzak at jboss.com
Date: 2009-04-27 08:48:53 -0400 (Mon, 27 Apr 2009)
New Revision: 10650
Added:
modules/trunk/persistence/
modules/trunk/persistence/pom.xml
modules/trunk/persistence/src/
modules/trunk/persistence/src/main/
modules/trunk/persistence/src/main/java/
modules/trunk/persistence/src/main/java/org/
modules/trunk/persistence/src/main/java/org/jboss/
modules/trunk/persistence/src/main/java/org/jboss/seam/
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/AbstractPersistenceProvider.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Entity.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerFactory.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxy.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxyInterceptor.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Filter.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextEntityManagerProxy.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextHibernateSessionProxy.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionFactory.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxy.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxyInterceptor.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityInterceptor.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityWrapper.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedHibernateSession.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContext.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Model.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContextManager.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/QueryParser.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/annotations/
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/annotations/FlushModeType.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Naming.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Reflections.java
modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Strings.java
Log:
initial import of persistence module
Added: modules/trunk/persistence/pom.xml
===================================================================
--- modules/trunk/persistence/pom.xml (rev 0)
+++ modules/trunk/persistence/pom.xml 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,44 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>seam-parent</artifactId>
+ <groupId>org.jboss.seam</groupId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.jboss.seam</groupId>
+ <artifactId>seam-persistence</artifactId>
+ <packaging>jar</packaging>
+ <version>3.0.0-SNAPSHOT</version>
+ <name>Seam Persistence</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.webbeans</groupId>
+ <artifactId>jsr299-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.webbeans</groupId>
+ <artifactId>webbeans-logging</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>jta</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.seam</groupId>
+ <artifactId>seam-el</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/AbstractPersistenceProvider.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/AbstractPersistenceProvider.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/AbstractPersistenceProvider.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,145 @@
+package org.jboss.seam.persistence;
+
+import java.lang.reflect.Method;
+import java.util.Date;
+
+import javax.persistence.EntityManager;
+import javax.persistence.OptimisticLockException;
+import javax.transaction.Synchronization;
+
+/**
+ * Provides a default implementation of PersistenceProvider methods where possible
+ *
+ * Other methods must be implemented
+ *
+ * @author Pete Muir
+ *
+ */
+public abstract class AbstractPersistenceProvider
+{
+
+ /**
+ * Set the flush mode to manual-only flushing. Called when
+ * an atomic persistence context is required.
+ */
+ public abstract void setFlushModeManual(EntityManager entityManager);
+
+ /**
+ * 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 abstract boolean isDirty(EntityManager entityManager);
+
+ /**
+ * Get the value of the entity identifier attribute.
+ *
+ * @param bean a managed entity instance
+ */
+ public Object getId(Object bean, EntityManager entityManager)
+ {
+ return Entity.forClass( bean.getClass() ).getIdentifier(bean);
+ }
+
+ /**
+ * 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 Entity.forClass(bean.getClass()).getName();
+ }
+
+ /**
+ * Get the value of the entity version attribute.
+ *
+ * @param bean a managed entity instance
+ */
+ public Object getVersion(Object bean, EntityManager entityManager)
+ {
+ return Entity.forClass( bean.getClass() ).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 abstract void enableFilter(Filter filter, EntityManager entityManager);
+
+ /**
+ * Register a Synchronization with the current transaction.
+ */
+ public abstract boolean registerSynchronization(Synchronization sync, EntityManager entityManager);
+
+ /**
+ * Wrap the delegate before returning it to the application
+ */
+ public Object proxyDelegate(Object delegate)
+ {
+ return delegate;
+ }
+
+ /**
+ * Wrap the entityManager before returning it to the application
+ */
+ public EntityManager proxyEntityManager(EntityManager entityManager)
+ {
+ return new EntityManagerProxy(entityManager);
+ }
+
+ /**
+ * 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 Entity.forClass(bean.getClass()).getBeanClass();
+ }
+
+ public Method getPostLoadMethod(Class beanClass, EntityManager entityManager)
+ {
+ return Entity.forClass(beanClass).getPostLoadMethod();
+ }
+
+ public Method getPrePersistMethod(Class beanClass, EntityManager entityManager)
+ {
+ return Entity.forClass(beanClass).getPrePersistMethod();
+ }
+
+ public Method getPreUpdateMethod(Class beanClass, EntityManager entityManager)
+ {
+ return Entity.forClass(beanClass).getPreUpdateMethod();
+ }
+
+ public Method getPreRemoveMethod(Class beanClass, EntityManager entityManager)
+ {
+ return Entity.forClass(beanClass).getPreRemoveMethod();
+ }
+
+}
\ No newline at end of file
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Entity.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Entity.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Entity.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,281 @@
+package org.jboss.seam.persistence;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.context.ApplicationScoped;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Id;
+import javax.persistence.PostLoad;
+import javax.persistence.PrePersist;
+import javax.persistence.PreRemove;
+import javax.persistence.PreUpdate;
+import javax.persistence.Version;
+
+import org.jboss.seam.init.EjbDescriptor;
+import org.jboss.seam.init.EjbEntityDescriptor;
+import org.jboss.seam.persistence.util.Reflections;
+
+/**
+ * Metamodel class for entity classes.
+ *
+ * A class will be identified as an entity class if it has an @Entity annotation.
+ *
+ * @author Gavin King
+ *
+ */
+ at ApplicationScoped
+public class Entity extends Model
+{
+ public Entity(Class<?> beanClass)
+ {
+ super(beanClass);
+ }
+
+ private Method preRemoveMethod;
+ private Method prePersistMethod;
+ private Method preUpdateMethod;
+ private Method postLoadMethod;
+ private Method identifierGetter;
+ private Field identifierField;
+ private Method versionGetter;
+ private Field versionField;
+ private String name;
+
+ public Method getPostLoadMethod()
+ {
+ return postLoadMethod;
+ }
+
+ public Method getPrePersistMethod()
+ {
+ return prePersistMethod;
+ }
+
+ public Method getPreRemoveMethod()
+ {
+ return preRemoveMethod;
+ }
+
+ public Method getPreUpdateMethod()
+ {
+ return preUpdateMethod;
+ }
+
+ public Object getIdentifier(Object entity)
+ {
+ if (identifierGetter != null)
+ {
+ return Reflections.invokeAndWrap(identifierGetter, entity);
+ }
+ else if (identifierField != null)
+ {
+ return Reflections.getAndWrap(identifierField, entity);
+ }
+ else
+ {
+ throw new IllegalStateException("@Id attribute not found for entity class: " + getBeanClass().getName());
+ }
+ }
+
+ public Object getVersion(Object entity)
+ {
+ if (versionGetter != null)
+ {
+ return Reflections.invokeAndWrap(versionGetter, entity);
+ }
+ else if (versionField != null)
+ {
+ return Reflections.getAndWrap(versionField, entity);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public static Entity forBean(Object bean)
+ {
+ return forClass(bean.getClass());
+ }
+
+ public static Entity forClass(Class clazz)
+ {
+ Class entityClass = Seam.getEntityClass(clazz);
+
+ if (entityClass == null)
+ {
+ throw new NotEntityException("Not an entity class: " + clazz.getName());
+ }
+ String name = getModelName(entityClass);
+ Model model = modelCache.get(name);
+ if (model == null || !(model instanceof Entity))
+ {
+ Entity entity = new Entity(entityClass);
+ modelCache.put(name, entity);
+ return entity;
+ }
+ else
+ {
+ return (Entity) model;
+ }
+ }
+
+ private void mergeAnnotationAndOrmXml(EjbEntityDescriptor descriptor)
+ {
+ // Lookup the name of the Entity from XML, annotation or default
+ this.name = lookupName(getBeanClass(), descriptor);
+ if (this.name == null)
+ {
+ throw new NotEntityException("Unable to establish name of entity " + getBeanClass());
+ }
+
+ if (descriptor != null)
+ {
+ // Set any methods and fields we need metadata for from the XML
+ // descriptor. These take priority over annotations
+
+ this.preRemoveMethod = getEntityCallbackMethod(getBeanClass(), descriptor.getPreRemoveMethodName());
+ this.prePersistMethod = getEntityCallbackMethod(getBeanClass(), descriptor.getPrePersistMethodName());
+ this.preUpdateMethod = getEntityCallbackMethod(getBeanClass(), descriptor.getPreUpdateMethodName());
+ this.postLoadMethod = getEntityCallbackMethod(getBeanClass(), descriptor.getPostLoadMethodName());
+
+ this.identifierField = descriptor.getIdentifierFieldName() != null ? Reflections.getField(getBeanClass(), descriptor.getIdentifierFieldName()) : null;
+ this.identifierGetter = descriptor.getIdentifierPropertyName() != null ? Reflections.getGetterMethod(getBeanClass(), descriptor.getIdentifierPropertyName()) : null;
+
+ this.versionField = descriptor.getVersionFieldName() != null ? Reflections.getField(getBeanClass(), descriptor.getVersionFieldName()) : null;
+ this.versionGetter = descriptor.getVersionPropertyName() != null ? Reflections.getGetterMethod(getBeanClass(), descriptor.getVersionPropertyName()) : null;
+ }
+
+ if (descriptor == null || !descriptor.isMetaDataComplete())
+ {
+ for ( Class<?> clazz=getBeanClass(); clazz!=Object.class; clazz = clazz.getSuperclass() )
+ {
+
+ for ( Method method: clazz.getDeclaredMethods() )
+ {
+ //TODO: does the spec allow multiple lifecycle method
+ // in the entity class heirarchy?
+ if (this.preRemoveMethod == null && method.isAnnotationPresent(PreRemove.class))
+ {
+ this.preRemoveMethod = method;
+ }
+ if (this.prePersistMethod == null && method.isAnnotationPresent(PrePersist.class) )
+ {
+ this.prePersistMethod = method;
+ }
+ if (preUpdateMethod == null && method.isAnnotationPresent(PreUpdate.class) )
+ {
+ preUpdateMethod = method;
+ }
+ if (postLoadMethod == null && method.isAnnotationPresent(PostLoad.class) )
+ {
+ postLoadMethod = method;
+ }
+ if (identifierField == null && identifierGetter == null && method.isAnnotationPresent(Id.class) || method.isAnnotationPresent(EmbeddedId.class))
+ {
+ identifierGetter = method;
+ }
+ if (versionField == null && versionGetter == null && method.isAnnotationPresent(Version.class) )
+ {
+ versionGetter = method;
+ }
+ }
+
+ if ( ( identifierGetter == null && identifierField == null ) || ( versionField == null && versionGetter == null ) )
+ {
+ for ( Field field: clazz.getDeclaredFields() )
+ {
+ if ( identifierGetter == null && identifierField == null && (field.isAnnotationPresent(Id.class) || field.isAnnotationPresent(EmbeddedId.class)))
+ {
+ identifierField = field;
+ }
+ if ( versionGetter == null && versionField == null && field.isAnnotationPresent(Version.class) )
+ {
+ versionField = field;
+ }
+ }
+ }
+ }
+ }
+
+ setAccessible(this.preRemoveMethod);
+ setAccessible(this.prePersistMethod);
+ setAccessible(this.preUpdateMethod);
+ setAccessible(this.postLoadMethod);
+ setAccessible(this.identifierField);
+ setAccessible(this.identifierGetter);
+ setAccessible(this.versionField);
+ setAccessible(this.versionGetter);
+ }
+
+ private void setAccessible(AccessibleObject accessibleObject)
+ {
+ if (accessibleObject != null)
+ {
+ accessibleObject.setAccessible(true);
+ }
+ }
+
+ private static String lookupName(Class<?> beanClass, EjbEntityDescriptor descriptor)
+ {
+ if (descriptor != null && descriptor.getEjbName() != null)
+ {
+ // XML overrides annotations
+ return descriptor.getEjbName();
+ }
+ else if ( (descriptor == null || !descriptor.isMetaDataComplete()) && beanClass.isAnnotationPresent(javax.persistence.Entity.class) && !"".equals(beanClass.getAnnotation(javax.persistence.Entity.class).name()))
+ {
+ // Is a name specified?
+ return beanClass.getAnnotation(javax.persistence.Entity.class).name();
+ }
+ else if (descriptor != null || beanClass.isAnnotationPresent(javax.persistence.Entity.class))
+ {
+ // Use the default name if either a descriptor is specified or the
+ // annotation is present
+ return beanClass.getName();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private static Method getEntityCallbackMethod(Class beanClass, String callbackMethodName)
+ {
+ try
+ {
+ if (callbackMethodName != null)
+ {
+ return Reflections.getMethod(beanClass, callbackMethodName);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IllegalArgumentException("Unable to find Entity callback method specified in orm.xml", e);
+ }
+ }
+
+ public static class NotEntityException extends IllegalArgumentException
+ {
+
+ public NotEntityException(String string)
+ {
+ super(string);
+ }
+
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerFactory.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerFactory.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerFactory.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,109 @@
+//$Id: EntityManagerFactory.java 6280 2007-09-27 15:29:56Z pmuir $
+package org.jboss.seam.persistence;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+import javax.context.ApplicationScoped;
+import javax.inject.Initializer;
+import javax.inject.Produces;
+import javax.persistence.Persistence;
+
+import org.hibernate.cfg.Environment;
+import org.jboss.seam.persistence.util.Naming;
+
+/**
+ * A Seam component that bootstraps an EntityManagerFactory,
+ * for use of JPA outside of Java EE 5 / Embedded JBoss.
+ *
+ * @author Gavin King
+ */
+ at ApplicationScoped
+public class EntityManagerFactory
+{
+ private javax.persistence.EntityManagerFactory entityManagerFactory;
+
+ private String persistenceUnitName;
+ private Map<String, String> persistenceUnitProperties;
+
+ @Produces
+ public javax.persistence.EntityManagerFactory getEntityManagerFactory()
+ {
+ return entityManagerFactory;
+ }
+
+ @Initializer
+ public void startup(Component component) throws Exception
+ {
+ if (persistenceUnitName==null)
+ {
+ persistenceUnitName = component.getName();
+ }
+ entityManagerFactory = createEntityManagerFactory();
+ }
+
+ @PreDestroy
+ public void shutdown()
+ {
+ if (entityManagerFactory!=null)
+ {
+ entityManagerFactory.close();
+ }
+ }
+
+ protected javax.persistence.EntityManagerFactory createEntityManagerFactory()
+ {
+ Map properties = new HashMap();
+ Hashtable<String, String> jndiProperties = Naming.getInitialContextProperties();
+ if ( jndiProperties!=null )
+ {
+ // Prefix regular JNDI properties for Hibernate
+ for (Map.Entry<String, String> entry : jndiProperties.entrySet())
+ {
+ properties.put( Environment.JNDI_PREFIX + "." + entry.getKey(), entry.getValue() );
+ }
+ }
+ if (persistenceUnitProperties!=null)
+ {
+ properties.putAll(persistenceUnitProperties);
+ }
+
+ if ( properties.isEmpty() )
+ {
+ return Persistence.createEntityManagerFactory(persistenceUnitName);
+ }
+ else
+ {
+ return Persistence.createEntityManagerFactory(persistenceUnitName, properties);
+ }
+ }
+
+ /**
+ * The persistence unit name
+ */
+ public String getPersistenceUnitName()
+ {
+ return persistenceUnitName;
+ }
+
+ public void setPersistenceUnitName(String persistenceUnitName)
+ {
+ this.persistenceUnitName = persistenceUnitName;
+ }
+
+ /**
+ * Properties to pass to Persistence.createEntityManagerFactory()
+ */
+ public Map<String, String> getPersistenceUnitProperties()
+ {
+ return persistenceUnitProperties;
+ }
+
+ public void setPersistenceUnitProperties(Map<String, String> persistenceUnitProperties)
+ {
+ this.persistenceUnitProperties = persistenceUnitProperties;
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxy.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxy.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxy.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,155 @@
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.Query;
+
+import org.jboss.seam.security.permission.PermissionManager;
+
+/**
+ * Proxies the EntityManager, and implements EL interpolation
+ * in JPA-QL
+ *
+ * @author Gavin King
+ *
+ */
+public class EntityManagerProxy implements EntityManager, Serializable
+{
+ private EntityManager delegate;
+
+ public EntityManagerProxy(EntityManager entityManager)
+ {
+ delegate = entityManager;
+ }
+
+ public void clear()
+ {
+ delegate.clear();
+ }
+
+ public void close()
+ {
+ delegate.close();
+ }
+
+ public boolean contains(Object entity)
+ {
+ return delegate.contains(entity);
+ }
+
+ public Query createNamedQuery(String name)
+ {
+ return delegate.createNamedQuery(name);
+ }
+
+ public Query createNativeQuery(String sql, Class clazz)
+ {
+ return delegate.createNativeQuery(sql, clazz);
+ }
+
+ public Query createNativeQuery(String sql, String lang)
+ {
+ return delegate.createNativeQuery(sql, lang);
+ }
+
+ public Query createNativeQuery(String sql)
+ {
+ return delegate.createNativeQuery(sql);
+ }
+
+ public Query createQuery(String ejbql)
+ {
+ if ( ejbql.indexOf('#')>0 )
+ {
+ QueryParser qp = new QueryParser(ejbql);
+ Query query = delegate.createQuery( qp.getEjbql() );
+ for (int i=0; i<qp.getParameterValueBindings().size(); i++)
+ {
+ query.setParameter(
+ QueryParser.getParameterName(i),
+ qp.getParameterValueBindings().get(i).getValue()
+ );
+ }
+ return query;
+ }
+ else
+ {
+ return delegate.createQuery(ejbql);
+ }
+ }
+
+ public <T> T find(Class<T> clazz, Object id)
+ {
+ return delegate.find(clazz, id);
+ }
+
+ public void flush()
+ {
+ delegate.flush();
+ }
+
+ public Object getDelegate()
+ {
+ return PersistenceProvider.instance().proxyDelegate( delegate.getDelegate() );
+ }
+
+ public FlushModeType getFlushMode()
+ {
+ return delegate.getFlushMode();
+ }
+
+ public <T> T getReference(Class<T> clazz, Object id)
+ {
+ return delegate.getReference(clazz, id);
+ }
+
+ public EntityTransaction getTransaction()
+ {
+ return delegate.getTransaction();
+ }
+
+ public boolean isOpen()
+ {
+ return delegate.isOpen();
+ }
+
+ public void joinTransaction()
+ {
+ delegate.joinTransaction();
+ }
+
+ public void lock(Object entity, LockModeType lm)
+ {
+ delegate.lock(entity, lm);
+ }
+
+ public <T> T merge(T entity)
+ {
+ return delegate.merge(entity);
+ }
+
+ public void persist(Object entity)
+ {
+ delegate.persist(entity);
+ }
+
+ public void refresh(Object entity)
+ {
+ delegate.refresh(entity);
+ }
+
+ public void remove(Object entity)
+ {
+ delegate.remove(entity);
+ PermissionManager.instance().clearPermissions(entity);
+ }
+
+ public void setFlushMode(FlushModeType fm)
+ {
+ delegate.setFlushMode(fm);
+ }
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxyInterceptor.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxyInterceptor.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/EntityManagerProxyInterceptor.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,67 @@
+package org.jboss.seam.persistence;
+
+import static org.jboss.seam.ComponentType.STATEFUL_SESSION_BEAN;
+import static org.jboss.seam.ComponentType.STATELESS_SESSION_BEAN;
+
+import javax.persistence.EntityManager;
+
+import org.jboss.seam.Component.BijectedAttribute;
+import org.jboss.seam.annotations.intercept.AroundInvoke;
+import org.jboss.seam.annotations.intercept.Interceptor;
+import org.jboss.seam.annotations.intercept.PostActivate;
+import org.jboss.seam.annotations.intercept.PostConstruct;
+import org.jboss.seam.intercept.AbstractInterceptor;
+import org.jboss.seam.intercept.InvocationContext;
+
+/**
+ * Proxy the EntityManager if injected using @PersistenceContext
+ *
+ * @author Pete Muir
+ */
+
+ at Interceptor(stateless=true)
+public class EntityManagerProxyInterceptor extends AbstractInterceptor
+{
+
+ @AroundInvoke
+ public Object aroundInvoke(InvocationContext ic) throws Exception
+ {
+ return ic.proceed();
+ }
+
+ @PostActivate
+ public void postActivate(InvocationContext invocation) throws Exception
+ {
+ //just in case the container does some special handling of PC serialization
+ proxyPersistenceContexts(invocation.getTarget());
+ invocation.proceed();
+ }
+
+ @PostConstruct
+ public void postConstruct(InvocationContext invocation) throws Exception
+ {
+ proxyPersistenceContexts(invocation.getTarget());
+ invocation.proceed();
+ }
+
+
+ private void proxyPersistenceContexts(Object bean)
+ {
+ //wrap any @PersistenceContext attributes in our proxy
+ for ( BijectedAttribute ba: getComponent().getPersistenceContextAttributes() )
+ {
+ Object object = ba.get(bean);
+ if ( ! ( object instanceof EntityManagerProxy ) && object instanceof EntityManager )
+ {
+ PersistenceProvider provider = PersistenceProvider.instance();
+ ba.set( bean, provider.proxyEntityManager( (EntityManager) object ) );
+ }
+ }
+ }
+
+ public boolean isInterceptorEnabled()
+ {
+ return getComponent().getType()==STATEFUL_SESSION_BEAN || getComponent().getType()==STATELESS_SESSION_BEAN;
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Filter.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Filter.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Filter.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,100 @@
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.core.Expressions.ValueExpression;
+
+/**
+ * Support for declarative application of
+ * Hibernate filters to persistence contexts.
+ *
+ * @see org.hibernate.Filter
+ * @see ManagedHibernateSession
+ * @see ManagedPersistenceContext
+ * @author Gavin King
+ */
+ at BypassInterceptors
+ at Scope(ScopeType.APPLICATION)
+public class Filter implements Serializable
+{
+ private String name;
+ // default to no parameters
+ private Map<String, ValueExpression> parameters = new HashMap<String, ValueExpression>();
+ private ValueExpression enabled;
+
+ @Create
+ public void create(Component component)
+ {
+ //default the filter name to the component name
+ if (name==null)
+ {
+ name = component.getName();
+ }
+ }
+
+ /**
+ * The filter parameters.
+ *
+ * @see org.hibernate.Filter#setParameter(String, Object)
+ */
+ public Map<String, ValueExpression> getParameters()
+ {
+ return parameters;
+ }
+ public void setParameters(Map<String, ValueExpression> parameters)
+ {
+ this.parameters = parameters;
+ }
+
+ /**
+ * The Hibernate filter name.
+ *
+ * @see org.hibernate.Session#enableFilter(String)
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public boolean isFilterEnabled()
+ {
+ ValueExpression enabledValueBinding = getEnabled();
+ if (enabledValueBinding==null)
+ {
+ return true;
+ }
+ else
+ {
+ Boolean enabled = (Boolean) enabledValueBinding.getValue();
+ return enabled!=null && enabled;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Filter(" + name + ")";
+ }
+
+ public ValueExpression getEnabled()
+ {
+ return enabled;
+ }
+
+ public void setEnabled(ValueExpression enabled)
+ {
+ this.enabled = enabled;
+ }
+}
\ No newline at end of file
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextEntityManagerProxy.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextEntityManagerProxy.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextEntityManagerProxy.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,50 @@
+//$Id: FullTextEntityManagerProxy.java 9696 2008-12-02 12:05:50Z shane.bryzak at jboss.com $
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+
+import org.apache.lucene.search.Query;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.jpa.FullTextEntityManager;
+import org.hibernate.search.jpa.FullTextQuery;
+
+/**
+ * Wrap a FullTextEntityManager
+ *
+ * @author Emmanuel Bernard
+ */
+public class FullTextEntityManagerProxy extends EntityManagerProxy implements FullTextEntityManager
+{
+ private FullTextEntityManager fullTextEntityManager;
+
+ public FullTextEntityManagerProxy(FullTextEntityManager entityManager)
+ {
+ super(entityManager);
+ this.fullTextEntityManager = entityManager;
+ }
+
+ public FullTextQuery createFullTextQuery(Query query, Class... classes)
+ {
+ return fullTextEntityManager.createFullTextQuery(query, classes);
+ }
+
+ public void index(Object object)
+ {
+ fullTextEntityManager.index(object);
+ }
+
+ public SearchFactory getSearchFactory()
+ {
+ return fullTextEntityManager.getSearchFactory();
+ }
+
+ public void purge(Class aClass, Serializable serializable)
+ {
+ fullTextEntityManager.purge(aClass, serializable);
+ }
+
+ public void purgeAll(Class aClass)
+ {
+ fullTextEntityManager.purgeAll(aClass);
+ }
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextHibernateSessionProxy.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextHibernateSessionProxy.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/FullTextHibernateSessionProxy.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,168 @@
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.search.FullTextQuery;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.type.Type;
+
+/**
+ * Wraps a Hibernate Search session
+ *
+ * @author Gavin King
+ *
+ */
+ at SuppressWarnings("deprecation")
+public class FullTextHibernateSessionProxy extends HibernateSessionProxy implements FullTextSession
+{
+ private FullTextSession fullTextSession;
+
+ public FullTextHibernateSessionProxy(FullTextSession fullTextSession)
+ {
+ super(fullTextSession);
+ this.fullTextSession = fullTextSession;
+ }
+
+ public void index(Object arg0)
+ {
+ fullTextSession.index(arg0);
+ }
+
+ public FullTextQuery createFullTextQuery(org.apache.lucene.search.Query arg0, Class... arg1)
+ {
+ return fullTextSession.createFullTextQuery(arg0, arg1);
+ }
+
+ public Query createSQLQuery(String arg0, String arg1, Class arg2)
+ {
+ return fullTextSession.createSQLQuery(arg0, arg1, arg2);
+ }
+
+ public Query createSQLQuery(String arg0, String[] arg1, Class[] arg2)
+ {
+ return fullTextSession.createSQLQuery(arg0, arg1, arg2);
+ }
+
+ public int delete(String arg0, Object arg1, Type arg2) throws HibernateException
+ {
+ return fullTextSession.delete(arg0, arg1, arg2);
+ }
+
+ public int delete(String arg0, Object[] arg1, Type[] arg2) throws HibernateException
+ {
+ return fullTextSession.delete(arg0, arg1, arg2);
+ }
+
+ public int delete(String arg0) throws HibernateException
+ {
+ return fullTextSession.delete(arg0);
+ }
+
+ public Collection filter(Object arg0, String arg1, Object arg2, Type arg3) throws HibernateException
+ {
+ return fullTextSession.filter(arg0, arg1, arg2, arg3);
+ }
+
+ public Collection filter(Object arg0, String arg1, Object[] arg2, Type[] arg3) throws HibernateException
+ {
+ return fullTextSession.filter(arg0, arg1, arg2, arg3);
+ }
+
+ public Collection filter(Object arg0, String arg1) throws HibernateException
+ {
+ return fullTextSession.filter(arg0, arg1);
+ }
+
+ public List find(String arg0, Object arg1, Type arg2) throws HibernateException
+ {
+ return fullTextSession.find(arg0, arg1, arg2);
+ }
+
+ public List find(String arg0, Object[] arg1, Type[] arg2) throws HibernateException
+ {
+ return fullTextSession.find(arg0, arg1, arg2);
+ }
+
+ public List find(String arg0) throws HibernateException
+ {
+ return fullTextSession.find(arg0);
+ }
+
+
+ public SearchFactory getSearchFactory()
+ {
+ return fullTextSession.getSearchFactory();
+ }
+
+ public void purge(Class aClass, Serializable serializable)
+ {
+ fullTextSession.purge(aClass, serializable);
+ }
+
+ public void purgeAll(Class aClass)
+ {
+ fullTextSession.purgeAll(aClass);
+ }
+
+ public Iterator iterate(String arg0, Object arg1, Type arg2) throws HibernateException
+ {
+ return fullTextSession.iterate(arg0, arg1, arg2);
+ }
+
+ public Iterator iterate(String arg0, Object[] arg1, Type[] arg2) throws HibernateException
+ {
+ return fullTextSession.iterate(arg0, arg1, arg2);
+ }
+
+ public Iterator iterate(String arg0) throws HibernateException
+ {
+ return fullTextSession.iterate(arg0);
+ }
+
+ public void save(Object arg0, Serializable arg1) throws HibernateException
+ {
+ fullTextSession.save(arg0, arg1);
+ }
+
+ public void save(String arg0, Object arg1, Serializable arg2) throws HibernateException
+ {
+ fullTextSession.save(arg0, arg1, arg2);
+ }
+
+ public Object saveOrUpdateCopy(Object arg0, Serializable arg1) throws HibernateException
+ {
+ return fullTextSession.saveOrUpdateCopy(arg0, arg1);
+ }
+
+ public Object saveOrUpdateCopy(Object arg0) throws HibernateException
+ {
+ return fullTextSession.saveOrUpdateCopy(arg0);
+ }
+
+ public Object saveOrUpdateCopy(String arg0, Object arg1, Serializable arg2) throws HibernateException
+ {
+ return fullTextSession.saveOrUpdateCopy(arg0, arg1, arg2);
+ }
+
+ public Object saveOrUpdateCopy(String arg0, Object arg1) throws HibernateException
+ {
+ return fullTextSession.saveOrUpdateCopy(arg0, arg1);
+ }
+
+ public void update(Object arg0, Serializable arg1) throws HibernateException
+ {
+ fullTextSession.update(arg0, arg1);
+ }
+
+ public void update(String arg0, Object arg1, Serializable arg2) throws HibernateException
+ {
+ fullTextSession.update(arg0, arg1, arg2);
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernatePersistenceProvider.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,393 @@
+package org.jboss.seam.persistence;
+import static org.jboss.seam.annotations.Install.FRAMEWORK;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.transaction.Synchronization;
+
+import org.hibernate.EntityMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Hibernate;
+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.jboss.seam.Component;
+import org.jboss.seam.Entity;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.Entity.NotEntityException;
+import org.jboss.seam.annotations.FlushModeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.core.Expressions.ValueExpression;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.log.Logging;
+/**
+ * Support for non-standardized features of Hibernate, when
+ * used as the JPA persistence provider.
+ *
+ * @author Gavin King
+ * @author Pete Muir
+ *
+ */
+ at Name("org.jboss.seam.persistence.persistenceProvider")
+ at Scope(ScopeType.STATELESS)
+ at BypassInterceptors
+ at Install(precedence=FRAMEWORK, classDependencies={"org.hibernate.Session", "javax.persistence.EntityManager"})
+public class HibernatePersistenceProvider extends PersistenceProvider
+{
+
+ private static Log log = Logging.getLog(HibernatePersistenceProvider.class);
+ private static Constructor FULL_TEXT_SESSION_PROXY_CONSTRUCTOR;
+ private static Method FULL_TEXT_SESSION_CONSTRUCTOR;
+ private static Constructor FULL_TEXT_ENTITYMANAGER_PROXY_CONSTRUCTOR;
+ 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");
+ FULL_TEXT_SESSION_CONSTRUCTOR = searchClass.getDeclaredMethod("createFullTextSession", Session.class);
+ Class fullTextSessionProxyClass = Class.forName("org.jboss.seam.persistence.FullTextHibernateSessionProxy");
+ Class fullTextSessionClass = Class.forName("org.hibernate.search.FullTextSession");
+ FULL_TEXT_SESSION_PROXY_CONSTRUCTOR = fullTextSessionProxyClass.getDeclaredConstructor(fullTextSessionClass);
+ Class jpaSearchClass = Class.forName("org.hibernate.search.jpa.Search");
+ FULL_TEXT_ENTITYMANAGER_CONSTRUCTOR = jpaSearchClass.getDeclaredMethod("createFullTextEntityManager", EntityManager.class);
+ Class fullTextEntityManagerProxyClass = Class.forName("org.jboss.seam.persistence.FullTextEntityManagerProxy");
+ Class fullTextEntityManagerClass = Class.forName("org.hibernate.search.jpa.FullTextEntityManager");
+ FULL_TEXT_ENTITYMANAGER_PROXY_CONSTRUCTOR = fullTextEntityManagerProxyClass.getDeclaredConstructor(fullTextEntityManagerClass);
+ log.debug("Hibernate Search is available :-)");
+ }
+ }
+ catch (Exception e)
+ {
+ log.debug("no Hibernate Search, sorry :-(", e);
+ }
+ }
+
+ @Override
+ public void init()
+ {
+ super.init();
+ featureSet.add(Feature.WILDCARD_AS_COUNT_QUERY_SUBJECT);
+ }
+
+ /**
+ * Wrap the Hibernate Session in a proxy that supports HQL
+ * EL interpolation and implements FullTextSession if Hibernate
+ * Search is available in the classpath.
+ */
+ static Session proxySession(Session session)
+ {
+ if (FULL_TEXT_SESSION_PROXY_CONSTRUCTOR==null)
+ {
+ return new HibernateSessionProxy(session);
+ }
+ else
+ {
+ try {
+ return (Session) FULL_TEXT_SESSION_PROXY_CONSTRUCTOR.newInstance( FULL_TEXT_SESSION_CONSTRUCTOR.invoke(null, session) );
+ }
+ catch(Exception e) {
+ log.warn("Unable to wrap into a FullTextSessionProxy, regular SessionProxy returned", e);
+ return new HibernateSessionProxy(session);
+ }
+ }
+ }
+
+ /**
+ * Wrap the delegate Hibernate Session in a proxy that supports HQL
+ * EL interpolation and implements FullTextSession if Hibernate
+ * Search is available in the classpath.
+ */
+ @Override
+ public Object proxyDelegate(Object delegate)
+ {
+ try
+ {
+ return proxySession( (Session) delegate );
+ }
+ catch (NotHibernateException nhe)
+ {
+ return super.proxyDelegate(delegate);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("could not proxy delegate", e);
+ }
+ }
+
+ @Override
+ public void setFlushModeManual(EntityManager entityManager)
+ {
+ try
+ {
+ getSession(entityManager).setFlushMode(FlushMode.MANUAL);
+ }
+ catch (NotHibernateException nhe)
+ {
+ super.setFlushModeManual(entityManager);
+ }
+ }
+
+ @Override
+ public void setRenderFlushMode()
+ {
+ PersistenceContexts.instance().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 void enableFilter(Filter f, EntityManager entityManager)
+ {
+ try
+ {
+ org.hibernate.Filter filter = getSession(entityManager).enableFilter( f.getName() );
+ for ( Map.Entry<String, ValueExpression> me: f.getParameters().entrySet() )
+ {
+ Object filterValue = me.getValue().getValue();
+ if ( filterValue instanceof Collection ) {
+ filter.setParameterList(me.getKey(), (Collection) filterValue);
+ } else {
+ filter.setParameter(me.getKey(), filterValue);
+ }
+ }
+ filter.validate();
+ }
+ catch (NotHibernateException nhe)
+ {
+ super.enableFilter(f, entityManager);
+ }
+
+ }
+
+ @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);
+ }
+ }
+
+ @Override
+ public EntityManager proxyEntityManager(EntityManager entityManager)
+ {
+ if (FULL_TEXT_ENTITYMANAGER_PROXY_CONSTRUCTOR==null)
+ {
+ return super.proxyEntityManager(entityManager);
+ }
+ else
+ {
+ try
+ {
+ return (EntityManager) FULL_TEXT_ENTITYMANAGER_PROXY_CONSTRUCTOR.newInstance(
+ FULL_TEXT_ENTITYMANAGER_CONSTRUCTOR.invoke(null, super.proxyEntityManager( entityManager) )
+ //TODO is double wrapping the right choice? ie to wrap the session?
+ );
+ }
+ catch (Exception e)
+ {
+ //throw new RuntimeException("could not proxy FullTextEntityManager", e);
+ return super.proxyEntityManager(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;
+ }
+
+ 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 {}
+
+ public static HibernatePersistenceProvider instance()
+ {
+ return (HibernatePersistenceProvider) Component.getInstance(HibernatePersistenceProvider.class, ScopeType.STATELESS);
+ }
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionFactory.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionFactory.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionFactory.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,248 @@
+//$Id: HibernateSessionFactory.java 6143 2007-09-07 00:59:34Z gavin $
+package org.jboss.seam.persistence;
+
+import java.io.File;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.AnnotationConfiguration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.util.ReflectHelper;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Destroy;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Startup;
+import org.jboss.seam.annotations.Unwrap;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.security.HibernateSecurityInterceptor;
+import org.jboss.seam.util.Naming;
+
+/**
+ * A Seam component that bootstraps a Hibernate SessionFactory
+ *
+ * <p>
+ * Loads Hibernate configuration options by checking:
+ * <li>hibernate.properties in root of the classpath
+ * <li>hibernate.cfg.xml in root of the classpath
+ * <li>cfgResourceName as location of a cfg.xml file
+ * <li>factory-supplied cfgProperties options
+ * <p>
+ * Note that this factory only supports cfg.xml files <b>or</b> programmatic
+ * <tt>cfgProperties</tt> supplied to the factory. Any
+ * <tt>hibernate.properties</tt> are always loaded from the classpath.
+ * <p>
+ * Mapping metadata can be supplied via
+ * <li>mappingClasses: equivalent to <mapping class="..."/>
+ * <li>mappingFiles: equivalent to <mapping file="..."/>
+ * <li>mappingJars: equivalent to <mapping jar="..."/>
+ * <li>mappingPackages: equivalent to <mapping package="..."/>
+ * <li>mappingResources: equivalent to <mapping resource="..."/>
+ * <p>
+ * or via cfg.xml files.
+ * <p>
+ * The <tt>jndiProperties</tt> are convenience, the factory will automatically
+ * prefix regular JNDI properties for use as Hibernate configuration properties.
+ *
+ * @author Gavin King
+ * @author Christian Bauer
+ */
+ at Scope(ScopeType.APPLICATION)
+ at BypassInterceptors
+ at Startup
+public class HibernateSessionFactory
+{
+ private SessionFactory sessionFactory;
+
+ private String cfgResourceName;
+ private Map<String, String> cfgProperties;
+ private List<String> mappingClasses;
+ private List<String> mappingFiles;
+ private List<String> mappingJars;
+ private List<String> mappingPackages;
+ private List<String> mappingResources;
+ private NamingStrategy namingStrategy;
+
+ @Unwrap
+ public SessionFactory getSessionFactory() throws Exception
+ {
+ return sessionFactory;
+ }
+
+ @Create
+ public void startup() throws Exception
+ {
+ sessionFactory = createSessionFactory();
+ }
+
+ @Destroy
+ public void shutdown()
+ {
+ if (sessionFactory!=null)
+ {
+ sessionFactory.close();
+ }
+ }
+
+ protected SessionFactory createSessionFactory() throws ClassNotFoundException
+ {
+ AnnotationConfiguration configuration = new AnnotationConfiguration();
+
+ // setup non-default naming strategy
+ if (namingStrategy != null)
+ {
+ configuration.setNamingStrategy(namingStrategy);
+ }
+
+ // Programmatic configuration
+ if (cfgProperties != null)
+ {
+ Properties props = new Properties();
+ props.putAll(cfgProperties);
+ configuration.setProperties(props);
+ }
+ Hashtable<String, String> jndiProperties = Naming.getInitialContextProperties();
+ if ( jndiProperties!=null )
+ {
+ // Prefix regular JNDI properties for Hibernate
+ for (Map.Entry<String, String> entry : jndiProperties.entrySet())
+ {
+ configuration.setProperty( Environment.JNDI_PREFIX + "." + entry.getKey(), entry.getValue() );
+ }
+ }
+ // hibernate.cfg.xml configuration
+ if (cfgProperties==null && cfgResourceName==null)
+ {
+ configuration.configure();
+ }
+ else if (cfgProperties==null && cfgResourceName!=null)
+ {
+ configuration.configure(cfgResourceName);
+ }
+ // Mapping metadata
+ if (mappingClasses!=null)
+ {
+ for (String className: mappingClasses)
+ {
+ configuration.addAnnotatedClass(ReflectHelper.classForName(className));
+ }
+ }
+ if (mappingFiles!=null)
+ {
+ for (String fileName: mappingFiles)
+ {
+ configuration.addFile(fileName);
+ }
+ }
+ if (mappingJars!=null)
+ {
+ for (String jarName: mappingJars)
+ {
+ configuration.addJar(new File(jarName));
+ }
+ }
+ if (mappingPackages!= null)
+ {
+ for (String packageName: mappingPackages)
+ {
+ configuration.addPackage(packageName);
+ }
+ }
+ if (mappingResources!= null)
+ {
+ for (String resourceName : mappingResources)
+ {
+ configuration.addResource(resourceName);
+ }
+ }
+
+ configuration.setInterceptor(new HibernateSecurityInterceptor(configuration.getInterceptor()));
+
+ return configuration.buildSessionFactory();
+ }
+
+ public String getCfgResourceName()
+ {
+ return cfgResourceName;
+ }
+
+ public void setCfgResourceName(String cfgFileName)
+ {
+ this.cfgResourceName = cfgFileName;
+ }
+
+ public NamingStrategy getNamingStrategy()
+ {
+ return namingStrategy;
+ }
+
+ public void setNamingStrategy(NamingStrategy namingStrategy)
+ {
+ this.namingStrategy = namingStrategy;
+ }
+
+ public Map<String, String> getCfgProperties()
+ {
+ return cfgProperties;
+ }
+
+ public void setCfgProperties(Map<String, String> cfgProperties)
+ {
+ this.cfgProperties = cfgProperties;
+ }
+
+ public List<String> getMappingClasses()
+ {
+ return mappingClasses;
+ }
+
+ public void setMappingClasses(List<String> mappingClasses)
+ {
+ this.mappingClasses = mappingClasses;
+ }
+
+ public List<String> getMappingFiles()
+ {
+ return mappingFiles;
+ }
+
+ public void setMappingFiles(List<String> mappingFiles)
+ {
+ this.mappingFiles = mappingFiles;
+ }
+
+ public List<String> getMappingJars()
+ {
+ return mappingJars;
+ }
+
+ public void setMappingJars(List<String> mappingJars)
+ {
+ this.mappingJars = mappingJars;
+ }
+
+ public List<String> getMappingPackages()
+ {
+ return mappingPackages;
+ }
+
+ public void setMappingPackages(List<String> mappingPackages)
+ {
+ this.mappingPackages = mappingPackages;
+ }
+
+ public List<String> getMappingResources()
+ {
+ return mappingResources;
+ }
+
+ public void setMappingResources(List<String> mappingResources)
+ {
+ this.mappingResources = mappingResources;
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxy.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxy.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxy.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,669 @@
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.Filter;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.ReplicationMode;
+import org.hibernate.SQLQuery;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.ActionQueue;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.event.EventListeners;
+import org.hibernate.event.EventSource;
+import org.hibernate.impl.CriteriaImpl;
+import org.hibernate.jdbc.Batcher;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.loader.custom.CustomQuery;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.stat.SessionStatistics;
+import org.hibernate.type.Type;
+
+/**
+ * Proxies the Session, and implements EL interpolation
+ * in HQL. Needs to implement SessionImplementor because
+ * DetachedCriteria casts the Session to SessionImplementor.
+ *
+ * @author Gavin King
+ * @author Emmanuel Bernard
+ * FIXME: EventSource should not really be there, remove once HSearch is fixed
+ *
+ */
+public class HibernateSessionProxy implements Session, SessionImplementor, EventSource
+{
+ private Session delegate;
+
+ /**
+ * Don't use that constructor directly, use HibernatePersistenceProvider.proxySession()
+ */
+ public HibernateSessionProxy(Session session)
+ {
+ delegate = session;
+ }
+
+ public Transaction beginTransaction() throws HibernateException
+ {
+ return delegate.beginTransaction();
+ }
+
+ public void cancelQuery() throws HibernateException
+ {
+ delegate.cancelQuery();
+ }
+
+ public void clear()
+ {
+ delegate.clear();
+ }
+
+ public Connection close() throws HibernateException
+ {
+ return delegate.close();
+ }
+
+ @SuppressWarnings("deprecation")
+ public Connection connection() throws HibernateException
+ {
+ return delegate.connection();
+ }
+
+ public boolean contains(Object arg0)
+ {
+ return delegate.contains(arg0);
+ }
+
+ public Criteria createCriteria(Class arg0, String arg1)
+ {
+ return delegate.createCriteria(arg0, arg1);
+ }
+
+ public Criteria createCriteria(Class arg0)
+ {
+ return delegate.createCriteria(arg0);
+ }
+
+ public Criteria createCriteria(String arg0, String arg1)
+ {
+ return delegate.createCriteria(arg0, arg1);
+ }
+
+ public Criteria createCriteria(String arg0)
+ {
+ return delegate.createCriteria(arg0);
+ }
+
+ public Query createFilter(Object arg0, String arg1) throws HibernateException
+ {
+ return delegate.createFilter(arg0, arg1);
+ }
+
+ public Query createQuery(String hql) throws HibernateException
+ {
+ if ( hql.indexOf('#')>0 )
+ {
+ QueryParser qp = new QueryParser(hql);
+ Query query = delegate.createQuery( qp.getEjbql() );
+ for (int i=0; i<qp.getParameterValueBindings().size(); i++)
+ {
+ query.setParameter(
+ QueryParser.getParameterName(i),
+ qp.getParameterValueBindings().get(i).getValue()
+ );
+ }
+ return query;
+ }
+ else
+ {
+ return delegate.createQuery(hql);
+ }
+ }
+
+ public SQLQuery createSQLQuery(String arg0) throws HibernateException
+ {
+ return delegate.createSQLQuery(arg0);
+ }
+
+ public void delete(Object arg0) throws HibernateException
+ {
+ delegate.delete(arg0);
+ }
+
+ public void delete(String arg0, Object arg1) throws HibernateException
+ {
+ delegate.delete(arg0, arg1);
+ }
+
+ public void disableFilter(String arg0)
+ {
+ delegate.disableFilter(arg0);
+ }
+
+ public Connection disconnect() throws HibernateException
+ {
+ return delegate.disconnect();
+ }
+
+ public Filter enableFilter(String arg0)
+ {
+ return delegate.enableFilter(arg0);
+ }
+
+ public void evict(Object arg0) throws HibernateException
+ {
+ delegate.evict(arg0);
+ }
+
+ public void flush() throws HibernateException
+ {
+ delegate.flush();
+ }
+
+ public Object get(Class arg0, Serializable arg1, LockMode arg2) throws HibernateException
+ {
+ return delegate.get(arg0, arg1, arg2);
+ }
+
+ public Object get(Class arg0, Serializable arg1) throws HibernateException
+ {
+ return delegate.get(arg0, arg1);
+ }
+
+ public Object get(String arg0, Serializable arg1, LockMode arg2) throws HibernateException
+ {
+ return delegate.get(arg0, arg1, arg2);
+ }
+
+ public Object get(String arg0, Serializable arg1) throws HibernateException
+ {
+ return delegate.get(arg0, arg1);
+ }
+
+ public CacheMode getCacheMode()
+ {
+ return delegate.getCacheMode();
+ }
+
+ public LockMode getCurrentLockMode(Object arg0) throws HibernateException
+ {
+ return delegate.getCurrentLockMode(arg0);
+ }
+
+ public Filter getEnabledFilter(String arg0)
+ {
+ return delegate.getEnabledFilter(arg0);
+ }
+
+ public EntityMode getEntityMode()
+ {
+ return delegate.getEntityMode();
+ }
+
+ public String getEntityName(Object arg0) throws HibernateException
+ {
+ return delegate.getEntityName(arg0);
+ }
+
+ public FlushMode getFlushMode()
+ {
+ return delegate.getFlushMode();
+ }
+
+ public Serializable getIdentifier(Object arg0) throws HibernateException
+ {
+ return delegate.getIdentifier(arg0);
+ }
+
+ public Query getNamedQuery(String arg0) throws HibernateException
+ {
+ return delegate.getNamedQuery(arg0);
+ }
+
+ public Session getSession(EntityMode arg0)
+ {
+ return delegate.getSession(arg0);
+ }
+
+ public SessionFactory getSessionFactory()
+ {
+ return delegate.getSessionFactory();
+ }
+
+ public SessionStatistics getStatistics()
+ {
+ return delegate.getStatistics();
+ }
+
+ public Transaction getTransaction()
+ {
+ return delegate.getTransaction();
+ }
+
+ public boolean isConnected()
+ {
+ return delegate.isConnected();
+ }
+
+ public boolean isDirty() throws HibernateException
+ {
+ return delegate.isDirty();
+ }
+
+ public boolean isOpen()
+ {
+ return delegate.isOpen();
+ }
+
+ public Object load(Class arg0, Serializable arg1, LockMode arg2) throws HibernateException
+ {
+ return delegate.load(arg0, arg1, arg2);
+ }
+
+ public Object load(Class arg0, Serializable arg1) throws HibernateException
+ {
+ return delegate.load(arg0, arg1);
+ }
+
+ public void load(Object arg0, Serializable arg1) throws HibernateException
+ {
+ delegate.load(arg0, arg1);
+ }
+
+ public Object load(String arg0, Serializable arg1, LockMode arg2) throws HibernateException
+ {
+ return delegate.load(arg0, arg1, arg2);
+ }
+
+ public Object load(String arg0, Serializable arg1) throws HibernateException
+ {
+ return delegate.load(arg0, arg1);
+ }
+
+ public void lock(Object arg0, LockMode arg1) throws HibernateException
+ {
+ delegate.lock(arg0, arg1);
+ }
+
+ public void lock(String arg0, Object arg1, LockMode arg2) throws HibernateException
+ {
+ delegate.lock(arg0, arg1, arg2);
+ }
+
+ public Object merge(Object arg0) throws HibernateException
+ {
+ return delegate.merge(arg0);
+ }
+
+ public Object merge(String arg0, Object arg1) throws HibernateException
+ {
+ return delegate.merge(arg0, arg1);
+ }
+
+ public void persist(Object arg0) throws HibernateException
+ {
+ delegate.persist(arg0);
+ }
+
+ public void persist(String arg0, Object arg1) throws HibernateException
+ {
+ delegate.persist(arg0, arg1);
+ }
+
+ public void reconnect() throws HibernateException
+ {
+ throw new UnsupportedOperationException("deprecated");
+ }
+
+ public void reconnect(Connection arg0) throws HibernateException
+ {
+ delegate.reconnect(arg0);
+ }
+
+ public void refresh(Object arg0, LockMode arg1) throws HibernateException
+ {
+ delegate.refresh(arg0, arg1);
+ }
+
+ public void refresh(Object arg0) throws HibernateException
+ {
+ delegate.refresh(arg0);
+ }
+
+ public void replicate(Object arg0, ReplicationMode arg1) throws HibernateException
+ {
+ delegate.replicate(arg0, arg1);
+ }
+
+ public void replicate(String arg0, Object arg1, ReplicationMode arg2) throws HibernateException
+ {
+ delegate.replicate(arg0, arg1, arg2);
+ }
+
+ public Serializable save(Object arg0) throws HibernateException
+ {
+ return delegate.save(arg0);
+ }
+
+ public Serializable save(String arg0, Object arg1) throws HibernateException
+ {
+ return delegate.save(arg0, arg1);
+ }
+
+ public void saveOrUpdate(Object arg0) throws HibernateException
+ {
+ delegate.saveOrUpdate(arg0);
+ }
+
+ public void saveOrUpdate(String arg0, Object arg1) throws HibernateException
+ {
+ delegate.saveOrUpdate(arg0, arg1);
+ }
+
+ public void setCacheMode(CacheMode arg0)
+ {
+ delegate.setCacheMode(arg0);
+ }
+
+ public void setFlushMode(FlushMode arg0)
+ {
+ delegate.setFlushMode(arg0);
+ }
+
+ public void setReadOnly(Object arg0, boolean arg1)
+ {
+ delegate.setReadOnly(arg0, arg1);
+ }
+
+ public void update(Object arg0) throws HibernateException
+ {
+ delegate.update(arg0);
+ }
+
+ public void update(String arg0, Object arg1) throws HibernateException
+ {
+ delegate.update(arg0, arg1);
+ }
+
+ private SessionImplementor getDelegateSessionImplementor()
+ {
+ return (SessionImplementor) delegate;
+ }
+
+ private EventSource getDelegateEventSource()
+ {
+ return (EventSource) delegate;
+ }
+
+ public void afterScrollOperation()
+ {
+ getDelegateSessionImplementor().afterScrollOperation();
+ }
+
+ public void afterTransactionCompletion(boolean arg0, Transaction arg1)
+ {
+ getDelegateSessionImplementor().afterTransactionCompletion(arg0, arg1);
+ }
+
+ public void beforeTransactionCompletion(Transaction arg0)
+ {
+ getDelegateSessionImplementor().beforeTransactionCompletion(arg0);
+ }
+
+ public String bestGuessEntityName(Object arg0)
+ {
+ return getDelegateSessionImplementor().bestGuessEntityName(arg0);
+ }
+
+ public int executeNativeUpdate(NativeSQLQuerySpecification arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().executeNativeUpdate(arg0, arg1);
+ }
+
+ public int executeUpdate(String arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().executeUpdate(arg0, arg1);
+ }
+
+ public Batcher getBatcher()
+ {
+ return getDelegateSessionImplementor().getBatcher();
+ }
+
+ public Serializable getContextEntityIdentifier(Object arg0)
+ {
+ return getDelegateSessionImplementor().getContextEntityIdentifier(arg0);
+ }
+
+ public int getDontFlushFromFind()
+ {
+ return getDelegateSessionImplementor().getDontFlushFromFind();
+ }
+
+ public Map getEnabledFilters()
+ {
+ return getDelegateSessionImplementor().getEnabledFilters();
+ }
+
+ public EntityPersister getEntityPersister(String arg0, Object arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().getEntityPersister(arg0, arg1);
+ }
+
+ public Object getEntityUsingInterceptor(EntityKey arg0) throws HibernateException
+ {
+ return getDelegateSessionImplementor().getEntityUsingInterceptor(arg0);
+ }
+
+ public SessionFactoryImplementor getFactory()
+ {
+ return getDelegateSessionImplementor().getFactory();
+ }
+
+ public String getFetchProfile()
+ {
+ return getDelegateSessionImplementor().getFetchProfile();
+ }
+
+ public Type getFilterParameterType(String arg0)
+ {
+ return getDelegateSessionImplementor().getFilterParameterType(arg0);
+ }
+
+ public Object getFilterParameterValue(String arg0)
+ {
+ return getDelegateSessionImplementor().getFilterParameterValue(arg0);
+ }
+
+ public Interceptor getInterceptor()
+ {
+ return getDelegateSessionImplementor().getInterceptor();
+ }
+
+ public JDBCContext getJDBCContext()
+ {
+ return getDelegateSessionImplementor().getJDBCContext();
+ }
+
+ public EventListeners getListeners()
+ {
+ return getDelegateSessionImplementor().getListeners();
+ }
+
+ public Query getNamedSQLQuery(String arg0)
+ {
+ return getDelegateSessionImplementor().getNamedSQLQuery(arg0);
+ }
+
+ public PersistenceContext getPersistenceContext()
+ {
+ return getDelegateSessionImplementor().getPersistenceContext();
+ }
+
+ public long getTimestamp()
+ {
+ return getDelegateSessionImplementor().getTimestamp();
+ }
+
+ public String guessEntityName(Object arg0) throws HibernateException
+ {
+ return getDelegateSessionImplementor().guessEntityName(arg0);
+ }
+
+ public Object immediateLoad(String arg0, Serializable arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().immediateLoad(arg0, arg1);
+ }
+
+ public void initializeCollection(PersistentCollection arg0, boolean arg1) throws HibernateException
+ {
+ getDelegateSessionImplementor().initializeCollection(arg0, arg1);
+ }
+
+ public Object instantiate(String arg0, Serializable arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().instantiate(arg0, arg1);
+ }
+
+ public Object internalLoad(String arg0, Serializable arg1, boolean arg2, boolean arg3) throws HibernateException
+ {
+ return getDelegateSessionImplementor().internalLoad(arg0, arg1, arg2, arg3);
+ }
+
+ public boolean isClosed()
+ {
+ return getDelegateSessionImplementor().isClosed();
+ }
+
+ public boolean isEventSource()
+ {
+ return getDelegateSessionImplementor().isEventSource();
+ }
+
+ public boolean isTransactionInProgress()
+ {
+ return getDelegateSessionImplementor().isTransactionInProgress();
+ }
+
+ public Iterator iterate(String arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().iterate(arg0, arg1);
+ }
+
+ public Iterator iterateFilter(Object arg0, String arg1, QueryParameters arg2) throws HibernateException
+ {
+ return getDelegateSessionImplementor().iterateFilter(arg0, arg1, arg2);
+ }
+
+ public List list(CriteriaImpl arg0)
+ {
+ return getDelegateSessionImplementor().list(arg0);
+ }
+
+ public List list(NativeSQLQuerySpecification arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().list(arg0, arg1);
+ }
+
+ public List list(String arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().list(arg0, arg1);
+ }
+
+ public List listCustomQuery(CustomQuery arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().listCustomQuery(arg0, arg1);
+ }
+
+ public List listFilter(Object arg0, String arg1, QueryParameters arg2) throws HibernateException
+ {
+ return getDelegateSessionImplementor().listFilter(arg0, arg1, arg2);
+ }
+
+ public ScrollableResults scroll(CriteriaImpl arg0, ScrollMode arg1)
+ {
+ return getDelegateSessionImplementor().scroll(arg0, arg1);
+ }
+
+ public ScrollableResults scroll(NativeSQLQuerySpecification arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().scroll(arg0, arg1);
+ }
+
+ public ScrollableResults scroll(String arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().scroll(arg0, arg1);
+ }
+
+ public ScrollableResults scrollCustomQuery(CustomQuery arg0, QueryParameters arg1) throws HibernateException
+ {
+ return getDelegateSessionImplementor().scrollCustomQuery(arg0, arg1);
+ }
+
+ public void setAutoClear(boolean arg0)
+ {
+ getDelegateSessionImplementor().setAutoClear(arg0);
+ }
+
+ public void setFetchProfile(String arg0)
+ {
+ getDelegateSessionImplementor().setFetchProfile(arg0);
+ }
+
+ public ActionQueue getActionQueue() {
+ return getDelegateEventSource().getActionQueue();
+ }
+
+ public Object instantiate(EntityPersister entityPersister, Serializable serializable) throws HibernateException {
+ return getDelegateEventSource().instantiate( entityPersister, serializable );
+ }
+
+ public void forceFlush(EntityEntry entityEntry) throws HibernateException {
+ getDelegateEventSource().forceFlush( entityEntry );
+ }
+
+ public void merge(String s, Object o, Map map) throws HibernateException {
+ getDelegateEventSource().merge( s, o, map );
+ }
+
+ public void persist(String s, Object o, Map map) throws HibernateException {
+ getDelegateEventSource().persist( s, o, map );
+ }
+
+ public void persistOnFlush(String s, Object o, Map map) {
+ getDelegateEventSource().persistOnFlush( s, o, map );
+ }
+
+ public void refresh(Object o, Map map) throws HibernateException {
+ getDelegateEventSource().refresh( o, map );
+ }
+
+ public void saveOrUpdateCopy(String s, Object o, Map map) throws HibernateException {
+ getDelegateEventSource().saveOrUpdateCopy( s, o , map );
+ }
+
+ public void delete(String s, Object o, boolean b, Set set) {
+ getDelegateEventSource().delete( s, o, b, set );
+ }
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxyInterceptor.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxyInterceptor.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/HibernateSessionProxyInterceptor.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,67 @@
+package org.jboss.seam.persistence;
+
+import static org.jboss.seam.ComponentType.STATEFUL_SESSION_BEAN;
+import static org.jboss.seam.ComponentType.STATELESS_SESSION_BEAN;
+
+import org.hibernate.Session;
+import org.jboss.seam.Component.BijectedAttribute;
+import org.jboss.seam.annotations.intercept.AroundInvoke;
+import org.jboss.seam.annotations.intercept.Interceptor;
+import org.jboss.seam.annotations.intercept.PostActivate;
+import org.jboss.seam.annotations.intercept.PostConstruct;
+import org.jboss.seam.intercept.AbstractInterceptor;
+import org.jboss.seam.intercept.InvocationContext;
+import org.jboss.seam.util.Reflections;
+
+/**
+ * Proxy the Hibernate Session if injected using @PersistenceContext
+ *
+ * @author Pete Muir
+ *
+ */
+
+ at Interceptor(stateless=true)
+public class HibernateSessionProxyInterceptor extends AbstractInterceptor
+{
+
+ @AroundInvoke
+ public Object aroundInvoke(InvocationContext ic) throws Exception
+ {
+ return ic.proceed();
+ }
+
+ @PostActivate
+ public void postActivate(InvocationContext invocation) throws Exception
+ {
+ //just in case the container does some special handling of PC serialization
+ proxyPersistenceContexts(invocation.getTarget());
+ invocation.proceed();
+ }
+
+ @PostConstruct
+ public void postConstruct(InvocationContext invocation) throws Exception
+ {
+ proxyPersistenceContexts(invocation.getTarget());
+ invocation.proceed();
+ }
+
+
+ private void proxyPersistenceContexts(Object bean)
+ {
+ //wrap any @PersistenceContext attributes in our proxy
+ for ( BijectedAttribute ba: getComponent().getPersistenceContextAttributes() )
+ {
+ Object object = ba.get(bean);
+ if ( ! ( object instanceof HibernateSessionProxy) && object instanceof Session)
+ {
+ ba.set( bean, HibernatePersistenceProvider.proxySession( (Session) object ) );
+ }
+ }
+ }
+
+ public boolean isInterceptorEnabled()
+ {
+ return (getComponent().getType()==STATEFUL_SESSION_BEAN || getComponent().getType()==STATELESS_SESSION_BEAN) && Reflections.isClassAvailable("org.hibernate.Session");
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityInterceptor.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityInterceptor.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityInterceptor.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,80 @@
+package org.jboss.seam.persistence;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+
+import org.jboss.seam.annotations.intercept.AroundInvoke;
+import org.jboss.seam.annotations.intercept.Interceptor;
+import org.jboss.seam.core.BijectionInterceptor;
+import org.jboss.seam.intercept.AbstractInterceptor;
+import org.jboss.seam.intercept.InvocationContext;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.transaction.Transaction;
+
+/**
+ * Swizzles entity references around each invocation, maintaining referential
+ * integrity even across passivation of the stateful bean or Seam-managed
+ * extended persistence context, and allowing for more efficient replication.
+ *
+ * @author Gavin King
+ * @author Pete Muir
+ *
+ */
+ at Interceptor(around = BijectionInterceptor.class)
+public class ManagedEntityInterceptor extends AbstractInterceptor
+{
+
+ private static LogProvider log = Logging.getLogProvider(ManagedEntityInterceptor.class);
+
+ private static ManagedEntityWrapper managedEntityWrapper = new ManagedEntityWrapper();
+
+ private boolean reentrant;
+
+ @AroundInvoke
+ public Object aroundInvoke(InvocationContext ctx) throws Exception
+ {
+ if (reentrant)
+ {
+ return ctx.proceed();
+ }
+ else
+ {
+ reentrant = true;
+ log.trace("Attempting to activate " + getComponent().getName() + " component");
+ managedEntityWrapper.deserialize(ctx.getTarget(), getComponent());
+ log.debug("Activated " + getComponent().getName() + " component");
+ try
+ {
+ return ctx.proceed();
+ }
+ finally
+ {
+ if (!isTransactionRolledBackOrMarkedRollback())
+ {
+ log.trace("Attempting to passivate " + getComponent().getName() + " component");
+ managedEntityWrapper.wrap(ctx.getTarget(), getComponent());
+ reentrant = false;
+ log.debug("Passivated " + getComponent().getName() + " component");
+ }
+ }
+ }
+ }
+
+ public boolean isInterceptorEnabled()
+ {
+ return getComponent().getScope() == CONVERSATION;
+ }
+
+ private static boolean isTransactionRolledBackOrMarkedRollback()
+ {
+ try
+ {
+ return Transaction.instance().isRolledBackOrMarkedRollback();
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityWrapper.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityWrapper.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedEntityWrapper.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,253 @@
+package org.jboss.seam.persistence;
+
+import static org.jboss.seam.util.JSF.DATA_MODEL;
+import static org.jboss.seam.util.JSF.getWrappedData;
+import static org.jboss.seam.util.JSF.setWrappedData;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.Seam;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.core.Manager;
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+import org.jboss.seam.util.Reflections;
+
+/**
+ * @author Gavin King
+ * @author Pete Muir
+ * @author Norman Richards
+ * @author Dan Allen
+ */
+public class ManagedEntityWrapper
+{
+
+ private static LogProvider log = Logging.getLogProvider(ManagedEntityWrapper.class);
+
+ public void wrap(Object target, Component component) throws Exception
+ {
+ if ( !touchedContextsExist() )
+ {
+ log.trace("No touched persistence contexts. Therefore, there are no entities in this conversation whose identities need to be preserved.");
+ return;
+ }
+
+ String oldCid = switchToConversationContextOfComponent(component);
+ Class beanClass = target.getClass();
+ for (; beanClass!=Object.class; beanClass=beanClass.getSuperclass())
+ {
+ log.trace("Examining fields on " + beanClass);
+ for ( Field field: beanClass.getDeclaredFields() )
+ {
+ if ( !ignore(field) )
+ {
+ Object value = getFieldValue(target, field);
+ if (value!=null)
+ {
+ Object dataModel = null;
+ if ( DATA_MODEL.isInstance(value) )
+ {
+ dataModel = value;
+ value = getWrappedData(dataModel);
+ }
+ if ( containsReferenceToEntityInstance(value) )
+ {
+ log.trace("Attempting to save wrapper for " + field + " (" + value + ")");
+ saveWrapper(target, component, field, dataModel, value);
+ }
+ else
+ {
+ log.trace("Clearing wrapper for " + field + " (" + value + ") as it isn't a entity reference");
+ clearWrapper(component, field);
+ }
+ }
+ else
+ {
+ log.trace("Clearing wrapper for " + field + " as it is null");
+ clearWrapper(component, field);
+ }
+ }
+ else
+ {
+ log.trace("Ignoring field " + field + " as it is static, transient or annotated with @In");
+ }
+ }
+ }
+ restorePreviousConversationContextIfNecessary(oldCid);
+ }
+
+ public void deserialize(Object controllerBean, Component component) throws Exception
+ {
+ if ( !touchedContextsExist() )
+ {
+ log.trace("No touched persistence contexts. Therefore, there are no entities in this conversation whose identities need to be restored.");
+ return;
+ }
+
+ Class beanClass = controllerBean.getClass();
+ for (; beanClass!=Object.class; beanClass=beanClass.getSuperclass())
+ {
+ log.trace("Examining fields on " + beanClass);
+ for ( Field field: beanClass.getDeclaredFields() )
+ {
+ if ( !ignore(field) )
+ {
+ Object value = getFieldValue(controllerBean, field);
+ Object dataModel = null;
+ if (value!=null && DATA_MODEL.isInstance(value) )
+ {
+ dataModel = value;
+ }
+ log.trace("Attempting to restore wrapper for " + field + " (" + value + ")");
+ //TODO: be more selective
+ getFromWrapper(controllerBean, component, field, dataModel);
+ }
+ else
+ {
+ log.trace("Ignoring field " + field + " as it is static, transient or annotated with @In");
+ }
+ }
+ }
+ }
+
+ private boolean containsReferenceToEntityInstance(Object value)
+ {
+ if (value == null)
+ {
+ return false;
+ }
+ else if (value instanceof Collection)
+ {
+ // Do a lazy man's generic check by scanning the collection until an entity is found (nested objects not considered).
+ for (Iterator iter = ((Collection) value).iterator(); iter.hasNext();)
+ {
+ Object v = iter.next();
+ if (v != null && Seam.getEntityClass(v.getClass()) != null)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else if (value instanceof Map)
+ {
+ // Do a lazy man's generic check by scanning the collection until an entity is found (nested objects not considered).
+ for (Iterator iter = ((Map) value).entrySet().iterator(); iter.hasNext();)
+ {
+ Entry e = (Entry) iter.next();
+ if ((e.getKey() != null && Seam.getEntityClass(e.getKey().getClass()) != null) ||
+ (e.getValue() != null && Seam.getEntityClass(e.getValue().getClass()) != null))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else if (Seam.getEntityClass(value.getClass()) != null)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private Object getFieldValue(Object bean, Field field) throws Exception
+ {
+ if ( !field.isAccessible() ) field.setAccessible(true);
+ Object value = Reflections.get(field, bean);
+ return value;
+ }
+
+ private boolean ignore(Field field)
+ {
+ return Modifier.isTransient( field.getModifiers() ) ||
+ Modifier.isStatic( field.getModifiers() )
+ || field.isAnnotationPresent(In.class);
+ }
+
+ private boolean touchedContextsExist()
+ {
+ PersistenceContexts touchedContexts = PersistenceContexts.instance();
+ return touchedContexts!=null && touchedContexts.getTouchedContexts().size()>0;
+ }
+
+ private String getFieldId(Component component, Field field)
+ {
+ return component.getName() + '.' + field.getName();
+ }
+
+ private void saveWrapper(Object bean, Component component, Field field, Object dataModel, Object value) throws Exception
+ {
+ Contexts.getConversationContext().set( getFieldId(component, field), value );
+ if (dataModel==null)
+ {
+ Reflections.set(field, bean, null);
+ }
+ else
+ {
+ // JBSEAM-1814, JBPAPP-1616 Clearing the wrapped data is simply unnecessary. Either we leave it alone, or we set the field to null.
+ //setWrappedData(dataModel, null);
+ }
+ }
+
+ private void clearWrapper(Component component, Field field) throws Exception
+ {
+ Contexts.getConversationContext().remove( getFieldId(component, field) );
+ }
+
+ private void getFromWrapper(Object bean, Component component, Field field, Object dataModel) throws Exception
+ {
+ Object value =Contexts.getConversationContext().get( getFieldId(component, field) );
+ if (value!=null)
+ {
+ if (dataModel==null)
+ {
+ Reflections.set(field, bean, value);
+ }
+ else
+ {
+ setWrappedData(dataModel, value);
+ }
+ }
+ }
+
+ /**
+ * Changes the thread's current conversation context to the one that holds a reference to this
+ * component. This is necessary if a nested conversation is making a call to a component in
+ * a parent conversation.
+ */
+ private String switchToConversationContextOfComponent(Component component)
+ {
+ Manager manager = Manager.instance();
+ if (manager.isNestedConversation())
+ {
+ String currentCid = manager.getCurrentConversationId();
+ String residentCid = manager.getCurrentConversationEntry().findPositionInConversationStack(component);
+ if (!currentCid.equals(residentCid))
+ {
+ Contexts.getConversationContext().flush();
+ Manager.instance().switchConversation(residentCid, false);
+ return currentCid;
+ }
+ }
+
+ return null;
+ }
+
+ private void restorePreviousConversationContextIfNecessary(String oldCid)
+ {
+ if (oldCid != null)
+ {
+ Contexts.getConversationContext().flush();
+ Manager.instance().switchConversation(oldCid, false);
+ }
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedHibernateSession.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedHibernateSession.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedHibernateSession.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,322 @@
+//$Id: ManagedHibernateSession.java 9081 2008-09-22 03:02:30Z dan.j.allen $
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+import javax.context.ConversationScoped;
+import javax.inject.Current;
+import javax.inject.Initializer;
+import javax.inject.Produces;
+import javax.naming.NamingException;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionEvent;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.hibernate.FlushMode;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.jboss.seam.core.Mutable;
+import org.jboss.seam.core.Expressions.ValueExpression;
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+import org.jboss.seam.persistence.annotations.FlushModeType;
+import org.jboss.seam.transaction.Transaction;
+import org.jboss.seam.transaction.UserTransaction;
+import org.jboss.seam.util.Naming;
+
+/**
+ * A Seam component that manages a conversation-scoped extended
+ * persistence context that can be shared by arbitrary other
+ * components.
+ *
+ * @author Gavin King
+ */
+ at ConversationScoped
+public class ManagedHibernateSession
+ implements Serializable, HttpSessionActivationListener, Mutable, PersistenceContextManager, Synchronization
+{
+
+ /** The serialVersionUID */
+ private static final long serialVersionUID = 3130309555079841107L;
+
+ private static final LogProvider log = Logging.getLogProvider(ManagedHibernateSession.class);
+
+ private Session session;
+ private String sessionFactoryJndiName;
+ private String componentName;
+ private ValueExpression<SessionFactory> sessionFactory;
+ private List<Filter> filters = new ArrayList<Filter>(0);
+
+ private transient boolean synchronizationRegistered;
+ private transient boolean destroyed;
+
+ @Current PersistenceContexts persistenceContexts;
+
+ public boolean clearDirty()
+ {
+ return true;
+ }
+
+ @Initializer
+ public void create(Component component)
+ {
+ this.componentName = component.getName();
+ if (sessionFactoryJndiName==null)
+ {
+ sessionFactoryJndiName = "java:/" + componentName;
+ }
+
+ persistenceContexts.touch(componentName);
+ }
+
+ private void initSession() throws Exception
+ {
+ session = getSessionFactoryFromJndiOrValueBinding().openSession();
+ setSessionFlushMode( persistenceContexts.getFlushMode() );
+ session = HibernatePersistenceProvider.proxySession(session);
+
+ for (Filter f: filters)
+ {
+ if ( f.isFilterEnabled() )
+ {
+ enableFilter(f);
+ }
+ }
+
+ if ( log.isDebugEnabled() )
+ {
+ log.debug("created seam managed session for session factory: "+ sessionFactoryJndiName);
+ }
+ }
+
+ private void enableFilter(Filter f)
+ {
+ org.hibernate.Filter filter = session.enableFilter( f.getName() );
+ for ( Map.Entry<String, ValueExpression> me: f.getParameters().entrySet() )
+ {
+ Object filterValue = me.getValue().getValue();
+ if ( filterValue instanceof Collection ) {
+ filter.setParameterList(me.getKey(), (Collection) filterValue);
+ } else {
+ filter.setParameter(me.getKey(), filterValue);
+ }
+ }
+ filter.validate();
+ }
+
+ @Produces public Session getSession() throws Exception
+ {
+ if (session==null) initSession();
+
+ if ( !synchronizationRegistered && !Lifecycle.isDestroying() )
+ {
+ joinTransaction();
+ }
+
+ return session;
+ }
+
+ private void joinTransaction() throws SystemException
+ {
+ UserTransaction transaction = Transaction.instance();
+ if ( transaction.isActive() )
+ {
+ session.isOpen();
+ try
+ {
+ transaction.registerSynchronization(this);
+ }
+ catch (Exception e)
+ {
+ session.getTransaction().registerSynchronization(this);
+ }
+ synchronizationRegistered = true;
+ }
+ }
+
+ //we can't use @PrePassivate because it is intercept NEVER
+ public void sessionWillPassivate(HttpSessionEvent event)
+ {
+ if (synchronizationRegistered)
+ {
+ throw new IllegalStateException("cannot passivate persistence context with active transaction");
+ }
+ if ( session!=null && session.isOpen() && !session.isDirty() )
+ {
+ session.close();
+ session = null;
+ }
+ }
+
+ //we can't use @PostActivate because it is intercept NEVER
+ public void sessionDidActivate(HttpSessionEvent event) {}
+
+ @PreDestroy
+ public void destroy()
+ {
+ destroyed = true;
+ if ( !synchronizationRegistered )
+ {
+ //in requests that come through SeamPhaseListener,
+ //there can be multiple transactions per request,
+ //but they are all completed by the time contexts
+ //are destroyed
+ //so wait until the end of the request to close
+ //the session
+ //on the other hand, if we are still waiting for
+ //the transaction to commit, leave it open
+ close();
+ }
+ persistenceContexts.untouch(componentName);
+ }
+
+ public void afterCompletion(int status)
+ {
+ synchronizationRegistered = false;
+ //if ( !Contexts.isConversationContextActive() )
+ if (destroyed)
+ {
+ //in calls to MDBs and remote calls to SBs, the
+ //transaction doesn't commit until after contexts
+ //are destroyed, so wait until the transaction
+ //completes before closing the session
+ //on the other hand, if we still have an active
+ //conversation context, leave it open
+ close();
+ }
+ }
+
+ public void beforeCompletion() {}
+
+ private void close()
+ {
+ boolean transactionActive = false;
+ try
+ {
+ transactionActive = Transaction.instance().isActive();
+ }
+ catch (SystemException se)
+ {
+ log.debug("could not get transaction status while destroying persistence context");
+ }
+
+ if ( transactionActive )
+ {
+ throw new IllegalStateException("attempting to destroy the persistence context while an active transaction exists (try installing <transaction:ejb-transaction/>)");
+ }
+
+ if ( log.isDebugEnabled() )
+ {
+ log.debug("destroying seam managed session for session factory: " + sessionFactoryJndiName);
+ }
+ if (session!=null && session.isOpen())
+ {
+ session.close();
+ }
+ }
+
+ private SessionFactory getSessionFactoryFromJndiOrValueBinding()
+ {
+ SessionFactory result = null;
+ //first try to find it via the value binding
+ if (sessionFactory!=null)
+ {
+ result = sessionFactory.getValue();
+ }
+ //if its not there, try JNDI
+ if (result==null)
+ {
+ try
+ {
+ result = (SessionFactory) Naming.getInitialContext().lookup(sessionFactoryJndiName);
+ }
+ catch (NamingException ne)
+ {
+ throw new IllegalArgumentException("SessionFactory not found in JNDI: " + sessionFactoryJndiName, ne);
+ }
+ }
+ return result;
+ }
+
+ public String getComponentName() {
+ return componentName;
+ }
+
+ public void changeFlushMode(FlushModeType flushMode)
+ {
+ if (session!=null && session.isOpen())
+ {
+ setSessionFlushMode(flushMode);
+ }
+ }
+
+ protected void setSessionFlushMode(FlushModeType flushMode)
+ {
+ switch (flushMode)
+ {
+ case AUTO:
+ session.setFlushMode(FlushMode.AUTO);
+ break;
+ case MANUAL:
+ session.setFlushMode(FlushMode.MANUAL);
+ break;
+ case COMMIT:
+ session.setFlushMode(FlushMode.COMMIT);
+ break;
+ }
+ }
+
+ /**
+ * The JNDI name of the Hibernate SessionFactory, if it is
+ * to be obtained from JNDI
+ */
+ public String getSessionFactoryJndiName()
+ {
+ return sessionFactoryJndiName;
+ }
+
+ public void setSessionFactoryJndiName(String sessionFactoryName)
+ {
+ this.sessionFactoryJndiName = sessionFactoryName;
+ }
+
+ /**
+ * A value binding expression that returns a SessionFactory,
+ * if it is to be obtained as a Seam component reference
+ */
+ public void setSessionFactory(ValueExpression<SessionFactory> sessionFactory)
+ {
+ this.sessionFactory = sessionFactory;
+ }
+
+ public ValueExpression<SessionFactory> getSessionFactory()
+ {
+ return sessionFactory;
+ }
+
+ /**
+ * Hibernate filters to enable automatically
+ */
+ public List<Filter> getFilters()
+ {
+ return filters;
+ }
+
+ public void setFilters(List<Filter> filters)
+ {
+ this.filters = filters;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ManagedHibernateSession(" + sessionFactoryJndiName + ")";
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContext.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContext.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/ManagedPersistenceContext.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,323 @@
+//$Id: ManagedPersistenceContext.java 9721 2008-12-04 08:29:25Z dan.j.allen $
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PreDestroy;
+import javax.context.ConversationScoped;
+import javax.inject.Current;
+import javax.inject.Initializer;
+import javax.inject.Produces;
+import javax.naming.NamingException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionEvent;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.jboss.seam.contexts.Lifecycle;
+import org.jboss.seam.core.Mutable;
+import org.jboss.seam.core.Expressions.ValueExpression;
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+import org.jboss.seam.persistence.annotations.FlushModeType;
+import org.jboss.seam.transaction.Transaction;
+import org.jboss.seam.transaction.UserTransaction;
+import org.jboss.seam.util.Naming;
+
+/**
+ * A Seam component that manages a conversation-scoped extended
+ * persistence context that can be shared by arbitrary other
+ * components.
+ *
+ * @author Gavin King
+ */
+ at ConversationScoped
+public class ManagedPersistenceContext
+ implements Serializable, HttpSessionActivationListener, Mutable, PersistenceContextManager, Synchronization
+{
+ private static final long serialVersionUID = -4972387440275848126L;
+ private static final LogProvider log = Logging.getLogProvider(ManagedPersistenceContext.class);
+
+ private transient EntityManager entityManager;
+ private String persistenceUnitJndiName;
+ private String componentName;
+ private ValueExpression<EntityManagerFactory> entityManagerFactory;
+ private List<Filter> filters = new ArrayList<Filter>(0);
+
+ private transient boolean synchronizationRegistered;
+ private transient boolean destroyed;
+
+ @Current PersistenceContexts persistenceContexts;
+ @Current PersistenceProvider persistenceProvider;
+
+ public boolean clearDirty()
+ {
+ return true;
+ }
+
+ @Initializer
+ public void create(Component component)
+ {
+ this.componentName = component.getName();
+ if (persistenceUnitJndiName==null)
+ {
+ persistenceUnitJndiName = "java:/" + componentName;
+ }
+
+ persistenceContexts.touch(componentName);
+ }
+
+ private void initEntityManager()
+ {
+ entityManager = getEntityManagerFactoryFromJndiOrValueBinding().createEntityManager();
+ entityManager = persistenceProvider.proxyEntityManager(entityManager);
+ setEntityManagerFlushMode( persistenceContexts.getFlushMode() );
+
+ for (Filter f: filters)
+ {
+ if ( f.isFilterEnabled() )
+ {
+ persistenceProvider.enableFilter(f, entityManager);
+ }
+ }
+
+ if ( log.isDebugEnabled() )
+ {
+ if (entityManagerFactory==null)
+ {
+ log.debug("created seam managed persistence context for persistence unit: "+ persistenceUnitJndiName);
+ }
+ else
+ {
+ log.debug("created seam managed persistence context from EntityManagerFactory");
+ }
+ }
+ }
+
+ @Produces
+ public EntityManager getEntityManager() throws NamingException, SystemException
+ {
+ if (entityManager==null) initEntityManager();
+
+ if ( !synchronizationRegistered && !Lifecycle.isDestroying() )
+ {
+ joinTransaction();
+ }
+
+ return entityManager;
+ }
+
+ private void joinTransaction() throws SystemException
+ {
+ UserTransaction transaction = Transaction.instance();
+ if ( transaction.isActive() )
+ {
+ transaction.enlist(entityManager);
+ try
+ {
+ transaction.registerSynchronization(this);
+ synchronizationRegistered = true;
+ }
+ catch (Exception e)
+ {
+ synchronizationRegistered = persistenceProvider.registerSynchronization(this, entityManager);
+ }
+ }
+ }
+
+ /**
+ * If a transaction is active, fail the passivation. The field holding the
+ * managed EntityManager is marked as transient so that it is not serialized
+ * (it can't be). The transient keyword was choosen because we don't want to
+ * forcefully close and nullify the EntityManager on every request because
+ * then we have to keep hitting the database to load the entities back into
+ * the persistence context. The only downside is that we cannot clean up
+ * on the old node before the session hops, but it turns out not to matter.
+ *
+ * Note that we must use the method on the
+ * {@link HttpSessionActivationListener} interface rather than
+ * <code>@PrePassivate</code> since interceptors are disabled on this component.
+ */
+ public void sessionWillPassivate(HttpSessionEvent event)
+ {
+ if (synchronizationRegistered)
+ {
+ throw new IllegalStateException("cannot passivate persistence context with active transaction");
+ }
+ }
+
+ /**
+ * Note that we must use the method on the {@link HttpSessionActivationListener}
+ * interface rather than @PostActivate since interceptors are disabled
+ * on this component.
+ */
+ public void sessionDidActivate(HttpSessionEvent event) {}
+
+ @PreDestroy
+ public void destroy()
+ {
+ destroyed = true;
+ if ( !synchronizationRegistered )
+ {
+ //in requests that come through SeamPhaseListener,
+ //there can be multiple transactions per request,
+ //but they are all completed by the time contexts
+ //are destroyed
+ //so wait until the end of the request to close
+ //the session
+ //on the other hand, if we are still waiting for
+ //the transaction to commit, leave it open
+ close();
+ }
+ persistenceContexts.untouch(componentName);
+ }
+
+ public void afterCompletion(int status)
+ {
+ synchronizationRegistered = false;
+ //if ( !Contexts.isConversationContextActive() )
+ if (destroyed)
+ {
+ //in calls to MDBs and remote calls to SBs, the
+ //transaction doesn't commit until after contexts
+ //are destroyed, so wait until the transaction
+ //completes before closing the session
+ //on the other hand, if we still have an active
+ //conversation context, leave it open
+ close();
+ }
+ }
+
+ public void beforeCompletion() {}
+
+ private void close()
+ {
+ boolean transactionActive = false;
+ try
+ {
+ transactionActive = Transaction.instance().isActive();
+ }
+ catch (SystemException se)
+ {
+ log.debug("could not get transaction status while destroying persistence context");
+ }
+
+ if ( transactionActive )
+ {
+ throw new IllegalStateException("attempting to destroy the persistence context while an active transaction exists (try installing <transaction:ejb-transaction/>)");
+ }
+
+ if ( log.isDebugEnabled() )
+ {
+ log.debug("destroying seam managed persistence context for persistence unit: " + persistenceUnitJndiName);
+ }
+
+ if (entityManager!=null && entityManager.isOpen())
+ {
+ entityManager.close();
+ }
+ }
+
+ public EntityManagerFactory getEntityManagerFactoryFromJndiOrValueBinding()
+ {
+ EntityManagerFactory result = null;
+ //first try to find it via the value binding
+ if (entityManagerFactory!=null)
+ {
+ result = entityManagerFactory.getValue();
+ }
+ //if its not there, try JNDI
+ if (result==null)
+ {
+ try
+ {
+ result = (EntityManagerFactory) Naming.getInitialContext().lookup(persistenceUnitJndiName);
+ }
+ catch (NamingException ne)
+ {
+ throw new IllegalArgumentException("EntityManagerFactory not found in JNDI : " + persistenceUnitJndiName, ne);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A value binding expression that returns an EntityManagerFactory,
+ * for use of JPA outside of Java EE 5 / Embeddable EJB3.
+ */
+ public ValueExpression<EntityManagerFactory> getEntityManagerFactory()
+ {
+ return entityManagerFactory;
+ }
+
+ public void setEntityManagerFactory(ValueExpression<EntityManagerFactory> entityManagerFactory)
+ {
+ this.entityManagerFactory = entityManagerFactory;
+ }
+
+ /**
+ * The JNDI name of the EntityManagerFactory, for
+ * use of JPA in Java EE 5 / Embeddable EJB3.
+ */
+ public String getPersistenceUnitJndiName()
+ {
+ return persistenceUnitJndiName;
+ }
+
+ public void setPersistenceUnitJndiName(String persistenceUnitName)
+ {
+ this.persistenceUnitJndiName = persistenceUnitName;
+ }
+
+ public String getComponentName()
+ {
+ return componentName;
+ }
+
+ /**
+ * Hibernate filters to enable automatically
+ */
+ public List<Filter> getFilters()
+ {
+ return filters;
+ }
+
+ public void setFilters(List<Filter> filters)
+ {
+ this.filters = filters;
+ }
+
+ public void changeFlushMode(FlushModeType flushMode)
+ {
+ if (entityManager!=null && entityManager.isOpen())
+ {
+ setEntityManagerFlushMode(flushMode);
+ }
+ }
+
+ protected void setEntityManagerFlushMode(FlushModeType flushMode)
+ {
+ switch (flushMode)
+ {
+ case AUTO:
+ entityManager.setFlushMode(javax.persistence.FlushModeType.AUTO);
+ break;
+ case COMMIT:
+ entityManager.setFlushMode(javax.persistence.FlushModeType.COMMIT);
+ break;
+ case MANUAL:
+ persistenceProvider.setFlushModeManual(entityManager);
+ break;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ManagedPersistenceContext(" + persistenceUnitJndiName + ")";
+ }
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Model.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Model.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/Model.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,50 @@
+package org.jboss.seam.persistence;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class of metamodels. For a class which
+ * is neither an entity nor a Seam component,
+ * the concrete type of the metamodel object
+ * will be Model. For components or entities
+ * it is a subclass of Model.
+ *
+ * @author Gavin King
+ *
+ */
+public class Model
+{
+ protected static Map<String,Model> modelCache = new HashMap<String,Model>();
+
+ private Class<?> beanClass;
+
+ public Model(Class<?> beanClass)
+ {
+ this.beanClass = beanClass;
+ }
+
+ public final Class<?> getBeanClass()
+ {
+ return beanClass;
+ }
+
+ public static Model forClass(Class clazz)
+ {
+ String name = getModelName(clazz);
+ Model model = modelCache.get(name);
+ if ( model==null )
+ {
+ model = clazz.isAnnotationPresent(javax.persistence.Entity.class) ?
+ new Entity(clazz) : new Model(clazz);
+ modelCache.put(name, model);
+ }
+ return model;
+ }
+
+ static String getModelName(Class clazz)
+ {
+ return clazz.getName() + ".model";
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContextManager.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContextManager.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContextManager.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,15 @@
+package org.jboss.seam.persistence;
+
+import org.jboss.seam.persistence.annotations.FlushModeType;
+
+/**
+ * Support for changing flushmodes for an existing
+ * persistence context.
+ *
+ * @author Gavin King
+ *
+ */
+public interface PersistenceContextManager
+{
+ public void changeFlushMode(FlushModeType flushMode);
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceContexts.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,128 @@
+package org.jboss.seam.persistence;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.context.Conversation;
+import javax.context.ConversationScoped;
+import javax.inject.Current;
+import javax.inject.Initializer;
+
+import org.jboss.seam.persistence.annotations.FlushModeType;
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+
+/**
+ * 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 extends AbstractMutable implements Serializable
+{
+ private static final long serialVersionUID = -4897350516435283182L;
+ private static final LogProvider log = Logging.getLogProvider(PersistenceContexts.class);
+ private Set<String> set = new HashSet<String>();
+ 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;
+
+ @Current PersistenceProvider persistenceProvider;
+
+ @Initializer
+ public void create()
+ {
+ FlushModeType defaultFlushMode = Manager.instance().getDefaultFlushMode();
+ if (defaultFlushMode != null)
+ {
+ flushMode = defaultFlushMode;
+ }
+ else
+ {
+ flushMode = FlushModeType.AUTO;
+ }
+ }
+
+ public FlushModeType getFlushMode()
+ {
+ return flushMode;
+ }
+
+ public Set<String> getTouchedContexts()
+ {
+ return Collections.unmodifiableSet(set);
+ }
+
+ public void touch(String context)
+ {
+ if ( set.add(context) ) setDirty();
+ }
+
+ public void untouch(String context)
+ {
+ if ( set.remove(context) ) setDirty();
+ }
+
+ 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 (String name: set)
+ {
+ PersistenceContextManager pcm = (PersistenceContextManager) Contexts.getConversationContext().get(name);
+ if (pcm!=null)
+ {
+ try
+ {
+ pcm.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.setRenderFlushMode();
+ }
+
+ public void afterRender()
+ {
+ restoreFlushMode();
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/PersistenceProvider.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,210 @@
+package org.jboss.seam.persistence;
+
+import java.lang.reflect.Method;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.Named;
+import javax.annotation.PostConstruct;
+import javax.persistence.EntityManager;
+import javax.persistence.OptimisticLockException;
+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
+ *
+ */
+ at Named
+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>();
+
+ @PostConstruct // @Create method not called on stateless components
+ public void init() {}
+
+ /**
+ * Indicate whether this JPA provider supports the feature defined by the provided Feature enum value.
+ */
+ public boolean supportsFeature(Feature feature) {
+ return featureSet.contains(feature);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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 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 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;
+ }
+ /**
+ * Wrap the entityManager before returning it to the application
+ */
+ public EntityManager proxyEntityManager(EntityManager entityManager) {
+ return new EntityManagerProxy(entityManager);
+ }
+
+ /**
+ * 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 Entity.forBean(bean).getBeanClass();
+ }
+
+ public Method getPostLoadMethod(Object bean, EntityManager entityManager)
+ {
+ return Entity.forBean(bean).getPostLoadMethod();
+ }
+
+ public Method getPrePersistMethod(Object bean, EntityManager entityManager)
+ {
+ return Entity.forBean(bean).getPrePersistMethod();
+ }
+
+ public Method getPreUpdateMethod(Object bean, EntityManager entityManager)
+ {
+ return Entity.forBean(bean).getPreUpdateMethod();
+ }
+
+ public Method getPreRemoveMethod(Object bean, EntityManager entityManager)
+ {
+ return Entity.forBean(bean).getPreRemoveMethod();
+ }
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/QueryParser.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/QueryParser.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/QueryParser.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,58 @@
+package org.jboss.seam.persistence;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.jboss.seam.el.Expressions.ValueExpression;
+
+import org.jboss.seam.el.Expressions;
+
+public class QueryParser
+{
+ private List<ValueExpression> parameterValueBindings = new ArrayList<ValueExpression>();
+ private StringBuilder ejbqlBuilder;
+
+ public static String getParameterName(int loc)
+ {
+ return "el" + (loc+1);
+ }
+
+ public String getEjbql()
+ {
+ return ejbqlBuilder.toString();
+ }
+
+ public List<ValueExpression> getParameterValueBindings()
+ {
+ return parameterValueBindings;
+ }
+
+ public QueryParser(String ejbql)
+ {
+ this(ejbql, 0);
+ }
+
+ public QueryParser(String ejbql, int startingParameterNumber)
+ {
+ StringTokenizer tokens = new StringTokenizer(ejbql, "#}", true);
+ ejbqlBuilder = new StringBuilder(ejbql.length());
+ while (tokens.hasMoreTokens()) {
+ String token = tokens.nextToken();
+ if ("#".equals(token) && tokens.hasMoreTokens()) {
+ String expressionToken = tokens.nextToken();
+
+ if (!expressionToken.startsWith("{") || !tokens.hasMoreTokens()) {
+ ejbqlBuilder.append(token).append(expressionToken);
+ } else {
+ String expression = token + expressionToken + tokens.nextToken();
+ ejbqlBuilder.append(':').append( getParameterName( startingParameterNumber + parameterValueBindings.size() ) );
+ parameterValueBindings.add( Expressions.instance().createValueExpression(expression) );
+ }
+ } else {
+ ejbqlBuilder.append(token);
+ }
+ }
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/annotations/FlushModeType.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/annotations/FlushModeType.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/annotations/FlushModeType.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,42 @@
+package org.jboss.seam.persistence.annotations;
+
+/**
+ * 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/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Naming.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Naming.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Naming.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,75 @@
+package org.jboss.seam.persistence.util;
+
+import java.util.Hashtable;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+
+public final class Naming
+{
+ private static final LogProvider log = Logging.getLogProvider(Naming.class);
+
+ private static Hashtable initialContextProperties;
+
+ private static InitialContext initialContext;
+
+ public static InitialContext getInitialContext(
+ Hashtable<String, String> props) throws NamingException
+ {
+ if (props == null)
+ {
+ throw new IllegalStateException(
+ "JNDI properties not initialized, Seam was not started correctly");
+ }
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("JNDI InitialContext properties:" + props);
+ }
+
+ try
+ {
+ return props.size() == 0 ? new InitialContext() : new InitialContext(
+ props);
+ } catch (NamingException e)
+ {
+ log.debug("Could not obtain initial context", e);
+ throw e;
+ }
+
+ }
+
+ public static InitialContext getInitialContext() throws NamingException
+ {
+ if (initialContext == null)
+ initInitialContext();
+
+ return initialContext;
+ }
+
+ private static synchronized void initInitialContext() throws NamingException
+ {
+ if (initialContext == null)
+ {
+ initialContext = getInitialContext(initialContextProperties);
+ }
+ }
+
+ private Naming() {
+ }
+
+ public static void setInitialContextProperties(
+ Hashtable initialContextProperties)
+ {
+ Naming.initialContextProperties = initialContextProperties;
+ initialContext = null;
+ }
+
+ public static Hashtable getInitialContextProperties()
+ {
+ return initialContextProperties;
+ }
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Reflections.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Reflections.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Reflections.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,401 @@
+package org.jboss.seam.persistence.util;
+
+import java.beans.Introspector;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Reflections
+{
+
+ public static Object invoke(Method method, Object target, Object... args) throws Exception
+ {
+ try
+ {
+ return method.invoke( target, args );
+ }
+ catch (IllegalArgumentException iae)
+ {
+ String message = "Could not invoke method by reflection: " + toString(method);
+ if (args!=null && args.length>0)
+ {
+ message += " with parameters: (" + Strings.toClassNameString(", ", args) + ')';
+ }
+ message += " on: " + target.getClass().getName();
+ throw new IllegalArgumentException(message, iae);
+ }
+ catch (InvocationTargetException ite)
+ {
+ if ( ite.getCause() instanceof Exception )
+ {
+ throw (Exception) ite.getCause();
+ }
+ else
+ {
+ throw ite;
+ }
+ }
+ }
+
+ public static Object get(Field field, Object target) throws Exception
+ {
+ boolean accessible = field.isAccessible();
+ try
+ {
+ field.setAccessible(true);
+ return field.get(target);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ String message = "Could not get field value by reflection: " + toString(field) +
+ " on: " + target.getClass().getName();
+ throw new IllegalArgumentException(message, iae);
+ }
+ finally
+ {
+ field.setAccessible(accessible);
+ }
+ }
+
+ public static void set(Field field, Object target, Object value) throws Exception
+ {
+ try
+ {
+ field.set(target, value);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ // target may be null if field is static so use field.getDeclaringClass() instead
+ String message = "Could not set field value by reflection: " + toString(field) +
+ " on: " + field.getDeclaringClass().getName();
+ if (value==null)
+ {
+ message += " with null value";
+ }
+ else
+ {
+ message += " with value: " + value.getClass();
+ }
+ throw new IllegalArgumentException(message, iae);
+ }
+ }
+
+ public static Object getAndWrap(Field field, Object target)
+ {
+ boolean accessible = field.isAccessible();
+ try
+ {
+ field.setAccessible(true);
+ return get(field, target);
+ }
+ catch (Exception e)
+ {
+ if (e instanceof RuntimeException)
+ {
+ throw (RuntimeException) e;
+ }
+ else
+ {
+ throw new IllegalArgumentException("exception setting: " + field.getName(), e);
+ }
+ }
+ finally
+ {
+ field.setAccessible(accessible);
+ }
+ }
+
+ public static void setAndWrap(Field field, Object target, Object value)
+ {
+ boolean accessible = field.isAccessible();
+ try
+ {
+ field.setAccessible(true);
+ set(field, target, value);
+ }
+ catch (Exception e)
+ {
+ if (e instanceof RuntimeException)
+ {
+ throw (RuntimeException) e;
+ }
+ else
+ {
+ throw new IllegalArgumentException("exception setting: " + field.getName(), e);
+ }
+ }
+ finally
+ {
+ field.setAccessible(accessible);
+ }
+ }
+
+ public static Object invokeAndWrap(Method method, Object target, Object... args)
+ {
+ try
+ {
+ return invoke(method, target, args);
+ }
+ catch (Exception e)
+ {
+ if (e instanceof RuntimeException)
+ {
+ throw (RuntimeException) e;
+ }
+ else
+ {
+ throw new RuntimeException("exception invoking: " + method.getName(), e);
+ }
+ }
+ }
+
+ public static String toString(Method method)
+ {
+ return Strings.unqualify( method.getDeclaringClass().getName() ) +
+ '.' +
+ method.getName() +
+ '(' +
+ Strings.toString( ", ", method.getParameterTypes() ) +
+ ')';
+ }
+
+ public static String toString(Member member)
+ {
+ return Strings.unqualify( member.getDeclaringClass().getName() ) +
+ '.' +
+ member.getName();
+ }
+
+ public static Class classForName(String name) throws ClassNotFoundException
+ {
+ try
+ {
+ return Thread.currentThread().getContextClassLoader().loadClass(name);
+ }
+ catch (Exception e)
+ {
+ return Class.forName(name);
+ }
+ }
+
+ /**
+ * Return's true if the class can be loaded using Reflections.classForName()
+ */
+ public static boolean isClassAvailable(String name)
+ {
+ try
+ {
+ classForName(name);
+ }
+ catch (ClassNotFoundException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public static Class getCollectionElementType(Type collectionType)
+ {
+ if ( !(collectionType instanceof ParameterizedType) )
+ {
+ throw new IllegalArgumentException("collection type not parameterized");
+ }
+ Type[] typeArguments = ( (ParameterizedType) collectionType ).getActualTypeArguments();
+ if (typeArguments.length==0)
+ {
+ throw new IllegalArgumentException("no type arguments for collection type");
+ }
+ Type typeArgument = typeArguments.length==1 ? typeArguments[0] : typeArguments[1]; //handle Maps
+ if (typeArgument instanceof ParameterizedType)
+ {
+ typeArgument = ((ParameterizedType) typeArgument).getRawType();
+ }
+ if ( !(typeArgument instanceof Class) )
+ {
+ throw new IllegalArgumentException("type argument not a class");
+ }
+ return (Class) typeArgument;
+ }
+
+ public static Class getMapKeyType(Type collectionType)
+ {
+ if ( !(collectionType instanceof ParameterizedType) )
+ {
+ throw new IllegalArgumentException("collection type not parameterized");
+ }
+ Type[] typeArguments = ( (ParameterizedType) collectionType ).getActualTypeArguments();
+ if (typeArguments.length==0)
+ {
+ throw new IllegalArgumentException("no type arguments for collection type");
+ }
+ Type typeArgument = typeArguments[0];
+ if ( !(typeArgument instanceof Class) )
+ {
+ throw new IllegalArgumentException("type argument not a class");
+ }
+ return (Class) typeArgument;
+ }
+
+ public static Method getSetterMethod(Class clazz, String name)
+ {
+ Method[] methods = clazz.getMethods();
+ for (Method method: methods)
+ {
+ String methodName = method.getName();
+ if ( methodName.startsWith("set") && method.getParameterTypes().length==1 )
+ {
+ if ( Introspector.decapitalize( methodName.substring(3) ).equals(name) )
+ {
+ return method;
+ }
+ }
+ }
+ throw new IllegalArgumentException("no such setter method: " + clazz.getName() + '.' + name);
+ }
+
+ public static Method getGetterMethod(Class clazz, String name)
+ {
+ Method[] methods = clazz.getMethods();
+ for (Method method: methods)
+ {
+ String methodName = method.getName();
+ if ( method.getParameterTypes().length==0 )
+ {
+ if ( methodName.startsWith("get") )
+ {
+ if ( Introspector.decapitalize( methodName.substring(3) ).equals(name) )
+ {
+ return method;
+ }
+ }
+ else if ( methodName.startsWith("is") )
+ {
+ if ( Introspector.decapitalize( methodName.substring(2) ).equals(name) )
+ {
+ return method;
+ }
+ }
+ }
+ }
+ throw new IllegalArgumentException("no such getter method: " + clazz.getName() + '.' + name);
+ }
+
+ /**
+ * Get all the getter methods annotated with the given annotation. Returns an empty list if
+ * none are found
+ */
+ public static List<Method> getGetterMethods(Class clazz, Class annotation)
+ {
+ List<Method> methods = new ArrayList<Method>();
+ for (Method method : clazz.getMethods())
+ {
+ if (method.isAnnotationPresent(annotation))
+ {
+ methods.add(method);
+ }
+ }
+ return methods;
+ }
+
+ public static Field getField(Class clazz, String name)
+ {
+ for ( Class superClass = clazz; superClass!=Object.class; superClass=superClass.getSuperclass() )
+ {
+ try
+ {
+ return superClass.getDeclaredField(name);
+ }
+ catch (NoSuchFieldException nsfe) {}
+ }
+ throw new IllegalArgumentException("no such field: " + clazz.getName() + '.' + name);
+ }
+
+ /**
+ * Get all the fields which are annotated with the given annotation. Returns an empty list
+ * if none are found
+ */
+ public static List<Field> getFields(Class clazz, Class annotation)
+ {
+ List<Field> fields = new ArrayList<Field>();
+ for (Class superClass = clazz; superClass!=Object.class; superClass=superClass.getSuperclass())
+ {
+ for (Field field : superClass.getDeclaredFields())
+ {
+ if (field.isAnnotationPresent(annotation))
+ {
+ fields.add(field);
+ }
+ }
+ }
+ return fields;
+ }
+
+ public static Method getMethod(Annotation annotation, String name)
+ {
+ try
+ {
+ return annotation.annotationType().getMethod(name);
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ return null;
+ }
+ }
+
+ public static Method getMethod(Class clazz, String name)
+ {
+ for ( Class superClass = clazz; superClass!=Object.class; superClass=superClass.getSuperclass() )
+ {
+ try
+ {
+ return superClass.getDeclaredMethod(name);
+ }
+ catch (NoSuchMethodException nsme) {}
+ }
+ throw new IllegalArgumentException("no such method: " + clazz.getName() + '.' + name);
+ }
+
+ /**
+ * Check to see if clazz is an instance of name
+ */
+ public static boolean isInstanceOf(Class clazz, String name)
+ {
+ if (name == null)
+ {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+ for (Class c = clazz; c != Object.class; c = c.getSuperclass())
+ {
+ if (instanceOf(c, name))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean instanceOf(Class clazz, String name)
+ {
+ if (name.equals(clazz.getName()))
+ {
+ return true;
+ }
+ else
+ {
+ boolean found = false;
+ Class[] interfaces = clazz.getInterfaces();
+ for (int i = 0; i < interfaces.length && !found; i++)
+ {
+ found = instanceOf(interfaces[i], name);
+ }
+ return found;
+ }
+
+ }
+
+}
Added: modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Strings.java
===================================================================
--- modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Strings.java (rev 0)
+++ modules/trunk/persistence/src/main/java/org/jboss/seam/persistence/util/Strings.java 2009-04-27 12:48:53 UTC (rev 10650)
@@ -0,0 +1,147 @@
+package org.jboss.seam.persistence.util;
+
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.StringTokenizer;
+
+/**
+ * @author <a href="mailto:theute at jboss.org">Thomas Heute</a>
+ */
+public class Strings
+{
+
+ public static String unqualify(String name)
+ {
+ return unqualify(name, '.');
+ }
+
+ public static String unqualify(String name, char sep)
+ {
+ return name.substring( name.lastIndexOf(sep)+1, name.length() );
+ }
+
+ public static boolean isEmpty(String string)
+ {
+ int len;
+ if (string == null || (len = string.length()) == 0)
+ {
+ return true;
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ if ((Character.isWhitespace(string.charAt(i)) == false))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static String nullIfEmpty(String string)
+ {
+ return isEmpty(string) ? null : string;
+ }
+
+ public static String emptyIfNull(String string)
+ {
+ return string == null ? "" : string;
+ }
+
+ public static String toString(Object component)
+ {
+ try {
+ PropertyDescriptor[] props = Introspector.getBeanInfo( component.getClass() )
+ .getPropertyDescriptors();
+ StringBuilder builder = new StringBuilder();
+ for (PropertyDescriptor descriptor : props)
+ {
+ builder.append( descriptor.getName() )
+ .append('=')
+ .append( descriptor.getReadMethod().invoke(component) )
+ .append("; ");
+ }
+ return builder.toString();
+ }
+ catch (Exception e) {
+ return "";
+ }
+ }
+
+ public static String[] split(String strings, String delims)
+ {
+ if (strings==null)
+ {
+ return new String[0];
+ }
+ else
+ {
+ StringTokenizer tokens = new StringTokenizer(strings, delims);
+ String[] result = new String[ tokens.countTokens() ];
+ int i=0;
+ while ( tokens.hasMoreTokens() )
+ {
+ result[i++] = tokens.nextToken();
+ }
+ return result;
+ }
+ }
+
+ public static String toString(Object... objects)
+ {
+ return toString(" ", objects);
+ }
+
+ public static String toString(String sep, Object... objects)
+ {
+ if (objects.length==0) return "";
+ StringBuilder builder = new StringBuilder();
+ for (Object object: objects)
+ {
+ builder.append(sep).append(object);
+ }
+ return builder.substring(sep.length());
+ }
+
+ public static String toClassNameString(String sep, Object... objects)
+ {
+ if (objects.length==0) return "";
+ StringBuilder builder = new StringBuilder();
+ for (Object object: objects)
+ {
+ builder.append(sep);
+ if (object==null)
+ {
+ builder.append("null");
+ }
+ else
+ {
+ builder.append( object.getClass().getName() );
+ }
+ }
+ return builder.substring(sep.length());
+ }
+
+ public static String toString(String sep, Class... classes)
+ {
+ if (classes.length==0) return "";
+ StringBuilder builder = new StringBuilder();
+ for (Class clazz: classes)
+ {
+ builder.append(sep).append( clazz.getName() );
+ }
+ return builder.substring(sep.length());
+ }
+
+ public static String toString(InputStream in) throws IOException {
+ final StringBuilder out = new StringBuilder();
+ final byte[] b = new byte[4096];
+ for ( int n; (n = in.read(b)) != -1; )
+ {
+ out.append(new String(b, 0, n));
+ }
+ return out.toString();
+ }
+}
More information about the seam-commits
mailing list