Package org.jboss.seam.persistence

Source Code of org.jboss.seam.persistence.ManagedPersistenceContextExtension

/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and/or its affiliates, and individual
* contributors by the @authors tag. See the copyright.txt in the
* distribution for a full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.seam.persistence;

import org.jboss.logging.Logger;
import org.jboss.seam.persistence.util.EnvironmentUtils;
import org.jboss.seam.solder.bean.BeanBuilder;
import org.jboss.seam.solder.bean.Beans;
import org.jboss.seam.solder.bean.ContextualLifecycle;
import org.jboss.seam.solder.core.ExtensionManaged;
import org.jboss.seam.solder.literal.AnyLiteral;
import org.jboss.seam.solder.literal.ApplicationScopedLiteral;
import org.jboss.seam.solder.literal.DefaultLiteral;
import org.jboss.seam.solder.reflection.Reflections;
import org.jboss.seam.solder.reflection.annotated.AnnotatedTypeBuilder;
import org.jboss.seam.solder.reflection.annotated.Annotateds;
import org.jboss.seam.solder.util.service.ServiceLoader;

import javax.annotation.Resource;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AnnotatedCallable;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMember;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceUnit;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* Extension the wraps producer methods/fields that produce an entity manager
* factory to turn them into Seam Managed Persistence Contexts.
*
*
* @author Stuart Douglas
*
*/
public class ManagedPersistenceContextExtension implements Extension
{

   Set<Bean<?>> beans = new HashSet<Bean<?>>();

   List<SeamPersistenceProvider> persistenceProviders = new ArrayList<SeamPersistenceProvider>();

   private static final Logger log = Logger.getLogger(ManagedPersistenceContextExtension.class);

