/*
* 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.toolkit;
import java.io.*;
import java.util.*;
import gnu.getopt.*;
import org.griphyn.vdl.util.Logging;
import org.griphyn.vdl.util.ChimeraProperties;
import org.griphyn.vdl.dbschema.*;
import org.griphyn.vdl.directive.*;
import org.griphyn.vdl.annotation.*;
import edu.isi.pegasus.common.util.Separator;
import edu.isi.pegasus.common.util.Version;
/**
* This class inserts annotations into the backend database.
*
* @author Jens-S. Vöckler
* @author Yong Zhao
* @version $Revision$
*
*/
public class InsertMeta extends Toolkit
{
/**
* Constructor
*/
public InsertMeta(String appName)
{
super(appName);
}
/**
* Prints the usage string.
*/
public void showUsage()
{
String linefeed = System.getProperty( "line.separator", "\r\n" );
System.out.println(
"$Id$" + linefeed +
"VDS version " + Version.instance().toString() + linefeed );
System.out.println(
"Usage: " + this.m_application + " [general] [-n ns] [-i id] [-v vs] [-a arg] [mdf]" + linefeed +
"Or : " + this.m_application + " [general] [-f lfn] [metadata_file]" );
System.out.println( linefeed +
"General options: " + linefeed +
" -V|--version print version information and exit." + linefeed +
" -d|--dbase db associates the dbname with the database, unused." + linefeed +
" --verbose increases the verbosity level." + linefeed +
" -t|--type tr|dv limits candidates to either TR or DV, default is both." + linefeed +
linefeed +
"Option group 1: Arguments dealing with VDL definitions " + linefeed +
" -n|--vdlns ns limits candidates to definition namespace matches." + linefeed +
" -i|--vdlid id limits candidates to definition name matches." + linefeed +
" -v|--vdlvs vs limits candidates to definition version matches." + linefeed +
" -a|--arg arg limits to formal arguments, requires -t tr." + linefeed +
linefeed +
"Option group 2: Arguments dealing with VDL logical filenames" + linefeed +
" -f|--file lfn limits candidates to logical filename matches." + linefeed +
linefeed +
"Option groups 1 and 2 are mutually exclusive. The metadata file is a texual" + linefeed +
"file with at least three columns, the key, the type and the value(s)." + linefeed );
}
/**
* Creates a set of options.
* @return the assembled long option list
*/
protected LongOpt[] generateValidOptions()
{
LongOpt[] lo = new LongOpt[17];
lo[0] = new LongOpt( "dbase", LongOpt.REQUIRED_ARGUMENT, null, 'd' );
lo[1] = new LongOpt( "version", LongOpt.NO_ARGUMENT, null, 'V' );
lo[2] = new LongOpt( "help", LongOpt.NO_ARGUMENT, null, 'h' );
lo[3] = new LongOpt( "verbose", LongOpt.NO_ARGUMENT, null, 1 );
lo[4] = new LongOpt( "vdlns", LongOpt.REQUIRED_ARGUMENT, null, 'n' );
lo[5] = new LongOpt( "namespace", LongOpt.REQUIRED_ARGUMENT, null, 'n' );
lo[6] = new LongOpt( "ns", LongOpt.REQUIRED_ARGUMENT, null, 'n' );
lo[7] = new LongOpt( "vdlid", LongOpt.REQUIRED_ARGUMENT, null, 'i' );
lo[8] = new LongOpt( "name", LongOpt.REQUIRED_ARGUMENT, null, 'i' );
lo[9] = new LongOpt( "identifier", LongOpt.REQUIRED_ARGUMENT, null, 'i' );
lo[10] = new LongOpt( "id", LongOpt.REQUIRED_ARGUMENT, null, 'i' );
lo[11] = new LongOpt( "vdlvs", LongOpt.REQUIRED_ARGUMENT, null, 'v' );
lo[12] = new LongOpt( "vs", LongOpt.REQUIRED_ARGUMENT, null, 'v' );
lo[13] = new LongOpt( "arg", LongOpt.REQUIRED_ARGUMENT, null, 'a' );
lo[14] = new LongOpt( "args", LongOpt.REQUIRED_ARGUMENT, null, 'a' );
lo[15] = new LongOpt( "type", LongOpt.REQUIRED_ARGUMENT, null, 't' );
lo[16] = new LongOpt( "file", LongOpt.REQUIRED_ARGUMENT, null, 'f' );
return lo;
}
/**
* Inserts metadata for TR, DV, LFN.
*/
public static void main(String[] args)
{
int result = 0;
try {
InsertMeta me = new InsertMeta("insertmeta");
// no arguments -- yikes
if ( args.length == 0 ) {
me.showUsage();
return ;
}
// obtain commandline options first -- we may need the database stuff
Getopt opts = new Getopt( me.m_application, args,
"hd:t:n:i:v:a:f:V",
me.generateValidOptions() );
opts.setOpterr(false);
String secondary = null;
String primary = new String();
String type = null;
String vdlns = null;
String vdlid = null;
String vdlvs = null;
String lfn = null;
String arg = null;
int option = 0;
while ( (option = opts.getopt()) != -1 ) {
switch ( option ) {
case 1:
me.increaseVerbosity();
break;
case 'V':
System.out.println( "$Id$" );
System.out.println( "VDS version " + Version.instance().toString() );
return;
case 'a':
arg = opts.getOptarg();
break;
case 'd':
// currently inactive option
opts.getOptarg();
break;
case 'f':
lfn = opts.getOptarg();
break;
case 'i':
vdlid = opts.getOptarg();
break;
case 'n':
vdlns = opts.getOptarg();
break;
case 't':
type = opts.getOptarg();
break;
case 'v':
vdlvs = opts.getOptarg();
break;
case 'h':
default:
me.showUsage();
return;
}
}
boolean condition1 = ( lfn != null );
boolean condition2 = ( vdlns != null || vdlid != null || vdlvs != null );
// (a XOR b) <=> (a AND !b) OR (!a AND b)
// !(a XOR b) <=> (a OR !b) AND (!a OR b)
if ( (condition1 || ! condition2) && (! condition1 || condition2) ) {
me.showUsage();
throw new RuntimeException( "You must either specify the -n -i -v options, or\n" +
"\tuse the -f option!" );
}
int classType = -1;
if ( condition2 ) {
// metadata for TR or DV?
switch ( Character.toUpperCase(type.charAt(0)) ) {
case 'D': // DV
classType = Annotation.CLASS_DERIVATION;
break;
case 'T': // TR
classType = Annotation.CLASS_TRANSFORMATION;
if ( arg != null ) {
classType = Annotation.CLASS_DECLARE;
secondary = arg;
}
break;
default:
me.showUsage();
throw new RuntimeException( "invalid argument \"" + type + "\" for option t" );
}
// will be used for 'D' and 'T' only
primary = Separator.combine( vdlns, vdlid, vdlvs );
} else {
// must be condition1
classType = Annotation.CLASS_FILENAME;
primary = lfn;
}
// postcondition: variable "type" can be recycled now
// Connect the database.
String schemaName = ChimeraProperties.instance().getVDCSchemaName();
Connect connect = new Connect();
DatabaseSchema dbschema = connect.connectDatabase(schemaName);
if (! (dbschema instanceof Annotation)) {
dbschema.close();
throw new RuntimeException( "The database does not support metadata!" );
} else {
Annotation annotation = (Annotation) dbschema;
// open metadata file -- or read from stdin
String mdfile = ( opts.getOptind() < args.length ?
args[opts.getOptind()] : null );
LineNumberReader lnr = null;
if ( mdfile == null || mdfile.equals("-") ) {
System.err.println( "# reminder: reading from stdin" );
lnr = new LineNumberReader( new InputStreamReader(System.in) );
} else {
lnr = new LineNumberReader( new FileReader(mdfile) );
}
// parsing name-value pairs from the file
Logging.instance().log( "app", 1, "parsing name type value tuple");
StringTokenizer st = null;
String token, key, line = null;
while ( (line = lnr.readLine()) != null ) {
Logging.instance().log( "app", 3, lnr.getLineNumber() + ": " + line );
st = new StringTokenizer( line, " ", false );
int column = -1;
key = type = null;
StringBuffer value = new StringBuffer(80);
while ( st.hasMoreTokens() ) {
token = st.nextToken();
column++;
switch ( column ) {
case 0: // key
key = token;
break;
case 1: // type
type = token;
break;
case 2: // value
value.append(token);
break;
default: // addon
value.append(' ').append(token);
break;
}
}
// invalid line
if ( column < 2 ) {
// FIXME: Warn the user here?
continue;
}
// System.out.println("column=" + column );
// System.out.println("key=" + key );
// System.out.println("type=" + type );
// System.out.println("value=" + value );
Tuple tuple = null;
if ( type.equalsIgnoreCase("int") ||
type.equalsIgnoreCase("i") )
tuple = new TupleInteger(key, Long.parseLong(value.toString()));
else if ( type.equalsIgnoreCase("float") ||
type.equalsIgnoreCase("f") )
tuple = new TupleFloat(key, Float.parseFloat(value.toString()));
else if ( type.equalsIgnoreCase("bool") ||
type.equalsIgnoreCase("boolean") ||
type.equalsIgnoreCase("b") )
tuple = new TupleBoolean(key, Boolean.getBoolean(value.toString()));
else if ( type.equalsIgnoreCase("string") ||
type.equalsIgnoreCase("s") )
tuple = (Tuple) new TupleString(key, value.toString());
else if ( type.equalsIgnoreCase("date") ||
type.equalsIgnoreCase("d") )
tuple = (Tuple) new TupleDate(key, 0); // FIXME
else {
// FIXME: What about this case?
System.out.println("ERROR: InsertMeta: invalid type: " + type);
}
if ( tuple != null ) {
System.out.println("Processing (" + tuple.toString() + ")");
annotation.saveAnnotation(primary, secondary, classType, tuple, false);
} else {
// FIXME: What about this case?
System.out.println("ERROR: InsertMeta: Tuple creation failed.");
}
} // while
System.out.println("Metadata loaded successfully!");
}
// done
if ( dbschema != null ) dbschema.close();
} catch ( RuntimeException rte ) {
Logging.instance().log( "default", 0, "runtime error: " + rte.getMessage() );
System.err.println( "ERROR: " + rte.getMessage() );
result = 1;
} catch( Exception e ) {
Logging.instance().log( "default", 0, "FATAL: " + e.getMessage() );
e.printStackTrace();
System.err.println( "FATAL: " + e.getMessage() );
result = 2;
}
if ( result != 0 ) System.exit(result);
}
}