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.metadata.ClassMetadata; 046 047/** 048 * Supplements the services defined by {@link org.apache.tapestry5.hibernate.modules.HibernateCoreModule} with additional 049 * services and configuration specific to Tapestry web application. 050 */ 051public class HibernateModule 052{ 053 public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration) 054 { 055 configuration.add(HibernateSymbols.PROVIDE_ENTITY_VALUE_ENCODERS, "true"); 056 configuration.add(HibernateSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED, "false"); 057 } 058 059 /** 060 * Contributes the package "<root>.entities" to the configuration, so that it will be scanned for annotated 061 * entity classes. 062 */ 063 public static void contributeHibernateEntityPackageManager(Configuration<String> configuration, 064 065 @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM) 066 String appRootPackage) 067 { 068 configuration.add(appRootPackage + ".entities"); 069 } 070 071 @Contribute(ServiceOverride.class) 072 public static void provideInjectableSessionObject(MappedConfiguration<Class, Object> configuration, @HibernateCore 073 Session session) 074 { 075 configuration.add(Session.class, session); 076 } 077 078 /** 079 * Contributes {@link ValueEncoderFactory}s for all registered Hibernate entity classes. Encoding and decoding are 080 * based on the id property value of the entity using type coercion. Hence, if the id can be coerced to a String and 081 * back then the entity can be coerced. 082 */ 083 @SuppressWarnings("unchecked") 084 public static void contributeValueEncoderSource( 085 MappedConfiguration<Class, ValueEncoderFactory> configuration, 086 @Symbol(HibernateSymbols.PROVIDE_ENTITY_VALUE_ENCODERS) boolean provideEncoders, 087 final HibernateSessionSource sessionSource, final Session session, 088 final TypeCoercer typeCoercer, final PropertyAccess propertyAccess, 089 final LoggerSource loggerSource) 090 { 091 if (!provideEncoders) 092 return; 093 094 for (ClassMetadata classMetadata : sessionSource.getSessionFactory().getAllClassMetadata() 095 .values()) 096 { 097 final Class entityClass = classMetadata.getMappedClass(); 098 final String idenfierPropertyName = classMetadata.getIdentifierPropertyName(); 099 100 if (entityClass != null) 101 { 102 ValueEncoderFactory factory = new ValueEncoderFactory() 103 { 104 @Override 105 public ValueEncoder create(Class type) 106 { 107 return new HibernateEntityValueEncoder(entityClass, idenfierPropertyName, 108 session, propertyAccess, typeCoercer, 109 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 for (ClassMetadata classMetadata : sessionSource.getSessionFactory().getAllClassMetadata().values()) 166 { 167 final Class entityClass = classMetadata.getMappedClass(); 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 @Contribute(DashboardManager.class) 187 public static void provideHibernateDashboardTab(OrderedConfiguration<DashboardTab> configuration) 188 { 189 configuration.add("HibernateStatistics", new DashboardTab("Hibernate", "core/HibernateStatistics"), "after:Services"); 190 } 191}