/*
* This file or a portion of this file is licensed under the terms of
* the Globus Toolkit Public License, found in file ../GTPL, or at
* http://www.globus.org/toolkit/download/license.html. This notice must
* appear in redistributions of this file, with or without modification.
*
* Redistributions of this Software, with or without modification, must
* reproduce the GTPL in: (1) the Software, or (2) the Documentation or
* some other similar material which is provided with the Software (if
* any).
*
* Copyright 1999-2004 University of Chicago and The University of
* Southern California. All rights reserved.
*/
package org.griphyn.vdl.dbschema;
import java.sql.*;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.InetAddress;
import edu.isi.pegasus.common.util.Separator;
import org.griphyn.vdl.util.ChimeraProperties;
import org.griphyn.vdl.annotation.*;
import org.griphyn.vdl.classes.*;
import org.griphyn.vdl.util.Logging;
import org.griphyn.vdl.parser.*;
import org.griphyn.vdl.router.Cache;
import org.xml.sax.InputSource;
/**
* This class provides basic functionalities to interact with the
* backend database, such as insertion, deletion, and search.
* While the main database layout for storing definitions is derived
* from the "chunk" schema with minor improvements, the database
* layout of the annotations is shown in the following figure:<p>
*
* <img src="doc-files/AnnotationSchema-1.png" alt="annotation schema"><p>
*
* The central five elements that can receive annotations, all depend
* on the same sequence generator for their primary key. Their secondary
* key references the definition in question, or otherwise qualifies the
* element to annotate. Note that logical filenames can be annotated
* outside of any definitions.<p>
*
* Grouped along the outer edges, five primary data type tables store
* annotations efficiently. The distinction into separate data types is
* necessary to enable efficient searches and appropriate operations.
* Their primary key is also a foreign key referencing the five central
* elements.
*
* @author Jens-S. Vöckler
* @author Yong Zhao
* @version $Revision$
*/
public class AnnotationSchema extends DatabaseSchema
implements Advanced, Annotation
{
/**
* Name of the four parameter tables in human readable format.
*/
protected static final String[] c_lfn_names =
{ "ANNO_LFN_I", "ANNO_LFN_O", "ANNO_LFN_B" };
/**
* Communication between saveDefinition and deleteDefinition in
* update mode.
*/
protected boolean m_deferDeleteCommit;
/**
* An instance of the VDLx XML parser.
*/
private org.griphyn.vdl.parser.VDLxParser m_parser;
/**
* A cache for definitions to avoid reloading from the database.
*/
protected Cache m_cache;
/**
* Instantiates an XML parser for VDLx on demand. Since XML parsing
* and parser instantiation is an expensive business, the reader will
* only be generated on demand, and only once.
*
* @return a valid VDLx parser instance.
*/
private org.griphyn.vdl.parser.VDLxParser parserInstance()
{
if ( this.m_parser == null ) {
// obtain the schema location URL from the schema properties:
// url is a list of strings representing schema locations. The
// content exists in pairs, one of the namespace URI, one of the
// location URL.
String url = null;
try {
ChimeraProperties props = ChimeraProperties.instance();
url = m_dbschemaprops.getProperty( "xml.url",
props.getVDLSchemaLocation() );
} catch (IOException e) {
Logging.instance().log("chunk", 0, "ignored " + e);
}
this.m_parser = new org.griphyn.vdl.parser.VDLxParser(url);
}
// done
return this.m_parser;
}
/**
* Default constructor for the "chunk" schema.
*
* @param dbDriverName is the database driver name
*/
public AnnotationSchema( String dbDriverName )
throws ClassNotFoundException,
NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException,
SQLException, IOException
{
// load the driver from the properties
super( dbDriverName, VDC.PROPERTY_PREFIX );
Logging.instance().log( "dbschema", 3, "done with default schema c'tor" );
this.m_cache = this.m_dbdriver.cachingMakesSense() ? new Cache(600) : null;
this.m_deferDeleteCommit = false;
this.m_parser = null;
this.m_dbdriver.insertPreparedStatement( "stmt.save.definition",
"INSERT INTO anno_definition(id,type,name,namespace,version,xml) " +
"VALUES (?,?,?,?,?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.lfn_i",
"INSERT INTO anno_lfn_i(did,name) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.lfn_o",
"INSERT INTO anno_lfn_o(did,name) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.lfn_b",
"INSERT INTO anno_lfn_b(did,name) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.updt.definition",
"UPDATE anno_definition SET xml=? WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_tr",
"INSERT INTO anno_tr(id,did,mkey) VALUES (?,?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_dv",
"INSERT INTO anno_dv(id,did,mkey) VALUES (?,?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_lfn",
"INSERT INTO anno_lfn(id,name,mkey) VALUES (?,?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_targ",
"INSERT INTO anno_targ(id,did,name,mkey) VALUES (?,?,?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_call",
"INSERT INTO anno_call(id,did,pos,mkey) VALUES (?,?,?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_bool",
"INSERT INTO anno_bool(id,value) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_int",
"INSERT INTO anno_int(id,value) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_float",
"INSERT INTO anno_float(id,value) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_date",
"INSERT INTO anno_date(id,value) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.save.anno_text",
"INSERT INTO anno_text(id,value) VALUES (?,?)" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_i",
"SELECT distinct did FROM anno_lfn_i WHERE name=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_o",
"SELECT distinct did FROM anno_lfn_o WHERE name=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_b",
"SELECT distinct did FROM anno_lfn_b WHERE name=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_*",
"SELECT distinct did FROM anno_lfn_i WHERE name=? UNION " +
"SELECT distinct did FROM anno_lfn_o WHERE name=? UNION " +
"SELECT distinct did FROM anno_lfn_b WHERE name=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_*.name",
"SELECT distinct name FROM anno_lfn_i WHERE did=? UNION " +
"SELECT distinct name FROM anno_lfn_o WHERE did=? UNION " +
"SELECT distinct name FROM anno_lfn_b WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_i.name.ex",
"SELECT distinct name FROM anno_lfn_i WHERE name LIKE ?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_o.name.ex",
"SELECT distinct name FROM anno_lfn_o WHERE name LIKE ?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_b.name.ex",
"SELECT distinct name FROM anno_lfn_b WHERE name LIKE ?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.lfn_*.name.ex",
"SELECT distinct name FROM anno_lfn_i WHERE name LIKE ? UNION " +
"SELECT distinct name FROM anno_lfn_o WHERE name LIKE ? UNION " +
"SELECT distinct name FROM anno_lfn_b WHERE name LIKE ?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.big",
"SELECT id FROM anno_tr WHERE did=? UNION " +
"SELECT id FROM anno_dv WHERE did=? UNION " +
"SELECT id FROM anno_call WHERE did=? UNION " +
"SELECT id FROM anno_targ WHERE did=? UNION " +
// "SELECT id FROM anno_lfn WHERE name IN (" +
// " SELECT distinct name FROM lfn_i WHERE did=? UNION " +
// " SELECT distinct name FROM lfn_o WHERE did=? UNION " +
// " SELECT distinct name FROM lfn_b WHERE did=? )" );
"SELECT a.id FROM anno_lfn a, anno_lfn_i i WHERE i.name=a.name AND a.id=? UNION " +
"SELECT a.id FROM anno_lfn a, anno_lfn_o o WHERE o.name=a.name AND a.id=? UNION " +
"SELECT a.id FROM anno_lfn a, anno_lfn_b b WHERE b.name=a.name AND a.id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.xml.id",
"SELECT xml FROM anno_definition WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.xml",
"SELECT id,xml FROM anno_definition WHERE type=? AND name=? AND namespace=? AND version=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.id",
"SELECT id FROM anno_definition WHERE type=? AND name=? AND namespace=? AND version=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.xml",
"DELETE FROM anno_definition WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.lfn_i",
"DELETE FROM anno_lfn_i WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.lfn_o",
"DELETE FROM anno_lfn_o WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.lfn_b",
"DELETE FROM anno_lfn_b WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_bool",
"DELETE FROM anno_bool WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_int",
"DELETE FROM anno_int WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_float",
"DELETE FROM anno_float WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_date",
"DELETE FROM anno_date WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_text",
"DELETE FROM anno_text WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_tr",
"DELETE FROM anno_tr WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_dv",
"DELETE FROM anno_dv WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_lfn",
"DELETE FROM anno_lfn WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_targ",
"DELETE FROM anno_targ WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.delete.anno_call",
"DELETE FROM anno_call WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_tr",
"SELECT id FROM anno_tr WHERE did=? AND mkey=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_dv",
"SELECT id FROM anno_dv WHERE did=? AND mkey=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_lfn",
"SELECT id FROM anno_lfn WHERE name=? AND mkey=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_targ",
"SELECT id FROM anno_targ WHERE did=? AND name=? AND mkey=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_call",
"SELECT id FROM anno_call WHERE did=? AND pos=? AND mkey=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_bool",
"SELECT value FROM anno_bool WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_int",
"SELECT value FROM anno_int WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_float",
"SELECT value FROM anno_float WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_date",
"SELECT value FROM anno_date WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_text",
"SELECT value FROM anno_text WHERE id=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_tr2",
"SELECT id,mkey FROM anno_tr WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_dv2",
"SELECT id,mkey FROM anno_dv WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_lfn2",
"SELECT id,mkey FROM anno_lfn WHERE name=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_targ2",
"SELECT id,mkey FROM anno_targ WHERE did=? and name=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.select.anno_call2",
"SELECT id,mkey FROM anno_call WHERE did=? and pos=?" );
// udpates, take one
this.m_dbdriver.insertPreparedStatement( "stmt.update.anno_tr",
"UPDATE anno_tr SET did=? WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.udpate.anno_dv",
"UPDATE anno_dv SET did=? WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.update.anno_targ",
"UPDATE anno_targ SET did=? WHERE did=?" );
this.m_dbdriver.insertPreparedStatement( "stmt.update.anno_call",
"UPDATE anno_call SET did=? WHERE did=?" );
}
//
// lower level methods, working directly on specific definitions
//
/**
* Loads a single Definition from the backend database into an Java object.
* This method does not allow wildcarding!
*
* @param namespace namespace, null will be converted into empty string
* @param name name, null will be converted into empty string
* @param version version, null will be converted into empty string
* @param type type of the definition (TR or DV), must not be -1.
* @return the Definition as specified, or null if not found.
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
* @see #saveDefinition( Definition, boolean )
*/
public Definition
loadDefinition( String namespace,
String name,
String version,
int type )
throws SQLException
{
Definition result = null;
Logging.instance().log("xaction", 1, "START load definition" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.xml");
ps.setInt( i++, type );
ps.setString( i++, makeNotNull(name) );
ps.setString( i++, makeNotNull(namespace) );
ps.setString( i++, makeNotNull(version) );
Logging.instance().log( "chunk", 2, "SELECT xml FROM anno_definition" );
ResultSet rs = ps.executeQuery();
Logging.instance().log("xaction", 1, "INTER load definition" );
if ( rs.next() ) {
MyCallbackHandler cb = new MyCallbackHandler();
Long lid = new Long( rs.getLong("id") );
// FIXME: multiple null handlings missing
parserInstance().parse(
new org.xml.sax.InputSource(rs.getCharacterStream("xml")), cb );
result = cb.getDefinition();
// add to cache
if ( m_cache != null ) m_cache.set( lid, result );
} else {
Logging.instance().log( "chunk", 0, "Definition not found" );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL load definition" );
return result;
}
/**
* Load a single Definition from the backend database into a Java
* object by its primary key id. This is an internal helper function.
*
* @param id is a long which represent the primary id.
* @return the Definitions that was matched by the id.
*
* @see #loadDefinition( String, String, String, int )
* @see #saveDefinition( Definition, boolean )
*/
private Definition loadDefinition( long id )
throws SQLException
{
Definition result = null;
Long lid = new Long(id);
Logging.instance().log("xaction", 1, "START load definition " + lid );
// try grabbing from cache
if ( m_cache != null )
result = (Definition) m_cache.get(lid);
if ( result == null ) {
// no cache, or not in cache
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.xml.id" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
ResultSet rs = ps.executeQuery();
Logging.instance().log("xaction", 1, "INTER load definitions" );
if ( rs.next() ) {
MyCallbackHandler cb = new MyCallbackHandler();
// FIXME: multiple null handlings missing
parserInstance().parse(
new org.xml.sax.InputSource(rs.getCharacterStream("xml")), cb );
result = cb.getDefinition();
// add to cache
if ( m_cache != null ) m_cache.set( lid, result );
} else {
Logging.instance().log( "chunk", 0, "Definition not found" );
}
rs.close();
}
Logging.instance().log("xaction", 1, "FINAL load definitions" );
return result;
}
/**
* Compiles the name of a DV/TR for log messages.
*
* @param d is a definition
* @return the type plus FQDN of the definition
*/
private String what( Definition d )
{
StringBuffer result = new StringBuffer();
switch ( d.getType() ) {
case Definition.DERIVATION:
result.append( "DV" );
break;
case Definition.TRANSFORMATION:
result.append( "TR" );
break;
default:
result.append( "??" );
break;
}
result.append(' ').append( d.shortID() );
return result.toString();
}
/**
* Saves a Definition, that is either a Transformation or Derivation,
* into the backend database. This method, of course, does not allow
* wildcarding. The definition has to be completely specified and
* valid.<p>
* Please note that updating a definition will remove all the meta-
* data that was defined for the definition.
*
* @param definition is the new Definition to store.
* @param overwrite true, if existing defitions will be overwritten by
* new ones with the same primary (or secondary) key (-set), or false,
* if a new definition will be rejected on key matches.
*
* @return true, if the backend database was changed, or
* false, if the definition was not accepted into the backend.
*
* @see org.griphyn.vdl.classes.Definition
* @see org.griphyn.vdl.classes.Transformation
* @see org.griphyn.vdl.classes.Derivation
* @see #loadDefinition( String, String, String, int )
*/
public boolean
saveDefinition( Definition definition,
boolean overwrite )
throws SQLException
{
Logging.instance().log( "chunk", 2, "SAVE DEFINITION started" );
// figure out, if it already exists
long id = -1;
try {
Long temp = getDefinitionId(definition);
if ( temp != null ) id = temp.longValue();
} catch ( SQLException e ) {
String cause = e.getMessage();
Logging.instance().log( "app", 1, "Ignoring SQL exception" +
( cause==null ? "" : ": " + e.getMessage() ) );
m_dbdriver.clearWarnings();
}
boolean useInsert = ( id == -1 );
// if in insertion mode, complain and exit
if ( ! useInsert && ! overwrite ) {
Logging.instance().log( "app", 0, definition.shortID() +
" already exists (SQL anno_definition.id=" + id +
"), ignoring" );
return false;
}
Logging.instance().log( "app", 1, "Trying to add " + what(definition) );
PreparedStatement ps =
m_dbdriver.getPreparedStatement( useInsert ?
"stmt.save.definition" :
"stmt.updt.definition" );
if ( useInsert ) {
// INSERT
try {
id = m_dbdriver.sequence1( "def_id_seq" );
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "In " + definition.shortID() + ": " +
e.toString().trim() );
Logging.instance().log("xaction", 1, "START rollback" );
m_dbdriver.cancelPreparedStatement( "stmt.save.definition" );
m_dbdriver.rollback();
Logging.instance().log("xaction", 1, "FINAL rollback" );
return false;
}
// add ID explicitely from sequence to insertion
Logging.instance().log("xaction", 1, "START save definition" );
int i = 1;
longOrNull( ps, i++, id );
ps.setInt( i++, definition.getType() );
if ( definition.getName() == null )
throw new SQLException( "VDS inconsistency: " +
"The name of a definition is null" );
else
ps.setString( i++, definition.getName() );
ps.setString( i++, makeNotNull(definition.getNamespace()) );
ps.setString( i++, makeNotNull(definition.getVersion()) );
String xml = definition.toXML( (String) null, (String) null );
ps.setCharacterStream( i++, new StringReader(xml), xml.length() );
// save prepared values
Logging.instance().log( "chunk", 2, "INSERT INTO Definition" );
try {
ps.executeUpdate();
if ( id== -1 ) id = m_dbdriver.sequence2( ps, "def_id_seq", 1 );
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "In " + definition.shortID() + ": " +
e.toString().trim() );
Logging.instance().log("xaction", 1, "START rollback" );
m_dbdriver.cancelPreparedStatement( "stmt.save.definition" );
m_dbdriver.rollback();
Logging.instance().log("xaction", 1, "FINAL rollback" );
return false;
}
Logging.instance().log("xaction", 1, "FINAL save definition: ID=" + id );
} else {
// UPDATE
Logging.instance().log("xaction", 1, "START udpate definition" );
int i = 1;
String xml = definition.toXML( (String) null, (String) null );
ps.setCharacterStream( i++, new StringReader(xml), xml.length() );
longOrNull( ps, i++, id );
// update prepared values
Logging.instance().log( "chunk", 2, "UPDATE Definition" );
try {
ps.executeUpdate();
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "In " + definition.shortID() + ": " +
e.toString().trim() );
Logging.instance().log("xaction", 1, "START rollback" );
m_dbdriver.cancelPreparedStatement( "stmt.updt.definition" );
m_dbdriver.rollback();
Logging.instance().log("xaction", 1, "FINAL rollback" );
return false;
}
Logging.instance().log("xaction", 1, "FINAL update definition: ID=" + id );
// TODO: Drop all old LFNs
deleteLFNsForDefinitionId(id);
}
// batch save LFNs from Derivations
if ( definition instanceof Derivation ) {
Derivation derivation = (Derivation) definition;
Set alreadyKnown = new HashSet();
// ordering MUST MATCH classes.LFN constants!
PreparedStatement stmt[] = {
m_dbdriver.getPreparedStatement("stmt.save.lfn_i"),
m_dbdriver.getPreparedStatement("stmt.save.lfn_o"),
m_dbdriver.getPreparedStatement("stmt.save.lfn_b") };
int[] count = new int[ stmt.length ];
for ( int ii=0; ii<count.length; ++ii ) count[ii] = 0;
for ( Iterator j=derivation.iteratePass(); j.hasNext(); ) {
Value value = ((Pass) j.next()).getValue();
if ( value != null ) {
switch ( value.getContainerType() ) {
case Value.SCALAR:
// check Scalar contents for LFN
saveScalar( id, (Scalar) value, alreadyKnown, stmt, count );
break;
case Value.LIST:
// check List for Scalars for LFN
for ( Iterator k=((org.griphyn.vdl.classes.List)value).iterateScalar(); k.hasNext(); ) {
saveScalar( id, (Scalar) k.next(), alreadyKnown, stmt, count );
}
break;
default:
throw new RuntimeException( "unknown container type" );
}
}
}
for ( int ii=0; ii<stmt.length; ++ii ) {
// anything to do?
if ( count[ii] > 0 ) {
// batch insert
Logging.instance().log( "chunk", 2, "BATCH INSERT for " + count[ii] +
' ' + c_lfn_names[ii] );
Logging.instance().log( "xaction", 1, "START batch-add " + count[ii]
+ ' ' + c_lfn_names[ii] );
int[] update = stmt[ii].executeBatch();
Logging.instance().log( "xaction", 1, "FINAL batch-add " + count[ii]
+ ' ' + c_lfn_names[ii] );
}
}
}
// commit the changes
Logging.instance().log("xaction", 1, "START commit" );
this.m_dbdriver.commit();
Logging.instance().log("xaction", 1, "FINAL commit" );
// done
return true;
}
/**
* Saves all logical filenames from a Scalar object. This is a helper
* function to save a single definition.
*
* @param id is the definition id in the DEFINITION table
* @param scalar is a Scalar instance of which the LFNs are to be saved.
* @param already is a set of filenames that were already added during
* this session
* @param stmt is an array of the ids of the prepared statements for
* the different tables.
* @param count count the number of entries in a prepared statement.
*
* @see #saveDefinition( Definition, boolean )
*/
private void saveScalar( long id, Scalar scalar, Set already,
PreparedStatement[] stmt, int[] count )
throws SQLException
{
int result = 0;
for ( Iterator i=scalar.iterateLeaf(); i.hasNext(); ) {
Leaf leaf = (Leaf) i.next();
// only interested in logical filenames, nothing else
if ( leaf instanceof LFN ) {
LFN lfn = (LFN) leaf;
String name = lfn.getFilename();
// already inserted previously?
if ( already.contains(name) ) continue;
else already.add(name);
// adjust!
int index = -1;
int link = lfn.getLink();
switch ( link ) {
case LFN.INPUT:
index = 0;
break;
case LFN.OUTPUT:
index = 1;
break;
case LFN.INOUT:
index = 2;
break;
default:
throw new RuntimeException( "Illegal linkage " + link + " for " + name );
}
int n = 1;
if ( m_dbdriver.preferString() ) stmt[index].setString( n++, Long.toString(id) );
else stmt[index].setLong( n++, id );
stmt[index].setString( n++, name );
Logging.instance().log( "chunk", 3, "adding LFN " + LFN.toString(link)
+ ':' + name );
stmt[index].addBatch();
count[index]++;
}
}
}
//
// higher level methods, allowing for wildcarding unless working on
// a single Definition.
//
/**
* Obtains the primary key id for a given definition. "Fake" definitions
* are NOT permissable. This is an internal helper function.
*
* @param namespace is the specific namespace, null will be mapped to ""
* @param name is the specific name, null will be mapped to ""
* @param version is the specific version, null will be mapped to ""
* @param type is the type identifier, -1 is not allowed.
* @return the id of the definition, or null if not found.
*
* @see #getDefinitionId( String, String, String, int )
*/
protected Long getSpecificDefinitionId( String namespace,
String name,
String version,
int type )
throws SQLException
{
Logging.instance().log("xaction", 1, "START select ID from DEFINITION" );
Long result = null;
// ps.resetPreparedStatement( "stmt.select.id" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.id");
ps.setInt( i++, type );
ps.setString( i++, makeNotNull(name) );
ps.setString( i++, makeNotNull(namespace) );
ps.setString( i++, makeNotNull(version) );
Logging.instance().log( "chunk", 2, "SELECT id FROM definition" );
ResultSet rs = ps.executeQuery();
Logging.instance().log("xaction", 1, "INTER select ID from DEFINITION" );
if ( rs.next() ) result = new Long( rs.getLong(1) );
else Logging.instance().log( "chunk", 0, "Definition not found" );
rs.close();
Logging.instance().log("xaction", 1, "FINAL select ID from DEFINITION" );
return result;
}
/**
* Obtains the primary key id for a given definition. "Fake" definitions
* are permissable. This is an internal helper function.
*
* @param d is a definition specification.
* @return the id of the definition, or null if not found.
*
* @see #getSpecificDefinitionId( String, String, String, int )
* @see #getDefinitionId( String, String, String, int )
*/
protected Long getDefinitionId( Definition d )
throws SQLException
{
return getSpecificDefinitionId( d.getNamespace(),
d.getName(),
d.getVersion(),
d.getType() );
}
/**
* Obtains the list of primary key ids for a matching definitions.
* This method allows for wildcards in the usual fashion. Use null for
* strings as wildcards, and -1 for the type wildcard. This method may
* return an empty list, but it will not return null. This is an
* internal helper function.
*
* @param namespace namespace, null to match any namespace
* @param name name, null to match any name
* @param version version, null to match any version
* @param type definition type (TR or DV)
* @return a possibly empty list containing all matching
* definition ids as Longs.
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
* @see #getDefinitionId( Definition )
*/
protected java.util.List getDefinitionId( String namespace,
String name,
String version,
int type )
throws SQLException
{
java.util.List result = new ArrayList();
Logging.instance().log("xaction", 1, "START select IDs from DEFINITION" );
java.util.List select = new ArrayList(1);
select.add( new String("distinct id") );
java.util.Map where = new TreeMap();
if ( type != -1 ) where.put( "type", Integer.toString(type) );
if ( namespace != null ) where.put( "namespace", namespace );
if ( name != null ) where.put( "name", name );
if ( version != null ) where.put( "version", version );
ResultSet rs = m_dbdriver.select(select,"anno_definition",where,null);
while ( rs.next() )
result.add( new Long( rs.getLong("id") ) );
rs.close();
Logging.instance().log("xaction", 1, "FINAL select IDs from DEFINITION" );
return result;
}
/**
* Obtains the list of primary key ids for a matching definitions.
* This method allows for wildcards in the usual fashion. Use null for
* strings as wildcards, and -1 for the type wildcard. It also allows
* special characters '%' and '_' in strings. This method may
* return an empty list, but it will not return null. This is an
* internal helper function.
*
* @param namespace namespace, null to match any namespace
* @param name name, null to match any name
* @param version version, null to match any version
* @param type definition type (TR or DV)
* @return a possibly empty list containing all matching
* definition ids as Longs.
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
* @see #getDefinitionId( Definition )
*/
protected java.util.List getDefinitionIdEx( String namespace,
String name,
String version,
int type )
throws SQLException
{
java.util.List result = new ArrayList();
Logging.instance().log("xaction", 1, "START select IDs from DEFINITION" );
java.util.List select = new ArrayList(1);
select.add( new String("distinct id") );
java.util.Map where = new TreeMap();
java.util.Map operator = new TreeMap();
if ( type != -1 ) where.put( "type", Integer.toString(type) );
if ( namespace != null ) {
where.put( "namespace", namespace );
operator.put( "namespace", "LIKE" );
}
if ( name != null ) {
where.put( "name", name );
operator.put( "name", "LIKE" );
}
if ( version != null ) {
where.put( "version", version );
operator.put( "version", "LIKE" );
}
ResultSet rs = m_dbdriver.select( select, "anno_definition", where, operator, null );
while ( rs.next() )
result.add( new Long( rs.getLong("id") ) );
rs.close();
Logging.instance().log("xaction", 1, "FINAL select IDs from DEFINITION" );
return result;
}
/**
* Search the database for the existence of a definition.
*
* @param definition the definition object to search for
* @return true, if the definition exists, false if not found
*/
public boolean containsDefinition( Definition definition )
throws SQLException
{
boolean result = false;
try {
result = ( getDefinitionId(definition) != null );
} catch ( SQLException sql ) {
// ignore
this.m_dbdriver.clearWarnings();
}
return result;
}
/**
* Deletes the joined annotations when a definition is being deleted.
*
* @param id is the definition id to remove
* @return list of all annotation ids that were removed
*/
private java.util.List deleteAnnotationFromDefinition( long id )
throws SQLException
{
PreparedStatement ps = null;
ResultSet rs = null;
ArrayList idlist = new ArrayList();
boolean preferString = m_dbdriver.preferString();
//
// part 1: assemble all affected annotation ids
//
// fnlist := collect list of filenames WHERE id=$id
// annolist := SELECT distinct id FROM anno_$rest WHERE did=$id
// annolist += SELECT distinct id FROM anno_lfn WHERE name IN $fnlist
Logging.instance().log("xaction", 1, "START *huge* union" );
ps = this.m_dbdriver.getPreparedStatement( "stmt.select.big" );
for ( int i=1; i<=7; ++i ) {
if ( preferString ) ps.setString( i, Long.toString(id) );
else ps.setLong( i, id );
}
rs = ps.executeQuery();
while ( rs.next() ) {
idlist.add( new Long( rs.getLong(1) ) );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL *huge* union" );
//
// part 2: remove all affected annotations
//
// DELETE anno_$type WHERE id IN $annolist
// DELETE anno_$rest WHERE id IN $annolist
Logging.instance().log("xaction", 1, "START delete annotations" );
// list of all statements we need to access
PreparedStatement list[] = {
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_bool"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_int"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_float"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_date"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_text"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_tr"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_dv"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_lfn"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_targ"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_call")
};
// prepare and batch all statements
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
id = ((Long) i.next()).longValue();
for ( int j=0; j<list.length; ++j ) {
if ( preferString ) list[j].setString( 1, Long.toString(id) );
else list[j].setLong( 1, id );
list[j].addBatch();
}
}
// run all batches
Logging.instance().log("xaction", 1, "INTER delete annotations" );
for ( int j=0; j<list.length; ++j ) {
int[] status = new int[ idlist.size() ];
try {
status = list[j].executeBatch();
} catch ( NullPointerException npe ) {
Logging.instance().log( "app", 1, "tripped over NPE, ignoring!" );
}
}
Logging.instance().log("xaction", 1, "FINAL delete annotation" );
if ( ! m_deferDeleteCommit ) m_dbdriver.commit();
return idlist;
}
/**
* Deletes all logical filenames that are associated with a
* particular definition. Note that this method does not commit
* the changes, as it is supposed to be called from other methods.
*
* @param did is the definition id to remove LFNs for
* @return number of rows affected, may be zero.
*/
private int deleteLFNsForDefinitionId( long did )
throws SQLException
{
int status, result = 0;
PreparedStatement ps = null;
boolean preferString = m_dbdriver.preferString();
Logging.instance().log( "xaction", 1, "START DELETE FROM lfn_i" );
ps = m_dbdriver.getPreparedStatement( "stmt.delete.lfn_i" );
if ( preferString ) ps.setString( 1, Long.toString(did) );
else ps.setLong( 1, did );
result = ps.executeUpdate();
Logging.instance().log( "xaction", 1, "FINAL DELETE FROM lfn_i: " +
result );
Logging.instance().log( "xaction", 1, "START DELETE FROM lfn_o" );
ps = m_dbdriver.getPreparedStatement( "stmt.delete.lfn_o" );
if ( preferString ) ps.setString( 1, Long.toString(did) );
else ps.setLong( 1, did );
status = ps.executeUpdate();
result += status;
Logging.instance().log( "xaction", 1, "FINAL DELETE FROM lfn_o: " +
status );
Logging.instance().log( "xaction", 1, "START DELETE FROM lfn_b" );
ps = m_dbdriver.getPreparedStatement( "stmt.delete.lfn_b" );
if ( preferString ) ps.setString( 1, Long.toString(did) );
else ps.setLong( 1, did );
status = ps.executeUpdate();
result += status;
Logging.instance().log( "xaction", 1, "FINAL DELETE FROM lfn_b: " +
status );
return result;
}
/**
* Delete a specific Definition objects from the database. No wildcard
* matching will be done. "Fake" definitions are permissable, meaning
* it just has the secondary key triple.
*
* @param definition is the definition specification to delete
* @return true is something was deleted, false if non existent.
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
*/
public boolean deleteDefinition( Definition definition )
throws SQLException
{
int result = 0;
PreparedStatement ps = null;
//
// TODO: turn into a stored procedure call
//
Logging.instance().log("xaction", 1, "START delete definition" );
Long defId = getDefinitionId(definition);
boolean preferString = m_dbdriver.preferString();
if ( defId != null ) {
long id = defId.longValue();
deleteAnnotationFromDefinition(id);
deleteLFNsForDefinitionId(id);
Logging.instance().log( "xaction", 1, "START DELETE FROM definition" );
ps = m_dbdriver.getPreparedStatement( "stmt.delete.xml" );
if ( preferString ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
result = ps.executeUpdate();
Logging.instance().log( "xaction", 1, "FINAL DELETE FROM definition: " + result );
if ( ! m_deferDeleteCommit ) m_dbdriver.commit();
}
Logging.instance().log("xaction", 1, "FINAL delete definition" );
return ( result != 0 );
}
/**
* Delete Definition objects from the database. This method allows for
* wildcards in the usual fashion. Use null for strings as wildcards,
* and -1 for the type wildcard. For efficiency reasons, this method
* will return an empty list.
*
* @param namespace namespace, null to match any namespace
* @param name name, null to match any name
* @param version version, null to match any version
* @param type definition type (TR or DV)
* @return a list containing all Definitions that were deleted
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
*/
public java.util.List deleteDefinition( String namespace,
String name,
String version,
int type )
throws SQLException
{
java.util.List result = new ArrayList();
Logging.instance().log("xaction", 1, "START delete definitions" );
java.util.List idlist = getDefinitionId( namespace, name, version, type );
if ( idlist.size() == 0 ) return result;
// postcondition: contains all IDs, count(id)>0, to be deleted
// save old values
if ( ! m_deferDeleteCommit ) {
// we come from saveDefinition, thus we won't need saved values
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
Definition d = loadDefinition( ((Long) i.next()).longValue() );
if ( d != null ) result.add(d);
}
}
// remove all affected annoations by walking through them
// yuk, this is probably extremely expensive
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
long id = ((Long) i.next()).longValue();
deleteAnnotationFromDefinition(id);
}
// list of all statements we need to access
PreparedStatement ps[] = {
this.m_dbdriver.getPreparedStatement("stmt.delete.lfn_i"),
this.m_dbdriver.getPreparedStatement("stmt.delete.lfn_o"),
this.m_dbdriver.getPreparedStatement("stmt.delete.lfn_b"),
this.m_dbdriver.getPreparedStatement("stmt.delete.xml")
};
// prepare and batch all statements
boolean preferString = m_dbdriver.preferString();
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
long id = ((Long) i.next()).longValue();
for ( int j=0; j<ps.length; ++j ) {
if ( preferString ) ps[j].setString( 1, Long.toString(id) );
else ps[j].setLong( 1, id );
ps[j].addBatch();
}
}
// run all batches
Logging.instance().log("xaction", 1, "INTER delete definitions" );
for ( int j=0; j<ps.length; ++j ) {
int[] status = new int[ idlist.size() ];
try {
status = ps[j].executeBatch();
} catch ( NullPointerException npe ) {
Logging.instance().log( "app", 1, "tripped over NPE, ignoring!" );
}
}
Logging.instance().log("xaction", 1, "FINAL delete definitions" );
if ( ! m_deferDeleteCommit ) m_dbdriver.commit();
return result;
}
/**
* Search the database for definitions by ns::name:version triple
* and by type (either Transformation or Derivation). This version
* of the search allows for jokers expressed as null value
*
* @param namespace namespace, null to match any namespace
* @param name name, null to match any name
* @param version version, null to match any version
* @param type type of definition (TR/DV, or both)
* @return a list of definitions
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
*/
public java.util.List searchDefinition( String namespace,
String name,
String version,
int type )
throws SQLException
{
java.util.List idlist = getDefinitionId( namespace, name, version, type );
// TODO: make this a batch or sproc
java.util.List result = new ArrayList();
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
Definition d = loadDefinition( ((Long) i.next()).longValue() );
if ( d != null ) result.add(d);
}
return result;
}
/**
* Searches the database for all derivations that contain a certain LFN.
* The linkage is an additional constraint. This method does not allow
* jokers.
*
* @param lfn the LFN name
* @param link the linkage type of the LFN
* @return a list of Definition items that match the criterion.
*
* @see org.griphyn.vdl.classes.LFN#NONE
* @see org.griphyn.vdl.classes.LFN#INPUT
* @see org.griphyn.vdl.classes.LFN#OUTPUT
* @see org.griphyn.vdl.classes.LFN#INOUT
*/
public java.util.List searchFilename( String lfn, int link )
throws SQLException
{
if ( lfn == null )
throw new NullPointerException("You must query for a filename");
Logging.instance().log("xaction", 1, "START select LFNs" );
PreparedStatement ps = null;
if ( link == -1 ) {
// wildcard match
ps = this.m_dbdriver.getPreparedStatement( "stmt.select.lfn_*" );
for ( int ii=0; ii<c_lfn_names.length; ++ii ) ps.setString( ii+1, lfn );
Logging.instance().log( "chunk", 2, "SELECT distinct id FROM anno_lfn_*" +
" WHERE name='" + lfn + "'" );
} else if ( LFN.isInRange(link) ) {
// known linkage, one table only
// ordering MUST MATCH classes.LFN constants!
switch ( link ) {
case LFN.NONE:
throw new RuntimeException( "The linkage \"none\" is not permitted" );
// break;
case LFN.INPUT:
ps = this.m_dbdriver.getPreparedStatement("stmt.select.lfn_i");
break;
case LFN.OUTPUT:
ps = this.m_dbdriver.getPreparedStatement("stmt.select.lfn_o");
break;
case LFN.INOUT:
ps = this.m_dbdriver.getPreparedStatement("stmt.select.lfn_b");
break;
};
ps.setString( 1, lfn );
Logging.instance().log( "chunk", 2, "SELECT distinct id FROM " +
c_lfn_names[link-1] + " WHERE name='" + lfn + "'" );
} else {
throw new RuntimeException( "The linkage " + link + " is not permitted" );
}
ResultSet rs = ps.executeQuery();
// TODO: make this a batch or sproc
java.util.List result = new ArrayList();
while ( rs.next() ) {
Definition d = loadDefinition( rs.getLong(1) );
if ( d != null ) result.add(d);
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select LFNs" );
return result;
}
//
//
// annotations
//
//
/**
* Retrieves the annotation id of a given transformation.
*
* @param did is the definition id of the transformation
* @param key is the key to search for.
* @return -1 if not found, or the correction annotation id.
* @exception SQLException if some database operation fails.
*/
private long getAnnotationIdTransformation( long did, String key )
throws SQLException
{
long result = -1;
Logging.instance().log("xaction", 1, "START select anno_tr" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_tr" );
if ( m_dbdriver.preferString() ) ps.setString( i++, Long.toString(did) );
else ps.setLong( i++, did );
ps.setString( i++, makeNotNull(key) );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_tr" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) result = rs.getLong(1);
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_tr.id = " + result );
return result;
}
/**
* Retrieves the annotation id of a given derivation id.
*
* @param did is the definition id of the derivation
* @param key is the key to search for.
* @return -1 if not found, or the correction annotation id.
* @exception SQLException if some database operation fails.
*/
private long getAnnotationIdDerivation( long did, String key )
throws SQLException
{
long result = -1;
Logging.instance().log("xaction", 1, "START select anno_dv" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_dv" );
if ( m_dbdriver.preferString() ) ps.setString( i++, Long.toString(did) );
else ps.setLong( i++, did );
ps.setString( i++, makeNotNull(key) );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_dv" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) result = rs.getLong(1);
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_dv.id = " + result );
return result;
}
/**
* Retrieves the annotation id of a given transformation formal argument.
*
* @param did is the definition id of the transformation
* @param farg is the formal argument name
* @param key is the key to search for.
* @return -1 if not found, or the correction annotation id.
* @exception SQLException if some database operation fails.
*/
private long getAnnotationIdDeclare( long did, String farg, String key )
throws SQLException
{
long result = -1;
Logging.instance().log("xaction", 1, "START select anno_targ" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_targ" );
if ( m_dbdriver.preferString() ) ps.setString( i++, Long.toString(did) );
else ps.setLong( i++, did );
ps.setString( i++, makeNotNull(farg) );
ps.setString( i++, makeNotNull(key) );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_targ" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) result = rs.getLong(1);
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_targ.id = " + result );
return result;
}
/**
* Retrieves the annotation id of a given call within a transformation.
*
* @param did is the definition id of the transformation
* @param pos is the position of the call statement
* @param key is the key to search for.
* @return -1 if not found, or the correction annotation id.
* @exception SQLException if some database operation fails.
*/
private long getAnnotationIdCall( long did, int pos, String key )
throws SQLException
{
long result = -1;
Logging.instance().log("xaction", 1, "START select anno_call" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_call" );
if ( m_dbdriver.preferString() ) {
ps.setString( i++, Long.toString(did) );
ps.setString( i++, Integer.toString(pos) );
} else {
ps.setLong( i++, did );
ps.setInt( i++, pos );
}
ps.setString( i++, makeNotNull(key) );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_call" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) result = rs.getLong(1);
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_call.id = " + result );
return result;
}
/**
* Retrieves the annotation id of a given logical filename.
*
* @param lfn is the logical filename.
* @param key is the key to search for.
* @return -1 if not found, or the correction annotation id.
* @exception SQLException if some database operation fails.
*/
private long getAnnotationIdFilename( String lfn, String key )
throws SQLException
{
long result = -1;
Logging.instance().log("xaction", 1, "START select anno_lfn" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_lfn" );
ps.setString( i++, makeNotNull(lfn) );
ps.setString( i++, makeNotNull(key) );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_lfn" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) result = rs.getLong(1);
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_lfn.id = " + result );
return result;
}
/**
* Deletes an annotation with the specified key.
*
* @param primary is the primary object specifier for the class.
* According to the type, this is either the FQDI, or the filename.
* @param secondary is a helper argument for annotations to calls
* and formal arguments, and should be null for all other classes.
* For calls, the argument must be packed into {@link java.lang.Integer}.
* @param kind defines the kind/class of object to annotate.
* @param key is the annotation key.
* @return true, if the database was modified, false otherwise.
* @exception SQLException, if something went wrong during database
* access.
*/
public boolean deleteAnnotation( String primary, Object secondary,
int kind, String key )
throws SQLException, IllegalArgumentException
{
boolean result = true;
switch ( kind ) {
case CLASS_TRANSFORMATION:
result = deleteAnnotationTransformation( primary, key );
break;
case CLASS_DERIVATION:
result = deleteAnnotationDerivation( primary, key );
break;
case CLASS_CALL:
// may throw ClassCastException
result = deleteAnnotationCall( primary, ((Integer) secondary).intValue(), key );
break;
case CLASS_DECLARE:
// may throw ClassCastException
result = deleteAnnotationDeclare( primary, ((String) secondary), key );
break;
case CLASS_FILENAME:
result = deleteAnnotationFilename( primary, key );
break;
default:
throw new IllegalArgumentException( "The class kind=" + kind + " cannot be annotated" );
}
return result;
}
/**
* Deletes an annotation value with the specified annotation id.
*
* @param id is the annotation id for which to delete
*
* @return true, if the database was modified, false otherwise.
* @exception SQLException, if something went wrong during database
* access.
*/
private boolean deleteAnnotationValue( long id )
throws SQLException
{
PreparedStatement list[] = {
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_bool"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_int"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_float"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_date"),
this.m_dbdriver.getPreparedStatement("stmt.delete.anno_text")
};
boolean result = true;
// prepare and batch all statements
for ( int j=0; j<list.length; ++j ) {
if ( m_dbdriver.preferString() ) list[j].setString( 1, Long.toString(id) );
else list[j].setLong( 1, id );
list[j].addBatch();
}
// run all batches
Logging.instance().log("xaction", 1, "INTER delete annotations" );
for ( int j=0; j<list.length; ++j ) {
int[] status = new int[1];
try {
status = list[j].executeBatch();
result = (result &&( status[0] != 0));
} catch ( NullPointerException npe ) {
Logging.instance().log( "app", 1, "tripped over NPE, ignoring!" );
}
}
Logging.instance().log("xaction", 1, "FINAL delete annotation" );
if ( ! m_deferDeleteCommit ) m_dbdriver.commit();
return result;
}
/**
* Deletes an annotation in a type table with the specified
* annotation id. The table is determined from the type of the
* annotational tuple.
*
* @param id is the annotation id for which to delete
* @param kind is the class of object.
* @return true, if the database was modified, false otherwise.
* @exception SQLException, if something went wrong during database
* access.
*/
private boolean deleteAnnotationKey( long id, int kind )
throws SQLException
{
Logging.instance().log("xaction", 1, "START delete anno_<key>" );
PreparedStatement ps = null;
switch (kind) {
case CLASS_FILENAME:
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_lfn" );
break;
case CLASS_TRANSFORMATION:
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_tr" );
break;
case CLASS_DERIVATION:
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_dv" );
break;
case CLASS_DECLARE:
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_targ" );
break;
case CLASS_CALL:
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_call" );
break;
default:
throw new SQLException( "Don't know the class of object" );
}
if ( m_dbdriver.preferString() )
ps.setString( 1, Long.toString(id) );
else
ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "DELETE FROM anno_<key>" );
int rc = ps.executeUpdate();
Logging.instance().log("xaction", 1, "FINAL delete anno_<key>" );
boolean ret = deleteAnnotationValue(id);
return ( rc != 0 && ret );
}
/**
* Deletes an annotation in a type table with the specified
* annotation id. The table is determined from the type of the
* annotational tuple.
*
* @param id is the annotation id for which to delete
* @param annotation is the annotation which determines the type
* @return true, if the database was modified, false otherwise.
* @exception SQLException, if something went wrong during database
* access.
*/
private boolean deleteAnnotationValue( long id, Tuple annotation )
throws SQLException
{
Logging.instance().log("xaction", 1, "START delete anno_<value>" );
PreparedStatement ps = null;
if ( annotation instanceof TupleBoolean )
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_bool" );
else if ( annotation instanceof TupleDate )
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_date" );
else if ( annotation instanceof TupleFloat )
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_float" );
else if ( annotation instanceof TupleInteger )
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_int" );
else if ( annotation instanceof TupleString )
ps = m_dbdriver.getPreparedStatement( "stmt.delete.anno_text" );
else
throw new SQLException( "Don't know the tuple type" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "DELETE FROM anno_<value>" );
int rc = ps.executeUpdate();
Logging.instance().log("xaction", 1, "FINAL delete anno_<value>" );
return ( rc != 0 );
}
/**
* Deletes a specific key in an annotated transformation.
*
* @param fqdi is the FQDI of the transformation
* @param key is the key to search for
* @return true, if the database was modified, false otherwise.
* @see org.griphyn.vdl.classes.Transformation
*/
public boolean deleteAnnotationTransformation( String fqdi, String key )
throws SQLException, IllegalArgumentException
{
int kind = CLASS_TRANSFORMATION;
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain possible existing anno_tr id
long id = getAnnotationIdTransformation( did.longValue(), key );
// no such key, if the id is -1, handled by finalizer
return deleteAnnotationKey( id, kind );
}
/**
* Deletes a specific key in an annotated derivation.
*
* @param fqdi is the FQDI of the derivation
* @param key is the key to search for
* @return true, if the database was modified, false otherwise.
* @see org.griphyn.vdl.classes.Derivation
*/
public boolean deleteAnnotationDerivation( String fqdi, String key )
throws SQLException, IllegalArgumentException
{
int kind = CLASS_DERIVATION;
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.DERIVATION );
if ( did == null ) throw new SQLException( "Unknown DV " + fqdi );
// obtain possible existing anno_dv id
long id = getAnnotationIdDerivation( did.longValue(), key );
// no such key, if the id does not exist
return deleteAnnotationKey( id, kind );
}
/**
* Deletes a specific key in an annotated formal argument.
*
* @param fqdi is the FQDI of the transformation
* @param farg is the name of the formal argument
* @param key is the key to search for
* @return true, if the database was modified, false otherwise.
* @see org.griphyn.vdl.classes.Declare
*/
public boolean deleteAnnotationDeclare( String fqdi, String farg,
String key )
throws SQLException, IllegalArgumentException
{
int kind = CLASS_DECLARE;
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain possible existing anno_call id
long id = getAnnotationIdDeclare( did.longValue(), farg, key );
// no such key, if the id does not exist
return deleteAnnotationKey( id, kind );
}
/**
* Deletes a specific key for a call statement.
*
* @param fqdi is the FQDI of the transformation
* @param index is the number of the call to annotate.
* @param key is the key to search for
* @return true, if the database was modified, false otherwise.
* @see org.griphyn.vdl.classes.Call
*/
public boolean deleteAnnotationCall( String fqdi, int index,
String key )
throws SQLException, IllegalArgumentException
{
int kind = CLASS_CALL;
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain possible existing anno_call id
long id = getAnnotationIdCall( did.longValue(), index, key );
// no such key, if the id does not exist
return deleteAnnotationKey( id, kind );
}
/**
* Deletes a specific key in an annotated filename.
*
* @param filename is the name of the file that was annotated.
* @param key is the key to search for
* @return true, if the database was modified, false otherwise.
* @see org.griphyn.vdl.classes.LFN
*/
public boolean deleteAnnotationFilename( String filename, String key )
throws SQLException, IllegalArgumentException
{
int kind = CLASS_FILENAME;
// obtain possible existing anno_lfn id
long id = getAnnotationIdFilename( filename, key );
// no such key, if the id does not exist
return deleteAnnotationKey( id, kind );
}
/**
* Inserts a tuple into the correct type-table for annotations.
*
* @param id is the annotation id for which to insert.
* @param annotation is the annotation to insert. Only the type
* and value will be taken, as the key was inserted elsewhere.
* @return true, if the database was modified, false otherwise.
* @exception SQLException if something during the database access
* went awry.
*/
private boolean saveAnnotationValue( long id, Tuple annotation )
throws SQLException
{
Logging.instance().log("xaction", 1, "START save anno_<value>" );
PreparedStatement ps = null;
if ( annotation instanceof TupleBoolean ) {
ps = m_dbdriver.getPreparedStatement( "stmt.save.anno_bool" );
ps.setBoolean( 2, ((Boolean) annotation.getValue()).booleanValue() );
} else if ( annotation instanceof TupleDate ) {
ps = m_dbdriver.getPreparedStatement( "stmt.save.anno_date" );
ps.setTimestamp( 2, ((Timestamp) annotation.getValue()) );
} else if ( annotation instanceof TupleFloat ) {
ps = m_dbdriver.getPreparedStatement( "stmt.save.anno_float" );
ps.setDouble( 2, ((Double) annotation.getValue()).doubleValue() );
} else if ( annotation instanceof TupleInteger ) {
ps = m_dbdriver.getPreparedStatement( "stmt.save.anno_int" );
ps.setLong( 2, ((Long) annotation.getValue()).longValue() );
} else if ( annotation instanceof TupleString ) {
ps = m_dbdriver.getPreparedStatement( "stmt.save.anno_text" );
// ps.setString( 2, ((String) annotation.getValue()) );
String value = (String) annotation.getValue();
ps.setCharacterStream( 2, new StringReader(value), value.length() );
} else
throw new SQLException( "Don't know the tuple type" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "INSERT INTO anno_<value>" );
int rc = ps.executeUpdate();
Logging.instance().log("xaction", 1, "FINAL save anno_<value>" );
return ( rc != 0 );
}
/**
* Annotates a transformation with a tuple.
*
* @param fqdi is the FQDI to annotate
* @param annotation is the value to place
* @param overwrite is a predicate on replace or maintain.
* @return the insertion id, or -1, if the database was untouched
* @see org.griphyn.vdl.classes.Transformation
*/
public long saveAnnotationTransformation( String fqdi,
Tuple annotation,
boolean overwrite )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain possible existing anno_tr id
long id = getAnnotationIdTransformation( did.longValue(), annotation.getKey() );
// insert into anno_tr with new id, if id does not exist
if ( id == -1 ) {
// obtain new id
id = m_dbdriver.sequence1( "anno_id_seq" );
Logging.instance().log("xaction", 1, "START save anno_tr" );
PreparedStatement ps =
m_dbdriver.getPreparedStatement( "stmt.save.anno_tr" );
int i = 1;
longOrNull( ps, i++, id );
if ( m_dbdriver.preferString() ) ps.setString( i++, did.toString() );
else ps.setLong( i++, did.longValue() );
ps.setString( i++, makeNotNull( annotation.getKey() ) );
// save prepared values
Logging.instance().log( "chunk", 2, "INSERT INTO anno_tr" );
try {
int rc = ps.executeUpdate();
if ( id == -1 ) id = m_dbdriver.sequence2( ps, "anno_id_seq", 1 );
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "While inserting into anno_tr: " +
e.toString().trim() );
// rollback in saveInvocation()
m_dbdriver.cancelPreparedStatement( "stmt.save.anno_tr" );
throw e; // re-throw
}
Logging.instance().log("xaction", 1, "FINAL save anno_tr: ID=" + id );
} else {
// id does exist, nothing to do in anno_tr
}
// delete before insert if overwrite mode
if ( overwrite ) deleteAnnotationValue( id, annotation );
return ( saveAnnotationValue( id, annotation ) ? id : -1 );
}
/**
* Annotates a derivation with a tuple.
*
* @param fqdi is the FQDI to annotate
* @param annotation is the value to place
* @param overwrite is a predicate on replace or maintain.
* @return the insertion id, or -1, if the database was untouched
* @see org.griphyn.vdl.classes.Derivation
*/
public long saveAnnotationDerivation( String fqdi,
Tuple annotation,
boolean overwrite )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.DERIVATION );
if ( did == null ) throw new SQLException( "Unknown DV " + fqdi );
// obtain possible existing anno_dv id
long id = getAnnotationIdDerivation( did.longValue(), annotation.getKey() );
// insert into anno_dv with new id, if id does not exist
if ( id == -1 ) {
// obtain new id
id = m_dbdriver.sequence1( "anno_id_seq" );
Logging.instance().log("xaction", 1, "START save anno_dv" );
PreparedStatement ps =
m_dbdriver.getPreparedStatement( "stmt.save.anno_dv" );
int i = 1;
longOrNull( ps, i++, id );
if ( m_dbdriver.preferString() ) ps.setString( i++, did.toString() );
else ps.setLong( i++, did.longValue() );
ps.setString( i++, makeNotNull( annotation.getKey() ) );
// save prepared values
Logging.instance().log( "chunk", 2, "INSERT INTO anno_dv" );
try {
int rc = ps.executeUpdate();
if ( id == -1 ) id = m_dbdriver.sequence2( ps, "anno_id_seq", 1 );
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "While inserting into anno_tr: " +
e.toString().trim() );
// rollback in saveInvocation()
m_dbdriver.cancelPreparedStatement( "stmt.save.anno_tr" );
throw e; // re-throw
}
Logging.instance().log("xaction", 1, "FINAL save anno_dv: ID=" + id );
} else {
// id does exist, nothing to do in anno_tr
}
// delete before insert if overwrite mode
if ( overwrite ) deleteAnnotationValue( id, annotation );
return ( saveAnnotationValue( id, annotation ) ? id : -1 );
}
/**
* Annotates a transformation argument with a tuple.
*
* @param fqdi is the FQDI to annotate
* @param formalname is the name of the formal argument to annotoate.
* @param annotation is the value to place
* @param overwrite is a predicate on replace or maintain.
* @return the insertion id, or -1, if the database was untouched
* @see org.griphyn.vdl.classes.Declare
*/
public long saveAnnotationDeclare( String fqdi,
String formalname,
Tuple annotation,
boolean overwrite )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
Transformation tr = (Transformation)loadDefinition( did.longValue());
boolean found = false;
for (Iterator i=tr.iterateDeclare(); i.hasNext();) {
String arg = ((Declare)i.next()).getName();
if (arg.equals(formalname)) {
found = true;
break;
}
}
if ( !found ) throw new SQLException( "Invalid argument " + formalname + " for TR " + fqdi );
// obtain possible existing anno_farg id
long id = getAnnotationIdDeclare( did.longValue(), formalname, annotation.getKey() );
// insert into anno_dv with new id, if id does not exist
if ( id == -1 ) {
// obtain new id
id = m_dbdriver.sequence1( "anno_id_seq" );
Logging.instance().log("xaction", 1, "START save anno_targ" );
PreparedStatement ps =
m_dbdriver.getPreparedStatement( "stmt.save.anno_targ" );
int i = 1;
longOrNull( ps, i++, id );
if ( m_dbdriver.preferString() ) ps.setString( i++, did.toString() );
else ps.setLong( i++, did.longValue() );
ps.setString( i++, makeNotNull( formalname ) );
ps.setString( i++, makeNotNull( annotation.getKey() ) );
// save prepared values
Logging.instance().log( "chunk", 2, "INSERT INTO anno_targ" );
try {
int rc = ps.executeUpdate();
if ( id==-1 ) id = m_dbdriver.sequence2( ps, "anno_id_seq", 1 );
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "While inserting into anno_targ: " +
e.toString().trim() );
// rollback in saveInvocation()
m_dbdriver.cancelPreparedStatement( "stmt.save.anno_targ" );
throw e; // re-throw
}
Logging.instance().log("xaction", 1, "FINAL save anno_targ: ID=" + id );
} else {
// id does exist, nothing to do in anno_targ
}
// delete before insert if overwrite mode
if ( overwrite ) deleteAnnotationValue( id, annotation );
return ( saveAnnotationValue( id, annotation ) ? id : -1 );
}
/**
* Annotates a transformation call with a tuple.
*
* @param fqdi is the FQDI to annotate
* @param index is the number of the call to annotate.
* @param annotation is the value to place
* @param overwrite is a predicate on replace or maintain.
* @return the insertion id, or -1, if the database was untouched
* @see org.griphyn.vdl.classes.Call
*/
public long saveAnnotationCall( String fqdi,
int index,
Tuple annotation,
boolean overwrite )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
Transformation tr = (Transformation)loadDefinition( did.longValue());
if (index <=0 || tr.getCallCount() < index)
throw new SQLException( "Invalid position " + index + " for TR " + fqdi );
// obtain possible existing anno_call id
long id = getAnnotationIdCall( did.longValue(), index, annotation.getKey() );
// insert into anno_dv with new id, if id does not exist
if ( id == -1 ) {
// obtain new id
id = m_dbdriver.sequence1( "anno_id_seq" );
Logging.instance().log("xaction", 1, "START save anno_call" );
PreparedStatement ps =
m_dbdriver.getPreparedStatement( "stmt.save.anno_call" );
int i = 1;
longOrNull( ps, i++, id );
if ( m_dbdriver.preferString() ) {
ps.setString( i++, did.toString() );
ps.setString( i++, Integer.toString(index) );
} else {
ps.setLong( i++, did.longValue() );
ps.setInt( i++, index );
}
ps.setString( i++, makeNotNull( annotation.getKey() ) );
// save prepared values
Logging.instance().log( "chunk", 2, "INSERT INTO anno_call" );
try {
int rc = ps.executeUpdate();
if ( id==-1 ) id = m_dbdriver.sequence2( ps, "anno_id_seq", 1 );
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "While inserting into anno_call: " +
e.toString().trim() );
// rollback in saveInvocation()
m_dbdriver.cancelPreparedStatement( "stmt.save.anno_call" );
throw e; // re-throw
}
Logging.instance().log("xaction", 1, "FINAL save anno_targ: ID=" + id );
} else {
// id does exist, nothing to do in anno_targ
}
// delete before insert if overwrite mode
if ( overwrite ) deleteAnnotationValue( id, annotation );
return ( saveAnnotationValue( id, annotation ) ? id : -1 );
}
/**
* Annotates a logical filename with a tuple.
*
* @param filename is the FQDI to annotate
* @param annotation is the value to place
* @param overwrite is a predicate on replace or maintain.
* @return the insertion id, or -1, if the database was untouched
* @see org.griphyn.vdl.classes.LFN
*/
public long saveAnnotationFilename( String filename,
Tuple annotation,
boolean overwrite )
throws SQLException, IllegalArgumentException
{
// obtain possible existing anno_lfn id
long id = getAnnotationIdFilename( filename, annotation.getKey() );
// insert into anno_dv with new id, if id does not exist
if ( id == -1 ) {
// obtain new id
id = m_dbdriver.sequence1( "anno_id_seq" );
Logging.instance().log("xaction", 1, "START save anno_lfn" );
PreparedStatement ps =
m_dbdriver.getPreparedStatement( "stmt.save.anno_lfn" );
int i = 1;
longOrNull( ps, i++, id );
ps.setString( i++, makeNotNull( filename ) );
ps.setString( i++, makeNotNull( annotation.getKey() ) );
// save prepared values
Logging.instance().log( "chunk", 2, "INSERT INTO anno_lfn" );
try {
int rc = ps.executeUpdate();
if ( id==-1 ) id = m_dbdriver.sequence2( ps, "anno_id_seq", 1 );
} catch ( SQLException e ) {
Logging.instance().log( "app", 0, "While inserting into anno_lfn: " +
e.toString().trim() );
// rollback in saveInvocation()
m_dbdriver.cancelPreparedStatement( "stmt.save.anno_lfn" );
throw e; // re-throw
}
Logging.instance().log("xaction", 1, "FINAL save anno_lfn: ID=" + id );
} else {
// id does exist, nothing to do in anno_targ
}
// delete before insert if overwrite mode
if ( overwrite ) deleteAnnotationValue( id, annotation );
return (saveAnnotationValue( id, annotation ) ? id : -1 );
}
/**
* Annotates any of the annotatable classes with the specified tuple.
* This is an interface method to the various class-specific methods.
*
* @param primary is the primary object specifier for the class.
* According to the type, this is either the FQDI, or the filename.
* @param secondary is a helper argument for annotations to calls
* and formal arguments, and should be null for all other classes.
* For calls, the argument must be packed into {@link java.lang.Integer}.
* @param kind defines the kind/class of object to annotate.
* @param annotation is the value to place into the class.
* @param overwrite is a predicate on replace or maintain.
* @return the insertion id, or -1, if the database was untouched
* @see #saveAnnotationTransformation( String, Tuple, boolean )
* @see #saveAnnotationDerivation( String, Tuple, boolean )
* @see #saveAnnotationCall( String, int, Tuple, boolean )
* @see #saveAnnotationDeclare( String, String, Tuple, boolean )
* @see #saveAnnotationFilename( String, Tuple, boolean )
*/
public long saveAnnotation( String primary, Object secondary,
int kind, Tuple annotation, boolean overwrite )
throws SQLException, IllegalArgumentException
{
long result = -1;
switch ( kind ) {
case CLASS_TRANSFORMATION:
result = saveAnnotationTransformation( primary, annotation, overwrite );
break;
case CLASS_DERIVATION:
result = saveAnnotationDerivation( primary, annotation, overwrite );
break;
case CLASS_CALL:
// may throw ClassCastException
result = saveAnnotationCall( primary, ((Integer) secondary).intValue(),
annotation, overwrite );
break;
case CLASS_DECLARE:
// may throw ClassCastException
result = saveAnnotationDeclare( primary, ((String) secondary),
annotation, overwrite );
break;
case CLASS_FILENAME:
result = saveAnnotationFilename( primary, annotation, overwrite );
break;
default:
throw new IllegalArgumentException( "The class kind=" + kind + " cannot be annotated" );
}
if (result != -1)
if ( ! m_deferDeleteCommit )
m_dbdriver.commit();
return result;
}
/**
* Obtains the value at a specific id from the boolean annotations.
*
* @param id is the annotation id
* @param key is used to create the tuple
* @return null if not found, or a valid tuple otherwise.
*/
private TupleBoolean loadAnnotationBoolean( long id, String key )
throws SQLException
{
TupleBoolean result = null;
Logging.instance().log("xaction", 1, "START select anno_bool" );
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_bool" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "SELECT value FROM anno_bool" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) {
boolean value = rs.getBoolean(1);
result = new TupleBoolean( key, value );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_bool" );
return result;
}
/**
* Obtains the value at a specific id from the integer annotations.
*
* @param id is the annotation id
* @param key is used to create the tuple
* @return null if not found, or a valid tuple otherwise.
*/
private TupleInteger loadAnnotationInteger( long id, String key )
throws SQLException
{
TupleInteger result = null;
Logging.instance().log("xaction", 1, "START select anno_int" );
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_int" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "SELECT value FROM anno_int" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) {
long value = rs.getLong(1);
result = new TupleInteger( key, value );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_int" );
return result;
}
/**
* Obtains the value at a specific id from the float annotations.
*
* @param id is the annotation id
* @param key is used to create the tuple
* @return null if not found, or a valid tuple otherwise.
*/
private TupleFloat loadAnnotationFloat( long id, String key )
throws SQLException
{
TupleFloat result = null;
Logging.instance().log("xaction", 1, "START select anno_float" );
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_float" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "SELECT value FROM anno_float" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) {
double value = rs.getDouble(1);
result = new TupleFloat( key, value );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_float" );
return result;
}
/**
* Obtains the value at a specific id from the date annotations.
*
* @param id is the annotation id
* @param key is used to create the tuple
* @return null if not found, or a valid tuple otherwise.
*/
private TupleDate loadAnnotationDate( long id, String key )
throws SQLException
{
TupleDate result = null;
Logging.instance().log("xaction", 1, "START select anno_date" );
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_date" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "SELECT value FROM anno_date" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) {
java.sql.Timestamp value = rs.getTimestamp(1);
result = new TupleDate( key, value );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_date" );
return result;
}
/**
* Obtains the value at a specific id from the string annotations.
*
* @param id is the annotation id
* @param key is used to create the tuple
* @return null if not found, or a valid tuple otherwise.
*/
private TupleString loadAnnotationString( long id, String key )
throws SQLException
{
TupleString result = null;
Logging.instance().log("xaction", 1, "START select anno_text" );
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_text" );
if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(id) );
else ps.setLong( 1, id );
Logging.instance().log( "chunk", 2, "SELECT value FROM anno_text" );
ResultSet rs = ps.executeQuery();
if ( rs.next() ) {
Reader r = rs.getCharacterStream(1);
StringBuffer temp = new StringBuffer(128);
try {
int ch;
while ( (ch = r.read()) >= 0 ) temp.append( (char) ch);
} catch ( IOException ioe ) {
throw new SQLException(ioe.getMessage());
}
result = new TupleString( key, temp.toString() );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_text" );
return result;
}
/**
* Tries to retrieve a tuple value from its annotation id by
* walking over all tables, most likely one first. This is an
* internal function helping to keep common code common.
*
* @param id is the annotation id to search for
* @param key is the key for tuple creation.
* @return null, if the id was -1 (no such id), or if nothing
* was found.
*/
private Tuple loadAnnotationFinal( long id, String key )
throws SQLException
{
Tuple result = null;
if ( id != -1 ) {
// order by likelyhood
result = loadAnnotationString( id, key );
if ( result == null ) result = loadAnnotationInteger( id, key );
if ( result == null ) result = loadAnnotationFloat( id, key );
if ( result == null ) result = loadAnnotationDate( id, key );
if ( result == null ) result = loadAnnotationBoolean( id, key );
}
return result;
}
/**
* Obtains the value to a specific key in an annotated transformation.
*
* @param fqdi is the FQDI of the transformation
* @param key is the key to search for
* @return the annotated value, or null if not found.
* @see org.griphyn.vdl.classes.Transformation
*/
public Tuple loadAnnotationTransformation( String fqdi, String key )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain possible existing anno_tr id
long id = getAnnotationIdTransformation( did.longValue(), key );
// no such key, if the id is -1, handled by finalizer
return loadAnnotationFinal( id, key );
}
/**
* Obtains the value to a specific key in an annotated derivation.
*
* @param fqdi is the FQDI of the derivation
* @param key is the key to search for
* @return the annotated value, or null if not found.
* @see org.griphyn.vdl.classes.Derivation
*/
public Tuple loadAnnotationDerivation( String fqdi, String key )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.DERIVATION );
if ( did == null ) throw new SQLException( "Unknown DV " + fqdi );
// obtain possible existing anno_dv id
long id = getAnnotationIdDerivation( did.longValue(), key );
// no such key, if the id does not exist
return loadAnnotationFinal( id, key );
}
/**
* Obtains the value to a specific key in an annotated formal argument.
*
* @param fqdi is the FQDI of the transformation
* @param farg is the name of the formal argument
* @param key is the key to search for
* @return the annotated value, or null if not found
* @see org.griphyn.vdl.classes.Declare
*/
public Tuple loadAnnotationDeclare( String fqdi, String farg,
String key )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain possible existing anno_call id
long id = getAnnotationIdDeclare( did.longValue(), farg, key );
// no such key, if the id does not exist
return loadAnnotationFinal( id, key );
}
/**
* Obtains the value to a specific key for a call statement.
*
* @param fqdi is the FQDI of the transformation
* @param index is the number of the call to annotate.
* @param key is the key to search for
* @return the annotated value, or null if not found
* @see org.griphyn.vdl.classes.Call
*/
public Tuple loadAnnotationCall( String fqdi, int index,
String key )
throws SQLException, IllegalArgumentException
{
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain possible existing anno_call id
long id = getAnnotationIdCall( did.longValue(), index, key );
// no such key, if the id does not exist
return loadAnnotationFinal( id, key );
}
/**
* Obtains the value to a specific key in an annotated filename.
*
* @param filename is the name of the file that was annotated.
* @param key is the key to search for
* @return the annotated value, or null if not found.
* @see org.griphyn.vdl.classes.LFN
*/
public Tuple loadAnnotationFilename( String filename, String key )
throws SQLException, IllegalArgumentException
{
// obtain possible existing anno_lfn id
long id = getAnnotationIdFilename( filename, key );
// no such key, if the id does not exist
return loadAnnotationFinal( id, key );
}
/**
* Retrieves a specific annotation from an annotatable classes with
* the specified tuple. This is an interface method to the various
* class-specific methods.
*
* @param primary is the primary object specifier for the class.
* According to the type, this is either the FQDI, or the filename.
* @param secondary is a helper argument for annotations to calls
* and formal arguments, and should be null for all other classes.
* For calls, the argument must be packed into {@link java.lang.Integer}.
* @param kind defines the kind/class of object to annotate.
* @param key is the key to look for.
* @return null if not found, otherwise the annotation tuple.
* @see #loadAnnotationTransformation( String, String )
* @see #loadAnnotationDerivation( String, String )
* @see #loadAnnotationCall( String, int, String )
* @see #loadAnnotationDeclare( String, String, String )
* @see #loadAnnotationFilename( String, String )
*/
public Tuple loadAnnotation( String primary, Object secondary,
int kind, String key )
throws SQLException, IllegalArgumentException
{
Tuple result = null;
switch ( kind ) {
case CLASS_TRANSFORMATION:
result = loadAnnotationTransformation( primary, key );
break;
case CLASS_DERIVATION:
result = loadAnnotationDerivation( primary, key );
break;
case CLASS_CALL:
// may throw ClassCastException
result = loadAnnotationCall( primary, ((Integer) secondary).intValue(), key );
break;
case CLASS_DECLARE:
// may throw ClassCastException
result = loadAnnotationDeclare( primary, ((String) secondary), key );
break;
case CLASS_FILENAME:
result = loadAnnotationFilename( primary, key );
break;
default:
throw new IllegalArgumentException( "The class kind=" + kind + " cannot be annotated" );
}
return result;
}
/**
* Lists all annotations for a transformation.
*
* @param fqdi is the FQDI of the transformation
* @return a list of tuples, which may be empty.
* @see org.griphyn.vdl.classes.Transformation
*/
public java.util.List loadAnnotationTransformation( String fqdi )
throws SQLException, IllegalArgumentException
{
java.util.List result = new java.util.ArrayList();
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain all anno_tr ids
Logging.instance().log("xaction", 1, "START select anno_tr2" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_tr2" );
if ( m_dbdriver.preferString() ) ps.setString( i++, did.toString() );
else ps.setLong( i++, did.longValue() );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_tr" );
ResultSet rs = ps.executeQuery();
while ( rs.next() ) {
Tuple temp = loadAnnotationFinal( rs.getLong(1), rs.getString(2) );
if ( temp != null ) result.add(temp);
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_tr2" );
return result;
}
/**
* Lists all annotations for a derivation.
*
* @param fqdi is the FQDI of the derivation
* @return a list of tuples, which may be empty.
* @see org.griphyn.vdl.classes.Derivation
*/
public java.util.List loadAnnotationDerivation( String fqdi )
throws SQLException, IllegalArgumentException
{
java.util.List result = new java.util.ArrayList();
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.DERIVATION );
if ( did == null ) throw new SQLException( "Unknown DV " + fqdi );
// obtain all anno_tr ids
Logging.instance().log("xaction", 1, "START select anno_dv2" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_dv2" );
if ( m_dbdriver.preferString() ) ps.setString( i++, did.toString() );
else ps.setLong( i++, did.longValue() );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_dv" );
ResultSet rs = ps.executeQuery();
while ( rs.next() ) {
Tuple temp = loadAnnotationFinal( rs.getLong(1), rs.getString(2) );
if ( temp != null ) result.add(temp);
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_dv2" );
return result;
}
/**
* Lists all annotations for a formal argument.
*
* @param fqdi is the FQDI of the transformation
* @param farg is the name of the formal argument
* @return a list of tuples, which may be empty.
* @see org.griphyn.vdl.classes.Declare
*/
public java.util.List loadAnnotationDeclare( String fqdi, String farg )
throws SQLException, IllegalArgumentException
{
java.util.List result = new java.util.ArrayList();
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain all anno_tr ids
Logging.instance().log("xaction", 1, "START select anno_targ2" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_targ2" );
if ( m_dbdriver.preferString() ) ps.setString( i++, did.toString() );
else ps.setLong( i++, did.longValue() );
ps.setString( i++, farg );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_targ" );
ResultSet rs = ps.executeQuery();
while ( rs.next() ) {
Tuple temp = loadAnnotationFinal( rs.getLong(1), rs.getString(2) );
if ( temp != null ) result.add(temp);
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_targ2" );
return result;
}
/**
* Lists all annotations for a call statement.
*
* @param fqdi is the FQDI of the transformation
* @param index is the number of the call to annotate.
* @return a list of tuples, which may be empty.
* @see org.griphyn.vdl.classes.Call
*/
public java.util.List loadAnnotationCall( String fqdi, int index )
throws SQLException, IllegalArgumentException
{
java.util.List result = new java.util.ArrayList();
// split FQDI
String[] names = Separator.split(fqdi); // may throw IAE
// obtain DID for FQDI
Long did = getSpecificDefinitionId( names[0], names[1], names[2],
Definition.TRANSFORMATION );
if ( did == null ) throw new SQLException( "Unknown TR " + fqdi );
// obtain all anno_tr ids
Logging.instance().log("xaction", 1, "START select anno_call2" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_call2" );
if ( m_dbdriver.preferString() ) {
ps.setString( i++, did.toString() );
ps.setString( i++, Integer.toString(index) );
} else {
ps.setLong( i++, did.longValue() );
ps.setInt( i++, index );
}
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_call" );
ResultSet rs = ps.executeQuery();
while ( rs.next() ) {
Tuple temp = loadAnnotationFinal( rs.getLong(1), rs.getString(2) );
if ( temp != null ) result.add(temp);
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_call2" );
return result;
}
/**
* Lists all annotations for a logical filename.
*
* @param filename is the logical filename.
* @return a list of tuples, which may be empty.
* @see org.griphyn.vdl.classes.LFN
*/
public java.util.List loadAnnotationFilename( String filename )
throws SQLException, IllegalArgumentException
{
java.util.List result = new java.util.ArrayList();
// obtain all anno_tr ids
Logging.instance().log("xaction", 1, "START select anno_lfn2" );
int i = 1;
PreparedStatement ps = m_dbdriver.getPreparedStatement( "stmt.select.anno_lfn2" );
ps.setString( i++, filename );
Logging.instance().log( "chunk", 2, "SELECT id FROM anno_lfn" );
ResultSet rs = ps.executeQuery();
while ( rs.next() ) {
Tuple temp = loadAnnotationFinal( rs.getLong(1), rs.getString(2) );
if ( temp != null ) result.add(temp);
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select anno_lfn2" );
return result;
}
/**
* Retrieves all annotations from an annotatable classes with
* the specified tuple. This is an interface method to the various
* class-specific methods.
*
* @param primary is the primary object specifier for the class.
* According to the type, this is either the FQDI, or the filename.
* @param secondary is a helper argument for annotations to calls
* and formal arguments, and should be null for all other classes.
* For calls, the argument must be packed into {@link java.lang.Integer}.
* @param kind defines the kind/class of object to annotate.
*
* @return null if not found, otherwise the annotation tuple.
* @see #loadAnnotationTransformation( String )
* @see #loadAnnotationDerivation( String )
* @see #loadAnnotationCall( String, int )
* @see #loadAnnotationDeclare( String, String )
* @see #loadAnnotationFilename( String )
*/
public java.util.List loadAnnotation( String primary,
Object secondary,
int kind )
throws SQLException, IllegalArgumentException
{
switch ( kind ) {
case CLASS_TRANSFORMATION:
return loadAnnotationTransformation( primary );
case CLASS_DERIVATION:
return loadAnnotationDerivation( primary );
case CLASS_CALL:
// may throw ClassCastException
return loadAnnotationCall( primary, ((Integer) secondary).intValue() );
case CLASS_DECLARE:
// may throw ClassCastException
return loadAnnotationDeclare( primary, ((String) secondary) );
case CLASS_FILENAME:
return loadAnnotationFilename( primary );
default:
throw new IllegalArgumentException( "The class kind=" + kind + " cannot be annotated" );
}
}
/**
* Search for LFNs or Definitions that has certain annotations
*
* @param kind defines the kind/class of object annotated.
* @param arg is used only for TR ARG and TR CALL. For the former
* it is the name of the argument (String), for the latter the position of
* the call (Integer).
* @param tree stores the query tree to query the annotation
* @return a list of LFNs if search for filenames, otherwise a list of
* definitions.
* @exception SQLException if something goes wrong with the database.
* @see org.griphyn.vdl.annotation.QueryTree
*/
public java.util.List searchAnnotation( int kind,
Object arg,
QueryTree tree)
throws SQLException
{
java.util.List result = new java.util.ArrayList();
if ( tree == null)
return result;
String sql = tree.toSQL(kind, arg);
if (sql == null || sql.equals(""))
return result;
// obtain all anno_tr ids
Logging.instance().log("xaction", 1, "START search annotation" );
// use backdoor, why don't we change this into some nicer name???
ResultSet rs = backdoor(sql);
while ( rs.next() ) {
if (kind == Annotation.CLASS_FILENAME) {
String fn = rs.getString(1);
result.add(fn);
} else {
Definition d = loadDefinition( rs.getLong(1) ) ;
if ( d != null ) result.add(d);
}
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL search annotation" );
return result;
}
/**
* A not very generic method to search annotation (and anything) in
* the database. Selects any rows in one or more colums from one or
* more tables restricted by some condition, possibly ordered.<p>
*
* WARNING: This is a method for internal use only.
*
* @param select is the ordered set of column names to select, or
* simply a one-value list with an asterisk.
* @param table is the name of the table to select from.
* @param where is a collection of column names and values they must equal.
* @param order is an optional ordering string.
* @return something to search for results in.
* @exception SQLException if something goes wrong with the database.
* @see org.griphyn.vdl.dbdriver.DatabaseDriver#select( java.util.List, String, java.util.Map, String )
*/
public ResultSet searchAnnotation( java.util.List select,
String table,
java.util.Map where,
String order )
throws SQLException
{
return m_dbdriver.select( select, table, where, order );
}
/**
* Delete one or more definitions from the backend database. The key
* triple parameters may be wildcards. Wildcards are expressed as
* <code>null</code> value, or have special characters '%' and '_'.
*
* @param namespace namespace
* @param name name
* @param version version
* @param type definition type (TR or DV)
* @return a list of definitions that were deleted.
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
*/
public java.util.List
deleteDefinitionEx( String namespace,
String name,
String version,
int type )
throws SQLException
{
java.util.List result = new ArrayList();
Logging.instance().log("xaction", 1, "START delete definitions" );
java.util.List idlist = getDefinitionIdEx( namespace, name, version, type );
if ( idlist.size() == 0 ) return result;
// postcondition: contains all IDs, count(id)>0, to be deleted
// save old values
if ( ! m_deferDeleteCommit ) {
// we come from saveDefinition, thus we won't need saved values
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
Definition d = loadDefinition( ((Long) i.next()).longValue() );
if ( d != null ) result.add(d);
}
}
// remove all affected annoations by walking through them
// yuk, this is probably extremely expensive
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
long id = ((Long) i.next()).longValue();
deleteAnnotationFromDefinition(id);
}
// list of all statements we need to access
PreparedStatement ps[] = {
this.m_dbdriver.getPreparedStatement("stmt.delete.lfn_i"),
this.m_dbdriver.getPreparedStatement("stmt.delete.lfn_o"),
this.m_dbdriver.getPreparedStatement("stmt.delete.lfn_b"),
this.m_dbdriver.getPreparedStatement("stmt.delete.xml")
};
// prepare and batch all statements
boolean preferString = m_dbdriver.preferString();
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
long id = ((Long) i.next()).longValue();
for ( int j=0; j<ps.length; ++j ) {
if ( preferString ) ps[j].setString( 1, Long.toString(id) );
else ps[j].setLong( 1, id );
ps[j].addBatch();
}
}
// run all batches
Logging.instance().log("xaction", 1, "INTER delete definitions" );
for ( int j=0; j<ps.length; ++j ) {
int[] status = new int[ idlist.size() ];
try {
status = ps[j].executeBatch();
} catch ( NullPointerException npe ) {
Logging.instance().log( "app", 1, "tripped over NPE, ignoring!" );
}
}
Logging.instance().log("xaction", 1, "FINAL delete definitions" );
if ( ! m_deferDeleteCommit ) m_dbdriver.commit();
return result;
}
/**
* Search the database for definitions by ns::name:version triple
* and by type (either Transformation or Derivation). This version
* of the search allows for jokers expressed as null value
*
* @param namespace namespace, null to match any namespace
* @param name name, null to match any name
* @param version version, null to match any version
* @param type type of definition, see below, or -1 as wildcard
* @return a list of Definition items, which may be empty
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
* @see #loadDefinition( String, String, String, int )
*/
public java.util.List
searchDefinitionEx( String namespace,
String name,
String version,
int type )
throws SQLException
{
java.util.List idlist = getDefinitionIdEx( namespace, name, version, type );
// TODO: make this a batch or sproc
java.util.List result = new ArrayList();
for ( Iterator i=idlist.iterator(); i.hasNext(); ) {
Definition d = loadDefinition( ((Long) i.next()).longValue() );
if ( d != null ) result.add(d);
}
return result;
}
/**
* Searches the database for all LFNs that match a certain pattern.
* The linkage is an additional constraint. This method allows
* joker characters such as '%' and '_'.
*
* @param lfn the LFN name
* @param link the linkage type of the LFN
* @return a list of filenames that match the criterion.
*
* @see org.griphyn.vdl.classes.LFN#NONE
* @see org.griphyn.vdl.classes.LFN#INPUT
* @see org.griphyn.vdl.classes.LFN#OUTPUT
* @see org.griphyn.vdl.classes.LFN#INOUT
*/
public java.util.List
searchLFN( String lfn,
int link )
throws SQLException
{
if ( lfn == null )
throw new NullPointerException("You must query for a filename");
Logging.instance().log("xaction", 1, "START select LFNs" );
PreparedStatement ps = null;
if ( link == -1 ) {
// wildcard match
ps = this.m_dbdriver.getPreparedStatement( "stmt.select.lfn_*.name.ex" );
for ( int ii=0; ii<c_lfn_names.length; ++ii ) ps.setString( ii+1, lfn );
Logging.instance().log( "chunk", 2, "SELECT distinct name FROM lfn_*" +
" WHERE name LIKE '" + lfn + "'" );
} else if ( LFN.isInRange(link) ) {
// known linkage, one table only
// ordering MUST MATCH classes.LFN constants!
switch ( link ) {
case LFN.NONE:
throw new RuntimeException( "The linkage \"none\" is not permitted" );
// break;
case LFN.INPUT:
ps = this.m_dbdriver.getPreparedStatement("stmt.select.lfn_i.name.ex");
break;
case LFN.OUTPUT:
ps = this.m_dbdriver.getPreparedStatement("stmt.select.lfn_o.name.ex");
break;
case LFN.INOUT:
ps = this.m_dbdriver.getPreparedStatement("stmt.select.lfn_b.name.ex");
break;
};
ps.setString( 1, lfn );
Logging.instance().log( "chunk", 2, "SELECT distinct name FROM " +
c_lfn_names[link-1] + " WHERE name LIKE '" + lfn + "'" );
} else {
throw new RuntimeException( "The linkage " + link + " is not permitted" );
}
ResultSet rs = ps.executeQuery();
// TODO: make this a batch or sproc
java.util.List result = new ArrayList();
while ( rs.next() ) {
result.add( rs.getString("name") );
}
rs.close();
Logging.instance().log("xaction", 1, "FINAL select LFNs" );
return result;
}
/**
* Searches the database for a list of namespaces of the definitions
* Sorted in ascending order.
*
* @param type type of definition, see below, or -1 for both
* @return a list of namespaces
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
*/
public java.util.List
getNamespaceList( int type )
throws SQLException
{
java.util.List result = new ArrayList();
Logging.instance().log("xaction", 1, "START select namespaces from DEFINITION" );
java.util.List select = new ArrayList(1);
select.add( new String("distinct namespace") );
java.util.Map where = new TreeMap();
if ( type != -1 ) where.put( "type", Integer.toString(type) );
String order = " ORDER BY namespace";
Logging.instance().log("xaction", 1, "START select namespaces" );
ResultSet rs = m_dbdriver.select( select, "anno_definition", where, order);
while ( rs.next() )
result.add( new String( rs.getString("namespace") ) );
rs.close();
Logging.instance().log("xaction", 1, "FINAL select namespaces from DEFINITION" );
return result;
}
/**
* Searches the database for a list of fully-qualified names of
* the definitions sorted in ascending order.
*
* @param type type of definition, see below, or -1 for both
* @return a list of FQDNs
*
* @see org.griphyn.vdl.classes.Definition#TRANSFORMATION
* @see org.griphyn.vdl.classes.Definition#DERIVATION
*/
public java.util.List
getFQDNList( int type )
throws SQLException
{
java.util.List result = new ArrayList();
Logging.instance().log("xaction", 1, "START select triplets from DEFINITION" );
java.util.List select = new ArrayList(1);
select.add( new String("namespace, name, version") );
java.util.Map where = new TreeMap();
if ( type != -1 ) where.put( "type", Integer.toString(type) );
String order = " ORDER BY namespace, name, version";
Logging.instance().log("xaction", 1, "START select triplets" );
ResultSet rs = m_dbdriver.select( select, "anno_definition", where, order);
while ( rs.next() )
result.add( new String( Separator.combine( rs.getString("namespace"),
rs.getString("name"),
rs.getString("version"))) );
rs.close();
Logging.instance().log("xaction", 1, "FINAL select triplets from DEFINITION" );
return result;
}
/**
* A too generic method to search annotation (and anything) in
* the database. This method is also responsible for breaking
* any no-database-based backends.<p>
*
* WARNING: This is a method for internal use only.
*
* @param query is an SQL query statement.
* @return something to search for results in.
* @exception SQLException if something goes wrong with the database.
*/
public ResultSet backdoor( String query )
throws SQLException
{
return m_dbdriver.backdoor( query );
}
}