/* * Copyright (c) 2009, Jan Stender, Bjoern Kolbeck, Mikael Hoegqvist, * Felix Hupfeld, Felix Langner, Zuse Institute Berlin * * Licensed under the BSD License, see LICENSE file for details. * */ package de.mxro.thrd.babudb05.conversion; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.Map.Entry; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import de.mxro.thrd.xstreemfs.foundation.logging.Logging; /** * A class loader that loads classes from a BabuDB JAR. * * @author stender * */ public class BabuDBVersionReader extends ClassLoader { private Map<String, byte[]> classes; private Object babuDB; /** * Creates a BabuDB JAR class loader for the given BabuDB data version. It * will automatically attempt to load the JAR with the given data version * number from 'org.xtreemfs.babudb.conversion.jars'. * * @param ver * the data version * @param cfgProps * the configuration properties needed to access the old version * of the database * @throws IOException * if an I/O error occurred */ public BabuDBVersionReader(int ver, Properties cfgProps) throws IOException { super(null); this.classes = new HashMap<String, byte[]>(); // load all classes from JAR JarInputStream jis = new JarInputStream(getClass().getResourceAsStream("jars/" + ver + ".jar")); for (;;) { JarEntry next = jis.getNextJarEntry(); if (next == null) break; if (!next.getName().endsWith(".class")) continue; byte[] buf = new byte[4096]; ByteArrayOutputStream out = new ByteArrayOutputStream(); for (;;) { int len = jis.read(buf); if (len <= 0) break; out.write(buf, 0, len); } String className = next.getName().substring(0, next.getName().length() - ".class".length()) .replace('/', '.'); classes.put(className, out.toByteArray()); out.close(); } jis.close(); this.babuDB = initBabuDB(cfgProps); } public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { byte[] classBytes = classes.get(name); if (classBytes == null) return findSystemClass(name); Class<?> clazz = defineClass(name, classBytes, 0, classBytes.length); if (resolve) resolveClass(clazz); return clazz; } public Iterator<Entry<byte[], byte[]>> getIndexContent(String dbName, int indexId) { try { // retrieve the database manager Object dbManager = babuDB.getClass().getMethod("getDatabaseManager").invoke(babuDB); // retrieve the database Object database = dbManager.getClass().getMethod("getDatabase", String.class).invoke(dbManager, dbName); // perform a prefix lookup for the complete index Object query = database.getClass().getMethod("prefixLookup", int.class, byte[].class, Object.class).invoke(database, indexId, new byte[0], null); // get the iterator from the query object Iterator<Entry<byte[], byte[]>> it = (Iterator<Entry<byte[], byte[]>>) query.getClass() .getMethod("get").invoke(query); return it; } catch (Exception exc) { Logging.logError(Logging.LEVEL_CRIT, this, exc); return null; } } public void shutdown() { if (babuDB == null) return; try { babuDB.getClass().getMethod("shutdown").invoke(babuDB); babuDB = null; } catch (Exception exc) { Logging.logError(Logging.LEVEL_ERROR, this, exc); } } public Set<String> getAllDatabases() { try { // retrieve the database manager Object dbManager = babuDB.getClass().getMethod("getDatabaseManager").invoke(babuDB); // get the list of databases Map<String, ?> map = (Map<String, ?>) dbManager.getClass().getMethod("getDatabases").invoke( dbManager); return map.keySet(); } catch (Exception exc) { Logging.logError(Logging.LEVEL_ERROR, this, exc); return null; } } public int getNumIndics(String dbName) { try { // retrieve the database manager Object dbManager = babuDB.getClass().getMethod("getDatabaseManager").invoke(babuDB); // retrieve the database Object database = dbManager.getClass().getMethod("getDatabase", String.class).invoke(dbManager, dbName); int i = 0; try { for (;; i++) { // perform a prefix lookup for the complete index Object query = database.getClass().getMethod("lookup", int.class, byte[].class, Object.class).invoke(database, i, new byte[0], null); // get the iterator from the query object query.getClass().getMethod("get").invoke(query); } } catch (Exception exc) { // ignore } return i; } catch (Exception exc) { Logging.logError(Logging.LEVEL_ERROR, this, exc); return 0; } } public String[] getAllSnapshots(String dbName) { try { // retrieve the database manager Object snapManager = babuDB.getClass().getMethod("getSnapshotManager").invoke(babuDB); // retrieve the database return (String[]) snapManager.getClass().getMethod("getAllSnapshots", String.class).invoke( snapManager, dbName); } catch (Exception exc) { Logging.logError(Logging.LEVEL_ERROR, this, exc); return null; } } public Iterator<Entry<byte[], byte[]>> getIndexContent(String dbName, String snapName, int indexId) { try { // retrieve the database manager Object snapManager = babuDB.getClass().getMethod("getSnapshotManager").invoke(babuDB); // retrieve the database Object database = snapManager.getClass().getMethod("getSnapshotDB", String.class, String.class) .invoke(snapManager, dbName, snapName); // perform a prefix lookup for the complete index Object query = database.getClass().getMethod("prefixLookup", int.class, byte[].class, Object.class).invoke(database, indexId, new byte[0], null); // get the iterator from the query object Iterator<Entry<byte[], byte[]>> it = (Iterator<Entry<byte[], byte[]>>) query.getClass() .getMethod("get").invoke(query); return it; } catch (Exception exc) { Logging.logError(Logging.LEVEL_CRIT, this, exc); return null; } } /** * Checks if a certain data version JAR is supported by the class loader. * * @param ver * the version to be checked * * @return <code>true</code>, if it is supported, <code>false</code>, * otherwise */ public static boolean checkVersionSupport(int ver) { JarInputStream jis = null; try { jis = new JarInputStream(BabuDBVersionReader.class.getResourceAsStream("jars/" + ver + ".jar")); return true; } catch (Exception exc) { return false; } finally { if (jis != null) try { jis.close(); } catch (IOException exc) { // ignore } } } protected Object initBabuDB(Properties cfgProps) { try { assert (babuDB == null); // create a BabuDB configuration Class<?> cfgCls = loadClass("org.xtreemfs.babudb.config.BabuDBConfig"); Object cfg = cfgCls.getConstructor(Properties.class).newInstance(cfgProps); // create a BabuDB instance Class<?> babuDBFactoryCls = loadClass("org.xtreemfs.babudb.BabuDBFactory"); return babuDBFactoryCls.getMethod("createBabuDB", cfgCls).invoke(null, cfg); } catch (Exception exc) { Logging.logError(Logging.LEVEL_ERROR, this, exc); return null; } } }