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.io.*;
020: import java.lang.reflect.*;
021: import java.net.InetAddress;
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.parser.*;
026: import org.griphyn.vdl.router.Cache;
027: import org.xml.sax.InputSource;
028:
029: /**
030: * This class provides basic functionalities to interact with the
031: * backend database, such as insertion, deletion, and search of
032: * entities in the VDC.
033: *
034: * @author Jens-S. Vöckler
035: * @author Yong Zhao
036: * @version $Revision: 50 $
037: */
038: public class ChunkSchema extends DatabaseSchema implements VDC {
039: /**
040: * Name of the four parameter tables in human readable format.
041: */
042: protected static final String[] c_lfn_names = { "VDC_NLFN",
043: "VDC_ILFN", "VDC_OLFN", "VDC_BLFN" };
044:
045: /**
046: * Communication between saveDefinition and deleteDefinition in
047: * update mode.
048: */
049: protected boolean m_deferDeleteCommit;
050:
051: /**
052: * An instance of the VDLx XML parser.
053: */
054: private org.griphyn.vdl.parser.VDLxParser m_parser;
055:
056: /**
057: * A cache for definitions to avoid reloading from the database.
058: */
059: protected Cache m_cache;
060:
061: /**
062: * Instantiates an XML parser for VDLx on demand. Since XML parsing
063: * XML parsing and parser instantiation is an expensive business, the
064: * reader will only be generated on demand.
065: *
066: * @return a valid VDLx parser instance.
067: */
068: private org.griphyn.vdl.parser.VDLxParser parserInstance() {
069: if (this .m_parser == null) {
070: // obtain the schema location URL from the schema properties:
071: // url is a list of strings representing schema locations. The
072: // content exists in pairs, one of the namespace URI, one of the
073: // location URL.
074: String url = null;
075: try {
076: ChimeraProperties props = ChimeraProperties.instance();
077: url = m_dbschemaprops.getProperty("xml.url", props
078: .getVDLSchemaLocation());
079: } catch (IOException e) {
080: Logging.instance().log("chunk", 0, "ignored " + e);
081: }
082: this .m_parser = new org.griphyn.vdl.parser.VDLxParser(url);
083: }
084:
085: // done
086: return this .m_parser;
087: }
088:
089: /**
090: * Default constructor for the "chunk" schema.
091: *
092: * @param dbDriverName is the database driver name
093: */
094: public ChunkSchema(String dbDriverName)
095: throws ClassNotFoundException, NoSuchMethodException,
096: InstantiationException, IllegalAccessException,
097: InvocationTargetException, SQLException, IOException {
098: // load the driver from the properties
099: super (dbDriverName, PROPERTY_PREFIX);
100: Logging.instance().log("dbschema", 3,
101: "done with default schema c'tor");
102:
103: this .m_cache = this .m_dbdriver.cachingMakesSense() ? new Cache(
104: 600) : null;
105: this .m_deferDeleteCommit = false;
106: this .m_parser = null;
107:
108: this .m_dbdriver.insertPreparedStatement("stmt.save.definition",
109: "INSERT INTO vdc_definition(id,type,name,namespace,version,xml) "
110: + "VALUES (?,?,?,?,?,?)");
111:
112: this .m_dbdriver.insertPreparedStatement("stmt.save.nlfn",
113: "INSERT INTO vdc_nlfn(id,name) VALUES (?,?)");
114: this .m_dbdriver.insertPreparedStatement("stmt.save.ilfn",
115: "INSERT INTO vdc_ilfn(id,name) VALUES (?,?)");
116: this .m_dbdriver.insertPreparedStatement("stmt.save.olfn",
117: "INSERT INTO vdc_olfn(id,name) VALUES (?,?)");
118: this .m_dbdriver.insertPreparedStatement("stmt.save.blfn",
119: "INSERT INTO vdc_blfn(id,name) VALUES (?,?)");
120:
121: this .m_dbdriver.insertPreparedStatement("stmt.select.nlfn",
122: "SELECT distinct id FROM vdc_nlfn WHERE name=?");
123: this .m_dbdriver.insertPreparedStatement("stmt.select.ilfn",
124: "SELECT distinct id FROM vdc_ilfn WHERE name=?");
125: this .m_dbdriver.insertPreparedStatement("stmt.select.olfn",
126: "SELECT distinct id FROM vdc_olfn WHERE name=?");
127: this .m_dbdriver.insertPreparedStatement("stmt.select.blfn",
128: "SELECT distinct id FROM vdc_blfn WHERE name=?");
129: this .m_dbdriver
130: .insertPreparedStatement(
131: "stmt.select.all.lfn",
132: "SELECT distinct did FROM vdc_nlfn WHERE name=? UNION "
133: + "SELECT distinct did FROM vdc_ilfn WHERE name=? UNION "
134: + "SELECT distinct did FROM vdc_olfn WHERE name=? UNION "
135: + "SELECT distinct did FROM vdc_blfn WHERE name=?");
136:
137: this .m_dbdriver.insertPreparedStatement("stmt.select.xml.id",
138: "SELECT xml FROM vdc_definition WHERE id=?");
139: this .m_dbdriver
140: .insertPreparedStatement(
141: "stmt.select.xml",
142: "SELECT id,xml FROM vdc_definition WHERE type=? AND name=? AND namespace=? AND version=?");
143: this .m_dbdriver
144: .insertPreparedStatement(
145: "stmt.select.id",
146: "SELECT id FROM vdc_definition WHERE type=? AND name=? AND namespace=? AND version=?");
147:
148: this .m_dbdriver.insertPreparedStatement("stmt.delete.xml",
149: "DELETE FROM vdc_definition WHERE id=?");
150: this .m_dbdriver.insertPreparedStatement("stmt.delete.nlfn",
151: "DELETE FROM vdc_nlfn WHERE id=?");
152: this .m_dbdriver.insertPreparedStatement("stmt.delete.ilfn",
153: "DELETE FROM vdc_ilfn WHERE id=?");
154: this .m_dbdriver.insertPreparedStatement("stmt.delete.olfn",
155: "DELETE FROM vdc_olfn WHERE id=?");
156: this .m_dbdriver.insertPreparedStatement("stmt.delete.blfn",
157: "DELETE FROM vdc_blfn WHERE id=?");
158: }
159:
160: //
161: // lower level methods, working directly on specific definitions
162: //
163:
164: /**
165: * Loads a single Definition from the backend database into an Java object.
166: * This method does not allow wildcarding!
167: *
168: * @param namespace namespace, null will be converted into empty string
169: * @param name name, null will be converted into empty string
170: * @param version version, null will be converted into empty string
171: * @param type type of the definition (TR or DV), must not be -1.
172: * @return the Definition as specified, or null if not found.
173: *
174: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
175: * @see org.griphyn.vdl.classes.Definition#DERIVATION
176: * @see #saveDefinition( Definition, boolean )
177: */
178: public Definition loadDefinition(String namespace, String name,
179: String version, int type) throws SQLException {
180: Definition result = null;
181: Logging.instance().log("xaction", 1, "START load definition");
182:
183: int i = 1;
184: PreparedStatement ps = m_dbdriver
185: .getPreparedStatement("stmt.select.xml");
186: ps.setInt(i++, type);
187: ps.setString(i++, makeNotNull(name));
188: ps.setString(i++, makeNotNull(namespace));
189: ps.setString(i++, makeNotNull(version));
190: Logging.instance()
191: .log("chunk", 2, "SELECT xml FROM definition");
192:
193: ResultSet rs = ps.executeQuery();
194: Logging.instance().log("xaction", 1, "INTER load definition");
195:
196: if (rs.next()) {
197: MyCallbackHandler cb = new MyCallbackHandler();
198: Long lid = new Long(rs.getLong("id"));
199: // FIXME: multiple null handlings missing
200: parserInstance().parse(
201: new org.xml.sax.InputSource(rs
202: .getCharacterStream("xml")), cb);
203: result = cb.getDefinition();
204:
205: // add to cache
206: if (m_cache != null)
207: m_cache.set(lid, result);
208: } else {
209: Logging.instance().log("chunk", 0, "Definition not found");
210: }
211:
212: rs.close();
213: Logging.instance().log("xaction", 1, "FINAL load definition");
214: return result;
215: }
216:
217: /**
218: * Load a single Definition from the backend database into a Java
219: * object by its primary key id. This is an internal helper function.
220: *
221: * @param id is a long which represent the primary id.
222: * @return the Definitions that was matched by the id.
223: *
224: * @see #loadDefinition( String, String, String, int )
225: * @see #saveDefinition( Definition, boolean )
226: */
227: private Definition loadDefinition(long id) throws SQLException {
228: Definition result = null;
229: Long lid = new Long(id);
230: Logging.instance().log("xaction", 1,
231: "START load definition " + lid);
232:
233: // try grabbing from cache
234: if (m_cache != null)
235: result = (Definition) m_cache.get(lid);
236:
237: if (result == null) {
238: // no cache, or not in cache
239: PreparedStatement ps = m_dbdriver
240: .getPreparedStatement("stmt.select.xml.id");
241: if (m_dbdriver.preferString())
242: ps.setString(1, Long.toString(id));
243: else
244: ps.setLong(1, id);
245: ResultSet rs = ps.executeQuery();
246: Logging.instance().log("xaction", 1,
247: "INTER load definitions");
248:
249: if (rs.next()) {
250: MyCallbackHandler cb = new MyCallbackHandler();
251:
252: // FIXME: multiple null handlings missing
253: parserInstance().parse(
254: new org.xml.sax.InputSource(rs
255: .getCharacterStream("xml")), cb);
256: result = cb.getDefinition();
257:
258: // add to cache
259: if (m_cache != null)
260: m_cache.set(lid, result);
261: } else {
262: Logging.instance().log("chunk", 0,
263: "Definition not found");
264: }
265: rs.close();
266: }
267:
268: Logging.instance().log("xaction", 1, "FINAL load definitions");
269: return result;
270: }
271:
272: /**
273: * Compiles the name of a DV/TR for log messages.
274: *
275: * @param d is a definition
276: * @return the type plus FQDN of the definition
277: */
278: private String what(Definition d) {
279: StringBuffer result = new StringBuffer();
280: switch (d.getType()) {
281: case Definition.DERIVATION:
282: result.append("DV");
283: break;
284: case Definition.TRANSFORMATION:
285: result.append("TR");
286: break;
287: default:
288: result.append("??");
289: break;
290: }
291:
292: result.append(' ').append(d.shortID());
293: return result.toString();
294: }
295:
296: /**
297: * Saves a Definition, that is either a Transformation or Derivation,
298: * into the backend database. This method, of course, does not allow
299: * wildcarding. The definition has to be completely specified and
300: * valid.
301: *
302: * @param definition is the new Definition to store.
303: * @param overwrite true, if existing defitions will be overwritten by
304: * new ones with the same primary (or secondary) key (-set), or false,
305: * if a new definition will be rejected on key matches.
306: *
307: * @return true, if the backend database was changed, or
308: * false, if the definition was not accepted into the backend.
309: *
310: * @see org.griphyn.vdl.classes.Definition
311: * @see org.griphyn.vdl.classes.Transformation
312: * @see org.griphyn.vdl.classes.Derivation
313: * @see #loadDefinition( String, String, String, int )
314: */
315: public boolean saveDefinition(Definition definition,
316: boolean overwrite) throws SQLException {
317: Logging.instance().log("chunk", 2, "SAVE DEFINITION started");
318:
319: // figure out, if it already exists
320: long probe = -1;
321: try {
322: Long temp = getDefinitionId(definition);
323: if (temp != null)
324: probe = temp.longValue();
325: } catch (SQLException e) {
326: String cause = e.getMessage();
327: Logging.instance().log(
328: "app",
329: 1,
330: "Ignoring SQL exception"
331: + (cause == null ? "" : ": " + cause));
332: m_dbdriver.clearWarnings();
333: }
334:
335: if (probe != -1) {
336: if (overwrite) {
337: // in overwrite mode, remove old version
338: Logging.instance().log("app", 1,
339: "Deleting old " + definition.shortID());
340:
341: // remove old definition from database (delete-before-insert)
342: try {
343: this .m_deferDeleteCommit = true;
344: deleteDefinition(definition);
345: } catch (SQLException e) {
346: String cause = e.getMessage();
347: Logging.instance().log(
348: "app",
349: 1,
350: "Ignoring SQL exception"
351: + (cause == null ? "" : ": "
352: + e.getMessage()));
353: } finally {
354: this .m_deferDeleteCommit = false;
355: }
356: } else {
357: // not overwriting, tell user
358: Logging
359: .instance()
360: .log(
361: "app",
362: 0,
363: definition.shortID()
364: + " already exists (SQL vdc_definition.id="
365: + probe + "), ignoring");
366: return false;
367: }
368: }
369:
370: // Definition is prestine (now)
371: Logging.instance().log("app", 1,
372: "Trying to add " + what(definition));
373:
374: long id = -1;
375: try {
376: id = m_dbdriver.sequence1("def_id_seq");
377: } catch (SQLException e) {
378: Logging.instance().log(
379: "app",
380: 0,
381: "In " + definition.shortID() + ": "
382: + e.toString().trim());
383: Logging.instance().log("xaction", 1, "START rollback");
384: m_dbdriver.cancelPreparedStatement("stmt.save.definition");
385: m_dbdriver.rollback();
386: Logging.instance().log("xaction", 1, "FINAL rollback");
387: return false;
388: }
389:
390: // add ID explicitely from sequence to insertion -- -1 is autoinc
391: Logging.instance().log("xaction", 1, "START save definition");
392: PreparedStatement ps = m_dbdriver
393: .getPreparedStatement("stmt.save.definition");
394: int i = 1;
395: longOrNull(ps, i++, id);
396: ps.setInt(i++, definition.getType());
397: if (definition.getName() == null)
398: throw new SQLException(
399: "VDS inconsistency: The name of a definition is null");
400: else
401: ps.setString(i++, definition.getName());
402: ps.setString(i++, makeNotNull(definition.getNamespace()));
403: ps.setString(i++, makeNotNull(definition.getVersion()));
404: String xml = definition.toXML((String) null, (String) null);
405: ps.setCharacterStream(i++, new StringReader(xml), xml.length());
406:
407: // save prepared values
408: Logging.instance().log("chunk", 2, "INSERT INTO Definition");
409: try {
410: ps.executeUpdate();
411: if (id == -1)
412: id = m_dbdriver.sequence2(ps, "def_id_seq", 1);
413: } catch (SQLException e) {
414: Logging.instance().log(
415: "app",
416: 0,
417: "In " + definition.shortID() + ": "
418: + e.toString().trim());
419: Logging.instance().log("xaction", 1, "START rollback");
420: m_dbdriver.cancelPreparedStatement("stmt.save.definition");
421: m_dbdriver.rollback();
422: Logging.instance().log("xaction", 1, "FINAL rollback");
423: return false;
424: }
425: Logging.instance().log("xaction", 1,
426: "FINAL save definition: ID=" + id);
427:
428: /* NOT YET
429: *
430: // add to cache
431: if ( m_cache != null ) m_cache.set( new Long(id), definition );
432: *
433: */
434:
435: // batch save LFNs from Derivations
436: if (definition instanceof Derivation) {
437: Derivation derivation = (Derivation) definition;
438: Set alreadyKnown = new HashSet();
439: // ordering MUST MATCH classes.LFN constants!
440: PreparedStatement stmt[] = {
441: m_dbdriver.getPreparedStatement("stmt.save.nlfn"),
442: m_dbdriver.getPreparedStatement("stmt.save.ilfn"),
443: m_dbdriver.getPreparedStatement("stmt.save.olfn"),
444: m_dbdriver.getPreparedStatement("stmt.save.blfn") };
445: int[] count = new int[stmt.length];
446: for (int ii = 0; ii < count.length; ++ii)
447: count[ii] = 0;
448:
449: for (Iterator j = derivation.iteratePass(); j.hasNext();) {
450: Value value = ((Pass) j.next()).getValue();
451: if (value != null) {
452: switch (value.getContainerType()) {
453: case Value.SCALAR:
454: // check Scalar contents for LFN
455: saveScalar(id, (Scalar) value, alreadyKnown,
456: stmt, count);
457: break;
458: case Value.LIST:
459: // check List for Scalars for LFN
460: for (Iterator k = ((org.griphyn.vdl.classes.List) value)
461: .iterateScalar(); k.hasNext();) {
462: saveScalar(id, (Scalar) k.next(),
463: alreadyKnown, stmt, count);
464: }
465: break;
466: default:
467: throw new RuntimeException(
468: "unknown container type");
469: }
470: }
471: }
472:
473: for (int ii = 0; ii < stmt.length; ++ii) {
474: // anything to do?
475: if (count[ii] > 0) {
476: // batch insert
477: Logging.instance().log(
478: "chunk",
479: 2,
480: "BATCH INSERT for " + count[ii] + ' '
481: + c_lfn_names[ii] + 's');
482:
483: Logging.instance().log(
484: "xaction",
485: 1,
486: "START batch-add " + count[ii] + ' '
487: + c_lfn_names[ii]);
488: int[] update = stmt[ii].executeBatch();
489: Logging.instance().log(
490: "xaction",
491: 1,
492: "FINAL batch-add " + count[ii] + ' '
493: + c_lfn_names[ii]);
494: }
495: }
496: }
497:
498: // commit the changes
499: Logging.instance().log("xaction", 1, "START commit");
500: this .m_dbdriver.commit();
501: Logging.instance().log("xaction", 1, "FINAL commit");
502:
503: // done
504: return true;
505: }
506:
507: /**
508: * Saves all logical filenames from a Scalar object. This is a helper
509: * function to save a single definition.
510: *
511: * @param id is the definition id in the DEFINITION table
512: * @param scalar is a Scalar instance of which the LFNs are to be saved.
513: * @param already is a set of filenames that were already added during
514: * this session
515: * @param stmt is an array of the ids of the prepared statements for
516: * the different tables.
517: * @param count count the number of entries in a prepared statement.
518: *
519: * @see #saveDefinition( Definition, boolean )
520: */
521: private void saveScalar(long id, Scalar scalar, Set already,
522: PreparedStatement[] stmt, int[] count) throws SQLException {
523: int result = 0;
524: for (Iterator i = scalar.iterateLeaf(); i.hasNext();) {
525: Leaf leaf = (Leaf) i.next();
526: // only interested in logical filenames, nothing else
527: if (leaf instanceof LFN) {
528: LFN lfn = (LFN) leaf;
529: String name = lfn.getFilename();
530:
531: // already inserted previously?
532: if (already.contains(name))
533: continue;
534: else
535: already.add(name);
536:
537: // which one to chose
538: int link = lfn.getLink();
539: if (!LFN.isInRange(link))
540: throw new RuntimeException(
541: "unknown LFN linkage type");
542:
543: int n = 1;
544: if (m_dbdriver.preferString())
545: stmt[link].setString(n++, Long.toString(id));
546: else
547: stmt[link].setLong(n++, id);
548: stmt[link].setString(n++, name);
549: // only keep filenames and linkage in ancillary tables
550: // stringOrNull( stmt[link], n++, lfn.getTemporary() );
551: // FIXME: dontTransfer, dontRegister?
552: stmt[link].addBatch();
553:
554: count[link]++;
555: }
556: }
557: }
558:
559: //
560: // higher level methods, allowing for wildcarding unless working on
561: // a single Definition.
562: //
563:
564: /**
565: * Obtains the primary key id for a given definition. "Fake" definitions
566: * are permissable. This is an internal helper function.
567: *
568: * @param d is a definition specification.
569: * @return the id of the definition, or null if not found.
570: *
571: * @see #getDefinitionId( String, String, String, int )
572: */
573: protected Long getDefinitionId(Definition d) throws SQLException {
574: Logging.instance().log("xaction", 1,
575: "START select ID from DEFINITION");
576: Long result = null;
577:
578: // ps.resetPreparedStatement( "stmt.select.id" );
579: int i = 1;
580: PreparedStatement ps = m_dbdriver
581: .getPreparedStatement("stmt.select.id");
582: ps.setInt(i++, d.getType());
583: ps.setString(i++, makeNotNull(d.getName()));
584: ps.setString(i++, makeNotNull(d.getNamespace()));
585: ps.setString(i++, makeNotNull(d.getVersion()));
586: Logging.instance().log("chunk", 2, "SELECT id FROM definition");
587:
588: ResultSet rs = ps.executeQuery();
589: Logging.instance().log("xaction", 1,
590: "INTER select ID from DEFINITION");
591: if (rs.next())
592: result = new Long(rs.getLong(1));
593: else
594: Logging.instance().log("chunk", 0, "Definition not found");
595:
596: rs.close();
597: Logging.instance().log("xaction", 1,
598: "FINAL select ID from DEFINITION");
599: return result;
600: }
601:
602: /**
603: * Obtains the list of primary key ids for a matching definitions.
604: * This method allows for wildcards in the usual fashion. Use null for
605: * strings as wildcards, and -1 for the type wildcard. This method may
606: * return an empty list, but it will not return null. This is an
607: * internal helper function.
608: *
609: * @param namespace namespace, null to match any namespace
610: * @param name name, null to match any name
611: * @param version version, null to match any version
612: * @param type definition type (TR or DV)
613: * @return a possibly empty list containing all matching
614: * definition ids as Longs.
615: *
616: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
617: * @see org.griphyn.vdl.classes.Definition#DERIVATION
618: * @see #getDefinitionId( Definition )
619: */
620: protected java.util.List getDefinitionId(String namespace,
621: String name, String version, int type) throws SQLException {
622: java.util.List result = new ArrayList();
623: Logging.instance().log("xaction", 1,
624: "START select IDs from DEFINITION");
625:
626: java.util.List select = new ArrayList(1);
627: select.add(new String("distinct id"));
628:
629: java.util.Map where = new TreeMap();
630: if (type != -1)
631: where.put("type", Integer.toString(type));
632: if (namespace != null)
633: where.put("namespace", namespace);
634: if (name != null)
635: where.put("name", name);
636: if (version != null)
637: where.put("version", version);
638:
639: Logging.instance().log("xaction", 1, "START select IDs");
640: ResultSet rs = m_dbdriver.select(select, "vdc_definition",
641: where, null);
642:
643: while (rs.next())
644: result.add(new Long(rs.getLong("id")));
645:
646: rs.close();
647: Logging.instance().log("xaction", 1,
648: "FINAL select IDs from DEFINITION");
649: return result;
650: }
651:
652: /**
653: * Search the database for the existence of a definition.
654: *
655: * @param definition the definition object to search for
656: * @return true, if the definition exists, false if not found
657: */
658: public boolean containsDefinition(Definition definition)
659: throws SQLException {
660: boolean result = false;
661: try {
662: result = (getDefinitionId(definition) != null);
663: } catch (SQLException sql) {
664: // ignore
665: }
666: return result;
667: }
668:
669: /**
670: * Delete a specific Definition objects from the database. No wildcard
671: * matching will be done. "Fake" definitions are permissable, meaning
672: * it just has the secondary key triple.
673: *
674: * @param definition is the definition specification to delete
675: * @return true is something was deleted, false if non existent.
676: *
677: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
678: * @see org.griphyn.vdl.classes.Definition#DERIVATION
679: */
680: public boolean deleteDefinition(Definition definition)
681: throws SQLException {
682: int result = 0;
683: PreparedStatement ps = null;
684:
685: //
686: // TODO: turn into a stored procedure call
687: //
688: Logging.instance().log("xaction", 1, "START delete definition");
689: Long defId = getDefinitionId(definition);
690: boolean preferString = m_dbdriver.preferString();
691: if (defId != null) {
692: long id = defId.longValue();
693:
694: Logging.instance().log("xaction", 1,
695: "START DELETE FROM nlfn");
696: ps = m_dbdriver.getPreparedStatement("stmt.delete.nlfn");
697: if (preferString)
698: ps.setString(1, Long.toString(id));
699: else
700: ps.setLong(1, id);
701: result = ps.executeUpdate();
702: Logging.instance().log("xaction", 1,
703: "FINAL DELETE FROM nlfn: " + result);
704:
705: Logging.instance().log("xaction", 1,
706: "START DELETE FROM ilfn");
707: ps = m_dbdriver.getPreparedStatement("stmt.delete.ilfn");
708: if (preferString)
709: ps.setString(1, Long.toString(id));
710: else
711: ps.setLong(1, id);
712: result = ps.executeUpdate();
713: Logging.instance().log("xaction", 1,
714: "FINAL DELETE FROM ilfn: " + result);
715:
716: Logging.instance().log("xaction", 1,
717: "START DELETE FROM olfn");
718: ps = m_dbdriver.getPreparedStatement("stmt.delete.olfn");
719: if (preferString)
720: ps.setString(1, Long.toString(id));
721: else
722: ps.setLong(1, id);
723: result = ps.executeUpdate();
724: Logging.instance().log("xaction", 1,
725: "FINAL DELETE FROM olfn: " + result);
726:
727: Logging.instance().log("xaction", 1,
728: "START DELETE FROM blfn");
729: ps = m_dbdriver.getPreparedStatement("stmt.delete.blfn");
730: if (preferString)
731: ps.setString(1, Long.toString(id));
732: else
733: ps.setLong(1, id);
734: result = ps.executeUpdate();
735: Logging.instance().log("xaction", 1,
736: "FINAL DELETE FROM blfn: " + result);
737:
738: Logging.instance().log("xaction", 1,
739: "START DELETE FROM definition");
740: ps = m_dbdriver.getPreparedStatement("stmt.delete.xml");
741: if (preferString)
742: ps.setString(1, Long.toString(id));
743: else
744: ps.setLong(1, id);
745: result = ps.executeUpdate();
746: Logging.instance().log("xaction", 1,
747: "FINAL DELETE FROM definition: " + result);
748:
749: if (!m_deferDeleteCommit)
750: m_dbdriver.commit();
751: }
752:
753: Logging.instance().log("xaction", 1, "FINAL delete definition");
754: return (result != 0);
755: }
756:
757: /**
758: * Delete Definition objects from the database. This method allows for
759: * wildcards in the usual fashion. Use null for strings as wildcards,
760: * and -1 for the type wildcard. For efficiency reasons, this method
761: * will return an empty list.
762: *
763: * @param namespace namespace, null to match any namespace
764: * @param name name, null to match any name
765: * @param version version, null to match any version
766: * @param type definition type (TR or DV)
767: * @return a list containing all Definitions that were deleted
768: *
769: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
770: * @see org.griphyn.vdl.classes.Definition#DERIVATION
771: */
772: public java.util.List deleteDefinition(String namespace,
773: String name, String version, int type) throws SQLException {
774: java.util.List result = new ArrayList();
775: Logging.instance()
776: .log("xaction", 1, "START delete definitions");
777:
778: java.util.List idlist = getDefinitionId(namespace, name,
779: version, type);
780: if (idlist.size() == 0)
781: return result;
782: // postcondition: contains all IDs, count(id)>0, to be deleted
783:
784: // save old values
785: if (!m_deferDeleteCommit) {
786: // we come from saveDefinition, thus we won't need saved values
787: for (Iterator i = idlist.iterator(); i.hasNext();) {
788: Definition d = loadDefinition(((Long) i.next())
789: .longValue());
790: if (d != null)
791: result.add(d);
792: }
793: }
794:
795: // list of all statements we need to access
796: PreparedStatement ps[] = {
797: this .m_dbdriver
798: .getPreparedStatement("stmt.delete.nlfn"),
799: this .m_dbdriver
800: .getPreparedStatement("stmt.delete.ilfn"),
801: this .m_dbdriver
802: .getPreparedStatement("stmt.delete.olfn"),
803: this .m_dbdriver
804: .getPreparedStatement("stmt.delete.blfn"),
805: this .m_dbdriver.getPreparedStatement("stmt.delete.xml") };
806:
807: // prepare and batch all statements
808: boolean preferString = m_dbdriver.preferString();
809: for (Iterator i = idlist.iterator(); i.hasNext();) {
810: long id = ((Long) i.next()).longValue();
811: for (int j = 0; j < ps.length; ++j) {
812: if (preferString)
813: ps[j].setString(1, Long.toString(id));
814: else
815: ps[j].setLong(1, id);
816: ps[j].addBatch();
817: }
818: }
819:
820: // run all batches
821: Logging.instance()
822: .log("xaction", 1, "INTER delete definitions");
823: for (int j = 0; j < ps.length; ++j) {
824: int[] status = new int[idlist.size()];
825: try {
826: status = ps[j].executeBatch();
827: } catch (NullPointerException npe) {
828: Logging.instance().log("app", 1,
829: "tripped over NPE, ignoring!");
830: }
831: }
832:
833: Logging.instance()
834: .log("xaction", 1, "FINAL delete definitions");
835: if (!m_deferDeleteCommit)
836: m_dbdriver.commit();
837: return result;
838: }
839:
840: /**
841: * Search the database for definitions by ns::name:version triple
842: * and by type (either Transformation or Derivation). This version
843: * of the search allows for jokers expressed as null value
844: *
845: * @param namespace namespace, null to match any namespace
846: * @param name name, null to match any name
847: * @param version version, null to match any version
848: * @param type type of definition (TR/DV, or both)
849: * @return a list of definitions
850: *
851: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
852: * @see org.griphyn.vdl.classes.Definition#DERIVATION
853: */
854: public java.util.List searchDefinition(String namespace,
855: String name, String version, int type) throws SQLException {
856: java.util.List idlist = getDefinitionId(namespace, name,
857: version, type);
858:
859: // TODO: make this a batch or sproc
860: java.util.List result = new ArrayList();
861: for (Iterator i = idlist.iterator(); i.hasNext();) {
862: Definition d = loadDefinition(((Long) i.next()).longValue());
863: if (d != null)
864: result.add(d);
865: }
866: return result;
867: }
868:
869: /**
870: * Searches the database for all derivations that contain a certain LFN.
871: * The linkage is an additional constraint. This method does not allow
872: * jokers.
873: *
874: * @param lfn the LFN name
875: * @param link the linkage type of the LFN
876: * @return a list of Definition items that match the criterion.
877: *
878: * @see org.griphyn.vdl.classes.LFN#NONE
879: * @see org.griphyn.vdl.classes.LFN#INPUT
880: * @see org.griphyn.vdl.classes.LFN#OUTPUT
881: * @see org.griphyn.vdl.classes.LFN#INOUT
882: */
883: public java.util.List searchFilename(String lfn, int link)
884: throws SQLException {
885: if (lfn == null)
886: throw new NullPointerException(
887: "You must query for a filename");
888:
889: PreparedStatement ps = null;
890: if (link == -1) {
891: // wildcard match
892: ps = this .m_dbdriver
893: .getPreparedStatement("stmt.select.all.lfn");
894: for (int ii = 0; ii < c_lfn_names.length; ++ii)
895: ps.setString(ii + 1, lfn);
896: Logging.instance().log(
897: "chunk",
898: 2,
899: "SELECT distinct id FROM all lfn" + " WHERE name='"
900: + lfn + "'");
901: } else if (LFN.isInRange(link)) {
902: // known linkage, one table only
903: switch (link) {
904: case LFN.NONE:
905: ps = this .m_dbdriver
906: .getPreparedStatement("stmt.select.nlfn");
907: break;
908: case LFN.INPUT:
909: ps = this .m_dbdriver
910: .getPreparedStatement("stmt.select.ilfn");
911: break;
912: case LFN.OUTPUT:
913: ps = this .m_dbdriver
914: .getPreparedStatement("stmt.select.olfn");
915: break;
916: case LFN.INOUT:
917: ps = this .m_dbdriver
918: .getPreparedStatement("stmt.select.blfn");
919: break;
920: }
921: ;
922:
923: ps.setString(1, lfn);
924: Logging.instance().log(
925: "chunk",
926: 2,
927: "SELECT distinct id FROM " + c_lfn_names[link]
928: + " WHERE name='" + lfn + "'");
929: } else {
930: throw new RuntimeException("Unknown linkage value " + link);
931: }
932:
933: ResultSet rs = ps.executeQuery();
934:
935: // TODO: make this a batch or sproc
936: java.util.List result = new ArrayList();
937: while (rs.next()) {
938: Definition d = loadDefinition(rs.getLong(1));
939: if (d != null)
940: result.add(d);
941: }
942:
943: rs.close();
944: Logging.instance().log("xaction", 1, "FINAL select LFNs");
945: return result;
946: }
947: }
|