    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 "&lt;root&gt;.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}