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.web.modules; 016 017import org.apache.tapestry5.ValueEncoder; 018import org.apache.tapestry5.commons.Configuration; 019import org.apache.tapestry5.commons.MappedConfiguration; 020import org.apache.tapestry5.commons.OrderedConfiguration; 021import org.apache.tapestry5.commons.services.PropertyAccess; 022import org.apache.tapestry5.commons.services.TypeCoercer; 023import org.apache.tapestry5.hibernate.HibernateCore; 024import org.apache.tapestry5.hibernate.HibernateSessionSource; 025import org.apache.tapestry5.hibernate.HibernateSymbols; 026import org.apache.tapestry5.hibernate.web.HibernatePersistenceConstants; 027import org.apache.tapestry5.hibernate.web.internal.CommitAfterWorker; 028import org.apache.tapestry5.hibernate.web.internal.EntityApplicationStatePersistenceStrategy; 029import org.apache.tapestry5.hibernate.web.internal.EntityPersistentFieldStrategy; 030import org.apache.tapestry5.hibernate.web.internal.HibernateEntityValueEncoder; 031import org.apache.tapestry5.http.internal.TapestryHttpInternalConstants; 032import org.apache.tapestry5.ioc.LoggerSource; 033import org.apache.tapestry5.ioc.annotations.Contribute; 034import org.apache.tapestry5.ioc.annotations.Primary; 035import org.apache.tapestry5.ioc.annotations.Symbol; 036import org.apache.tapestry5.ioc.services.ServiceOverride; 037import org.apache.tapestry5.services.ApplicationStateContribution; 038import org.apache.tapestry5.services.ApplicationStatePersistenceStrategy; 039import org.apache.tapestry5.services.ComponentClassResolver; 040import org.apache.tapestry5.services.LibraryMapping; 041import org.apache.tapestry5.services.PersistentFieldStrategy; 042import org.apache.tapestry5.services.ValueEncoderFactory; 043import org.apache.tapestry5.services.dashboard.DashboardManager; 044import org.apache.tapestry5.services.dashboard.DashboardTab; 045import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 046import org.hibernate.Session; 047import org.hibernate.metadata.ClassMetadata; 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(TapestryHttpInternalConstants.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( 087 MappedConfiguration<Class, ValueEncoderFactory> configuration, 088 @Symbol(HibernateSymbols.PROVIDE_ENTITY_VALUE_ENCODERS) boolean provideEncoders, 089 final HibernateSessionSource sessionSource, final Session session, 090 final TypeCoercer typeCoercer, final PropertyAccess propertyAccess, 091 final LoggerSource loggerSource) 092 { 093 if (!provideEncoders) 094 return; 095 096 for (ClassMetadata classMetadata : sessionSource.getSessionFactory().getAllClassMetadata() 097 .values()) 098 { 099 final Class entityClass = classMetadata.getMappedClass(); 100 final String idenfierPropertyName = classMetadata.getIdentifierPropertyName(); 101 102 if (entityClass != null) 103 { 104 ValueEncoderFactory factory = new ValueEncoderFactory() 105 { 106 @Override 107 public ValueEncoder create(Class type) 108 { 109 return new HibernateEntityValueEncoder(entityClass, idenfierPropertyName, 110 session, propertyAccess, typeCoercer, 111 loggerSource.getLogger(entityClass)); 112 } 113 }; 114 115 configuration.add(entityClass, factory); 116 117 } 118 } 119 } 120 121 /** 122 * Contributes the following: 123 * <dl> 124 * <dt>entity</dt> 125 * <dd>Stores the id of the entity and reloads from the {@link Session}</dd> 126 * </dl> 127 */ 128 public static void contributePersistentFieldManager( 129 MappedConfiguration<String, PersistentFieldStrategy> configuration) 130 { 131 configuration.addInstance(HibernatePersistenceConstants.ENTITY, EntityPersistentFieldStrategy.class); 132 } 133 134 /** 135 * Contributes the following strategy: 136 * <dl> 137 * <dt>entity</dt> 138 * <dd>Stores the id of the entity and reloads from the {@link Session}</dd> 139 * </dl> 140 */ 141 public void contributeApplicationStatePersistenceStrategySource( 142 MappedConfiguration<String, ApplicationStatePersistenceStrategy> configuration) 143 { 144 configuration 145 .addInstance(HibernatePersistenceConstants.ENTITY, EntityApplicationStatePersistenceStrategy.class); 146 } 147 148 /** 149 * Contributes {@link ApplicationStateContribution}s for all registered Hibernate entity classes. 150 * 151 * @param configuration 152 * Configuration to contribute 153 * @param entitySessionStatePersistenceStrategyEnabled 154 * indicates if contribution should take place 155 * @param sessionSource 156 * creates Hibernate session 157 */ 158 public static void contributeApplicationStateManager( 159 MappedConfiguration<Class, ApplicationStateContribution> configuration, 160 @Symbol(HibernateSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED) 161 boolean entitySessionStatePersistenceStrategyEnabled, HibernateSessionSource sessionSource) 162 { 163 164 if (!entitySessionStatePersistenceStrategyEnabled) 165 return; 166 167 for (ClassMetadata classMetadata : sessionSource.getSessionFactory().getAllClassMetadata().values()) 168 { 169 final Class entityClass = classMetadata.getMappedClass(); 170 configuration.add(entityClass, new ApplicationStateContribution(HibernatePersistenceConstants.ENTITY)); 171 } 172 } 173 174 /** 175 * Adds the CommitAfter annotation work, to process the 176 * {@link org.apache.tapestry5.hibernate.annotations.CommitAfter} annotation. 177 */ 178 @Contribute(ComponentClassTransformWorker2.class) 179 @Primary 180 public static void provideCommitAfterAnnotationSupport( 181 OrderedConfiguration<ComponentClassTransformWorker2> configuration) 182 { 183 // If logging is enabled, we want logging to be the first advice, wrapping around the commit advice. 184 185 configuration.addInstance("CommitAfter", CommitAfterWorker.class, "after:Log"); 186 } 187 188 @Contribute(DashboardManager.class) 189 public static void provideHibernateDashboardTab(OrderedConfiguration<DashboardTab> configuration) 190 { 191 configuration.add("HibernateStatistics", new DashboardTab("Hibernate", "hibernate/HibernateStatistics"), "after:Services"); 192 } 193 194 @Contribute(ComponentClassResolver.class) 195 public static void provideLibraryMapping(Configuration<LibraryMapping> configuration) 196 { 197 configuration.add(new LibraryMapping("hibernate", "org.apache.tapestry5.hibernate.web")); 198 } 199}