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.tynamo.jpa;
016    
017    import org.tynamo.jpa.internal.CommitAfterWorker;
018    import org.tynamo.jpa.internal.EntityPersistentFieldStrategy;
019    import org.tynamo.jpa.internal.JPAEntityValueEncoder;
020    import org.apache.tapestry5.ValueEncoder;
021    import org.apache.tapestry5.ioc.Configuration;
022    import org.apache.tapestry5.ioc.LoggerSource;
023    import org.apache.tapestry5.ioc.MappedConfiguration;
024    import org.apache.tapestry5.ioc.OrderedConfiguration;
025    import org.apache.tapestry5.ioc.annotations.Symbol;
026    import org.apache.tapestry5.ioc.services.PropertyAccess;
027    import org.apache.tapestry5.ioc.services.TypeCoercer;
028    import org.apache.tapestry5.services.*;
029    
030    import javax.persistence.EntityManager;
031    import javax.persistence.EntityManagerFactory;
032    import javax.persistence.metamodel.EntityType;
033    import javax.persistence.metamodel.Metamodel;
034    
035    /**
036     * Supplements the services defined by {@link eu.cuetech.tapestry.jpa.JPACoreModule} with additional
037     * services and configuration specific to Tapestry web application.
038     */
039    @SuppressWarnings({"JavaDoc"})
040    public class JPAModule {
041            public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration) {
042                    configuration.add(JPASymbols.PROVIDE_ENTITY_VALUE_ENCODERS, "true");
043            }
044    
045            /**
046             * Contributes the package "&lt;root&gt;.entities" to the configuration, so that it will be
047             * scanned for annotated entity classes.
048             * <p/>
049             * public static void contributeHibernateEntityPackageManager(Configuration<String>
050             * configuration,
051             *
052             * @Inject
053             * @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM) String appRootPackage) {
054             * configuration.add(appRootPackage +
055             * ".entities"); }
056             */
057    
058            public static void contributeAlias(Configuration<AliasContribution> configuration, @JPACore EntityManager em) {
059                    configuration.add(AliasContribution.create(EntityManager.class, em));
060            }
061    
062            /**
063             * Contributes the following:
064             * <dl>
065             * <dt>entity</dt>
066             * <dd>Stores the id of the entity and reloads from the {@link EntityManager}</dd>
067             * </dl>
068             */
069            public static void contributePersistentFieldManager(
070                            MappedConfiguration<String, PersistentFieldStrategy> configuration) {
071                    configuration.addInstance("entity", EntityPersistentFieldStrategy.class);
072            }
073    
074            /**
075             * Adds the CommitAfter annotation work, to process the
076             * {@link eu.cuetech.tapestry.jpa.annotations.CommitAfter} annotation.
077             */
078            public static void contributeComponentClassTransformWorker(
079                            OrderedConfiguration<ComponentClassTransformWorker> configuration) {
080                    // If logging is enabled, we want logging to be the first advice, wrapping around the commit
081                    // advice.
082    
083                    configuration.addInstance("CommitAfter", CommitAfterWorker.class, "after:Log");
084            }
085    
086            /**
087             * Contribution to the {@link org.apache.tapestry5.services.ComponentClassResolver} service
088             * configuration.
089             */
090            public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration) {
091                    configuration.add(new LibraryMapping("jpa", "org.tynamo.tapestry.jpa"));
092            }
093    
094            /**
095             * Contributes {@link ValueEncoderFactory}s for all registered JPA entity classes. Encoding and
096             * decoding are based on the id property value of the entity using type coercion. Hence, if the
097             * id can be coerced to a String and back then the entity can be coerced.
098             */
099            @SuppressWarnings("unchecked")
100            public static void contributeValueEncoderSource(MappedConfiguration<Class, ValueEncoderFactory> configuration,
101                                                                                                            @Symbol(JPASymbols.PROVIDE_ENTITY_VALUE_ENCODERS) boolean provideEncoders,
102                                                                                                            final JPAEntityManagerSource ems, final EntityManager em, final TypeCoercer typeCoercer,
103                                                                                                            final PropertyAccess propertyAccess, final LoggerSource loggerSource) {
104                    if (!provideEncoders)
105                            return;
106    
107                    ems.create(); // create
108                    EntityManagerFactory emf = ems.getEntityManagerFactory();
109                    Metamodel metamodel = emf.getMetamodel();
110                    for (EntityType<?> et : metamodel.getEntities()) {
111    
112                            final EntityType<?> etype = et;
113                            ValueEncoderFactory factory = new ValueEncoderFactory() {
114                                    public ValueEncoder create(Class type) {
115                                            return new JPAEntityValueEncoder(etype.getJavaType(), em, propertyAccess, typeCoercer, loggerSource
116                                                            .getLogger(etype.getJavaType()));
117                                    }
118                            };
119    
120                            configuration.add(etype.getJavaType(), factory);
121                    }
122    
123            }
124    
125    }