• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject.persist.jpa;
18 
19 import com.google.common.annotations.VisibleForTesting;
20 import com.google.common.base.Preconditions;
21 import com.google.inject.Inject;
22 import com.google.inject.Provider;
23 import com.google.inject.Singleton;
24 import com.google.inject.persist.PersistService;
25 import com.google.inject.persist.UnitOfWork;
26 import java.lang.annotation.Documented;
27 import java.lang.annotation.ElementType;
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.lang.annotation.Target;
31 import java.util.Map;
32 import javax.persistence.EntityManager;
33 import javax.persistence.EntityManagerFactory;
34 import javax.persistence.Persistence;
35 
36 /** @author Dhanji R. Prasanna (dhanji@gmail.com) */
37 @Singleton
38 class JpaPersistService implements Provider<EntityManager>, UnitOfWork, PersistService {
39   private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<>();
40 
41   private final String persistenceUnitName;
42   private final Map<?, ?> persistenceProperties;
43 
44   @Inject
JpaPersistService( @pa String persistenceUnitName, @Nullable @Jpa Map<?, ?> persistenceProperties)45   public JpaPersistService(
46       @Jpa String persistenceUnitName, @Nullable @Jpa Map<?, ?> persistenceProperties) {
47     this.persistenceUnitName = persistenceUnitName;
48     this.persistenceProperties = persistenceProperties;
49   }
50 
51   @Override
get()52   public EntityManager get() {
53     if (!isWorking()) {
54       begin();
55     }
56 
57     EntityManager em = entityManager.get();
58     Preconditions.checkState(
59         null != em,
60         "Requested EntityManager outside work unit. "
61             + "Try calling UnitOfWork.begin() first, or use a PersistFilter if you "
62             + "are inside a servlet environment.");
63 
64     return em;
65   }
66 
isWorking()67   public boolean isWorking() {
68     return entityManager.get() != null;
69   }
70 
71   @Override
begin()72   public void begin() {
73     Preconditions.checkState(
74         null == entityManager.get(),
75         "Work already begun on this thread. Looks like you have called UnitOfWork.begin() twice"
76             + " without a balancing call to end() in between.");
77 
78     entityManager.set(emFactory.createEntityManager());
79   }
80 
81   @Override
end()82   public void end() {
83     EntityManager em = entityManager.get();
84 
85     // Let's not penalize users for calling end() multiple times.
86     if (null == em) {
87       return;
88     }
89 
90     try {
91       em.close();
92     } finally {
93       entityManager.remove();
94     }
95   }
96 
97   private volatile EntityManagerFactory emFactory;
98 
99   @VisibleForTesting
start(EntityManagerFactory emFactory)100   synchronized void start(EntityManagerFactory emFactory) {
101     this.emFactory = emFactory;
102   }
103 
104   @Override
start()105   public synchronized void start() {
106     Preconditions.checkState(null == emFactory, "Persistence service was already initialized.");
107 
108     if (null != persistenceProperties) {
109       this.emFactory =
110           Persistence.createEntityManagerFactory(persistenceUnitName, persistenceProperties);
111     } else {
112       this.emFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
113     }
114   }
115 
116   @Override
stop()117   public synchronized void stop() {
118     Preconditions.checkState(emFactory.isOpen(), "Persistence service was already shut down.");
119     emFactory.close();
120   }
121 
122   @Singleton
123   public static class EntityManagerFactoryProvider implements Provider<EntityManagerFactory> {
124     private final JpaPersistService emProvider;
125 
126     @Inject
EntityManagerFactoryProvider(JpaPersistService emProvider)127     public EntityManagerFactoryProvider(JpaPersistService emProvider) {
128       this.emProvider = emProvider;
129     }
130 
131     @Override
get()132     public EntityManagerFactory get() {
133       assert null != emProvider.emFactory;
134       return emProvider.emFactory;
135     }
136   }
137 
138   @Documented
139   @Retention(RetentionPolicy.RUNTIME)
140   @Target(ElementType.PARAMETER)
141   private @interface Nullable {}
142 }
143