001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file ../GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015: package org.griphyn.vdl.dbschema;
016:
017: import java.sql.*;
018: import java.util.*;
019: import java.lang.reflect.*;
020: import java.sql.SQLException;
021: import java.io.IOException;
022: import org.griphyn.vdl.util.ChimeraProperties;
023: import org.griphyn.vdl.classes.*;
024: import org.griphyn.vdl.util.Logging;
025: import org.griphyn.vdl.dbdriver.*;
026:
027: /**
028: * This is a class that falls back not on a real database backend,
029: * but rather on an existing Definitions data structure in main
030: * memory. This schema is for internal use only.</p>
031: *
032: * @author Jens-S. Vöckler
033: * @author Yong Zhao
034: * @version $Revision: 50 $
035: * @see org.griphyn.vdl.dbdriver
036: * @see org.griphyn.vdl.classes.Definitions
037: */
038: public class InMemorySchema extends DatabaseSchema implements VDC {
039: /**
040: * Stores a reference to the in-memory data structure that hold
041: * all definitions that we can access from within this instance.
042: */
043: protected Definitions m_memory;
044:
045: /**
046: * Default ctor does nothing.
047: */
048: protected InMemorySchema() {
049: super ();
050: this .m_memory = null;
051: }
052:
053: /**
054: * Dirty hack: Returns a reference to the in-memory database for
055: * preliminary routing into DAXes. This is to avoid the duplication
056: * of DVs in memory, as memory becomes quickly a scarce resource.
057: *
058: * @return a reference to the in-memory database.
059: */
060: public Definitions backdoor() {
061: return this .m_memory;
062: }
063:
064: /**
065: * Fakes a connect to the database. This class never uses any
066: * database, but instead applies all data to the provided
067: * reference to the in-memory structure. Subclasses may refine
068: * this view to work with files or URLs.
069: *
070: * @param memory is a reference to an existing in-memory Java
071: * object holding all our necessary definitions.
072: */
073: public InMemorySchema(Definitions memory)
074: throws ClassNotFoundException, NoSuchMethodException,
075: InstantiationException, IllegalAccessException,
076: InvocationTargetException, SQLException, IOException {
077: super (); // call minimalistic c'tor
078: this .m_memory = memory;
079: this .m_dbschemaprops = ChimeraProperties.instance()
080: .getDatabaseSchemaProperties(PROPERTY_PREFIX);
081: }
082:
083: /**
084: * Pass-thru to driver. Always returns false, as the backend is
085: * main memory.
086: *
087: * @return true, if it is feasible to cache results from the driver
088: * false, if requerying the driver is sufficiently fast (e.g. driver
089: * is in main memory, or driver does caching itself).
090: */
091: public boolean cachingMakesSense() {
092: return false;
093: }
094:
095: //
096: // lower level methods, working directly on specific definitions
097: //
098:
099: /**
100: * Loads a single Definition from the backend database into an Java object.
101: * This method does not allow wildcarding!
102: *
103: * @param namespace namespace, null will be converted into empty string
104: * @param name name, null will be converted into empty string
105: * @param version version, null will be converted into empty string
106: * @param type type of the definition (TR or DV), must not be -1.
107: * @return the Definition as specified, or null if not found.
108: *
109: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
110: * @see org.griphyn.vdl.classes.Definition#DERIVATION
111: * @see #saveDefinition( Definition, boolean )
112: * @see #searchDefinition( String, String, String, int )
113: */
114: public Definition loadDefinition(String namespace, String name,
115: String version, int type) throws SQLException {
116: // walk main memory
117: Definition result = null;
118: for (Iterator i = this .m_memory.iterateDefinition(); i
119: .hasNext();) {
120: Definition d = (Definition) i.next();
121: if (d.match(type, namespace, name, version)) {
122: result = d;
123: break;
124: }
125: }
126: return result;
127: }
128:
129: /**
130: * Saves a Definition, that is either a Transformation or Derivation,
131: * into the backend database.
132: *
133: * @param definition is the new Definition to store.
134: * @param overwrite true, if existing defitions will be overwritten by
135: * new ones with the same primary (or secondary) key (-set), or false,
136: * if a new definition will be rejected on key matches.
137: *
138: * @return true, if the backend database was changed, or
139: * false, if the definition was not accepted into the backend.
140: *
141: * @see org.griphyn.vdl.classes.Definition
142: * @see org.griphyn.vdl.classes.Transformation
143: * @see org.griphyn.vdl.classes.Derivation
144: * @see #loadDefinition( String, String, String, int )
145: * @see #deleteDefinition( String, String, String, int )
146: */
147: public boolean saveDefinition(Definition definition,
148: boolean overwrite) throws SQLException {
149: int position = this .m_memory.positionOfDefinition(definition);
150: if (position != -1) {
151: // definition already exists
152: if (overwrite) {
153: Logging.instance().log("app", 1,
154: "Modifying " + definition.shortID());
155: this .m_memory.setDefinition(position, definition);
156: return true;
157: } else {
158: Logging.instance().log("app", 1,
159: "Rejecting " + definition.shortID());
160: return false;
161: }
162: } else {
163: // definition does not exist
164: Logging.instance().log("app", 1,
165: "Adding " + definition.shortID());
166: this .m_memory.addDefinition(definition);
167: return true;
168: }
169: }
170:
171: //
172: // higher level methods, allowing for wildcarding as stated.
173: //
174:
175: /**
176: * Check with the backend database, if the given definition exists.
177: *
178: * @param definition is a Definition object to search for
179: * @return true, if the Definition exists, false if not found
180: */
181: public boolean containsDefinition(Definition definition)
182: throws SQLException {
183: return (this .m_memory.positionOfDefinition(definition) != -1);
184: }
185:
186: /**
187: * Delete a specific Definition objects from the database. No wildcard
188: * matching will be done. "Fake" definitions are permissable, meaning
189: * it just has the secondary key triple.<p>
190: * This method is not implemented!
191: *
192: * @param definition is the definition specification to delete
193: * @return true is something was deleted, false if non existent.
194: *
195: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
196: * @see org.griphyn.vdl.classes.Definition#DERIVATION
197: */
198: public boolean deleteDefinition(Definition definition)
199: throws SQLException {
200: return this .m_memory.removeDefinition(definition);
201: }
202:
203: /**
204: * Delete one or more definitions from the backend database. Depending
205: * on the matchAll flag the key triple parameters may be wildcards.
206: * Wildcards are expressed as <code>null</code> value.<p>
207: * This method is not implemented!
208: *
209: * @param namespace namespace
210: * @param name name
211: * @param version version
212: * @param type definition type (TR or DV)
213: * @return a list of definitions that were deleted.
214: *
215: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
216: * @see org.griphyn.vdl.classes.Definition#DERIVATION
217: */
218: public java.util.List deleteDefinition(String namespace,
219: String name, String version, int type) throws SQLException {
220: java.util.List result = new ArrayList();
221:
222: // walk the database
223: for (ListIterator i = this .m_memory.listIterateDefinition(); i
224: .hasNext();) {
225: Definition d = (Definition) i.next();
226: if (type == -1 || d.getType() == type) {
227: // yes, type matches, let's continue
228: String ns = d.getNamespace();
229: String id = d.getName();
230: String vs = d.getVersion();
231:
232: if ((namespace == null || // match all for null argument
233: ns != null && ns.equals(namespace))
234: && (name == null || // match all for null argument
235: id != null && id.equals(name))
236: && (version == null || // match all for null argument
237: vs != null && vs.equals(version))) {
238: // there was a match including nulls and jokers etc.
239: result.add(d);
240: i.remove();
241: }
242: }
243: }
244:
245: return result;
246: }
247:
248: /**
249: * Search the database for definitions by ns::name:version triple
250: * and by type (either Transformation or Derivation). This version
251: * of the search allows for jokers expressed as null value.<p>
252: * This method is not implemented!
253: *
254: * @param namespace namespace, null to match any namespace
255: * @param name name, null to match any name
256: * @param version version, null to match any version
257: * @param type type of definition, see below, or -1 as wildcard
258: * @return a list of Definition items, which may be empty
259: *
260: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
261: * @see org.griphyn.vdl.classes.Definition#DERIVATION
262: * @see #loadDefinition( String, String, String, int )
263: */
264: public java.util.List searchDefinition(String namespace,
265: String name, String version, int type) throws SQLException {
266: java.util.List result = new ArrayList();
267:
268: // walk the database
269: for (ListIterator i = this .m_memory.listIterateDefinition(); i
270: .hasNext();) {
271: Definition d = (Definition) i.next();
272: if (type == -1 || d.getType() == type) {
273: // yes, type matches, let's continue
274: String ns = d.getNamespace();
275: String id = d.getName();
276: String vs = d.getVersion();
277:
278: if ((namespace == null || // match all for null argument
279: ns != null && ns.equals(namespace))
280: && (name == null || // match all for null argument
281: id != null && id.equals(name))
282: && (version == null || // match all for null argument
283: vs != null && vs.equals(version))) {
284: result.add(d);
285: }
286: }
287: }
288:
289: return result;
290: }
291:
292: /**
293: * Searches the database for all derivations that contain a certain LFN.
294: * The linkage is an additional constraint. This method does not allow
295: * jokers.
296: *
297: * @param lfn the LFN name
298: * @param link the linkage type of the LFN
299: * @return a list of Definition items that match the criterion.
300: *
301: * @see org.griphyn.vdl.classes.LFN#NONE
302: * @see org.griphyn.vdl.classes.LFN#INPUT
303: * @see org.griphyn.vdl.classes.LFN#OUTPUT
304: * @see org.griphyn.vdl.classes.LFN#INOUT
305: */
306: public java.util.List searchFilename(String lfn, int link)
307: throws SQLException {
308: java.util.List result = new ArrayList();
309:
310: // check all Derivations (this may be time consuming!)
311: for (Iterator i = this .m_memory.iterateDefinition(); i
312: .hasNext();) {
313: Definition d = (Definition) i.next();
314: if (d instanceof Derivation) {
315: Derivation dv = (Derivation) d;
316: for (Iterator j = dv.iteratePass(); j.hasNext();) {
317: boolean found = false;
318: Value actual = ((Pass) j.next()).getValue();
319: switch (actual.getContainerType()) {
320: case Value.SCALAR:
321: // this is a regular SCALAR
322: if (scalarContainsLfn((Scalar) actual, lfn,
323: link)) {
324: // Logging.instance().log("search", 2, "found " + dv.shortID());
325: result.add(dv);
326: found = true;
327: }
328: break;
329: case Value.LIST:
330: // a LIST is a list of SCALARs
331: org.griphyn.vdl.classes.List list = (org.griphyn.vdl.classes.List) actual;
332: for (Iterator f = list.iterateScalar(); f
333: .hasNext();) {
334: if (scalarContainsLfn((Scalar) f.next(),
335: lfn, link)) {
336: // Logging.instance().log("search", 2, "found " + dv.shortID());
337: result.add(dv);
338: found = true;
339:
340: // skip all other scalars
341: break;
342: }
343: }
344: break;
345: default:
346: // this should not happen
347: Logging
348: .instance()
349: .log(
350: "default",
351: 0,
352: "WARNING: An actual argument \""
353: + actual.toString()
354: + "\" is neither SCALAR nor LIST");
355: break;
356: }
357:
358: // if found in one Pass, skip all the others
359: if (found)
360: break;
361: }
362: }
363: }
364:
365: return result;
366: }
367:
368: /**
369: * This helper function checks, if a given Scalar instance
370: * contains the specified logical filename as LFN instance anywhere
371: * in its sub-structures.
372: *
373: * @param scalar is a Scalar instance to check
374: * @param lfn is a logical filename string to check for
375: * @param link is the linkage type of the lfn.
376: * if -1, do not check the linkage type.
377: * @return true, if the file was found
378: */
379: protected boolean scalarContainsLfn(Scalar scalar, String lfn,
380: int link) {
381: for (Iterator e = scalar.iterateLeaf(); e.hasNext();) {
382: org.griphyn.vdl.classes.Leaf leaf = (org.griphyn.vdl.classes.Leaf) e
383: .next();
384: if (leaf instanceof LFN) {
385: LFN local = (LFN) leaf;
386: if ((link == -1 || local.getLink() == link)
387: && lfn.compareTo(local.getFilename()) == 0)
388: return true;
389: }
390: }
391: return false;
392: }
393: }
|