/* * This file is part of the HyperGraphDB source distribution. This is copyrighted * software. For permitted uses, licensing options and redistribution, please see * the LicensingInformation file at the root level of the distribution. * * Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved. */ package org.hypergraphdb; import java.io.File; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hypergraphdb.util.MemoryWarningSystem; /** * <p> * This class provides some facilities to manage several open HyperGraph databases * within a single virtual machine. This is useful when one needs to access a * currently open database by its location. * </p> * * <p> * The class essentially implements a static map of currently open databases. The * general name <code>HGEnvironment</code> reflects the intent to eventually * put JVM-wide operations here. * </p> * * @author Borislav Iordanov */ public class HGEnvironment { private static Map<String, HyperGraph> dbs = new HashMap<String, HyperGraph>(); private static Map<String, HGConfiguration> configs = new HashMap<String, HGConfiguration>(); private static MemoryWarningSystem memWarning = null; synchronized static void set(String location, HyperGraph graph) { dbs.put(normalize(location), graph); } synchronized static void remove(String location) { dbs.remove(normalize(location)); } static String normalize(String location) { File f = new File(location); try { return f.getCanonicalPath(); } catch (java.io.IOException ex) { ex.printStackTrace(System.err); return f.getAbsolutePath(); } } /** * <p> * Return the singleton {@link MemoryWarningSystem} attached to this * JVM. * </p> */ public static synchronized MemoryWarningSystem getMemoryWarningSystem() { if (memWarning == null) { memWarning = new MemoryWarningSystem(); } return memWarning; } /** * <p> * Retrieve an already opened or open a HyperGraph instance. Note that a new * database instance will potentially be created via <code>new HyperGraph(location)</code> * if it doesn't already exist. * </p> * * @param location The location of the HyperGraph instance. * @return The HyperGraph database instance. */ public synchronized static HyperGraph get(String location) { location = normalize(location); HyperGraph hg = dbs.get(location); if (hg == null) { hg = new HyperGraph(); hg.setConfig(getConfiguration(location)); hg.open(location); dbs.put(location, hg); } else if (!hg.isOpen()) { if (configs.containsKey(location)) hg.setConfig(configs.get(location)); hg.open(location); } return hg; } /** * <p>Retrieve the HyperGraphDB instance at the specified location and open it * (if not already opened) with the given configuration. If the instance has * already been opened, the configuration parameter is ignored. * * @param location The filesystem path of the database instance. * @param config The set of configuration parameters. * @return */ public synchronized static HyperGraph get(String location, HGConfiguration config) { location = normalize(location); configs.put(location, config); return get(location); } /** * <p> * Same as <code>get</code>, but will return <code>null</code> if there is * no database at that location. * </p> */ public synchronized static HyperGraph getExistingOnly(String location) { location = normalize(location); HyperGraph hg = dbs.get(location); if (hg == null) { if (exists(location)) hg = new HyperGraph(location); } else if (!hg.isOpen()) { if (configs.containsKey(location)) hg.setConfig(configs.get(location)); hg.open(location); } return hg; } /** * <p> * Return <code>true</code> if there is a HyperGraph database at the given location * and <code>false</code> otherwise. * </p> */ public synchronized static boolean exists(String location) { // This filename is pretty unique to HGDB, so if a directory has it, chances // are it's a HGDB database. String [] testfiles = new String[] {"hgstore_idx_HGATOMTYPE", "je.lck" }; File dir = new File(location); if (!dir.isDirectory()) return false; List<String> all = Arrays.asList(dir.list()); for (String testfile : testfiles) if (new File(dir, testfile).exists() || all.contains(testfile)) return true; return false; } /** * <p> * Return <code>true</code> if the database at the given location is already * open and <code>false</code> otherwise. * </p> */ public synchronized static boolean isOpen(String location) { HyperGraph graph = dbs.get(location); return graph != null && graph.isOpen(); } /** * <p> * Configure a HyperGraphDB instance before it is actually opened. If the instance * at that location is already opened, the new configuration will only take effect * if you close and re-open the instance. * </p> * * @param location The filesystem path to the database instance. * @param config A <code>HGConfiguration</code> with the desired parameters set. */ public synchronized static void configure(String location, HGConfiguration config) { configs.put(location, config); } /** * <p> * Retrieve the configuration of a HyperGraphDB instance. If no configuration was * previously defined, a new one will be created. * </p> * * @param location The filesystem path to the HyperGraphDB instance. */ public synchronized static HGConfiguration getConfiguration(String location) { location = normalize(location); HGConfiguration conf = configs.get(location); if (conf == null) { HyperGraph hg = dbs.get(location); if (hg != null) conf = hg.getConfig(); else conf = new HGConfiguration(); configs.put(location, conf); } return conf; } /** * * <p> * Close all currently open <code>HyperGraph</code> instances. This is generally * done by a HyperGraphDB internal shutdown hook registered with the JVM. But if * you need more control over the shutdown sequence, this method will gracefully * do so. * </p> * */ public synchronized static void closeAll() { for (HyperGraph graph : dbs.values()) { if (graph.isOpen()) try { graph.close(); } catch (Throwable t) { System.err.println("Problem closing HyperGraphDB instance at " + graph.getLocation() + ", stack trace follows..."); t.printStackTrace(System.err); } } dbs.clear(); } /** * * <p> * Disable the HyperGraph JVM shutdown hook. The role of the shutdown hook is the close * all open databases gracefully. If you disable, no such process is triggered upon * JVM shutdown. If you have your own shutdown hook that must take upon that task, you can * call the <code>closeAll</code> method. * </p> * */ public static void disableShutdownHook() { Runtime.getRuntime().removeShutdownHook(shutdownHook); } // Try to make sure all HyperGraphs are properly closed during shutdown. private static class OnShutdown implements Runnable { public void run() { closeAll(); } } private static Thread shutdownHook = new Thread(new OnShutdown()); static { Runtime.getRuntime().addShutdownHook(shutdownHook); } }