   public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event)
   {
      // we manually add Hibernate first.
      // we do not use the ServiceLoader approach for this, because it will blow
      // up if Hibernate is not on the classpath
      try
      {
         Class<?> hibernateProviderClass = Reflections.classForName("org.jboss.seam.persistence.HibernatePersistenceProvider", this.getClass().getClassLoader());
         SeamPersistenceProvider provider = (SeamPersistenceProvider) hibernateProviderClass.newInstance();
         persistenceProviders.add(provider);
      }
      catch (NoClassDefFoundError e)
      {
         log.debug("Hibernate not found on class path, HibernatePersistenceProvider not loaded.");
      }
      catch (ClassNotFoundException e)
      {
         log.debug("Hibernate not found on class path, HibernatePersistenceProvider not loaded.");
      }
      catch (InstantiationException e)
      {
         log.debug("InstantiationException creating HibernatePersistenceProvider: HibernatePersistenceProvider not loaded.");
      }
      catch (IllegalAccessException e)
      {
         log.error("IllegalAccessException creating HibernatePersistenceProvider: HibernatePersistenceProvider not loaded.");
      }

      ServiceLoader<SeamPersistenceProvider> providers = ServiceLoader.load(SeamPersistenceProvider.class);
      for (SeamPersistenceProvider i : providers)
      {
         persistenceProviders.add(i);
      }
      // this is always the last one considered
      persistenceProviders.add(new DefaultPersistenceProvider());
   }

   /**
    * loops through the fields on an AnnotatedType looking for a @PersistnceUnit
    * producer field that is annotated {@link org.jboss.seam.solder.core.ExtensionManaged}. Then a corresponding
    * smpc bean is created and registered. Any scope declaration on the producer
    * are removed as this is not supported by the spec
    *
    * For non-ee environments this extension also bootstraps @PersistenceUnit
    * producer fields
    *
    */
   public <T> void processAnnotatedType(@Observes final ProcessAnnotatedType<T> event, BeanManager manager)
   {
      AnnotatedTypeBuilder<T> modifiedType = null;
      for (AnnotatedField<? super T> field : event.getAnnotatedType().getFields())
      {
         boolean bootstrapped = false;
         if (field.isAnnotationPresent(PersistenceUnit.class) && field.isAnnotationPresent(Produces.class) && !EnvironmentUtils.isEEEnvironment())
         {
            bootstrapped = true;
            final String unitName = field.getAnnotation(PersistenceUnit.class).unitName();
            final Set<Annotation> qualifiers = Beans.getQualifiers(manager, field.getAnnotations());
            if (qualifiers.isEmpty())
            {
               qualifiers.add(DefaultLiteral.INSTANCE);
            }
            qualifiers.add(AnyLiteral.INSTANCE);
            beans.add(createEMFBean(unitName, qualifiers, event.getAnnotatedType(), manager));
         }
         // look for a seam managed persistence unit declaration on EE resource
         // producer fields
         if (field.isAnnotationPresent(ExtensionManaged.class) && (field.isAnnotationPresent(PersistenceUnit.class) || field.isAnnotationPresent(Resource.class)) && field.isAnnotationPresent(Produces.class) && EntityManagerFactory.class.isAssignableFrom(field.getJavaMember().getType()))
         {
            if (modifiedType == null)
            {
               modifiedType = new AnnotatedTypeBuilder().readFromType(event.getAnnotatedType());
            }
            Set<Annotation> qualifiers = new HashSet<Annotation>();
            Class<? extends Annotation> scope = Dependent.class;
            // get the qualifier and scope for the new bean
            for (Annotation annotation : field.getAnnotations())
            {
               if (manager.isQualifier(annotation.annotationType()))
               {
                  qualifiers.add(annotation);
               }
               else if (manager.isScope(annotation.annotationType()))
               {
                  scope = annotation.annotationType();
               }
            }
            if (qualifiers.isEmpty())
            {
               qualifiers.add(new DefaultLiteral());
            }
            qualifiers.add(AnyLiteral.INSTANCE);
            // we need to remove the scope, they are not nessesarily supported
            // on producer fields
            if (scope != Dependent.class)
            {
               modifiedType.removeFromField(field.getJavaMember(), scope);
            }
            if (bootstrapped)
            {
               modifiedType.removeFromField(field.getJavaMember(), Produces.class);
            }
            registerManagedPersistenceContext(qualifiers, scope, field.isAnnotationPresent(Alternative.class), manager, event.getAnnotatedType().getJavaClass().getClassLoader(), field, event.getAnnotatedType().getJavaClass());
            log.info("Configuring Seam Managed Persistence Context from producer field " + event.getAnnotatedType().getJavaClass().getName() + "." + field.getJavaMember().getName() + " with qualifiers " + qualifiers);
         }
         // now look for producer methods that produce an EntityManagerFactory.
         // This allows the user to manually configure an EntityManagerFactory
         // and return it from a producer method
      }
      // now look for SMPC's that are configured programatically via a producer
      // method. This looks for both EMF's and SessionFactories
      // The producer method has its scope changes to application scoped
      // this allows for programatic config of the SMPC
      for (AnnotatedMethod<? super T> method : event.getAnnotatedType().getMethods())
      {
         if (method.isAnnotationPresent(ExtensionManaged.class) && method.isAnnotationPresent(Produces.class) && EntityManagerFactory.class.isAssignableFrom(method.getJavaMember().getReturnType()))
         {
            if (modifiedType == null)
            {
               modifiedType = new AnnotatedTypeBuilder().readFromType(event.getAnnotatedType());
            }
            Set<Annotation> qualifiers = new HashSet<Annotation>();
            Class<? extends Annotation> scope = Dependent.class;
            // get the qualifier and scope for the new bean
            for (Annotation annotation : method.getAnnotations())
            {
               if (manager.isQualifier(annotation.annotationType()))
               {
                  qualifiers.add(annotation);
               }
               else if (manager.isScope(annotation.annotationType()))
               {
                  scope = annotation.annotationType();
               }
            }
            if (qualifiers.isEmpty())
            {
               qualifiers.add(new DefaultLiteral());
            }
            qualifiers.add(AnyLiteral.INSTANCE);
            // we need to change the scope to application scoped
            modifiedType.removeFromMethod(method.getJavaMember(), scope);
            modifiedType.addToMethod(method.getJavaMember(), ApplicationScopedLiteral.INSTANCE);
            registerManagedPersistenceContext(qualifiers, scope, method.isAnnotationPresent(Alternative.class), manager, event.getAnnotatedType().getJavaClass().getClassLoader(), method, event.getAnnotatedType().getJavaClass());
            log.info("Configuring Seam Managed Persistence Context from producer method " + event.getAnnotatedType().getJavaClass().getName() + "." + method.getJavaMember().getName() + " with qualifiers " + qualifiers);
         }
      }

      if (modifiedType != null)
      {
         event.setAnnotatedType(modifiedType.create());
      }
   }

   /**
    * Creates an EntityManagerFactory bean in a SE environment
    */
   private Bean<?> createEMFBean(final String unitName, final Set<Annotation> qualifiers, final AnnotatedType<?> type, final BeanManager beanManager)
   {
      BeanBuilder<EntityManagerFactory> builder = new BeanBuilder<EntityManagerFactory>(beanManager);
      Set<Type> types = new HashSet<Type>();
      types.add(EntityManagerFactory.class);
      types.add(Object.class);
      builder.beanClass(type.getJavaClass()).qualifiers(qualifiers).types(types);
      builder.beanLifecycle(new ContextualLifecycle<EntityManagerFactory>()
      {

         public void destroy(Bean<EntityManagerFactory> bean, EntityManagerFactory instance, CreationalContext<EntityManagerFactory> creationalContext)
         {
            instance.close();
            creationalContext.release();
         }

         public EntityManagerFactory create(Bean<EntityManagerFactory> bean, CreationalContext<EntityManagerFactory> creationalContext)
         {
            return Persistence.createEntityManagerFactory(unitName);
         }
      });
      return builder.create();
   }

   private void registerManagedPersistenceContext(Set<Annotation> qualifiers, Class<? extends Annotation> scope, boolean alternative, BeanManager manager, ClassLoader loader, AnnotatedMember<?> member, Class<?> declaringClass)
   {
      // we need to add all additional interfaces from our
      // SeamPersistenceProvider to the bean as at this stage we have no way of
      // knowing which persistence provider is actually in use. The only time
      // that this may cause slightly odd behaviour is if two providers are on
      // the class path, in which case the entity manager may be assignable to
      // additional interfaces that it does not support.
      Set<Class<?>> additionalInterfaces = new HashSet<Class<?>>();
      for (SeamPersistenceProvider i : persistenceProviders)
      {
         additionalInterfaces.addAll(i.getAdditionalEntityManagerInterfaces());
      }
      // create the new bean to be registered later
      ManagedPersistenceContextBeanLifecycle lifecycle = new ManagedPersistenceContextBeanLifecycle(qualifiers, loader, manager, additionalInterfaces, persistenceProviders);
      AnnotatedTypeBuilder<EntityManager> typeBuilder = new AnnotatedTypeBuilder().setJavaClass(EntityManager.class);
      BeanBuilder<EntityManager> builder = new BeanBuilder<EntityManager>(manager).readFromType(typeBuilder.create());
      builder.qualifiers(qualifiers);
      builder.scope(scope);
      builder.beanClass(member.getDeclaringType().getJavaClass());
      builder.getTypes().add(ManagedPersistenceContext.class);
      builder.getTypes().addAll(additionalInterfaces);
      builder.getTypes().add(Object.class);
      builder.beanLifecycle(lifecycle);
      builder.alternative(alternative);
      StringBuilder id = new StringBuilder("SMPC-" + ManagedPersistenceContextExtension.class.getName() + "-");
      if (member instanceof AnnotatedField<?>)
      {
         AnnotatedField<?> field = (AnnotatedField<?>) member;
         id.append(Annotateds.createFieldId(field));
      }
      else
      {
         AnnotatedCallable<?> method = (AnnotatedCallable<?>) member;
         id.append(Annotateds.createCallableId(method));
      }
      builder.id(id.toString());
      builder.passivationCapable(true);
      builder.toString("Seam Managed Persistence Context with qualifiers [" + qualifiers + "] with configured by [" + member + "] on class [" + declaringClass + "]");
      beans.add(builder.create());
   }

   public void afterBeanDiscovery(@Observes AfterBeanDiscovery event)
   {
      for (Bean<?> i : beans)
      {
         event.addBean(i);
      }

   }
}
TOP

Related Classes of org.jboss.seam.persistence.ManagedPersistenceContextExtension

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.