    001    // Copyright 2011 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
    015    package org.apache.tapestry5.jpa;
    016
    017    import org.apache.tapestry5.ValueEncoder;
    018    import org.apache.tapestry5.internal.InternalConstants;
    019    import org.apache.tapestry5.internal.jpa.*;
    020    import org.apache.tapestry5.internal.services.PersistentFieldManager;
    021    import org.apache.tapestry5.ioc.*;
    022    import org.apache.tapestry5.ioc.annotations.*;
    023    import org.apache.tapestry5.ioc.services.*;
    024    import org.apache.tapestry5.services.*;
    025    import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
    026    import org.slf4j.Logger;
    027
    028    import javax.persistence.EntityManagerFactory;
    029    import javax.persistence.metamodel.EntityType;
    030    import javax.persistence.metamodel.Metamodel;
    031    import javax.persistence.spi.PersistenceUnitInfo;
    032    import java.util.Collection;
    033    import java.util.Map;
    034
    035    /**
    036     * Defines core services for JPA support.
    037     *
    038     * @since 5.3
    039     */
    040    public class JpaModule
    041    {
    042        public static void bind(final ServiceBinder binder)
    043        {
    044            binder.bind(JpaTransactionAdvisor.class, JpaTransactionAdvisorImpl.class);
    045            binder.bind(PersistenceUnitConfigurer.class, PackageNamePersistenceUnitConfigurer.class).withSimpleId();
    046            binder.bind(EntityManagerSource.class, EntityManagerSourceImpl.class);
    047        }
    048
    049        public static JpaEntityPackageManager buildJpaEntityPackageManager(final Collection<String> packageNames)
    050        {
    051            return new JpaEntityPackageManager()
    052            {
    053                public Collection<String> getPackageNames()
    054                {
    055                    return packageNames;
    056                }
    057            };
    058        }
    059
    060        @Scope(ScopeConstants.PERTHREAD)
    061        public static EntityManagerManager buildEntityManagerManager(final EntityManagerSource entityManagerSource,
    062                                                                     final PerthreadManager perthreadManager, final Logger logger)
    063        {
    064            final EntityManagerManagerImpl service = new EntityManagerManagerImpl(entityManagerSource, logger);
    065
    066            perthreadManager.addThreadCleanupListener(service);
    067
    068            return service;
    069        }
    070
    071        @Contribute(JpaEntityPackageManager.class)
    072        public static void provideEntityPackages(Configuration<String> configuration,
    073
    074                                                 @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
    075                                                 String appRootPackage)
    076        {
    077            configuration.add(appRootPackage + ".entities");
    078        }
    079
    080        @Contribute(PersistentFieldManager.class)
    081        public static void provideEntityPersistentFieldStrategies(
    082                final MappedConfiguration<String, PersistentFieldStrategy> configuration)
    083        {
    084            configuration.addInstance(JpaPersistenceConstants.ENTITY, EntityPersistentFieldStrategy.class);
    085        }
    086
    087        @Contribute(ApplicationStatePersistenceStrategySource.class)
    088        public void provideApplicationStatePersistenceStrategies(
    089                final MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration)
    090        {
    091            configuration.addInstance(JpaPersistenceConstants.ENTITY, EntityApplicationStatePersistenceStrategy.class);
    092        }
    093
    094        @Contribute(ComponentClassTransformWorker2.class)
    095        @Primary
    096        public static void provideClassTransformWorkers(OrderedConfiguration<ComponentClassTransformWorker2> configuration)
    097        {
    098            configuration.addInstance("PersistenceContext", PersistenceContextWorker.class, "after:Property");
    099            configuration.addInstance("JPACommitAfter", CommitAfterWorker.class, "after:Log");
    100        }
    101
    102        @Contribute(MasterObjectProvider.class)
    103        public static void provideObjectProviders(final OrderedConfiguration<ObjectProvider> configuration)
    104        {
    105            configuration.addInstance("EntityManager", EntityManagerObjectProvider.class,
    106                    "before:AnnotationBasedContributions");
    107        }
    108
    109        @Contribute(SymbolProvider.class)
    110        @FactoryDefaults
    111        public static void provideFactoryDefaults(final MappedConfiguration<String, String> configuration)
    112        {
    113            configuration.add(JpaSymbols.PROVIDE_ENTITY_VALUE_ENCODERS, "true");
    114            configuration.add(JpaSymbols.EARLY_START_UP, "true");
    115            configuration.add(JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED, "true");
    116            configuration.add(JpaSymbols.PERSISTENCE_DESCRIPTOR, "/META-INF/persistence.xml");
    117        }
    118
    119        @Contribute(ValueEncoderSource.class)
    120        public static void provideValueEncoders(final MappedConfiguration<Class, ValueEncoderFactory> configuration,
    121                                                @Symbol(JpaSymbols.PROVIDE_ENTITY_VALUE_ENCODERS)
    122                                                final boolean provideEncoders, final EntityManagerSource entityManagerSource,
    123                                                final EntityManagerManager entityManagerManager, final TypeCoercer typeCoercer,
    124                                                final PropertyAccess propertyAccess, final LoggerSource loggerSource)
    125        {
    126
    127            if (!provideEncoders)
    128                return;
    129
    130            for (final PersistenceUnitInfo info : entityManagerSource.getPersistenceUnitInfos())
    131            {
    132                final EntityManagerFactory emf = entityManagerSource.getEntityManagerFactory(info.getPersistenceUnitName());
    133
    134                final Metamodel metamodel = emf.getMetamodel();
    135
    136                for (final EntityType<?> entity : metamodel.getEntities())
    137                {
    138                    final Class<?> javaType = entity.getJavaType();
    139
    140                    final ValueEncoderFactory factory = new ValueEncoderFactory()
    141                    {
    142                        public ValueEncoder create(final Class type)
    143                        {
    144                            return new JpaValueEncoder(entity, entityManagerManager, info.getPersistenceUnitName(),
    145                                    propertyAccess, typeCoercer, loggerSource.getLogger(javaType));
    146                        }
    147                    };
    148
    149                    configuration.add(javaType, factory);
    150                }
    151            }
    152        }
    153
    154        @Contribute(ApplicationStateManager.class)
    155        public static void provideApplicationStateContributions(
    156                final MappedConfiguration<Class, ApplicationStateContribution> configuration,
    157                final EntityManagerSource entityManagerSource,
    158                @Symbol(JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED)
    159                final boolean entitySessionStatePersistenceStrategyEnabled)
    160        {
    161
    162            if (!entitySessionStatePersistenceStrategyEnabled)
    163                return;
    164
    165            for (final PersistenceUnitInfo info : entityManagerSource.getPersistenceUnitInfos())
    166            {
    167                final EntityManagerFactory emf = entityManagerSource.getEntityManagerFactory(info.getPersistenceUnitName());
    168
    169                final Metamodel metamodel = emf.getMetamodel();
    170
    171                for (EntityType<?> entity : metamodel.getEntities())
    172                {
    173                    configuration.add(entity.getJavaType(), new ApplicationStateContribution(JpaPersistenceConstants.ENTITY));
    174                }
    175
    176            }
    177        }
    178
    179        @Startup
    180        public static void startupEarly(final EntityManagerManager entityManagerManager, @Symbol(JpaSymbols.EARLY_START_UP)
    181        final boolean earlyStartup)
    182        {
    183            if (!earlyStartup)
    184                return;
    185
    186            entityManagerManager.getEntityManagers();
    187
    188        }
    189    }