/*
* 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.Iterator;
import java.util.ListIterator;
import java.util.Vector;
import java.util.Enumeration;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
import java.lang.reflect.*;
import java.sql.SQLException;
import edu.isi.pegasus.common.util.DynamicLoader;
import org.griphyn.vdl.util.ChimeraProperties;
import org.griphyn.vdl.util.FileHelper;
import org.griphyn.vdl.util.Logging;
import org.griphyn.vdl.util.LockFileLock;
import org.griphyn.vdl.classes.*;
import org.griphyn.vdl.parser.*;
import org.griphyn.vdl.dbdriver.*;
/**
* This is a class that falls back not on a real database backend, but
* rather on an existing Definitions data structure that are read from
* file during construction (or rather, during open), and pushed back
* into file at destruction (or rather, during close).<p>
* While schemas in general should fall back onto drivers to perform
* actions, it is rather difficult to create a JDBC interface to file
* operations. Thus, the file operations are sneaked into this class.<p>
* This class is thought more for experimental use than production.
*
* @author Jens-S. Vöckler
* @author Yong Zhao
* @version $Revision$
* @see org.griphyn.vdl.dbdriver
* @see org.griphyn.vdl.classes.Definitions
*/
public class SingleFileSchema extends InMemorySchema
{
/**
* Save the name of the database file, so we can dump our memory.
*/
private String m_filename;
/**
* Save the file locking helper, once dynaloaded.
*/
private FileHelper m_filehelper;
/**
* An instance of the VDLx XML parser.
*/
private org.griphyn.vdl.parser.VDLxParser m_parser;
/**
* Fakes a connect to the database. This class load the memory
* database during construction time from the specified file.
*
* @param hyphen_d is the CLI argument being passed, and ignored for now.
*/
public SingleFileSchema( String hyphen_d )
throws ClassNotFoundException,
NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException,
SQLException, IOException
{
super(); // call minimalistic c'tor, no driver loading!
ChimeraProperties props = ChimeraProperties.instance();
// Start a new set of definitions
this.m_memory = new Definitions();
this.m_dbschemaprops =
props.getDatabaseSchemaProperties( PROPERTY_PREFIX );
// 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 = this.m_dbschemaprops.getProperty( "xml.url",
props.getVDLSchemaLocation() );
Logging.instance().log( "dbschema", 3, "schema=" + url );
this.m_parser = new org.griphyn.vdl.parser.VDLxParser(url);
Logging.instance().log( "dbschema", 3, "created reader" );
// obtain the file location from the schema properties
File db = new File( props.getSysConfDir(), "vds.db" );
this.m_filename =
this.m_dbschemaprops.getProperty( "file.store", db.getAbsolutePath() );
Logging.instance().log( "dbschema", 3, "filename=" + m_filename );
// Determine helper to provide locking functions
String locker = m_dbschemaprops.getProperty( "file.lock", "LockFileLock" );
if ( locker.indexOf('.') == -1 ) locker = "org.griphyn.vdl.util." + locker;
// dynamically load the file locking helper implementation
Logging.instance().log( "dbschema", 3, "trying to load " + locker );
DynamicLoader dl = new DynamicLoader(locker);
String arg[] = new String[1];
arg[0] = m_filename;
m_filehelper = (FileHelper) dl.instantiate(arg);
// FileHelper m_filehelper = new FileHelper2(this.m_filename);
File file = m_filehelper.openReader();
if ( file == null ) {
Logging.instance().log( "dbschema", 3, "openReader returned null" );
throw new SQLException( "Can't lock file " + this.m_memory );
}
// Does database exist?
try {
if ( file.exists() ) {
// file exists, read it unless empty
if ( file.length() > 0 ) {
// parse the complete file (database)
this.m_parser.parse(
new org.xml.sax.InputSource(
new BufferedReader(
new FileReader(file))),
new NoHassleHandler(this.m_memory) );
Logging.instance().log( "app", 1, this.m_memory.getDefinitionCount() +
" definitions loaded into main memory" );
}
}
} catch ( Exception e ) {
throw new SQLException( e.getMessage() );
} finally {
// always release locks
try { m_filehelper.closeReader(file); }
catch ( Exception e ) { throw new SQLException( e.getMessage() ); }
}
}
/**
* Disassociate from the database driver before finishing. In this
* case, dump the memory database back to the file that was saved.
* Mind that performing this action may throw NullPointerException
* in later stages!
*/
public void close()
throws SQLException
{
super.close();
// FileHelper m_filehelper = new FileHelper2(this.m_filename);
File file = m_filehelper.openWriter();
if (file == null) {
throw new SQLException("Unable to create file writer!");
}
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
this.m_memory.toXML(bw, "");
bw.flush();
bw.close();
} catch ( IOException e ) {
throw new SQLException( e.getMessage() );
} finally {
// always release locks
try { m_filehelper.closeWriter(file); }
catch ( Exception e ) { throw new SQLException( e.getMessage() ); }
}
}
}