/*
* ============================================================================
* GNU Lesser General Public License
* ============================================================================
*
* Beanlet - JSE Application Container.
* Copyright (C) 2006 Leon van Zantvoort
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Leon van Zantvoort
* 243 Acalanes Drive #11
* Sunnyvale, CA 94086
* USA
*
* zantvoort@users.sourceforge.net
* http://beanlet.org
*/
package org.beanlet.persistence.impl;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.PersistenceProperty;
import javax.persistence.PersistenceUnit;
import org.jargo.ComponentUnit;
/**
*
* @author Leon van Zantvoort
*/
public final class BeanletEntityManagerFactoryRegistry {
// Do not mix container and application factories to prevent clients from
// closing container factories.
private static final Map<BeanletPersistenceUnitInfo,
BeanletEntityManagerFactory> containerRegistry = new HashMap
<BeanletPersistenceUnitInfo, BeanletEntityManagerFactory>();
private static final Map<BeanletPersistenceUnitInfo,
BeanletEntityManagerFactory> applicationRegistry = new HashMap
<BeanletPersistenceUnitInfo, BeanletEntityManagerFactory>();
// Locking introduced, as 3CPO can run into deadlocks in the previous optimistic approach.
private static final Lock lock = new ReentrantLock();
private static final Map<BeanletPersistenceUnitInfo, ReadWriteLock> containerLockMap = new HashMap<BeanletPersistenceUnitInfo, ReadWriteLock>();
private static final Map<BeanletPersistenceUnitInfo, ReadWriteLock> applicationLockMap = new HashMap<BeanletPersistenceUnitInfo, ReadWriteLock>();
private static BeanletEntityManagerFactory createEntityManagerFactory(
BeanletPersistenceUnitInfo unitInfo, final Map<?, ?> map) {
EntityManagerFactory emf = PersistenceHelper.
createContainerEntityManagerFactory(unitInfo, map);
if (emf == null) {
throw new PersistenceException("EntityManagerFactory not available " +
"for unit '" + unitInfo.getPersistenceUnitName() + "'.");
}
return new InternalEntityManagerFactory(emf, map, unitInfo);
}
public static BeanletEntityManagerFactory getInstance(PersistenceUnit unit,
ComponentUnit componentUnit) throws PersistenceException {
BeanletPersistenceUnitInfoFactory factory =
BeanletPersistenceUnitInfoFactory.getInstance(componentUnit);
final BeanletPersistenceUnitInfo unitInfo = factory.getPersistenceUnitInfo(
unit.unitName());
lock.lock();
ReadWriteLock rwLock;
try {
rwLock = applicationLockMap.get(unitInfo);
if (rwLock == null) {
rwLock = new ReentrantReadWriteLock();
applicationLockMap.put(unitInfo, rwLock);
}
} finally {
lock.unlock();
}
rwLock.readLock().lock();
BeanletEntityManagerFactory emf = applicationRegistry.get(unitInfo);
rwLock.readLock().unlock();
if (emf == null) {
try {
rwLock.writeLock().lockInterruptibly();
emf = applicationRegistry.get(unitInfo);
if (emf == null) {
emf = createEntityManagerFactory(unitInfo, Collections.emptyMap());
applicationRegistry.put(unitInfo, emf);
componentUnit.addDestroyHook(new Runnable() {
public void run() {
applicationLockMap.remove(unitInfo);
applicationRegistry.remove(unitInfo).close();
}
});
}
} catch (InterruptedException e) {
throw new PersistenceException(e);
} finally {
rwLock.writeLock().unlock();
}
}
assert emf != null;
return emf;
}
public static BeanletEntityManagerFactory getInstance(PersistenceContext pctx,
ComponentUnit componentUnit) throws PersistenceException {
PersistenceProperty[] props = pctx.properties();
Map<String, String> map = new HashMap<String, String>();
for (PersistenceProperty p : props) {
map.put(p.name(), p.value());
}
BeanletPersistenceUnitInfoFactory factory =
BeanletPersistenceUnitInfoFactory.getInstance(componentUnit);
final BeanletPersistenceUnitInfo unitInfo = factory.getPersistenceUnitInfo(
pctx.unitName());
lock.lock();
ReadWriteLock rwLock;
try {
rwLock = containerLockMap.get(unitInfo);
if (rwLock == null) {
rwLock = new ReentrantReadWriteLock();
containerLockMap.put(unitInfo, rwLock);
}
} finally {
lock.unlock();
}
rwLock.readLock().lock();
BeanletEntityManagerFactory emf = containerRegistry.get(unitInfo);
rwLock.readLock().unlock();
if (emf == null) {
try {
rwLock.writeLock().lockInterruptibly();
emf = containerRegistry.get(unitInfo);
if (emf == null) {
emf = createEntityManagerFactory(unitInfo, map);
containerRegistry.put(unitInfo, emf);
componentUnit.addDestroyHook(new Runnable() {
public void run() {
containerLockMap.remove(unitInfo);
containerRegistry.remove(unitInfo).close();
}
});
}
} catch (InterruptedException e) {
throw new PersistenceException(e);
} finally {
rwLock.writeLock().unlock();
}
}
assert emf != null;
return emf;
}
}