View Javadoc
1   package org.apache.onami.persist;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import com.google.inject.Key;
23  import com.google.inject.PrivateModule;
24  import com.google.inject.util.Providers;
25  
26  import javax.persistence.EntityManagerFactory;
27  import javax.transaction.UserTransaction;
28  import java.util.Properties;
29  
30  import static org.apache.onami.persist.Preconditions.checkNotNull;
31  
32  /**
33   * Module for configuring a single persistence unit.
34   *
35   * @see PersistenceModule
36   */
37  class PersistenceUnitModule
38      extends PrivateModule
39  {
40  
41      /**
42       * The configuration for the persistence unit.
43       */
44      private final PersistenceUnitModuleConfiguration config;
45  
46      /**
47       * Transaction interceptor for this persistence unit.
48       */
49      private final TxnInterceptor transactionInterceptor;
50  
51      /**
52       * Container for adding this persistence unit.
53       */
54      private final AllPersistenceUnits allPersistenceUnits;
55  
56      /**
57       * Constructor.
58       *
59       * @param configurator           the configuration holding all configs.
60       * @param transactionInterceptor interceptor for the transactional annotation.
61       * @param allPersistenceUnits    container holding all persistence units.
62       */
63      PersistenceUnitModule( PersistenceUnitModuleConfiguration configurator, TxnInterceptor transactionInterceptor,
64                             AllPersistenceUnits allPersistenceUnits )
65      {
66          this.config = checkNotNull( configurator, "config is mandatory!" );
67          this.transactionInterceptor = checkNotNull( transactionInterceptor, "transactionInterceptor is mandatory!" );
68          this.allPersistenceUnits = checkNotNull( allPersistenceUnits, "allPersistenceUnits is mandatory!" );
69      }
70  
71      /**
72       * {@inheritDoc}
73       */
74      @Override
75      protected void configure()
76      {
77          bind( AnnotationHolder.class ).toInstance( config.getAnnotationHolder() );
78  
79          bindPersistenceServiceAndEntityManagerFactoryProviderAndProperties();
80          bindTransactionFacadeFactory();
81  
82          bind( EntityManagerProvider.class ).to( EntityManagerProviderImpl.class );
83          bind( UnitOfWork.class ).to( EntityManagerProviderImpl.class );
84  
85          exposePersistenceServiceAndEntityManagerProviderAndUnitOfWork();
86  
87          // request injection into transaction interceptor - this adds the required dependencies to the interceptor.
88          if ( transactionInterceptor != null )
89          {
90              requestInjection( transactionInterceptor );
91          }
92  
93          allPersistenceUnits.add( getPersistenceKey(), getUnitOfWorkKey() );
94      }
95  
96      /**
97       * exposes the following interfaces (optionally annotated if an annotation is defined in the configuration).
98       * <ul>
99       * <li>{@link PersistenceService}</li>
100      * <li>{@link EntityManagerProvider}</li>
101      * <li>{@link UnitOfWork}</li>
102      * </ul>
103      */
104     private void exposePersistenceServiceAndEntityManagerProviderAndUnitOfWork()
105     {
106         if ( config.isAnnotated() )
107         {
108             bindAndExposedAnnotated( PersistenceService.class );
109             bindAndExposedAnnotated( EntityManagerProvider.class );
110             bindAndExposedAnnotated( UnitOfWork.class );
111         }
112         else
113         {
114             expose( PersistenceService.class );
115             expose( EntityManagerProvider.class );
116             expose( UnitOfWork.class );
117         }
118     }
119 
120     /**
121      * helper to expose a binding with annotation added.
122      *
123      * @param type the type to expose.
124      * @param <T>  the type to expose.
125      */
126     private <T> void bindAndExposedAnnotated( Class<T> type )
127     {
128         bind( type ).annotatedWith( config.getAnnotation() ).to( Key.get( type ) );
129         expose( type ).annotatedWith( config.getAnnotation() );
130     }
131 
132 
133     private Key<PersistenceService> getPersistenceKey()
134     {
135         if ( config.isAnnotated() )
136         {
137             return Key.get( PersistenceService.class, config.getAnnotation() );
138         }
139         else
140         {
141             return Key.get( PersistenceService.class );
142         }
143     }
144 
145     private Key<UnitOfWork> getUnitOfWorkKey()
146     {
147         if ( config.isAnnotated() )
148         {
149             return Key.get( UnitOfWork.class, config.getAnnotation() );
150         }
151         else
152         {
153             return Key.get( UnitOfWork.class );
154         }
155     }
156 
157     private void bindPersistenceServiceAndEntityManagerFactoryProviderAndProperties()
158     {
159         if ( config.isApplicationManagedPersistenceUnit() )
160         {
161             bindApplicationManagedPersistenceServiceAndEntityManagerFactoryProviderAndProperties();
162         }
163         else
164         {
165             bindContainerManagedPersistenceServiceAndEntityManagerFactoryProviderAndProperties();
166         }
167     }
168 
169     private void bindApplicationManagedPersistenceServiceAndEntityManagerFactoryProviderAndProperties()
170     {
171         bind( PersistenceService.class ).to( ApplicationManagedEntityManagerFactoryProvider.class );
172         bind( EntityManagerFactoryProvider.class ).to( ApplicationManagedEntityManagerFactoryProvider.class );
173         bind( Properties.class ).annotatedWith( ForContainerManaged.class ).toProvider(
174             Providers.<Properties>of( null ) );
175         bind( Properties.class ).annotatedWith( ForApplicationManaged.class ).toProvider(
176             Providers.of( config.getProperties() ) );
177 
178         // required in ApplicationManagedEntityManagerFactoryProvider
179         bind( EntityManagerFactoryFactory.class );
180         // required in EntityManagerFactoryFactory
181         bind( String.class ).annotatedWith( ForApplicationManaged.class ).toInstance( config.getPuName() );
182     }
183 
184     private void bindContainerManagedPersistenceServiceAndEntityManagerFactoryProviderAndProperties()
185     {
186         bind( PersistenceService.class ).to( ContainerManagedEntityManagerFactoryProvider.class );
187         bind( EntityManagerFactoryProvider.class ).to( ContainerManagedEntityManagerFactoryProvider.class );
188         bind( Properties.class ).annotatedWith( ForContainerManaged.class ).toProvider(
189             Providers.of( config.getProperties() ) );
190         bind( Properties.class ).annotatedWith( ForApplicationManaged.class ).toProvider(
191             Providers.<Properties>of( null ) );
192 
193         // required in ContainerManagedEntityManagerFactoryProvider
194         bindEntityManagerFactorySource();
195     }
196 
197     private void bindEntityManagerFactorySource()
198     {
199         if ( config.isEmfProvidedByJndiLookup() )
200         {
201             bind( EntityManagerFactorySource.class ).to( EntityManagerFactorySourceByJndiLookup.class );
202 
203             // required in EntityManagerFactorySourceByJndiLookup
204             bind( String.class ).annotatedWith( ForContainerManaged.class ).toInstance( config.getEmfJndiName() );
205         }
206         else
207         {
208             bind( EntityManagerFactorySource.class ).to( EntityManagerFactorySourceViaProvider.class );
209 
210             // required in EntityManagerFactorySourceViaProvider
211             bindInternalEntityManagerFactoryProvider();
212         }
213     }
214 
215     private void bindInternalEntityManagerFactoryProvider()
216     {
217         if ( config.isEmfProvidedByInstance() )
218         {
219             bind( EntityManagerFactory.class ).annotatedWith( ForContainerManaged.class ).toInstance( config.getEmf() );
220         }
221         else if ( config.isEmfProvidedByProvider() )
222         {
223             bind( EntityManagerFactory.class ).annotatedWith( ForContainerManaged.class ).toProvider(
224                 Providers.guicify( config.getEmfProvider() ) );
225         }
226         else if ( config.isEmfProvidedByProviderKey() )
227         {
228             bind( EntityManagerFactory.class ).annotatedWith( ForContainerManaged.class ).toProvider(
229                 config.getEmfProviderKey() );
230         }
231         else
232         {
233             throw new RuntimeException( "EntityManager is improperly configured" );
234         }
235     }
236 
237     private void bindTransactionFacadeFactory()
238     {
239         if ( config.isJta() )
240         {
241             bindJtaTransactionFacadeFactory();
242         }
243         else
244         {
245             bind( TransactionFacadeFactory.class ).to( ResourceLocalTransactionFacadeFactory.class );
246         }
247     }
248 
249     private void bindJtaTransactionFacadeFactory()
250     {
251         bind( TransactionFacadeFactory.class ).to( JtaTransactionFacadeFactory.class );
252 
253         // required in JtaTransactionFacadeFactory
254         binInternalUserTransactionProvider();
255     }
256 
257     private void binInternalUserTransactionProvider()
258     {
259         if ( config.isUserTransactionProvidedByInstance() )
260         {
261             bind( UserTransaction.class ).toInstance( config.getUserTransaction() );
262         }
263         else if ( config.isUserTransactionProvidedByJndiLookup() )
264         {
265             bind( UserTransaction.class ).toProvider( UserTransactionProviderByJndiLookup.class );
266 
267             // required in UserTransactionProviderByJndiLookup
268             bind( String.class ).annotatedWith( UserTransactionJndiName.class ).toInstance( config.getUtJndiName() );
269         }
270         else if ( config.isUserTransactionProvidedByProvider() )
271         {
272             bind( UserTransaction.class ).toProvider( Providers.guicify( config.getUtProvider() ) );
273         }
274         else if ( config.isUserTransactionProvidedByProviderKey() )
275         {
276             bind( UserTransaction.class ).toProvider( config.getUtProviderKey() );
277         }
278         else
279         {
280             throw new RuntimeException( "UserTransaction is improperly configured" );
281         }
282     }
283 
284 }