/* * This file or a portion of this file is licensed under the terms of * the Globus Toolkit Public License, found in file ../GTPL, or at * http://www.globus.org/toolkit/download/license.html. This notice must * appear in redistributions of this file, with or without modification. * * Redistributions of this Software, with or without modification, must * reproduce the GTPL in: (1) the Software, or (2) the Documentation or * some other similar material which is provided with the Software (if * any). * * Copyright 1999-2004 University of Chicago and The University of * Southern California. All rights reserved. */ package org.griphyn.vdl.dbschema; import java.sql.*; import java.util.*; import java.lang.reflect.*; import java.sql.SQLException; import java.io.IOException; import org.griphyn.vdl.util.ChimeraProperties; import org.griphyn.vdl.classes.*; import org.griphyn.vdl.util.Logging; import org.griphyn.vdl.dbdriver.*; /** * This is a class that falls back not on a real database backend, * but rather on an existing Definitions data structure in main * memory. This schema is for internal use only.</p> * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ * @see org.griphyn.vdl.dbdriver * @see org.griphyn.vdl.classes.Definitions */ public class InMemorySchema extends DatabaseSchema implements VDC { /** * Stores a reference to the in-memory data structure that hold * all definitions that we can access from within this instance. */ protected Definitions m_memory; /** * Default ctor does nothing. */ protected InMemorySchema() { super(); this.m_memory = null; } /** * Dirty hack: Returns a reference to the in-memory database for * preliminary routing into DAXes. This is to avoid the duplication * of DVs in memory, as memory becomes quickly a scarce resource. * * @return a reference to the in-memory database. */ public Definitions backdoor() { return this.m_memory; } /** * Fakes a connect to the database. This class never uses any * database, but instead applies all data to the provided * reference to the in-memory structure. Subclasses may refine * this view to work with files or URLs. * * @param memory is a reference to an existing in-memory Java * object holding all our necessary definitions. */ public InMemorySchema( Definitions memory ) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, SQLException, IOException { super(); // call minimalistic c'tor this.m_memory = memory; this.m_dbschemaprops = ChimeraProperties.instance().getDatabaseSchemaProperties( PROPERTY_PREFIX ); } /** * Pass-thru to driver. Always returns false, as the backend is * main memory. * * @return true, if it is feasible to cache results from the driver * false, if requerying the driver is sufficiently fast (e.g. driver * is in main memory, or driver does caching itself). */ public boolean cachingMakesSense() { return false; } // // lower level methods, working directly on specific definitions // /** * Loads a single Definition from the backend database into an Java object. * This method does not allow wildcarding! * * @param namespace namespace, null will be converted into empty string * @param name name, null will be converted into empty string * @param version version, null will be converted into empty string * @param type type of the definition (TR or DV), must not be -1. * @return the Definition as specified, or null if not found. * * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION * @see org.griphyn.vdl.classes.Definition#DERIVATION * @see #saveDefinition( Definition, boolean ) * @see #searchDefinition( String, String, String, int ) */ public Definition loadDefinition( String namespace, String name, String version, int type ) throws SQLException { // walk main memory Definition result = null; for ( Iterator i=this.m_memory.iterateDefinition(); i.hasNext(); ) { Definition d = (Definition) i.next(); if ( d.match( type, namespace, name, version ) ) { result = d; break; } } return result; } /** * Saves a Definition, that is either a Transformation or Derivation, * into the backend database. * * @param definition is the new Definition to store. * @param overwrite true, if existing defitions will be overwritten by * new ones with the same primary (or secondary) key (-set), or false, * if a new definition will be rejected on key matches. * * @return true, if the backend database was changed, or * false, if the definition was not accepted into the backend. * * @see org.griphyn.vdl.classes.Definition * @see org.griphyn.vdl.classes.Transformation * @see org.griphyn.vdl.classes.Derivation * @see #loadDefinition( String, String, String, int ) * @see #deleteDefinition( String, String, String, int ) */ public boolean saveDefinition( Definition definition, boolean overwrite ) throws SQLException { int position = this.m_memory.positionOfDefinition(definition); if ( position != -1 ) { // definition already exists if ( overwrite ) { Logging.instance().log( "app", 1, "Modifying " + definition.shortID() ); this.m_memory.setDefinition( position, definition ); return true; } else { Logging.instance().log( "app", 1, "Rejecting " + definition.shortID() ); return false; } } else { // definition does not exist Logging.instance().log( "app", 1, "Adding " + definition.shortID() ); this.m_memory.addDefinition(definition); return true; } } // // higher level methods, allowing for wildcarding as stated. // /** * Check with the backend database, if the given definition exists. * * @param definition is a Definition object to search for * @return true, if the Definition exists, false if not found */ public boolean containsDefinition( Definition definition ) throws SQLException { return ( this.m_memory.positionOfDefinition(definition) != -1 ); } /** * Delete a specific Definition objects from the database. No wildcard * matching will be done. "Fake" definitions are permissable, meaning * it just has the secondary key triple.<p> * This method is not implemented! * * @param definition is the definition specification to delete * @return true is something was deleted, false if non existent. * * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION * @see org.griphyn.vdl.classes.Definition#DERIVATION */ public boolean deleteDefinition( Definition definition ) throws SQLException { return this.m_memory.removeDefinition(definition); } /** * Delete one or more definitions from the backend database. Depending * on the matchAll flag the key triple parameters may be wildcards. * Wildcards are expressed as <code>null</code> value.<p> * This method is not implemented! * * @param namespace namespace * @param name name * @param version version * @param type definition type (TR or DV) * @return a list of definitions that were deleted. * * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION * @see org.griphyn.vdl.classes.Definition#DERIVATION */ public java.util.List deleteDefinition( String namespace, String name, String version, int type ) throws SQLException { java.util.List result = new ArrayList(); // walk the database for ( ListIterator i=this.m_memory.listIterateDefinition(); i.hasNext(); ) { Definition d = (Definition) i.next(); if ( type == -1 || d.getType() == type ) { // yes, type matches, let's continue String ns = d.getNamespace(); String id = d.getName(); String vs = d.getVersion(); if ( ( namespace == null || // match all for null argument ns != null && ns.equals(namespace) ) && ( name == null || // match all for null argument id != null && id.equals(name) ) && ( version == null || // match all for null argument vs != null && vs.equals(version) ) ) { // there was a match including nulls and jokers etc. result.add(d); i.remove(); } } } return result; } /** * Search the database for definitions by ns::name:version triple * and by type (either Transformation or Derivation). This version * of the search allows for jokers expressed as null value.<p> * This method is not implemented! * * @param namespace namespace, null to match any namespace * @param name name, null to match any name * @param version version, null to match any version * @param type type of definition, see below, or -1 as wildcard * @return a list of Definition items, which may be empty * * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION * @see org.griphyn.vdl.classes.Definition#DERIVATION * @see #loadDefinition( String, String, String, int ) */ public java.util.List searchDefinition( String namespace, String name, String version, int type ) throws SQLException { java.util.List result = new ArrayList(); // walk the database for ( ListIterator i=this.m_memory.listIterateDefinition(); i.hasNext(); ) { Definition d = (Definition) i.next(); if ( type == -1 || d.getType() == type ) { // yes, type matches, let's continue String ns = d.getNamespace(); String id = d.getName(); String vs = d.getVersion(); if ( ( namespace == null || // match all for null argument ns != null && ns.equals(namespace) ) && ( name == null || // match all for null argument id != null && id.equals(name) ) && ( version == null || // match all for null argument vs != null && vs.equals(version) ) ) { result.add(d); } } } return result; } /** * Searches the database for all derivations that contain a certain LFN. * The linkage is an additional constraint. This method does not allow * jokers. * * @param lfn the LFN name * @param link the linkage type of the LFN * @return a list of Definition items that match the criterion. * * @see org.griphyn.vdl.classes.LFN#NONE * @see org.griphyn.vdl.classes.LFN#INPUT * @see org.griphyn.vdl.classes.LFN#OUTPUT * @see org.griphyn.vdl.classes.LFN#INOUT */ public java.util.List searchFilename( String lfn, int link ) throws SQLException { java.util.List result = new ArrayList(); // check all Derivations (this may be time consuming!) for ( Iterator i=this.m_memory.iterateDefinition(); i.hasNext(); ) { Definition d = (Definition) i.next(); if ( d instanceof Derivation ) { Derivation dv = (Derivation) d; for ( Iterator j=dv.iteratePass(); j.hasNext(); ) { boolean found = false; Value actual = ((Pass) j.next()).getValue(); switch ( actual.getContainerType() ) { case Value.SCALAR: // this is a regular SCALAR if ( scalarContainsLfn( (Scalar) actual, lfn, link ) ) { // Logging.instance().log("search", 2, "found " + dv.shortID()); result.add(dv); found = true; } break; case Value.LIST: // a LIST is a list of SCALARs org.griphyn.vdl.classes.List list = (org.griphyn.vdl.classes.List) actual; for ( Iterator f = list.iterateScalar(); f.hasNext() ; ) { if ( scalarContainsLfn( (Scalar) f.next(), lfn, link) ) { // Logging.instance().log("search", 2, "found " + dv.shortID()); result.add(dv); found = true; // skip all other scalars break; } } break; default: // this should not happen Logging.instance().log( "default", 0, "WARNING: An actual argument \"" + actual.toString() + "\" is neither SCALAR nor LIST" ); break; } // if found in one Pass, skip all the others if ( found ) break; } } } return result; } /** * This helper function checks, if a given Scalar instance * contains the specified logical filename as LFN instance anywhere * in its sub-structures. * * @param scalar is a Scalar instance to check * @param lfn is a logical filename string to check for * @param link is the linkage type of the lfn. * if -1, do not check the linkage type. * @return true, if the file was found */ protected boolean scalarContainsLfn( Scalar scalar, String lfn, int link ) { for ( Iterator e = scalar.iterateLeaf(); e.hasNext(); ) { org.griphyn.vdl.classes.Leaf leaf = (org.griphyn.vdl.classes.Leaf) e.next(); if ( leaf instanceof LFN ) { LFN local = (LFN) leaf; if ( (link == -1 || local.getLink() == link) && lfn.compareTo( local.getFilename() ) == 0 ) return true; } } return false; } }