blob: b8fe35c077aef5e15a24cca857472cfc232a89ba [file] [log] [blame]
/**
* Copyright (C) 2010 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.inject.persist.jpa;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.persist.PersistService;
import com.google.inject.persist.UnitOfWork;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Properties;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* @author Dhanji R. Prasanna (dhanji@gmail.com)
*/
@Singleton
class JpaPersistService implements Provider<EntityManager>, UnitOfWork, PersistService {
private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>();
private final String persistenceUnitName;
private final Properties persistenceProperties;
@Inject
public JpaPersistService(@Jpa String persistenceUnitName,
@Nullable @Jpa Properties persistenceProperties) {
this.persistenceUnitName = persistenceUnitName;
this.persistenceProperties = persistenceProperties;
}
public EntityManager get() {
if (!isWorking()) {
begin();
}
EntityManager em = entityManager.get();
Preconditions.checkState(null != em, "Requested EntityManager outside work unit. "
+ "Try calling UnitOfWork.begin() first, or use a PersistFilter if you "
+ "are inside a servlet environment.");
return em;
}
public boolean isWorking() {
return entityManager.get() != null;
}
public void begin() {
Preconditions.checkState(null == entityManager.get(),
"Work already begun on this thread. Looks like you have called UnitOfWork.begin() twice"
+ " without a balancing call to end() in between.");
entityManager.set(emFactory.createEntityManager());
}
public void end() {
EntityManager em = entityManager.get();
// Let's not penalize users for calling end() multiple times.
if (null == em) {
return;
}
em.close();
entityManager.remove();
}
private volatile EntityManagerFactory emFactory;
public synchronized void start() {
Preconditions.checkState(null == emFactory, "Persistence service was already initialized.");
if (null != persistenceProperties) {
this.emFactory = Persistence
.createEntityManagerFactory(persistenceUnitName, persistenceProperties);
} else {
this.emFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
}
}
public synchronized void stop() {
Preconditions.checkState(emFactory.isOpen(), "Persistence service was already shut down.");
emFactory.close();
}
@Singleton
public static class EntityManagerFactoryProvider implements Provider<EntityManagerFactory> {
private final JpaPersistService emProvider;
@Inject
public EntityManagerFactoryProvider(JpaPersistService emProvider) {
this.emProvider = emProvider;
}
public EntityManagerFactory get() {
assert null != emProvider.emFactory;
return emProvider.emFactory;
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
private @interface Nullable { }
}