001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     "Stephane Lacoin (aka matic) <slacoin@nuxeo.org>"
016 */
017package org.nuxeo.ecm.core.persistence;
018
019import javax.persistence.EntityManager;
020import javax.persistence.EntityManagerFactory;
021import javax.persistence.EntityTransaction;
022import javax.persistence.TransactionRequiredException;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogFactory;
026
027/**
028 * @author "Stephane Lacoin (aka matic) <slacoin@nuxeo.org>"
029 */
030public class PersistenceProvider {
031
032    protected static final Log log = LogFactory.getLog(PersistenceProvider.class);
033
034    protected EntityManagerFactory emf;
035
036    protected final EntityManagerFactoryProvider emfProvider;
037
038    public PersistenceProvider(EntityManagerFactoryProvider emfProvider) {
039        this.emfProvider = emfProvider;
040    }
041
042    public void openPersistenceUnit() {
043        if (emfProvider == null) {
044            throw new IllegalArgumentException("emfProvider not set");
045        }
046        if (emf == null) {
047            synchronized (PersistenceProvider.class) {
048                if (emf == null) {
049                    emf = emfProvider.getFactory();
050                }
051            }
052        }
053    }
054
055    public void closePersistenceUnit() {
056        if (emf == null) {
057            return;
058        }
059        if (emf.isOpen()) {
060            emf.close();
061        }
062        emf = null;
063    }
064
065    protected EntityManager doAcquireEntityManager() {
066        if (emf == null) {
067            openPersistenceUnit();
068        }
069        return emf.createEntityManager();
070    }
071
072    protected EntityTransaction getTransaction(EntityManager em) {
073        try {
074            return em.getTransaction();
075        } catch (IllegalStateException e) {
076            return null; // JTA container, no manual access to transaction
077        }
078    }
079
080    public EntityManager acquireEntityManager() {
081        return doAcquireEntityManager();
082    }
083
084    public EntityManager acquireEntityManagerWithActiveTransaction() {
085        EntityManager em = doAcquireEntityManager();
086        doBegin(em);
087        return em;
088    }
089
090    protected void doBegin(EntityManager em) {
091        EntityTransaction et = getTransaction(em);
092        if (et != null) {
093            et.begin();
094        }
095    }
096
097    protected void doCommit(EntityManager em) {
098        try {
099            em.flush();
100        } catch (TransactionRequiredException e) {
101            // ignore
102        }
103        EntityTransaction et = getTransaction(em);
104        if (et == null || !et.isActive()) {
105            return;
106        }
107        et.commit();
108    }
109
110    protected void doRollback(EntityManager em) {
111        try {
112            em.flush();
113        } catch (TransactionRequiredException e) {
114            // ignore
115        }
116        EntityTransaction et = getTransaction(em);
117        if (et == null || !et.isActive()) {
118            return;
119        }
120        et.rollback();
121    }
122
123    protected void releaseEntityManager(EntityManager em) {
124        if (!em.isOpen()) {
125            return;
126        }
127        try {
128            doCommit(em);
129        } finally {
130            if (em.isOpen()) {
131                em.clear();
132                em.close();
133            }
134        }
135    }
136
137    public void releaseEntityManagerWithRollback(EntityManager em) {
138        if (!em.isOpen()) {
139            return;
140        }
141        try {
142            doRollback(em);
143        } finally {
144            if (em.isOpen()) {
145                em.clear();
146                em.close();
147            }
148        }
149    }
150
151    public interface RunCallback<T> {
152        T runWith(EntityManager em);
153    }
154
155    public <T> T run(Boolean needActiveSession, RunCallback<T> callback) {
156        // needActiveSession now unused
157        Thread myThread = Thread.currentThread();
158        ClassLoader lastLoader = myThread.getContextClassLoader();
159        myThread.setContextClassLoader(getClass().getClassLoader());
160        try { // insure context class loader restoring
161            EntityManager em = doAcquireEntityManager();
162            doBegin(em);
163            try { // insure entity manager releasing
164                return callback.runWith(em);
165            } finally {
166                releaseEntityManager(em);
167            }
168        } finally {
169            myThread.setContextClassLoader(lastLoader);
170        }
171    }
172
173    public interface RunVoid {
174        void runWith(EntityManager em);
175    }
176
177    public void run(Boolean needActiveSession, RunVoid callback) {
178        // needActiveSession now unused
179        Thread myThread = Thread.currentThread();
180        ClassLoader lastLoader = myThread.getContextClassLoader();
181        myThread.setContextClassLoader(getClass().getClassLoader());
182        try { // insure context class loader restoring
183            EntityManager em = doAcquireEntityManager();
184            doBegin(em);
185            try { // insure entity manager releasing
186                callback.runWith(em);
187            } finally {
188                releaseEntityManager(em);
189            }
190        } finally {
191            myThread.setContextClassLoader(lastLoader);
192        }
193    }
194
195}