001/*
002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     "Stephane Lacoin (aka matic) <slacoin@nuxeo.org>"
018 */
019package org.nuxeo.ecm.core.persistence;
020
021import javax.persistence.EntityManager;
022import javax.persistence.EntityManagerFactory;
023import javax.persistence.EntityTransaction;
024import javax.persistence.TransactionRequiredException;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028
029/**
030 * @author Stephane Lacoin [aka matic]
031 */
032public class PersistenceProvider {
033
034    protected static final Log log = LogFactory.getLog(PersistenceProvider.class);
035
036    protected volatile EntityManagerFactory emf;
037
038    protected final EntityManagerFactoryProvider emfProvider;
039
040    public PersistenceProvider(EntityManagerFactoryProvider emfProvider) {
041        this.emfProvider = emfProvider;
042    }
043
044    public void openPersistenceUnit() {
045        if (emfProvider == null) {
046            throw new IllegalArgumentException("emfProvider not set");
047        }
048        if (emf == null) {
049            synchronized (PersistenceProvider.class) {
050                if (emf == null) {
051                    emf = emfProvider.getFactory();
052                }
053            }
054        }
055    }
056
057    public void closePersistenceUnit() {
058        if (emf == null) {
059            return;
060        }
061        if (emf.isOpen()) {
062            emf.close();
063        }
064        emf = null;
065    }
066
067    protected EntityManager doAcquireEntityManager() {
068        if (emf == null) {
069            openPersistenceUnit();
070        }
071        return emf.createEntityManager();
072    }
073
074    protected EntityTransaction getTransaction(EntityManager em) {
075        try {
076            return em.getTransaction();
077        } catch (IllegalStateException e) {
078            return null; // JTA container, no manual access to transaction
079        }
080    }
081
082    public EntityManager acquireEntityManager() {
083        return doAcquireEntityManager();
084    }
085
086    public EntityManager acquireEntityManagerWithActiveTransaction() {
087        EntityManager em = doAcquireEntityManager();
088        doBegin(em);
089        return em;
090    }
091
092    protected void doBegin(EntityManager em) {
093        EntityTransaction et = getTransaction(em);
094        if (et != null) {
095            et.begin();
096        }
097    }
098
099    protected void doCommit(EntityManager em) {
100        try {
101            em.flush();
102        } catch (TransactionRequiredException e) {
103            // ignore
104        }
105        EntityTransaction et = getTransaction(em);
106        if (et == null || !et.isActive()) {
107            return;
108        }
109        et.commit();
110    }
111
112    protected void doRollback(EntityManager em) {
113        try {
114            em.flush();
115        } catch (TransactionRequiredException e) {
116            // ignore
117        }
118        EntityTransaction et = getTransaction(em);
119        if (et == null || !et.isActive()) {
120            return;
121        }
122        et.rollback();
123    }
124
125    protected void releaseEntityManager(EntityManager em) {
126        if (!em.isOpen()) {
127            return;
128        }
129        try {
130            doCommit(em);
131        } finally {
132            if (em.isOpen()) {
133                em.clear();
134                em.close();
135            }
136        }
137    }
138
139    public void releaseEntityManagerWithRollback(EntityManager em) {
140        if (!em.isOpen()) {
141            return;
142        }
143        try {
144            doRollback(em);
145        } finally {
146            if (em.isOpen()) {
147                em.clear();
148                em.close();
149            }
150        }
151    }
152
153    public interface RunCallback<T> {
154        T runWith(EntityManager em);
155    }
156
157    public <T> T run(Boolean needActiveSession, RunCallback<T> callback) {
158        // needActiveSession now unused
159        Thread myThread = Thread.currentThread();
160        ClassLoader lastLoader = myThread.getContextClassLoader();
161        myThread.setContextClassLoader(getClass().getClassLoader());
162        try { // insure context class loader restoring
163            EntityManager em = doAcquireEntityManager();
164            doBegin(em);
165            try { // insure entity manager releasing
166                return callback.runWith(em);
167            } finally {
168                releaseEntityManager(em);
169            }
170        } finally {
171            myThread.setContextClassLoader(lastLoader);
172        }
173    }
174
175    public interface RunVoid {
176        void runWith(EntityManager em);
177    }
178
179    public void run(Boolean needActiveSession, RunVoid callback) {
180        // needActiveSession now unused
181        Thread myThread = Thread.currentThread();
182        ClassLoader lastLoader = myThread.getContextClassLoader();
183        myThread.setContextClassLoader(getClass().getClassLoader());
184        try { // insure context class loader restoring
185            EntityManager em = doAcquireEntityManager();
186            doBegin(em);
187            try { // insure entity manager releasing
188                callback.runWith(em);
189            } finally {
190                releaseEntityManager(em);
191            }
192        } finally {
193            myThread.setContextClassLoader(lastLoader);
194        }
195    }
196
197}