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