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