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    }