/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server.security.xacml.pdp.data;
import java.io.File;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.fcrepo.server.security.xacml.pdp.MelcoePDP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.fcrepo.common.Constants;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.dbxml.XmlContainer;
import com.sleepycat.dbxml.XmlContainerConfig;
import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlIndexSpecification;
import com.sleepycat.dbxml.XmlManager;
import com.sleepycat.dbxml.XmlManagerConfig;
import com.sleepycat.dbxml.XmlUpdateContext;
import com.sleepycat.dbxml.XmlValue;
/**
* Encapsulates access to DbXml
*
* @author Stephen Bayliss
* @version $Id$
*/
public class DbXmlManager {
private static final Logger log =
LoggerFactory.getLogger(DbXmlManager.class.getName());
private static final String XACML20_POLICY_NS =
Constants.XACML2_POLICY_SCHEMA.OS.uri;
public String DB_HOME = null;
public String CONTAINER = null;
public Map<String, Map<String, String>> indexMap = null;
public XmlManager manager = null;
public XmlUpdateContext updateContext = null;
public XmlContainer container = null;
public Environment env = null;
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public static final Lock readLock = rwl.readLock();
public static final Lock writeLock = rwl.writeLock();
public DbXmlManager(String databaseDirectory, String container)
throws PolicyStoreException {
setDatabaseDirectory(databaseDirectory);
setContainer(container);
}
/**
* Closes the dbxml container and manager.
*/
public void close() {
// getting a read lock will ensure all writes have finished
// if we are really closing assume that we don't care about reads
readLock.lock();
try {
if (container != null) {
try {
container.close();
container = null;
log.info("Closed container");
} catch (XmlException e) {
log.warn("close failed: " + e.getMessage(), e);
}
}
if (manager != null) {
try {
manager.close();
manager = null;
log.info("Closed manager");
} catch (XmlException e) {
log.warn("close failed: " + e.getMessage(), e);
}
}
} finally {
readLock.unlock();
}
}
public void deleteDatabase() {
readLock.lock();
try {
try {
//XmlIndexSpecification is = container.getIndexSpecification();
//container.setIndexSpecification(is);
container.close();
container = null;
} catch (XmlException e) {
log.warn("Error closing container " + e.getMessage());
}
//container.delete();
try {
manager.removeContainer(CONTAINER);
} catch (XmlException e) {
log.warn("Error removing container " + e.getMessage());
}
} finally {
readLock.unlock();
}
}
public void setDatabaseDirectory(String databaseDirectory) throws PolicyStoreException {
DB_HOME = MelcoePDP.PDP_HOME.getAbsolutePath() + databaseDirectory;
File db_home = new File(DB_HOME);
if (!db_home.exists()) {
try {
db_home.mkdirs();
} catch (Exception e) {
throw new PolicyStoreException("Could not create DB directory: "
+ db_home.getAbsolutePath());
}
}
if (log.isDebugEnabled()) {
log.debug("[config] databaseDirectory : " + db_home.getAbsolutePath());
}
}
public void setContainer(String container) {
CONTAINER = container;
if (log.isDebugEnabled()) {
log.debug("[config] container: " + container);
}
}
public void init() throws PolicyStoreException {
if (log.isDebugEnabled()) {
Runtime runtime = Runtime.getRuntime();
log.debug("Total memory: " + runtime.totalMemory() / 1024);
log.debug("Free memory: " + runtime.freeMemory() / 1024);
log.debug("Max memory: " + runtime.maxMemory() / 1024);
}
File envHome = new File(DB_HOME);
EnvironmentConfig envCfg = new EnvironmentConfig();
//envCfg.setRunRecovery(true);
envCfg.setAllowCreate(true);
envCfg.setInitializeCache(true);
envCfg.setInitializeLocking(false);
envCfg.setInitializeLogging(true);
envCfg.setTransactional(false);
XmlManagerConfig managerCfg = new XmlManagerConfig();
managerCfg.setAdoptEnvironment(true);
managerCfg.setAllowExternalAccess(true);
XmlContainerConfig containerCfg = new XmlContainerConfig();
containerCfg.setAllowCreate(true);
containerCfg.setTransactional(false);
try {
env = new Environment(envHome, envCfg);
manager = new XmlManager(env, managerCfg);
// XmlManager.setLogCategory(XmlManager.CATEGORY_NONE, true);
// XmlManager.setLogLevel(XmlManager.LEVEL_WARNING, true);
updateContext = manager.createUpdateContext();
} catch (Exception e) {
log.error("Error opening container: " + e.getMessage(), e);
close();
throw new PolicyStoreException(e.getMessage(), e);
}
try {
if (manager.existsContainer(CONTAINER) == 0) {
container =
manager.createContainer(CONTAINER,
containerCfg);
// if we just created a container we also need to add an
// index
XmlIndexSpecification is =
container.getIndexSpecification();
int idxType = 0;
int syntaxType = 0;
// Add the attribute value index
idxType |= XmlIndexSpecification.PATH_EDGE;
idxType |= XmlIndexSpecification.NODE_ELEMENT;
idxType |= XmlIndexSpecification.KEY_EQUALITY;
syntaxType = XmlValue.STRING;
is.addIndex(XACML20_POLICY_NS,
"AttributeValue",
idxType,
syntaxType);
// Add the metadata default index
idxType = 0;
idxType |= XmlIndexSpecification.PATH_NODE;
idxType |= XmlIndexSpecification.NODE_METADATA;
idxType |= XmlIndexSpecification.KEY_PRESENCE;
syntaxType = XmlValue.NONE;
is.addDefaultIndex(idxType, syntaxType);
container.setIndexSpecification(is, updateContext);
} else {
container =
manager.openContainer(CONTAINER, containerCfg);
}
} catch (XmlException e) {
if(e.getDatabaseException() instanceof com.sleepycat.db.DeadlockException){
log.error("Caught deadlock exception, create/open container", e);
}
log.error("Could not start database subsystem.", e);
close();
throw new PolicyStoreException(e.getMessage(), e);
}
log.info("Opened Container: " + CONTAINER);
}
}