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 }