001 // Copyright 2008, 2009 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 javax.persistence.EntityManager;
018
019 import org.apache.tapestry5.ioc.MappedConfiguration;
020 import org.apache.tapestry5.ioc.OrderedConfiguration;
021 import org.apache.tapestry5.ioc.ScopeConstants;
022 import org.apache.tapestry5.ioc.ServiceBinder;
023 import org.apache.tapestry5.ioc.annotations.Inject;
024 import org.apache.tapestry5.ioc.annotations.Marker;
025 import org.apache.tapestry5.ioc.annotations.Scope;
026 import org.apache.tapestry5.ioc.annotations.Symbol;
027 import org.apache.tapestry5.ioc.services.PerthreadManager;
028 import org.apache.tapestry5.ioc.services.PropertyShadowBuilder;
029 import org.apache.tapestry5.ioc.services.RegistryShutdownHub;
030 import org.slf4j.Logger;
031
032 import org.tynamo.jpa.internal.JPAEntityManagerSourceImpl;
033 import org.tynamo.jpa.internal.JPATransactionAdvisorImpl;
034 import org.tynamo.jpa.internal.JPATransactionDecoratorImpl;
035 import org.tynamo.jpa.internal.JPATransactionManagerImpl;
036
037 /**
038 * Defines core services that support initialization of Hibernate and access to the Hibernate
039 * {@link javax.persistence.EntityManager}.
040 */
041 @SuppressWarnings( { "JavaDoc" })
042 @Marker(JPACore.class)
043 public class JPACoreModule
044 {
045 public static void bind(ServiceBinder binder)
046 {
047 binder.bind(JPATransactionDecorator.class, JPATransactionDecoratorImpl.class);
048 binder.bind(JPATransactionAdvisor.class, JPATransactionAdvisorImpl.class);
049 // binder.bind(HibernateConfigurer.class,
050 // JPAHibernateConfigurer.class).withId("JPAHibernateConfigurer");
051 }
052
053 public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
054 {
055 configuration.add(JPASymbols.DEFAULT_CONFIGURATION, "true");
056 configuration.add(JPASymbols.EARLY_START_UP, "false");
057 }
058
059 public static void contributeRegistryStartup(OrderedConfiguration<Runnable> configuration,
060
061 @Symbol(JPASymbols.EARLY_START_UP) final boolean earlyStartup,
062
063 final JPAEntityManagerSource entityManagerSource)
064 {
065 configuration.add("JPAStartup", new Runnable()
066 {
067 public void run()
068 {
069 if (earlyStartup)
070 entityManagerSource.create();
071 }
072 });
073 }
074
075 /**
076 * The transaction manager manages transaction on a per-thread/per-request basis. Any active
077 * transaction will be rolled back at
078 * {@linkplain org.apache.tapestry5.ioc.Registry#cleanupThread() thread cleanup time}. The
079 * thread is cleaned up automatically in a Tapestry web application.
080 */
081 @Scope(ScopeConstants.PERTHREAD)
082 public static JPATransactionManager buildJPATransactionManager(JPAEntityManagerSource sessionSource,
083 PerthreadManager perthreadManager)
084 {
085 JPATransactionManagerImpl service = new JPATransactionManagerImpl(sessionSource);
086
087 perthreadManager.addThreadCleanupListener(service);
088
089 return service;
090 }
091
092 public static EntityManager buildEntityManager(JPATransactionManager transactionManager,
093 PropertyShadowBuilder propertyShadowBuilder)
094 {
095 // Here's the thing: the tapestry.hibernate.Session class doesn't have to be per-thread,
096 // since
097 // it will invoke getSession() on the JPASessionManager service (which is per-thread).
098 // On
099 // first invocation per request,
100 // this forces the HSM into existence (which creates the session and begins the
101 // transaction).
102 // Thus we don't actually create
103 // a session until we first try to access it, then the session continues to exist for the
104 // rest
105 // of the request.
106
107 return propertyShadowBuilder.build(transactionManager, "entityManager", EntityManager.class);
108 }
109
110 public static JPAEntityManagerSource buildJPAEntityManagerSource(Logger logger,
111 @Inject @Symbol(JPASymbols.PERSISTENCE_UNIT) String persistenceUnit, RegistryShutdownHub hub)
112 {
113 JPAEntityManagerSourceImpl hss = new JPAEntityManagerSourceImpl(logger, persistenceUnit);
114
115 hub.addRegistryShutdownListener(hss);
116
117 return hss;
118 }
119 }