001// Copyright 2007-2013 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.hibernate.modules; 016 017import org.apache.tapestry5.ValueEncoder; 018import org.apache.tapestry5.hibernate.HibernateCore; 019import org.apache.tapestry5.hibernate.HibernatePersistenceConstants; 020import org.apache.tapestry5.hibernate.HibernateSessionSource; 021import org.apache.tapestry5.hibernate.HibernateSymbols; 022import org.apache.tapestry5.internal.InternalConstants; 023import org.apache.tapestry5.internal.hibernate.CommitAfterWorker; 024import org.apache.tapestry5.internal.hibernate.EntityApplicationStatePersistenceStrategy; 025import org.apache.tapestry5.internal.hibernate.EntityPersistentFieldStrategy; 026import org.apache.tapestry5.internal.hibernate.HibernateEntityValueEncoder; 027import org.apache.tapestry5.ioc.Configuration; 028import org.apache.tapestry5.ioc.LoggerSource; 029import org.apache.tapestry5.ioc.MappedConfiguration; 030import org.apache.tapestry5.ioc.OrderedConfiguration; 031import org.apache.tapestry5.ioc.annotations.Contribute; 032import org.apache.tapestry5.ioc.annotations.Primary; 033import org.apache.tapestry5.ioc.annotations.Symbol; 034import org.apache.tapestry5.ioc.services.PropertyAccess; 035import org.apache.tapestry5.ioc.services.ServiceOverride; 036import org.apache.tapestry5.ioc.services.TypeCoercer; 037import org.apache.tapestry5.services.ApplicationStateContribution; 038import org.apache.tapestry5.services.ApplicationStatePersistenceStrategy; 039import org.apache.tapestry5.services.PersistentFieldStrategy; 040import org.apache.tapestry5.services.ValueEncoderFactory; 041import org.apache.tapestry5.services.dashboard.DashboardManager; 042import org.apache.tapestry5.services.dashboard.DashboardTab; 043import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 044import org.hibernate.Session; 045import org.hibernate.mapping.PersistentClass; 046 047import java.util.Iterator; 048 049/** 050 * Supplements the services defined by {@link org.apache.tapestry5.hibernate.modules.HibernateCoreModule} with additional 051 * services and configuration specific to Tapestry web application. 052 */ 053public class HibernateModule 054{ 055 public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration) 056 { 057 configuration.add(HibernateSymbols.PROVIDE_ENTITY_VALUE_ENCODERS, "true"); 058 configuration.add(HibernateSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED, "false"); 059 } 060 061 /** 062 * Contributes the package "<root>.entities" to the configuration, so that it will be scanned for annotated 063 * entity classes. 064 */ 065 public static void contributeHibernateEntityPackageManager(Configuration<String> configuration, 066 067 @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM) 068 String appRootPackage) 069 { 070 configuration.add(appRootPackage + ".entities"); 071 } 072 073 @Contribute(ServiceOverride.class) 074 public static void provideInjectableSessionObject(MappedConfiguration<Class, Object> configuration, @HibernateCore 075 Session session) 076 { 077 configuration.add(Session.class, session); 078 } 079 080 /** 081 * Contributes {@link ValueEncoderFactory}s for all registered Hibernate entity classes. Encoding and decoding are 082 * based on the id property value of the entity using type coercion. Hence, if the id can be coerced to a String and 083 * back then the entity can be coerced. 084 */ 085 @SuppressWarnings("unchecked") 086 public static void contributeValueEncoderSource(MappedConfiguration<Class, ValueEncoderFactory> configuration, 087 @Symbol(HibernateSymbols.PROVIDE_ENTITY_VALUE_ENCODERS) 088 boolean provideEncoders, final HibernateSessionSource sessionSource, final Session session, 089 final TypeCoercer typeCoercer, final PropertyAccess propertyAccess, final LoggerSource loggerSource) 090 { 091 if (!provideEncoders) 092 return; 093 094 org.hibernate.cfg.Configuration config = sessionSource.getConfiguration(); 095 Iterator<PersistentClass> mappings = config.getClassMappings(); 096 while (mappings.hasNext()) 097 { 098 final PersistentClass persistentClass = mappings.next(); 099 final Class entityClass = persistentClass.getMappedClass(); 100 101 if (entityClass != null) 102 { 103 ValueEncoderFactory factory = new ValueEncoderFactory() 104 { 105 @Override 106 public ValueEncoder create(Class type) 107 { 108 return new HibernateEntityValueEncoder(entityClass, persistentClass, session, propertyAccess, 109 typeCoercer, loggerSource.getLogger(entityClass)); 110 } 111 }; 112 113 configuration.add(entityClass, factory); 114 115 } 116 } 117 } 118 119 /** 120 * Contributes the following: 121 * <dl> 122 * <dt>entity</dt> 123 * <dd>Stores the id of the entity and reloads from the {@link Session}</dd> 124 * </dl> 125 */ 126 public static void contributePersistentFieldManager( 127 MappedConfiguration<String, PersistentFieldStrategy> configuration) 128 { 129 configuration.addInstance(HibernatePersistenceConstants.ENTITY, EntityPersistentFieldStrategy.class); 130 } 131 132 /** 133 * Contributes the following strategy: 134 * <dl> 135 * <dt>entity</dt> 136 * <dd>Stores the id of the entity and reloads from the {@link Session}</dd> 137 * </dl> 138 */ 139 public void contributeApplicationStatePersistenceStrategySource( 140 MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration) 141 { 142 configuration 143 .addInstance(HibernatePersistenceConstants.ENTITY, EntityApplicationStatePersistenceStrategy.class); 144 } 145 146 /** 147 * Contributes {@link ApplicationStateContribution}s for all registered Hibernate entity classes. 148 * 149 * @param configuration 150 * Configuration to contribute 151 * @param entitySessionStatePersistenceStrategyEnabled 152 * indicates if contribution should take place 153 * @param sessionSource 154 * creates Hibernate session 155 */ 156 public static void contributeApplicationStateManager( 157 MappedConfiguration<Class, ApplicationStateContribution> configuration, 158 @Symbol(HibernateSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED) 159 boolean entitySessionStatePersistenceStrategyEnabled, HibernateSessionSource sessionSource) 160 { 161 162 if (!entitySessionStatePersistenceStrategyEnabled) 163 return; 164 165 org.hibernate.cfg.Configuration config = sessionSource.getConfiguration(); 166 Iterator<PersistentClass> mappings = config.getClassMappings(); 167 while (mappings.hasNext()) 168 { 169 170 final PersistentClass persistentClass = mappings.next(); 171 final Class entityClass = persistentClass.getMappedClass(); 172 173 configuration.add(entityClass, new ApplicationStateContribution(HibernatePersistenceConstants.ENTITY)); 174 } 175 } 176 177 /** 178 * Adds the CommitAfter annotation work, to process the 179 * {@link org.apache.tapestry5.hibernate.annotations.CommitAfter} annotation. 180 */ 181 @Contribute(ComponentClassTransformWorker2.class) 182 @Primary 183 public static void provideCommitAfterAnnotationSupport( 184 OrderedConfiguration<ComponentClassTransformWorker2> configuration) 185 { 186 // If logging is enabled, we want logging to be the first advice, wrapping around the commit advice. 187 188 configuration.addInstance("CommitAfter", CommitAfterWorker.class, "after:Log"); 189 } 190 191 @Contribute(DashboardManager.class) 192 public static void provideHibernateDashboardTab(OrderedConfiguration<DashboardTab> configuration) 193 { 194 configuration.add("HibernateStatistics", new DashboardTab("Hibernate", "core/HibernateStatistics"), "after:Services"); 195 } 196}