001    // Copyright 2007, 2008 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 org.apache.tapestry5.ValueEncoder;
018    import org.apache.tapestry5.internal.InternalConstants;
019    import org.apache.tapestry5.internal.hibernate.CommitAfterWorker;
020    import org.apache.tapestry5.internal.hibernate.EntityPersistentFieldStrategy;
021    import org.apache.tapestry5.internal.hibernate.HibernateEntityValueEncoder;
022    import org.apache.tapestry5.ioc.Configuration;
023    import org.apache.tapestry5.ioc.LoggerSource;
024    import org.apache.tapestry5.ioc.MappedConfiguration;
025    import org.apache.tapestry5.ioc.OrderedConfiguration;
026    import org.apache.tapestry5.ioc.annotations.Inject;
027    import org.apache.tapestry5.ioc.annotations.Symbol;
028    import org.apache.tapestry5.ioc.services.PropertyAccess;
029    import org.apache.tapestry5.ioc.services.TypeCoercer;
030    import org.apache.tapestry5.services.AliasContribution;
031    import org.apache.tapestry5.services.ComponentClassTransformWorker;
032    import org.apache.tapestry5.services.LibraryMapping;
033    import org.apache.tapestry5.services.PersistentFieldStrategy;
034    import org.apache.tapestry5.services.ValueEncoderFactory;
035    import org.hibernate.Session;
036    import org.hibernate.mapping.PersistentClass;
037    
038    import java.util.Iterator;
039    
040    /**
041     * Supplements the services defined by {@link org.apache.tapestry5.hibernate.HibernateCoreModule} with additional
042     * services and configuration specific to Tapestry web application.
043     */
044    @SuppressWarnings({"JavaDoc"})
045    public class HibernateModule
046    {
047        public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
048        {
049            configuration.add(HibernateConstants.PROVIDE_ENTITY_VALUE_ENCODERS_SYMBOL, "true");
050        }
051    
052        /**
053         * Contributes the package "&lt;root&gt;.entities" to the configuration, so that it will be scanned for annotated
054         * entity classes.
055         */
056        public static void contributeHibernateEntityPackageManager(Configuration<String> configuration,
057    
058                                                                   @Inject
059                                                                   @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
060                                                                   String appRootPackage)
061        {
062            configuration.add(appRootPackage + ".entities");
063        }
064    
065    
066        public static void contributeAlias(Configuration<AliasContribution> configuration, @HibernateCore Session session)
067        {
068            configuration.add(AliasContribution.create(Session.class, session));
069        }
070    
071    
072        /**
073         * Contributes {@link ValueEncoderFactory}s for all registered Hibernate entity classes. Encoding and decoding are
074         * based on the id property value of the entity using type coercion. Hence, if the id can be coerced to a String and
075         * back then the entity can be coerced.
076         */
077        @SuppressWarnings("unchecked")
078        public static void contributeValueEncoderSource(MappedConfiguration<Class, ValueEncoderFactory> configuration,
079                                                        @Symbol(HibernateConstants.PROVIDE_ENTITY_VALUE_ENCODERS_SYMBOL)
080                                                        boolean provideEncoders,
081                                                        final HibernateSessionSource sessionSource,
082                                                        final Session session,
083                                                        final TypeCoercer typeCoercer,
084                                                        final PropertyAccess propertyAccess,
085                                                        final LoggerSource loggerSource)
086        {
087            if (!provideEncoders) return;
088    
089            org.hibernate.cfg.Configuration config = sessionSource.getConfiguration();
090            Iterator<PersistentClass> mappings = config.getClassMappings();
091            while (mappings.hasNext())
092            {
093                final PersistentClass persistentClass = mappings.next();
094                final Class entityClass = persistentClass.getMappedClass();
095    
096                ValueEncoderFactory factory = new ValueEncoderFactory()
097                {
098                    public ValueEncoder create(Class type)
099                    {
100                        return new HibernateEntityValueEncoder(entityClass, persistentClass, session, propertyAccess,
101                                                               typeCoercer, loggerSource.getLogger(entityClass));
102                    }
103                };
104    
105                configuration.add(entityClass, factory);
106            }
107        }
108    
109        /**
110         * Contributes the following: <dl> <dt>entity</dt> <dd>Stores the id of the entity and reloads from the {@link
111         * Session}</dd> </dl>
112         */
113        public static void contributePersistentFieldManager(
114                MappedConfiguration<String, PersistentFieldStrategy> configuration)
115        {
116            configuration.addInstance("entity", EntityPersistentFieldStrategy.class);
117        }
118    
119        /**
120         * Adds the CommitAfter annotation work, to process the {@link org.apache.tapestry5.hibernate.annotations.CommitAfter}
121         * annotation.
122         */
123        public static void contributeComponentClassTransformWorker(
124                OrderedConfiguration<ComponentClassTransformWorker> configuration)
125        {
126            // If logging is enabled, we want logging to be the first advice, wrapping around the commit advice.
127    
128            configuration.addInstance("CommitAfter", CommitAfterWorker.class, "after:Log");
129        }
130        
131        /**
132         * Contribution to the {@link org.apache.tapestry5.services.ComponentClassResolver} service configuration.
133         */
134        public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
135        {
136            configuration.add(new LibraryMapping("hibernate", "org.apache.tapestry5.hibernate"));
137        }
138    
139    }