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}