0001: /*
0002: * This file or a portion of this file is licensed under the terms of
0003: * the Globus Toolkit Public License, found in file ../GTPL, or at
0004: * http://www.globus.org/toolkit/download/license.html. This notice must
0005: * appear in redistributions of this file, with or without modification.
0006: *
0007: * Redistributions of this Software, with or without modification, must
0008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
0009: * some other similar material which is provided with the Software (if
0010: * any).
0011: *
0012: * Copyright 1999-2004 University of Chicago and The University of
0013: * Southern California. All rights reserved.
0014: */
0015: package org.griphyn.vdl.dbschema;
0016:
0017: import java.sql.*;
0018: import java.util.List;
0019: import java.util.ArrayList;
0020: import java.util.Properties;
0021: import java.io.*;
0022: import java.lang.reflect.*;
0023:
0024: import org.xmldb.api.base.*;
0025: import org.xmldb.api.modules.*;
0026: import org.xmldb.api.*;
0027: import javax.xml.transform.OutputKeys;
0028: import javax.xml.parsers.DocumentBuilder;
0029: import javax.xml.parsers.DocumentBuilderFactory;
0030: import javax.xml.parsers.ParserConfigurationException;
0031:
0032: import org.w3c.dom.Document;
0033: import org.w3c.dom.Element;
0034: import org.w3c.dom.DOMException;
0035: import org.xml.sax.SAXException;
0036: import org.xml.sax.SAXParseException;
0037: import org.xml.sax.InputSource;
0038:
0039: import org.griphyn.vdl.util.ChimeraProperties;
0040: import org.griphyn.vdl.classes.*;
0041: import org.griphyn.vdl.util.Logging;
0042: import org.griphyn.vdl.parser.*;
0043: import org.griphyn.vdl.router.Cache;
0044: import org.griphyn.vdl.annotation.*;
0045: import org.griphyn.common.util.Separator;
0046: import org.xml.sax.InputSource;
0047:
0048: /**
0049: * This class provides basic functionalities to interact with the
0050: * backend database, such as insertion, deletion, and search of
0051: * entities in the VDC.
0052: *
0053: * @author Jens-S. Vöckler
0054: * @author Yong Zhao
0055: * @version $Revision: 50 $
0056: */
0057: public class NXDSchema extends DatabaseSchema implements XDC {
0058: /**
0059: * An instance of the VDLx XML parser.
0060: */
0061: private org.griphyn.vdl.parser.VDLxParser m_parser;
0062:
0063: private DocumentBuilderFactory m_factory;
0064:
0065: private DocumentBuilder m_builder;
0066:
0067: /**
0068: * reference to collection '/db/vdc';
0069: */
0070: protected Collection m_db;
0071:
0072: protected Collection m_vdc;
0073:
0074: protected Collection m_meta;
0075:
0076: protected CollectionManagementService m_dbColService;
0077:
0078: protected CollectionManagementService m_vdcColService;
0079:
0080: protected XPathQueryService m_dbQrySvc;
0081:
0082: protected XPathQueryService m_vdcQrySvc;
0083:
0084: protected XPathQueryService m_metaQrySvc;
0085:
0086: protected XUpdateQueryService m_xupdQrySvc;
0087:
0088: /**
0089: * A cache for definitions to avoid reloading from the database.
0090: */
0091: protected Cache m_cache;
0092:
0093: /**
0094: * Instantiates an XML parser for VDLx on demand. Since XML parsing
0095: * and parser instantiation is an expensive business, the reader will
0096: * only be generated on demand.
0097: *
0098: * @return a valid VDLx parser instance.
0099: */
0100: private org.griphyn.vdl.parser.VDLxParser parserInstance() {
0101: if (this .m_parser == null) {
0102: // obtain the schema location URL from the schema properties:
0103: // url is a list of strings representing schema locations. The
0104: // content exists in pairs, one of the namespace URI, one of the
0105: // location URL.
0106: String url = null;
0107: try {
0108: ChimeraProperties props = ChimeraProperties.instance();
0109: url = m_dbschemaprops.getProperty("xml.url", props
0110: .getVDLSchemaLocation());
0111: } catch (IOException e) {
0112: Logging.instance().log("nxd", 0, "ignored " + e);
0113: }
0114: this .m_parser = new org.griphyn.vdl.parser.VDLxParser(url);
0115: }
0116:
0117: // done
0118: return this .m_parser;
0119: }
0120:
0121: /**
0122: * Default constructor for the NXD schema.
0123: */
0124: public NXDSchema(String dbDriver) throws ClassNotFoundException,
0125: NoSuchMethodException, InstantiationException,
0126: IllegalAccessException, InvocationTargetException,
0127: SQLException, IOException, ParserConfigurationException {
0128: // load the driver from the properties
0129: super (); // call minimalistic c'tor, no driver loading!
0130: ChimeraProperties props = ChimeraProperties.instance();
0131:
0132: m_dbschemaprops = props
0133: .getDatabaseSchemaProperties(PROPERTY_PREFIX);
0134:
0135: m_cache = null;
0136: m_parser = null;
0137:
0138: // extract those properties specific to the database driver.
0139: // use default settings.
0140: String driverPrefix = null;
0141: String driverName = props.getDatabaseDriverName(driverPrefix);
0142: Properties driverprops = props
0143: .getDatabaseDriverProperties(driverPrefix);
0144: String url = props.getDatabaseURL(driverPrefix);
0145: String user = driverprops.getProperty("user", "guest");
0146: String passwd = driverprops.getProperty("password", "guest");
0147:
0148: try {
0149: m_factory = DocumentBuilderFactory.newInstance();
0150: m_builder = m_factory.newDocumentBuilder();
0151:
0152: Class cl = Class.forName(driverName);
0153: Database database = (Database) cl.newInstance();
0154: DatabaseManager.registerDatabase(database);
0155:
0156: // get the collection
0157: m_db = DatabaseManager.getCollection(url + "/db", user,
0158: passwd);
0159: m_dbColService = (CollectionManagementService) m_db
0160: .getService("CollectionManagementService", "1.0");
0161:
0162: m_vdc = m_db.getChildCollection("vdc");
0163:
0164: if (m_vdc == null) {
0165: // collection does not exist, create
0166: m_vdc = m_dbColService.createCollection("vdc");
0167: }
0168: m_vdc.setProperty(OutputKeys.INDENT, "no");
0169:
0170: m_meta = m_db.getChildCollection("metadata");
0171:
0172: if (m_meta == null) {
0173: // collection does not exist, create
0174: m_meta = m_dbColService.createCollection("metadata");
0175: }
0176: m_meta.setProperty(OutputKeys.INDENT, "no");
0177:
0178: m_vdcColService = (CollectionManagementService) m_vdc
0179: .getService("CollectionManagementService", "1.0");
0180:
0181: m_dbQrySvc = (XPathQueryService) m_db.getService(
0182: "XPathQueryService", "1.0");
0183:
0184: m_vdcQrySvc = (XPathQueryService) m_vdc.getService(
0185: "XPathQueryService", "1.0");
0186:
0187: m_metaQrySvc = (XPathQueryService) m_meta.getService(
0188: "XPathQueryService", "1.0");
0189:
0190: m_dbQrySvc.setProperty("indent", "no");
0191:
0192: m_vdcQrySvc.setProperty("indent", "no");
0193:
0194: m_metaQrySvc.setProperty("indent", "no");
0195:
0196: XUpdateQueryService m_xupdQrySvc = (XUpdateQueryService) m_meta
0197: .getService("XUpdateQueryService", "1.0");
0198:
0199: } catch (XMLDBException e) {
0200: throw new SQLException(e.getMessage());
0201: }
0202: }
0203:
0204: private String getDefinitionId(Definition def) {
0205: String prefix = (def.getType() == Definition.TRANSFORMATION) ? "TR_"
0206: : "DV_";
0207: String version = def.getVersion();
0208: String suffix = "";
0209: if (version != null)
0210: suffix = "_" + version;
0211: return prefix + def.getName() + suffix;
0212: }
0213:
0214: private String getDefinitionId(String name, String version, int type) {
0215: String prefix = (type == Definition.TRANSFORMATION) ? "TR_"
0216: : "DV_";
0217: String suffix = "";
0218: if (version != null)
0219: suffix = "_" + version;
0220: return prefix + name + suffix;
0221: }
0222:
0223: //
0224: // lower level methods, working directly on specific definitions
0225: //
0226:
0227: /**
0228: * Loads a single Definition from the backend database into an Java object.
0229: * This method does not allow wildcarding!
0230: *
0231: * @param namespace namespace, null will be converted into empty string
0232: * @param name name, null will be converted into empty string
0233: * @param version version, null will be converted into empty string
0234: * @param type type of the definition (TR or DV), must not be -1.
0235: * @return the Definition as specified, or null if not found.
0236: *
0237: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0238: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0239: * @see #saveDefinition( Definition, boolean )
0240: */
0241: public Definition loadDefinition(String namespace, String name,
0242: String version, int type) throws SQLException {
0243: Definition result = null;
0244: Logging.instance().log("xaction", 1, "START load definition");
0245:
0246: try {
0247: Collection col;
0248: if (namespace != null)
0249: col = m_vdc.getChildCollection(namespace);
0250: else
0251: col = m_vdc;
0252: String id = getDefinitionId(name, version, type);
0253: //Logging.instance().log( "nxd", 0, "Definition id " + id );
0254: XMLResource res = (XMLResource) col.getResource(id);
0255: if (res != null) {
0256: MyCallbackHandler cb = new MyCallbackHandler();
0257:
0258: parserInstance().parse(
0259: new org.xml.sax.InputSource(new StringReader(
0260: (String) res.getContent())), cb);
0261: result = cb.getDefinition();
0262:
0263: } else {
0264: Logging.instance()
0265: .log("nxd", 0, "Definition not found");
0266: }
0267: } catch (Exception e) {
0268: throw new SQLException(e.getMessage());
0269: }
0270: Logging.instance().log("xaction", 1, "FINAL load definition");
0271: return result;
0272: }
0273:
0274: /**
0275: * Saves a Definition, that is either a Transformation or Derivation,
0276: * into the backend database. This method, of course, does not allow
0277: * wildcarding. The definition has to be completely specified and
0278: * valid.
0279: *
0280: * @param definition is the new Definition to store.
0281: * @param overwrite true, if existing defitions will be overwritten by
0282: * new ones with the same primary (or secondary) key (-set), or false,
0283: * if a new definition will be rejected on key matches.
0284: *
0285: * @return true, if the backend database was changed, or
0286: * false, if the definition was not accepted into the backend.
0287: *
0288: * @see org.griphyn.vdl.classes.Definition
0289: * @see org.griphyn.vdl.classes.Transformation
0290: * @see org.griphyn.vdl.classes.Derivation
0291: * @see #loadDefinition( String, String, String, int )
0292: */
0293: public boolean saveDefinition(Definition definition,
0294: boolean overwrite) throws SQLException {
0295: Logging.instance().log("nxd", 2, "START save definition");
0296:
0297: try {
0298: String namespace = definition.getNamespace();
0299: Collection col;
0300: if (namespace != null)
0301: col = m_vdc.getChildCollection(namespace);
0302: else
0303: col = m_vdc;
0304: String id = getDefinitionId(definition);
0305:
0306: if (col == null) {
0307: // collection does not exist, create
0308: col = m_vdcColService.createCollection(namespace);
0309: } else if (!overwrite) {
0310: if (col.getResource(id) != null) {
0311: Logging.instance().log(
0312: "app",
0313: 0,
0314: definition.shortID()
0315: + " already exists, ignoring");
0316: return false;
0317: }
0318: }
0319:
0320: // create new XMLResource; an id will be assigned to the new resource
0321: XMLResource document = (XMLResource) col.createResource(id,
0322: "XMLResource");
0323: document.setContent(definition.toXML("", null));
0324: col.storeResource(document);
0325:
0326: // add to cache
0327: //if ( m_cache != null ) m_cache.set( new Long(id), definition );
0328:
0329: } catch (Exception e) {
0330: throw new SQLException(e.getMessage());
0331: }
0332: // done
0333: Logging.instance().log("nxd", 2, "FINAL save definition");
0334: return true;
0335: }
0336:
0337: /**
0338: * Search the database for the existence of a definition.
0339: *
0340: * @param definition the definition object to search for
0341: * @return true, if the definition exists, false if not found
0342: */
0343: public boolean containsDefinition(Definition definition)
0344: throws SQLException {
0345: boolean result = false;
0346: try {
0347: String namespace = definition.getNamespace();
0348: Collection col;
0349: if (namespace != null)
0350: col = m_vdc.getChildCollection(namespace);
0351: else
0352: col = m_vdc;
0353: String id = getDefinitionId(definition);
0354:
0355: if (col != null) {
0356: if (col.getResource(id) != null) {
0357: result = true;
0358: }
0359: }
0360: } catch (Exception e) {
0361: throw new SQLException(e.getMessage());
0362: }
0363: return result;
0364: }
0365:
0366: /**
0367: * Delete a specific Definition objects from the database. No wildcard
0368: * matching will be done. "Fake" definitions are permissable, meaning
0369: * it just has the secondary key triple.
0370: *
0371: * @param definition is the definition specification to delete
0372: * @return true is something was deleted, false if non existent.
0373: *
0374: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0375: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0376: */
0377: public boolean deleteDefinition(Definition definition)
0378: throws SQLException {
0379: boolean result = false;
0380:
0381: Logging.instance().log("xaction", 1, "START delete definition");
0382:
0383: try {
0384: String namespace = definition.getNamespace();
0385: Collection col;
0386: if (namespace != null)
0387: col = m_vdc.getChildCollection(namespace);
0388: else
0389: col = m_vdc;
0390: String id = getDefinitionId(definition);
0391:
0392: if (col != null) {
0393: XMLResource res = (XMLResource) col.getResource(id);
0394: if (res != null) {
0395: col.removeResource(res);
0396: result = true;
0397: }
0398: }
0399: } catch (Exception e) {
0400: // ignore
0401: }
0402:
0403: Logging.instance().log("xaction", 1, "FINAL delete definition");
0404: return result;
0405: }
0406:
0407: /**
0408: * Delete Definition objects from the database. This method allows for
0409: * wildcards in the usual fashion. Use null for strings as wildcards,
0410: * and -1 for the type wildcard.
0411: *
0412: * @param namespace namespace, null to match any namespace
0413: * @param name name, null to match any name
0414: * @param version version, null to match any version
0415: * @param type definition type (TR or DV)
0416: * @return a list containing all Definitions that were deleted
0417: *
0418: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0419: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0420: */
0421: public java.util.List deleteDefinition(String namespace,
0422: String name, String version, int type) throws SQLException {
0423: Logging.instance()
0424: .log("xaction", 1, "START delete definitions");
0425:
0426: java.util.List result = searchDefinition(namespace, name,
0427: version, type);
0428: for (int i = 0; i < result.size(); i++)
0429: deleteDefinition((Definition) result.get(i));
0430:
0431: Logging.instance()
0432: .log("xaction", 1, "FINAL delete definitions");
0433: return result;
0434: }
0435:
0436: /**
0437: * Search the database for definitions by ns::name:version triple
0438: * and by type (either Transformation or Derivation). This version
0439: * of the search allows for jokers expressed as null value
0440: *
0441: * @param namespace namespace, null to match any namespace
0442: * @param name name, null to match any name
0443: * @param version version, null to match any version
0444: * @param type type of definition (TR/DV, or both)
0445: * @return a list of definitions
0446: *
0447: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0448: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0449: */
0450: public java.util.List searchDefinition(String namespace,
0451: String name, String version, int type) throws SQLException {
0452: String xquery = ""; //"declare namespace vdl='http://www.griphyn.org/chimera/VDL';"
0453:
0454: String triple = "";
0455: if (namespace != null)
0456: triple += "[@namespace='" + namespace + "']";
0457:
0458: if (name != null)
0459: triple += "[@name='" + name + "']";
0460:
0461: if (version != null)
0462: triple += "[@version='" + version + "']";
0463:
0464: if (type != -1) {
0465: if (type == Definition.TRANSFORMATION)
0466: xquery = "//transformation" + triple;
0467: else
0468: xquery += "//derivation" + triple;
0469: } else
0470: xquery = "//derivation" + triple + "|//transformation"
0471: + triple;
0472:
0473: return searchDefinition(xquery);
0474: }
0475:
0476: /**
0477: * Searches the database for all derivations that satisfies a certain query.
0478: *
0479: * @param xquery the query statement
0480: * @return a list of definitions
0481: */
0482: public java.util.List searchDefinition(String xquery)
0483: throws SQLException {
0484: if (xquery == null)
0485: throw new NullPointerException("You must specify a query!");
0486:
0487: java.util.List result = new ArrayList();
0488:
0489: try {
0490: Logging.instance().log("xaction", 1, "query: " + xquery);
0491:
0492: ResourceSet rs = m_dbQrySvc.query(xquery);
0493: ResourceIterator i = rs.getIterator();
0494: while (i.hasMoreResources()) {
0495: Resource res = i.nextResource();
0496:
0497: MyCallbackHandler cb = new MyCallbackHandler();
0498:
0499: parserInstance().parse(
0500: new org.xml.sax.InputSource(new StringReader(
0501: (String) res.getContent())), cb);
0502: result.add(cb.getDefinition());
0503: }
0504:
0505: } catch (Exception e) {
0506: throw new SQLException(e.getMessage());
0507: }
0508:
0509: return result;
0510: }
0511:
0512: /**
0513: * Searches the database for elements that satisfies a certain query.
0514: *
0515: * @param xquery the query statement
0516: * @return a list of string
0517: */
0518: public java.util.List searchElements(String xquery)
0519: throws SQLException {
0520: if (xquery == null)
0521: throw new NullPointerException("You must specify a query!");
0522:
0523: java.util.List result = new ArrayList();
0524:
0525: try {
0526: Logging.instance().log("nxd", 1, "query: " + xquery);
0527:
0528: ResourceSet rs = m_dbQrySvc.query(xquery);
0529: ResourceIterator i = rs.getIterator();
0530: while (i.hasMoreResources()) {
0531: Resource res = i.nextResource();
0532: result.add((String) res.getContent());
0533: }
0534: } catch (Exception e) {
0535: throw new SQLException(e.getMessage());
0536: }
0537: return result;
0538: }
0539:
0540: /**
0541: * Searches the database for annotations that satisfies a certain query.
0542: *
0543: * @param xquery the query statement
0544: * @return true if found, false otherwise
0545: */
0546: public XMLResource findAnnotation(String xquery)
0547: throws SQLException {
0548: if (xquery == null)
0549: return null;
0550:
0551: try {
0552: Logging.instance().log("nxd", 1, "query: " + xquery);
0553:
0554: ResourceSet rs = m_metaQrySvc.query(xquery);
0555: ResourceIterator i = rs.getIterator();
0556: if (i.hasMoreResources()) {
0557: XMLResource res = (XMLResource) i.nextResource();
0558: return res;
0559: } else
0560: return null;
0561: } catch (Exception e) {
0562: throw new SQLException(e.getMessage());
0563: }
0564: }
0565:
0566: public java.util.List searchFilename(String lfn, int link)
0567: throws SQLException {
0568: if (lfn == null)
0569: throw new NullPointerException(
0570: "You must query for a filename");
0571:
0572: String linkQuery = "";
0573: String type = LFN.toString(link);
0574: if (type != null)
0575: linkQuery = "[@link = '" + type + "']";
0576:
0577: String xquery = "//derivation[.//lfn[@file = '" + lfn + "']"
0578: + linkQuery + "]";
0579: java.util.List result = searchDefinition(xquery);
0580:
0581: Logging.instance().log("xaction", 1, "FINAL select LFNs");
0582: return result;
0583: }
0584:
0585: /**
0586: * Delete one or more definitions from the backend database. The key
0587: * triple parameters may be wildcards. Wildcards are expressed as
0588: * <code>null</code> value, or have regular expression.
0589: *
0590: * @param namespace namespace
0591: * @param name name
0592: * @param version version
0593: * @param type definition type (TR or DV)
0594: * @return a list of definitions that were deleted.
0595: *
0596: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0597: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0598: */
0599: public java.util.List deleteDefinitionEx(String namespace,
0600: String name, String version, int type) throws SQLException {
0601: Logging.instance().log("xaction", 1,
0602: "START delete definitions ex");
0603:
0604: java.util.List result = searchDefinitionEx(namespace, name,
0605: version, type);
0606: for (int i = 0; i < result.size(); i++)
0607: deleteDefinition((Definition) result.get(i));
0608:
0609: Logging.instance().log("xaction", 1,
0610: "FINAL delete definitions ex");
0611: return result;
0612: }
0613:
0614: /**
0615: * Searches the database for definitions by ns::name:version triple
0616: * and by type (either Transformation or Derivation). This version of
0617: * the search allows for jokers expressed as null value
0618: *
0619: * @param namespace namespace, null to match any namespace
0620: * @param name name, null to match any name
0621: * @param version version, null to match any version
0622: * @param type type of definition, see below, or -1 as wildcard
0623: * @return a list of Definition items, which may be empty
0624: *
0625: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0626: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0627: * @see #loadDefinition( String, String, String, int )
0628: */
0629: public java.util.List searchDefinitionEx(String namespace,
0630: String name, String version, int type) throws SQLException {
0631: String xquery = "";
0632:
0633: String triple = "";
0634: if (namespace != null)
0635: triple += "[matches(@namespace, '" + namespace + "')]";
0636:
0637: if (name != null)
0638: triple += "[matches(@name, '" + name + "')]";
0639:
0640: if (version != null)
0641: triple += "[matches(@version, '" + version + "')]";
0642:
0643: if (type != -1) {
0644: if (type == Definition.TRANSFORMATION)
0645: xquery = "//transformation" + triple;
0646: else
0647: xquery += "//derivation" + triple;
0648: } else
0649: xquery = "//derivation" + triple + "|//transformation"
0650: + triple;
0651: return searchDefinition(xquery);
0652: }
0653:
0654: /**
0655: * Searches the database for all LFNs that match a certain pattern.
0656: * The linkage is an additional constraint. This method allows
0657: * regular expression
0658: *
0659: * @param lfn the LFN name
0660: * @param link the linkage type of the LFN
0661: * @return a list of filenames that match the criterion.
0662: *
0663: * @see org.griphyn.vdl.classes.LFN#NONE
0664: * @see org.griphyn.vdl.classes.LFN#INPUT
0665: * @see org.griphyn.vdl.classes.LFN#OUTPUT
0666: * @see org.griphyn.vdl.classes.LFN#INOUT
0667: */
0668: public java.util.List searchLFN(String lfn, int link)
0669: throws SQLException {
0670: if (lfn == null)
0671: throw new NullPointerException(
0672: "You must query for a filename");
0673:
0674: String linkQuery = "";
0675: String type = LFN.toString(link);
0676: if (type != null)
0677: linkQuery = "[@link = '" + type + "')]";
0678:
0679: String xquery =
0680: // "//lfn[matches(@file, '" + lfn + "')]" + linkQuery + "/@file";
0681: "//lfn" + linkQuery + "/@file[matches(., '" + lfn + "')]";
0682: java.util.List result = searchElements(xquery);
0683:
0684: Logging.instance().log("xaction", 1, "FINAL select LFNs");
0685: return result;
0686: }
0687:
0688: /**
0689: * Searches the database for a list of namespaces of the definitions
0690: * Sorted in ascending order.
0691: *
0692: * @param type type of definition, see below, or -1 for both
0693: * @return a list of namespaces
0694: *
0695: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0696: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0697: */
0698: public java.util.List getNamespaceList(int type)
0699: throws SQLException {
0700:
0701: String xquery = "";
0702: if (type == Definition.TRANSFORMATION)
0703: xquery = "for $n in distinct-values(//transformation/@namespace) order by $n return $n";
0704: else if (type == Definition.DERIVATION)
0705: xquery = "for $n in distinct-values(//derivation/@namespace) order by $n return $n";
0706: else
0707: xquery = "for $n in distinct-values(//derivation/@namespace|//transformation/@namespace) order by $n return $n";
0708:
0709: java.util.List result = searchElements(xquery);
0710:
0711: Logging.instance().log("xaction", 1, "FINAL select LFNs");
0712: return result;
0713: }
0714:
0715: /**
0716: * Searches the database for a list of fully-qualified names of
0717: * the definitions sorted in ascending order.
0718: *
0719: * @param type type of definition, see below, or -1 for both.
0720: * @return a list of FQDNs
0721: *
0722: * @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
0723: * @see org.griphyn.vdl.classes.Definition#DERIVATION
0724: */
0725: public java.util.List getFQDNList(int type) throws SQLException {
0726: String xquery = "";
0727:
0728: if (type == Definition.TRANSFORMATION)
0729: xquery = "for $d in //transformation order by $d/@namespace empty least, $d/@name, $d/@version return string-join((string-join(($d/@namespace, $d/@name), '::'), $d/@version), ':')";
0730: else if (type == Definition.DERIVATION)
0731: xquery = "for $d in //derivation order by $d/@namespace empty least, $d/@name, $d/@version return string-join((string-join(($d/@namespace, $d/@name), '::'), $d/@version), ':')";
0732: else
0733: xquery = "for $d in (//transformation|//derivation) order by $d/@namespace empty least, $d/@name, $d/@version return string-join((string-join(($d/@namespace, $d/@name), '::'), $d/@version), ':')";
0734:
0735: java.util.List result = searchElements(xquery);
0736:
0737: Logging.instance().log("xaction", 1, "FINAL select LFNs");
0738: return result;
0739: }
0740:
0741: /**
0742: * Deletes an annotation with the specified key.
0743: *
0744: * @param primary is the primary object specifier for the class.
0745: * According to the type, this is either the FQDI, or the filename.
0746: * @param secondary is a helper argument for annotations to calls
0747: * and formal arguments, and should be null for all other classes.
0748: * For calls, the argument must be packed into {@link java.lang.Integer}.
0749: * @param kind defines the kind/class of object to annotate.
0750: * @param key is the annotation key.
0751: * @return true, if the database was modified, false otherwise.
0752: * @exception SQLException, if something went wrong during database
0753: * access.
0754: */
0755: public boolean deleteAnnotation(String primary, Object secondary,
0756: int kind, String key) throws SQLException,
0757: IllegalArgumentException {
0758: String subject = "";
0759: String select = null;
0760:
0761: switch (kind) {
0762: case CLASS_TRANSFORMATION:
0763: subject = "tr";
0764: break;
0765: case CLASS_DERIVATION:
0766: subject = "dv";
0767: break;
0768: case CLASS_CALL:
0769: // may throw ClassCastException
0770: subject = "tr";
0771: select = "call[" + ((Integer) secondary).intValue() + "]";
0772: break;
0773: case CLASS_DECLARE:
0774: subject = "tr";
0775: // may throw ClassCastException
0776: //select = "declare[@name='" + (String)secondary + "']";
0777: select = (String) secondary;
0778: break;
0779: case CLASS_FILENAME:
0780: subject = "lfn";
0781: break;
0782: default:
0783: throw new IllegalArgumentException("The class kind=" + kind
0784: + " cannot be annotated");
0785: }
0786:
0787: try {
0788: XMLResource res = null;
0789: String xquery = "/annotation/metadata[@subject=\""
0790: + subject + "\"][@name=\"" + primary + "\"]";
0791: if (select == null) {
0792: if (kind != CLASS_FILENAME) {
0793: xquery += "[empty(@select)]";
0794: }
0795: } else {
0796: xquery += "[@select=\"" + select + "\"]";
0797: }
0798:
0799: xquery += "/attribute[@name=\"" + key + "\"]";
0800:
0801: if ((res = findAnnotation(xquery)) != null) {
0802: String id = res.getDocumentId();
0803:
0804: // get the document
0805: XMLResource document = (XMLResource) m_meta
0806: .getResource(id);
0807: m_meta.removeResource(document);
0808: return true;
0809: }
0810: return false;
0811: } catch (XMLDBException e) {
0812: throw new SQLException(e.getMessage());
0813: }
0814: }
0815:
0816: /**
0817: * Deletes a specific key in an annotated transformation.
0818: *
0819: * @param fqdi is the FQDI of the transformation
0820: * @param key is the key to search for
0821: * @return true, if the database was modified, false otherwise.
0822: * @see org.griphyn.vdl.classes.Transformation
0823: */
0824: public boolean deleteAnnotationTransformation(String fqdi,
0825: String key) throws SQLException, IllegalArgumentException {
0826: return deleteAnnotation(fqdi, null, CLASS_TRANSFORMATION, key);
0827: }
0828:
0829: /**
0830: * Deletes a specific key in an annotated derivation.
0831: *
0832: * @param fqdi is the FQDI of the derivation
0833: * @param key is the key to search for
0834: * @return true, if the database was modified, false otherwise.
0835: * @see org.griphyn.vdl.classes.Derivation
0836: */
0837: public boolean deleteAnnotationDerivation(String fqdi, String key)
0838: throws SQLException, IllegalArgumentException {
0839: return deleteAnnotation(fqdi, null, CLASS_DERIVATION, key);
0840: }
0841:
0842: /**
0843: * Deletes a specific key in an annotated formal argument.
0844: *
0845: * @param fqdi is the FQDI of the transformation
0846: * @param farg is the name of the formal argument
0847: * @param key is the key to search for
0848: * @return true, if the database was modified, false otherwise.
0849: * @see org.griphyn.vdl.classes.Declare
0850: */
0851: public boolean deleteAnnotationDeclare(String fqdi, String farg,
0852: String key) throws SQLException, IllegalArgumentException {
0853: return deleteAnnotation(fqdi, farg, CLASS_DECLARE, key);
0854: }
0855:
0856: /**
0857: * Deletes a specific key for a call statement.
0858: *
0859: * @param fqdi is the FQDI of the transformation
0860: * @param index is the number of the call to annotate.
0861: * @param key is the key to search for
0862: * @return true, if the database was modified, false otherwise.
0863: * @see org.griphyn.vdl.classes.Call
0864: */
0865: public boolean deleteAnnotationCall(String fqdi, int index,
0866: String key) throws SQLException, IllegalArgumentException {
0867: return deleteAnnotation(fqdi, new Integer(index), CLASS_CALL,
0868: key);
0869: }
0870:
0871: /**
0872: * Deletes a specific key in an annotated filename.
0873: *
0874: * @param filename is the name of the file that was annotated.
0875: * @param key is the key to search for
0876: * @return true, if the database was modified, false otherwise.
0877: * @see org.griphyn.vdl.classes.LFN
0878: */
0879: public boolean deleteAnnotationFilename(String filename, String key)
0880: throws SQLException, IllegalArgumentException {
0881: return deleteAnnotation(filename, null, CLASS_FILENAME, key);
0882: }
0883:
0884: /**
0885: * Annotates a transformation with a tuple.
0886: *
0887: * @param fqdi is the FQDI to annotate
0888: * @param annotation is the value to place
0889: * @param overwrite is a predicate on replace or maintain.
0890: * @return the insertion id, or -1, if the database was untouched
0891: * @see org.griphyn.vdl.classes.Transformation
0892: */
0893: public long saveAnnotationTransformation(String fqdi,
0894: Tuple annotation, boolean overwrite) throws SQLException,
0895: IllegalArgumentException {
0896: /*
0897: try {
0898: String key = annotation.getKey();
0899: String type = annotation.getTypeString();
0900: Object value = annotation.getValue();
0901:
0902: Logging.instance().log( "nxd", 2, "INSERT INTO anno_tr" );
0903:
0904: String id = null;
0905: XMLResource res = null;
0906:
0907: String xupdate =
0908: "<xu:modifications version=\"1.0\" " +
0909: "xmlns:xu=\"http://www.xmldb.org/xupdate\">";
0910: String xquery = "//annotation/metadata[@subject='tr'][@name='" +
0911: fqdi + "']";
0912: if ((res = findAnnotation(xquery)) != null) {
0913: //annotation for tr exists
0914: id = res.getDocumentId();
0915: String xquery_attr = xquery + "/attribute[@name='" + key + "']/text()";
0916: if (findAnnotation(xquery_attr)!=null) {
0917: //attribute already exists
0918: Logging.instance().log( "nxd", 2, "Attribute already exists." );
0919:
0920: if (!overwrite)
0921: return -1;
0922: xupdate += "<xu:update select=\"" + xquery + "\">" +
0923: value + "</xu:update>";
0924: //xupdate += "<xu:update select=\"" + xquery_attr + "/@type\">" +
0925: //type + "</xu:update>";
0926: } else {
0927: //attribute does not exist
0928: Logging.instance().log( "nxd", 2, "Attribute does not exist." );
0929:
0930: xupdate += "<xu:append select=\"" + xquery + "\">" +
0931: "<xu:element name=\"attribute\">" +
0932: "<xu:attribute name=\"name\">" + key + "</xu:attribute>" +
0933: "<xu:attribute name=\"type\">" + type + "</xu:attribute>" +
0934: value + "</xu:element>" +
0935: "</xu:append>";
0936: }
0937: xupdate += "</xu:modifications>";
0938: System.out.println(xupdate);
0939: long l = m_xupdQrySvc.update(xupdate);
0940: } else {
0941: //create the annotation
0942: String anno = "<annotation><metadata subject=\"tr\" name=\"" + fqdi + "\">" +
0943: "<attribute name=\"" + key + "\" type=\"" + type + "\">" + value + "</attribute>" +
0944: "</metadata></annotation>";
0945:
0946: // create new XMLResource; an id will be assigned to the new resource
0947: XMLResource document = (XMLResource)m_meta.createResource(null, "XMLResource");
0948: document.setContent(anno);
0949: m_meta.storeResource(document);
0950: }
0951: return 0;
0952: } catch (XMLDBException e) {
0953: throw new SQLException(e.getMessage());
0954: }
0955: */
0956: return saveAnnotation(fqdi, null, CLASS_TRANSFORMATION,
0957: annotation, overwrite);
0958: }
0959:
0960: /**
0961: * Annotates a derivation with a tuple.
0962: *
0963: * @param fqdi is the FQDI to annotate
0964: * @param annotation is the value to place
0965: * @param overwrite is a predicate on replace or maintain.
0966: * @return the insertion id, or -1, if the database was untouched
0967: * @see org.griphyn.vdl.classes.Derivation
0968: */
0969: public long saveAnnotationDerivation(String fqdi, Tuple annotation,
0970: boolean overwrite) throws SQLException,
0971: IllegalArgumentException {
0972: return saveAnnotation(fqdi, null, CLASS_DERIVATION, annotation,
0973: overwrite);
0974: }
0975:
0976: /**
0977: * Annotates a transformation argument with a tuple.
0978: *
0979: * @param fqdi is the FQDI to annotate
0980: * @param formalname is the name of the formal argument to annotoate.
0981: * @param annotation is the value to place
0982: * @param overwrite is a predicate on replace or maintain.
0983: * @return the insertion id, or -1, if the database was untouched
0984: * @see org.griphyn.vdl.classes.Declare
0985: */
0986: public long saveAnnotationDeclare(String fqdi, String formalname,
0987: Tuple annotation, boolean overwrite) throws SQLException,
0988: IllegalArgumentException {
0989: return saveAnnotation(fqdi, formalname, CLASS_DECLARE,
0990: annotation, overwrite);
0991: }
0992:
0993: /**
0994: * Annotates a transformation call with a tuple.
0995: *
0996: * @param fqdi is the FQDI to annotate
0997: * @param index is the number of the call to annotate.
0998: * @param annotation is the value to place
0999: * @param overwrite is a predicate on replace or maintain.
1000: * @return the insertion id, or -1, if the database was untouched
1001: * @see org.griphyn.vdl.classes.Call
1002: */
1003: public long saveAnnotationCall(String fqdi, int index,
1004: Tuple annotation, boolean overwrite) throws SQLException,
1005: IllegalArgumentException {
1006: return saveAnnotation(fqdi, new Integer(index), CLASS_CALL,
1007: annotation, overwrite);
1008: }
1009:
1010: /**
1011: * Annotates a logical filename with a tuple.
1012: *
1013: * @param filename is the FQDI to annotate
1014: * @param annotation is the value to place
1015: * @param overwrite is a predicate on replace or maintain.
1016: * @return the insertion id, or -1, if the database was untouched
1017: * @see org.griphyn.vdl.classes.LFN
1018: */
1019: public long saveAnnotationFilename(String filename,
1020: Tuple annotation, boolean overwrite) throws SQLException,
1021: IllegalArgumentException {
1022: return saveAnnotation(filename, null, CLASS_FILENAME,
1023: annotation, overwrite);
1024: }
1025:
1026: /**
1027: * Annotates any of the annotatable classes with the specified tuple.
1028: * This is an interface method to the various class-specific methods.
1029: *
1030: * @param primary is the primary object specifier for the class.
1031: * According to the type, this is either the FQDI, or the filename.
1032: * @param secondary is a helper argument for annotations to calls
1033: * and formal arguments, and should be null for all other classes.
1034: * For calls, the argument must be packed into {@link java.lang.Integer}.
1035: * @param kind defines the kind/class of object to annotate.
1036: * @param annotation is the value to place into the class.
1037: * @param overwrite is a predicate on replace or maintain.
1038: * @return the insertion id, or -1, if the database was untouched
1039: * @see #saveAnnotationTransformation( String, Tuple, boolean )
1040: * @see #saveAnnotationDerivation( String, Tuple, boolean )
1041: * @see #saveAnnotationCall( String, int, Tuple, boolean )
1042: * @see #saveAnnotationDeclare( String, String, Tuple, boolean )
1043: * @see #saveAnnotationFilename( String, Tuple, boolean )
1044: */
1045: public long saveAnnotation(String primary, Object secondary,
1046: int kind, Tuple annotation, boolean overwrite)
1047: throws SQLException, IllegalArgumentException {
1048: long result = -1;
1049: String subject = "";
1050: String select = null;
1051: String q_sec = null;
1052: String defn = "transformation";
1053:
1054: switch (kind) {
1055: case CLASS_TRANSFORMATION:
1056: subject = "tr";
1057: break;
1058: case CLASS_DERIVATION:
1059: subject = "dv";
1060: defn = "derivation";
1061: break;
1062: case CLASS_CALL:
1063: // may throw ClassCastException
1064: subject = "tr";
1065: select = "call[" + ((Integer) secondary).intValue() + "]";
1066: q_sec = select;
1067: break;
1068: case CLASS_DECLARE:
1069: subject = "tr";
1070: // may throw ClassCastException
1071: q_sec = "declare[@name='" + (String) secondary + "']";
1072: select = (String) secondary;
1073: break;
1074: case CLASS_FILENAME:
1075: subject = "lfn";
1076: break;
1077: default:
1078: throw new IllegalArgumentException("The class kind=" + kind
1079: + " cannot be annotated");
1080: }
1081:
1082: try {
1083:
1084: if (kind != CLASS_FILENAME) {
1085: String[] names = Separator.split(primary);
1086: String q_ns, q_name, q_ver;
1087:
1088: if (names[0] == null)
1089: q_ns = "[empty(@namespace)]";
1090: else
1091: q_ns = "[@namespace='" + names[0] + "']";
1092:
1093: if (names[1] == null)
1094: q_name = "[empty(@name)]";
1095: else
1096: q_name = "[@name='" + names[1] + "']";
1097:
1098: if (names[2] == null)
1099: q_ver = "[empty(@version)]";
1100: else
1101: q_ver = "[@version='" + names[2] + "']";
1102:
1103: //check if tr/dv is valid
1104: String xquery = "//" + defn + q_ns + q_name + q_ver;
1105: if (q_sec != null)
1106: xquery += "/" + q_sec;
1107: Logging.instance().log("nxd", 0, "query: " + xquery);
1108: ResourceSet rs = m_vdcQrySvc.query(xquery);
1109: ResourceIterator i = rs.getIterator();
1110: if (!i.hasMoreResources()) {
1111: Logging.instance().log("app", 0,
1112: "definition not found!");
1113: return -1;
1114: }
1115: }
1116:
1117: String key = annotation.getKey();
1118: String type = annotation.getTypeString();
1119: Object value = annotation.getValue();
1120:
1121: String id = null;
1122: XMLResource res = null;
1123: String xquery = "/annotation/metadata[@subject=\""
1124: + subject + "\"][@name=\"" + primary + "\"]";
1125: if (select == null) {
1126: if (kind != CLASS_FILENAME) {
1127: xquery += "[empty(@select)]";
1128: }
1129: } else {
1130: xquery += "[@select=\"" + select + "\"]";
1131: }
1132:
1133: xquery += "/attribute[@name=\"" + key + "\"]";
1134:
1135: if ((res = findAnnotation(xquery)) != null) {
1136: if (!overwrite) {
1137: System.err.println("key " + key
1138: + " already defined!");
1139: return -1;
1140: }
1141: id = res.getDocumentId();
1142: }
1143:
1144: //create the annotation
1145: String anno = "<annotation xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"><metadata subject=\""
1146: + subject + "\" name=\"" + primary + "\"";
1147: if (select != null)
1148: anno += " select=\"" + select + "\"";
1149: anno += ">" + "<attribute name=\"" + key
1150: + "\" xsi:type=\"xs:" + type + "\">" + value
1151: + "</attribute>" + "</metadata></annotation>";
1152:
1153: // create new XMLResource; an id will be assigned to the new resource
1154: XMLResource document = (XMLResource) m_meta.createResource(
1155: id, "XMLResource");
1156:
1157: document.setContent(anno);
1158: m_meta.storeResource(document);
1159:
1160: return 0;
1161: } catch (XMLDBException e) {
1162: throw new SQLException(e.getMessage());
1163: }
1164: }
1165:
1166: /**
1167: * Obtains the value to a specific key in an annotated transformation.
1168: *
1169: * @param fqdi is the FQDI of the transformation
1170: * @param key is the key to search for
1171: * @return the annotated value, or null if not found.
1172: * @see org.griphyn.vdl.classes.Transformation
1173: */
1174: public Tuple loadAnnotationTransformation(String fqdi, String key)
1175: throws SQLException, IllegalArgumentException {
1176: return loadAnnotation(fqdi, null, CLASS_TRANSFORMATION, key);
1177: }
1178:
1179: /**
1180: * Obtains the value to a specific key in an annotated derivation.
1181: *
1182: * @param fqdi is the FQDI of the derivation
1183: * @param key is the key to search for
1184: * @return the annotated value, or null if not found.
1185: * @see org.griphyn.vdl.classes.Derivation
1186: */
1187: public Tuple loadAnnotationDerivation(String fqdi, String key)
1188: throws SQLException, IllegalArgumentException {
1189: return loadAnnotation(fqdi, null, CLASS_DERIVATION, key);
1190: }
1191:
1192: /**
1193: * Obtains the value to a specific key in an annotated formal argument.
1194: *
1195: * @param fqdi is the FQDI of the transformation
1196: * @param farg is the name of the formal argument
1197: * @param key is the key to search for
1198: * @return the annotated value, or null if not found
1199: * @see org.griphyn.vdl.classes.Declare
1200: */
1201: public Tuple loadAnnotationDeclare(String fqdi, String farg,
1202: String key) throws SQLException, IllegalArgumentException {
1203: return loadAnnotation(fqdi, farg, CLASS_DECLARE, key);
1204: }
1205:
1206: /**
1207: * Obtains the value to a specific key for a call statement.
1208: *
1209: * @param fqdi is the FQDI of the transformation
1210: * @param index is the number of the call to annotate.
1211: * @param key is the key to search for
1212: * @return the annotated value, or null if not found
1213: * @see org.griphyn.vdl.classes.Call
1214: */
1215: public Tuple loadAnnotationCall(String fqdi, int index, String key)
1216: throws SQLException, IllegalArgumentException {
1217: return loadAnnotation(fqdi, new Integer(index), CLASS_CALL, key);
1218: }
1219:
1220: /**
1221: * Obtains the value to a specific key in an annotated filename.
1222: *
1223: * @param filename is the name of the file that was annotated.
1224: * @param key is the key to search for
1225: * @return the annotated value, or null if not found.
1226: * @see org.griphyn.vdl.classes.LFN
1227: */
1228: public Tuple loadAnnotationFilename(String filename, String key)
1229: throws SQLException, IllegalArgumentException {
1230: return loadAnnotation(filename, null, CLASS_FILENAME, key);
1231: }
1232:
1233: /**
1234: * Retrieves a specific annotation from an annotatable classes with
1235: * the specified tuple. This is an interface method to the various
1236: * class-specific methods.
1237: *
1238: * @param primary is the primary object specifier for the class.
1239: * According to the type, this is either the FQDI, or the filename.
1240: * @param secondary is a helper argument for annotations to calls
1241: * and formal arguments, and should be null for all other classes.
1242: * For calls, the argument must be packed into {@link java.lang.Integer}.
1243: * @param kind defines the kind/class of object to annotate.
1244: * @param key is the key to look for.
1245: * @return null if not found, otherwise the annotation tuple.
1246: * @see #loadAnnotationTransformation( String, String )
1247: * @see #loadAnnotationDerivation( String, String )
1248: * @see #loadAnnotationCall( String, int, String )
1249: * @see #loadAnnotationDeclare( String, String, String )
1250: * @see #loadAnnotationFilename( String, String )
1251: */
1252: public Tuple loadAnnotation(String primary, Object secondary,
1253: int kind, String key) throws SQLException,
1254: IllegalArgumentException {
1255: Tuple result = null;
1256: String subject = "";
1257: String select = null;
1258:
1259: switch (kind) {
1260: case CLASS_TRANSFORMATION:
1261: subject = "tr";
1262: break;
1263: case CLASS_DERIVATION:
1264: subject = "dv";
1265: break;
1266: case CLASS_CALL:
1267: // may throw ClassCastException
1268: subject = "tr";
1269: select = "call[" + ((Integer) secondary).intValue() + "]";
1270: break;
1271: case CLASS_DECLARE:
1272: subject = "tr";
1273: // may throw ClassCastException
1274: //select = "declare[@name='" + (String)secondary + "']";
1275: select = (String) secondary;
1276: break;
1277: case CLASS_FILENAME:
1278: subject = "lfn";
1279: break;
1280: default:
1281: throw new IllegalArgumentException("The class kind=" + kind
1282: + " cannot be annotated");
1283: }
1284:
1285: try {
1286: String id = null;
1287: String xquery = "/annotation/metadata[@subject=\""
1288: + subject + "\"][@name=\"" + primary + "\"]";
1289: if (select == null) {
1290: if (kind != CLASS_FILENAME) {
1291: xquery += "[empty(@select)]";
1292: }
1293: } else {
1294: xquery += "[@select=\"" + select + "\"]";
1295: }
1296:
1297: xquery += "/attribute[@name=\"" + key + "\"]";
1298:
1299: XMLResource res = null;
1300: if ((res = findAnnotation(xquery)) != null) {
1301: result = loadAnnotationResource(res);
1302: }
1303: return result;
1304: } catch (Exception e) {
1305: throw new SQLException(e.getMessage());
1306: }
1307: }
1308:
1309: /**
1310: * get the annotation from a XML resource
1311: */
1312: protected Tuple loadAnnotationResource(XMLResource res)
1313: throws SQLException {
1314: Tuple result = null;
1315:
1316: if (res == null)
1317: return result;
1318:
1319: Element elem;
1320: try {
1321: elem = (Element) res.getContentAsDOM();
1322: } catch (Exception e) {
1323: throw new SQLException(e.getMessage());
1324: }
1325: if (elem != null) {
1326: String key = elem.getAttribute("name");
1327: String type = elem
1328: .getAttributeNS(
1329: "http://www.w3.org/2001/XMLSchema-instance",
1330: "type");
1331: String value = elem.getFirstChild().getNodeValue();
1332: if (key == null || type == null || value == null)
1333: return result;
1334: if (type.equals("xs:string")) {
1335: result = new TupleString(key, null);
1336: result.setValue(value);
1337: return result;
1338: }
1339: if (type.equals("xs:float")) {
1340: result = new TupleFloat(key, 0);
1341: result.setValue(value);
1342: return result;
1343: }
1344: if (type.equals("xs:int")) {
1345: result = new TupleInteger(key, 0);
1346: result.setValue(value);
1347: return result;
1348: }
1349: if (type.equals("xs:boolean")) {
1350: result = new TupleBoolean(key, false);
1351: result.setValue(value);
1352: return result;
1353: }
1354: if (type.equals("xs:date")) {
1355: result = new TupleDate(key, null);
1356: result.setValue(value);
1357: return result;
1358: }
1359: }
1360: return result;
1361: }
1362:
1363: /**
1364: * Lists all annotations for a transformation.
1365: *
1366: * @param fqdi is the FQDI of the transformation
1367: * @return a list of tuples, which may be empty.
1368: * @see org.griphyn.vdl.classes.Transformation
1369: */
1370: public java.util.List loadAnnotationTransformation(String fqdi)
1371: throws SQLException, IllegalArgumentException {
1372: return loadAnnotation(fqdi, null, CLASS_TRANSFORMATION);
1373: }
1374:
1375: /**
1376: * Lists all annotations for a derivation.
1377: *
1378: * @param fqdi is the FQDI of the derivation
1379: * @return a list of tuples, which may be empty.
1380: * @see org.griphyn.vdl.classes.Derivation
1381: */
1382: public java.util.List loadAnnotationDerivation(String fqdi)
1383: throws SQLException, IllegalArgumentException {
1384: return loadAnnotation(fqdi, null, CLASS_DERIVATION);
1385: }
1386:
1387: /**
1388: * Lists all annotations for a formal argument.
1389: *
1390: * @param fqdi is the FQDI of the transformation
1391: * @param farg is the name of the formal argument
1392: * @return a list of tuples, which may be empty.
1393: * @see org.griphyn.vdl.classes.Declare
1394: */
1395: public java.util.List loadAnnotationDeclare(String fqdi, String farg)
1396: throws SQLException, IllegalArgumentException {
1397: return loadAnnotation(fqdi, farg, CLASS_DECLARE);
1398: }
1399:
1400: /**
1401: * Lists all annotations for a call statement.
1402: *
1403: * @param fqdi is the FQDI of the transformation
1404: * @param index is the number of the call to annotate.
1405: * @return a list of tuples, which may be empty.
1406: * @see org.griphyn.vdl.classes.Call
1407: */
1408: public java.util.List loadAnnotationCall(String fqdi, int index)
1409: throws SQLException, IllegalArgumentException {
1410: return loadAnnotation(fqdi, new Integer(index), CLASS_CALL);
1411: }
1412:
1413: /**
1414: * Lists all annotations for a logical filename.
1415: *
1416: * @param filename is the logical filename.
1417: * @return a list of tuples, which may be empty.
1418: * @see org.griphyn.vdl.classes.LFN
1419: */
1420: public java.util.List loadAnnotationFilename(String filename)
1421: throws SQLException, IllegalArgumentException {
1422: return loadAnnotation(filename, null, CLASS_FILENAME);
1423: }
1424:
1425: /**
1426: * Retrieves all annotations from an annotatable classes with
1427: * the specified tuple. This is an interface method to the various
1428: * class-specific methods.
1429: *
1430: * @param primary is the primary object specifier for the class.
1431: * According to the type, this is either the FQDI, or the filename.
1432: * @param secondary is a helper argument for annotations to calls
1433: * and formal arguments, and should be null for all other classes.
1434: * For calls, the argument must be packed into {@link java.lang.Integer}.
1435: * @param kind defines the kind/class of object to annotate.
1436: *
1437: * @return null if not found, otherwise the annotation tuple.
1438: * @see #loadAnnotationTransformation( String )
1439: * @see #loadAnnotationDerivation( String )
1440: * @see #loadAnnotationCall( String, int )
1441: * @see #loadAnnotationDeclare( String, String )
1442: * @see #loadAnnotationFilename( String )
1443: */
1444: public java.util.List loadAnnotation(String primary,
1445: Object secondary, int kind) throws SQLException,
1446: IllegalArgumentException {
1447: java.util.List result = new java.util.ArrayList();
1448: String subject = "";
1449: String select = null;
1450:
1451: switch (kind) {
1452: case CLASS_TRANSFORMATION:
1453: subject = "tr";
1454: break;
1455: case CLASS_DERIVATION:
1456: subject = "dv";
1457: break;
1458: case CLASS_CALL:
1459: // may throw ClassCastException
1460: subject = "tr";
1461: select = "call[" + ((Integer) secondary).intValue() + "]";
1462: break;
1463: case CLASS_DECLARE:
1464: subject = "tr";
1465: // may throw ClassCastException
1466: //select = "declare[@name='" + (String)secondary + "']";
1467: select = (String) secondary;
1468: break;
1469: case CLASS_FILENAME:
1470: subject = "lfn";
1471: break;
1472: default:
1473: throw new IllegalArgumentException("The class kind=" + kind
1474: + " cannot be annotated");
1475: }
1476:
1477: try {
1478: String id = null;
1479: String xquery = "/annotation/metadata[@subject=\""
1480: + subject + "\"][@name=\"" + primary + "\"]";
1481: if (select == null) {
1482: if (kind != CLASS_FILENAME) {
1483: xquery += "[empty(@select)]";
1484: }
1485: } else {
1486: xquery += "[@select=\"" + select + "\"]";
1487: }
1488:
1489: xquery += "/attribute";
1490: Logging.instance().log("nxd", 1, "query: " + xquery);
1491:
1492: ResourceSet rs = m_metaQrySvc.query(xquery);
1493: ResourceIterator i = rs.getIterator();
1494: while (i.hasMoreResources()) {
1495: XMLResource res = (XMLResource) i.nextResource();
1496: Tuple tuple = loadAnnotationResource(res);
1497: if (tuple != null) {
1498: result.add(tuple);
1499: }
1500: }
1501: return result;
1502: } catch (Exception e) {
1503: throw new SQLException(e.getMessage());
1504: }
1505: }
1506:
1507: /**
1508: * Search for LFNs or Definitions that has certain annotations
1509: *
1510: * @param kind defines the kind/class of object annotated.
1511: * @param arg is used only for TR ARG and TR CALL. For the former
1512: * it is the name of the argument (String), for the latter the position of
1513: * the call (Integer).
1514: * @param tree stores the query tree to query the annotation
1515: * @return a list of LFNs if search for filenames, otherwise a list of
1516: * definitions.
1517: * @exception SQLException if something goes wrong with the database.
1518: * @see org.griphyn.vdl.annotation.QueryTree
1519: */
1520: public java.util.List searchAnnotation(int kind, Object arg,
1521: QueryTree tree) throws SQLException {
1522: java.util.List result = new java.util.ArrayList();
1523:
1524: if (tree == null)
1525: return result;
1526:
1527: String subject = "";
1528: String defn = "transformation";
1529: String select = null;
1530:
1531: switch (kind) {
1532: case CLASS_TRANSFORMATION:
1533: subject = "tr";
1534: break;
1535: case CLASS_DERIVATION:
1536: subject = "dv";
1537: defn = "derivation";
1538: break;
1539: case CLASS_CALL:
1540: // may throw ClassCastException
1541: subject = "tr";
1542: select = "call[" + ((Integer) arg).intValue() + "]";
1543: break;
1544: case CLASS_DECLARE:
1545: subject = "tr";
1546: // may throw ClassCastException
1547: //select = "declare[@name='" + (String)arg + "']";
1548: select = (String) arg;
1549: break;
1550: case CLASS_FILENAME:
1551: subject = "lfn";
1552: break;
1553: default:
1554: throw new IllegalArgumentException("The class kind=" + kind
1555: + " cannot be annotated");
1556: }
1557:
1558: try {
1559: String id = null;
1560: String cond = "[@subject=\"" + subject + "\"]";
1561: if (select == null) {
1562: if (kind != CLASS_FILENAME) {
1563: cond += "[empty(@select)]";
1564: }
1565: } else {
1566: cond += "[@select=\"" + select + "\"]";
1567: }
1568: String xquery = "for $mn in distinct-values(//annotation/metadata"
1569: + cond
1570: + "/@name) "
1571: + "let $m := //annotation/metadata[@name=$mn]"
1572: + cond;
1573:
1574: String where = " where ";
1575: where += tree.toXQuery("$m/attribute");
1576:
1577: if (kind == CLASS_FILENAME) {
1578: xquery += ", $r := $m";
1579: xquery += where;
1580: xquery += " return $mn";
1581:
1582: return searchElements(xquery);
1583: } else {
1584: xquery += ", $n := substring-before($mn, '::'), $na := substring-after($mn, '::'), $iv := if ($na) then $na else $mn, $v := substring-after($iv, ':'), $ib := substring-before($iv, ':'), $i := if ($ib) then $ib else $iv,";
1585: xquery += " $t := if ($n) then if ($v) then //"
1586: + defn
1587: + "[@namespace=$n][@name=$i][@version=$v] else //"
1588: + defn
1589: + "[@namespace=$n][@name=$i][empty(@version)] else if ($v) then //"
1590: + defn
1591: + "[empty(@namespace)][@name=$i][@version=$v] else //"
1592: + defn
1593: + "[empty(@namespace)][@name=$i][empty(@version)]";
1594:
1595: xquery += where;
1596: if (kind == CLASS_DECLARE)
1597: xquery += " return $t[" + "declare[@name='"
1598: + select + "']" + "]";
1599: else
1600: xquery += " return $t";
1601: return searchDefinition(xquery);
1602: }
1603:
1604: } catch (Exception e) {
1605: throw new SQLException(e.getMessage());
1606: }
1607: }
1608:
1609: /**
1610: * pass-thru to driver.
1611: * @return true, if it is feasible to cache results from the driver
1612: * false, if requerying the driver is sufficiently fast (e.g. driver
1613: * is in main memory, or driver does caching itself).
1614: */
1615: public boolean cachingMakesSense() {
1616: return true;
1617: }
1618:
1619: public void close() throws SQLException {
1620: try {
1621: //m_vdc.close();
1622: //m_db.close();
1623: } catch (Exception e) {
1624: throw new SQLException(e.getMessage());
1625: }
1626: }
1627: }
|