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 27 import java.lang.annotation.Documented; 28 import java.lang.annotation.ElementType; 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 import java.lang.annotation.Target; 32 import java.util.Map; 33 34 import javax.persistence.EntityManager; 35 import javax.persistence.EntityManagerFactory; 36 import javax.persistence.Persistence; 37 38 /** 39 * @author Dhanji R. Prasanna (dhanji@gmail.com) 40 */ 41 @Singleton 42 class JpaPersistService implements Provider<EntityManager>, UnitOfWork, PersistService { 43 private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>(); 44 45 private final String persistenceUnitName; 46 private final Map<?,?> persistenceProperties; 47 48 @Inject JpaPersistService(@pa String persistenceUnitName, @Nullable @Jpa Map<?,?> persistenceProperties)49 public JpaPersistService(@Jpa String persistenceUnitName, 50 @Nullable @Jpa Map<?,?> persistenceProperties) { 51 this.persistenceUnitName = persistenceUnitName; 52 this.persistenceProperties = persistenceProperties; 53 } 54 get()55 public EntityManager get() { 56 if (!isWorking()) { 57 begin(); 58 } 59 60 EntityManager em = entityManager.get(); 61 Preconditions.checkState(null != em, "Requested EntityManager outside work unit. " 62 + "Try calling UnitOfWork.begin() first, or use a PersistFilter if you " 63 + "are inside a servlet environment."); 64 65 return em; 66 } 67 isWorking()68 public boolean isWorking() { 69 return entityManager.get() != null; 70 } 71 begin()72 public void begin() { 73 Preconditions.checkState(null == entityManager.get(), 74 "Work already begun on this thread. Looks like you have called UnitOfWork.begin() twice" 75 + " without a balancing call to end() in between."); 76 77 entityManager.set(emFactory.createEntityManager()); 78 } 79 end()80 public void end() { 81 EntityManager em = entityManager.get(); 82 83 // Let's not penalize users for calling end() multiple times. 84 if (null == em) { 85 return; 86 } 87 88 try { 89 em.close(); 90 } 91 finally { 92 entityManager.remove(); 93 } 94 } 95 96 private volatile EntityManagerFactory emFactory; 97 98 @VisibleForTesting start(EntityManagerFactory emFactory)99 synchronized void start(EntityManagerFactory emFactory) { 100 this.emFactory = emFactory; 101 } 102 start()103 public synchronized void start() { 104 Preconditions.checkState(null == emFactory, "Persistence service was already initialized."); 105 106 if (null != persistenceProperties) { 107 this.emFactory = Persistence 108 .createEntityManagerFactory(persistenceUnitName, persistenceProperties); 109 } else { 110 this.emFactory = Persistence.createEntityManagerFactory(persistenceUnitName); 111 } 112 } 113 stop()114 public synchronized void stop() { 115 Preconditions.checkState(emFactory.isOpen(), "Persistence service was already shut down."); 116 emFactory.close(); 117 } 118 119 @Singleton 120 public static class EntityManagerFactoryProvider implements Provider<EntityManagerFactory> { 121 private final JpaPersistService emProvider; 122 123 @Inject EntityManagerFactoryProvider(JpaPersistService emProvider)124 public EntityManagerFactoryProvider(JpaPersistService emProvider) { 125 this.emProvider = emProvider; 126 } 127 get()128 public EntityManagerFactory get() { 129 assert null != emProvider.emFactory; 130 return emProvider.emFactory; 131 } 132 } 133 134 @Documented 135 @Retention(RetentionPolicy.RUNTIME) 136 @Target(ElementType.PARAMETER) 137 private @interface Nullable { } 138 139 } 140