    001// Copyright 2011-2014 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007// http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014
    015package org.apache.tapestry5.jpa.modules;
    016
    017import java.util.Collection;
    018
    019import javax.persistence.EntityManagerFactory;
    020import javax.persistence.metamodel.EntityType;
    021import javax.persistence.metamodel.Metamodel;
    022import javax.persistence.spi.PersistenceUnitInfo;
    023
    024import org.apache.tapestry5.ValueEncoder;
    025import org.apache.tapestry5.commons.Configuration;
    026import org.apache.tapestry5.commons.MappedConfiguration;
    027import org.apache.tapestry5.commons.ObjectProvider;
    028import org.apache.tapestry5.commons.OrderedConfiguration;
    029import org.apache.tapestry5.commons.services.PropertyAccess;
    030import org.apache.tapestry5.commons.services.TypeCoercer;
    031import org.apache.tapestry5.http.internal.TapestryHttpInternalConstants;
    032import org.apache.tapestry5.internal.jpa.CommitAfterWorker;
    033import org.apache.tapestry5.internal.jpa.EntityApplicationStatePersistenceStrategy;
    034import org.apache.tapestry5.internal.jpa.EntityManagerManagerImpl;
    035import org.apache.tapestry5.internal.jpa.EntityManagerObjectProvider;
    036import org.apache.tapestry5.internal.jpa.EntityManagerSourceImpl;
    037import org.apache.tapestry5.internal.jpa.EntityPersistentFieldStrategy;
    038import org.apache.tapestry5.internal.jpa.EntityTransactionManagerImpl;
    039import org.apache.tapestry5.internal.jpa.JpaTransactionAdvisorImpl;
    040import org.apache.tapestry5.internal.jpa.JpaValueEncoder;
    041import org.apache.tapestry5.internal.jpa.PackageNamePersistenceUnitConfigurer;
    042import org.apache.tapestry5.internal.jpa.PersistenceContextWorker;
    043import org.apache.tapestry5.internal.services.PersistentFieldManager;
    044import org.apache.tapestry5.ioc.LoggerSource;
    045import org.apache.tapestry5.ioc.ScopeConstants;
    046import org.apache.tapestry5.ioc.ServiceBinder;
    047import org.apache.tapestry5.ioc.annotations.Contribute;
    048import org.apache.tapestry5.ioc.annotations.Primary;
    049import org.apache.tapestry5.ioc.annotations.Scope;
    050import org.apache.tapestry5.ioc.annotations.Startup;
    051import org.apache.tapestry5.ioc.annotations.Symbol;
    052import org.apache.tapestry5.ioc.services.FactoryDefaults;
    053import org.apache.tapestry5.ioc.services.MasterObjectProvider;
    054import org.apache.tapestry5.ioc.services.PerthreadManager;
    055import org.apache.tapestry5.ioc.services.SymbolProvider;
    056import org.apache.tapestry5.jpa.EntityManagerManager;
    057import org.apache.tapestry5.jpa.EntityManagerSource;
    058import org.apache.tapestry5.jpa.EntityTransactionManager;
    059import org.apache.tapestry5.jpa.JpaEntityPackageManager;
    060import org.apache.tapestry5.jpa.JpaPersistenceConstants;
    061import org.apache.tapestry5.jpa.JpaSymbols;
    062import org.apache.tapestry5.jpa.JpaTransactionAdvisor;
    063import org.apache.tapestry5.jpa.PersistenceUnitConfigurer;
    064import org.apache.tapestry5.services.ApplicationStateContribution;
    065import org.apache.tapestry5.services.ApplicationStateManager;
    066import org.apache.tapestry5.services.ApplicationStatePersistenceStrategy;
    067import org.apache.tapestry5.services.ApplicationStatePersistenceStrategySource;
    068import org.apache.tapestry5.services.PersistentFieldStrategy;
    069import org.apache.tapestry5.services.ValueEncoderFactory;
    070import org.apache.tapestry5.services.ValueEncoderSource;
    071import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
    072import org.slf4j.Logger;
    073
    074/**
    075 * Defines core services for JPA support.
    076 *
    077 * @since 5.3
    078 */
    079public class JpaModule
    080{
    081    public static void bind(final ServiceBinder binder)
    082    {
    083        binder.bind(JpaTransactionAdvisor.class, JpaTransactionAdvisorImpl.class);
    084        binder.bind(PersistenceUnitConfigurer.class, PackageNamePersistenceUnitConfigurer.class).withSimpleId();
    085        binder.bind(EntityManagerSource.class, EntityManagerSourceImpl.class);
    086        binder.bind(EntityTransactionManager.class, EntityTransactionManagerImpl.class);
    087
    088    }
    089
    090    public static JpaEntityPackageManager buildJpaEntityPackageManager(final Collection<String> packageNames)
    091    {
    092        return new JpaEntityPackageManager()
    093        {
    094            @Override
    095            public Collection<String> getPackageNames()
    096            {
    097                return packageNames;
    098            }
    099        };
    100    }
    101
    102    @Scope(ScopeConstants.PERTHREAD)
    103    public static EntityManagerManager buildEntityManagerManager(final EntityManagerSource entityManagerSource,
    104                                                                 final PerthreadManager perthreadManager, final Logger logger)
    105    {
    106        final EntityManagerManagerImpl service = new EntityManagerManagerImpl(entityManagerSource, logger);
    107
    108        perthreadManager.addThreadCleanupListener(service);
    109
    110        return service;
    111    }
    112
    113    @Contribute(JpaEntityPackageManager.class)
    114    public static void provideEntityPackages(Configuration<String> configuration,
    115
    116                                             @Symbol(TapestryHttpInternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
    117                                             String appRootPackage)
    118    {
    119        configuration.add(appRootPackage + ".entities");
    120    }
    121
    122    @Contribute(PersistentFieldManager.class)
    123    public static void provideEntityPersistentFieldStrategies(
    124            final MappedConfiguration<String, PersistentFieldStrategy> configuration)
    125    {
    126        configuration.addInstance(JpaPersistenceConstants.ENTITY, EntityPersistentFieldStrategy.class);
    127    }
    128
    129    @Contribute(ApplicationStatePersistenceStrategySource.class)
    130    public void provideApplicationStatePersistenceStrategies(
    131            final MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration)
    132    {
    133        configuration.addInstance(JpaPersistenceConstants.ENTITY, EntityApplicationStatePersistenceStrategy.class);
    134    }
    135
    136    @Contribute(ComponentClassTransformWorker2.class)
    137    @Primary
    138    public static void provideClassTransformWorkers(OrderedConfiguration<ComponentClassTransformWorker2> configuration)
    139    {
    140        configuration.addInstance("PersistenceContext", PersistenceContextWorker.class, "after:Property");
    141        configuration.addInstance("JPACommitAfter", CommitAfterWorker.class, "after:Log");
    142    }
    143
    144    @Contribute(MasterObjectProvider.class)
    145    public static void provideObjectProviders(final OrderedConfiguration<ObjectProvider> configuration)
    146    {
    147        configuration.addInstance("EntityManager", EntityManagerObjectProvider.class,
    148                "before:AnnotationBasedContributions");
    149    }
    150
    151    @Contribute(SymbolProvider.class)
    152    @FactoryDefaults
    153    public static void provideFactoryDefaults(final MappedConfiguration<String, String> configuration)
    154    {
    155        configuration.add(JpaSymbols.PROVIDE_ENTITY_VALUE_ENCODERS, "true");
    156        configuration.add(JpaSymbols.EARLY_START_UP, "true");
    157        configuration.add(JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED, "true");
    158        configuration.add(JpaSymbols.PERSISTENCE_DESCRIPTOR, "/META-INF/persistence.xml");
    159    }
    160
    161    @Contribute(ValueEncoderSource.class)
    162    public static void provideValueEncoders(final MappedConfiguration<Class, ValueEncoderFactory> configuration,
    163                                            @Symbol(JpaSymbols.PROVIDE_ENTITY_VALUE_ENCODERS)
    164                                            final boolean provideEncoders, final EntityManagerSource entityManagerSource,
    165                                            final EntityManagerManager entityManagerManager, final TypeCoercer typeCoercer,
    166                                            final PropertyAccess propertyAccess, final LoggerSource loggerSource)
    167    {
    168
    169        if (!provideEncoders)
    170            return;
    171
    172        for (final PersistenceUnitInfo info : entityManagerSource.getPersistenceUnitInfos())
    173        {
    174            final EntityManagerFactory emf = entityManagerSource.getEntityManagerFactory(info.getPersistenceUnitName());
    175
    176            final Metamodel metamodel = emf.getMetamodel();
    177
    178            for (final EntityType<?> entity : metamodel.getEntities())
    179            {
    180                final Class<?> javaType = entity.getJavaType();
    181
    182                final ValueEncoderFactory factory = new ValueEncoderFactory()
    183                {
    184                    @Override
    185                    public ValueEncoder create(final Class type)
    186                    {
    187                        return new JpaValueEncoder(entity, entityManagerManager, info.getPersistenceUnitName(),
    188                                propertyAccess, typeCoercer, loggerSource.getLogger(javaType));
    189                    }
    190                };
    191
    192                configuration.add(javaType, factory);
    193            }
    194        }
    195    }
    196
    197    @Contribute(ApplicationStateManager.class)
    198    public static void provideApplicationStateContributions(
    199            final MappedConfiguration<Class, ApplicationStateContribution> configuration,
    200            final EntityManagerSource entityManagerSource,
    201            @Symbol(JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED)
    202            final boolean entitySessionStatePersistenceStrategyEnabled)
    203    {
    204
    205        if (!entitySessionStatePersistenceStrategyEnabled)
    206            return;
    207
    208        for (final PersistenceUnitInfo info : entityManagerSource.getPersistenceUnitInfos())
    209        {
    210            final EntityManagerFactory emf = entityManagerSource.getEntityManagerFactory(info.getPersistenceUnitName());
    211
    212            final Metamodel metamodel = emf.getMetamodel();
    213
    214            for (EntityType<?> entity : metamodel.getEntities())
    215            {
    216                configuration.add(entity.getJavaType(), new ApplicationStateContribution(JpaPersistenceConstants.ENTITY));
    217            }
    218
    219        }
    220    }
    221
    222    @Startup
    223    public static void startupEarly(final EntityManagerManager entityManagerManager, @Symbol(JpaSymbols.EARLY_START_UP)
    224    final boolean earlyStartup)
    225    {
    226        if (earlyStartup)
    227        {
    228            entityManagerManager.getEntityManagers();
    229        }
    230    }
    231}