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 public ValueEncoder create(Class type) 106 { 107 return new HibernateEntityValueEncoder(entityClass, persistentClass, session, propertyAccess, 108 typeCoercer, loggerSource.getLogger(entityClass)); 109 } 110 }; 111 112 configuration.add(entityClass, factory); 113 114 } 115 } 116 } 117 118 /** 119 * Contributes the following: 120 * <dl> 121 * <dt>entity</dt> 122 * <dd>Stores the id of the entity and reloads from the {@link Session}</dd> 123 * </dl> 124 */ 125 public static void contributePersistentFieldManager( 126 MappedConfiguration<String, PersistentFieldStrategy> configuration) 127 { 128 configuration.addInstance(HibernatePersistenceConstants.ENTITY, EntityPersistentFieldStrategy.class); 129 } 130 131 /** 132 * Contributes the following strategy: 133 * <dl> 134 * <dt>entity</dt> 135 * <dd>Stores the id of the entity and reloads from the {@link Session}</dd> 136 * </dl> 137 */ 138 public void contributeApplicationStatePersistenceStrategySource( 139 MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration) 140 { 141 configuration 142 .addInstance(HibernatePersistenceConstants.ENTITY, EntityApplicationStatePersistenceStrategy.class); 143 } 144 145 /** 146 * Contributes {@link ApplicationStateContribution}s for all registered Hibernate entity classes. 147 * 148 * @param configuration 149 * Configuration to contribute 150 * @param entitySessionStatePersistenceStrategyEnabled 151 * indicates if contribution should take place 152 * @param sessionSource 153 * creates Hibernate session 154 */ 155 public static void contributeApplicationStateManager( 156 MappedConfiguration<Class, ApplicationStateContribution> configuration, 157 @Symbol(HibernateSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED) 158 boolean entitySessionStatePersistenceStrategyEnabled, HibernateSessionSource sessionSource) 159 { 160 161 if (!entitySessionStatePersistenceStrategyEnabled) 162 return; 163 164 org.hibernate.cfg.Configuration config = sessionSource.getConfiguration(); 165 Iterator<PersistentClass> mappings = config.getClassMappings(); 166 while (mappings.hasNext()) 167 { 168 169 final PersistentClass persistentClass = mappings.next(); 170 final Class entityClass = persistentClass.getMappedClass(); 171 172 configuration.add(entityClass, new ApplicationStateContribution(HibernatePersistenceConstants.ENTITY)); 173 } 174 } 175 176 /** 177 * Adds the CommitAfter annotation work, to process the 178 * {@link org.apache.tapestry5.hibernate.annotations.CommitAfter} annotation. 179 */ 180 @Contribute(ComponentClassTransformWorker2.class) 181 @Primary 182 public static void provideCommitAfterAnnotationSupport( 183 OrderedConfiguration<ComponentClassTransformWorker2> configuration) 184 { 185 // If logging is enabled, we want logging to be the first advice, wrapping around the commit advice. 186 187 configuration.addInstance("CommitAfter", CommitAfterWorker.class, "after:Log"); 188 } 189 190 @Contribute(DashboardManager.class) 191 public static void provideHibernateDashboardTab(OrderedConfiguration<DashboardTab> configuration) 192 { 193 configuration.add("HibernateStatistics", new DashboardTab("Hibernate", "core/HibernateStatistics"), "after:Services"); 194 } 195}