/* * 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 org.griphyn.vdl.util.ChimeraProperties; import edu.isi.pegasus.common.util.Separator; import org.griphyn.vdl.workflow.*; import org.griphyn.vdl.util.Logging; /** * This class provides basic functionalities to interact with the * backend database for workflow records. Currently, only searches * that fill the workflow class are implemented. * * @author Jens-S. Vöckler * @author Mike Wilde * @version $Revision$ */ public class WorkflowSchema extends DatabaseSchema implements WF { /** * Default constructor for access to the WF set of tables. * * @param dbDriverName is the database driver name */ public WorkflowSchema( String dbDriverName ) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, SQLException, IOException { // load the driver from the properties super( dbDriverName, PROPERTY_PREFIX ); Logging.instance().log( "dbschema", 3, "done with parent schema c'tor" ); // Note: Does not rely on optional JDBC3 features this.m_dbdriver.insertPreparedStatement( "work.select.all", "SELECT * FROM wf_work" ); this.m_dbdriver.insertPreparedStatement( "work.select.mtime", "SELECT * FROM wf_work WHERE mtime >= ?" ); this.m_dbdriver.insertPreparedStatement( "work.select.sk", "SELECT * FROM wf_work WHERE basedir=? AND vogroup=? " + "AND workflow=? AND run=?" ); this.m_dbdriver.insertPreparedStatement( "job.select.all", "SELECT * FROM wf_jobstate" ); this.m_dbdriver.insertPreparedStatement( "job.select.mtime", "SELECT * FROM wf_jobstate WHERE wfid IN " + "( SELECT id FROM wf_work WHERE mtime >= ? )" ); this.m_dbdriver.insertPreparedStatement( "job.select.sk", "SELECT * FROM wf_jobstate WHERE wfid=? AND jobid=?" ); } /** * Converts a regular datum into an SQL timestamp. * @param date is a regular Java date * @return a SQL timestamp obtained from the Date. */ protected java.sql.Timestamp toStamp( java.util.Date date ) { return new java.sql.Timestamp( date.getTime() ); } /** * Converts a SQL timestamp into a regular datum. * @param date is SQL timestamp from the database * @return a regular Java date */ protected java.util.Date fromStamp( java.sql.Timestamp date ) { return new java.util.Date( date.getTime() ); } /** * Obtains all jobs that belong to a particular workflow. * * @param wfid is the workflow identifier for jobs. * @return a list of all jobs */ private java.util.List getAllJobs( long wfid ) throws SQLException { java.util.List result = new ArrayList(); Logging.instance().log("xaction", 1, "START load jobs for work" ); PreparedStatement ps = m_dbdriver.getPreparedStatement( "job.select.work" ); if ( m_dbdriver.preferString() ) ps.setString( 1, Long.toString(wfid) ); else ps.setLong( 1, wfid ); ResultSet rs = ps.executeQuery(); Logging.instance().log("xaction", 1, "INTER load jobs for work" ); while ( rs.next() ) { JobStateEntry j = new JobStateEntry( wfid, rs.getString("id") ); j.setState( rs.getString("state") ); j.setModificationTime( fromStamp(rs.getTimestamp("mtime")) ); j.setSite( rs.getString("site") ); result.add(j); } rs.close(); Logging.instance().log("xaction", 1, "FINAL load jobs for work" ); return result; } /** * Converts the output of a result set into a workflow * * @param rs is the result set of a query, which is better valid. * @param withJobs if true, also add the jobs, if false, no jobs. * @return a workflow instance created from the result set. */ protected WorkEntry convertResultSet( ResultSet rs, boolean withJobs ) throws SQLException { WorkEntry result = new WorkEntry( rs.getLong("id"), rs.getString("basedir"), rs.getString("vogroup"), rs.getString("workflow"), rs.getString("run") ); result.setCreator( rs.getString("creator") ); result.setCreationTime( fromStamp(rs.getTimestamp("ctime")) ); result.setState( rs.getInt("state") ); result.setModificationTime( fromStamp(rs.getTimestamp("mtime")) ); if ( withJobs ) result.setJob( getAllJobs( rs.getLong("id") ) ); return result; } /** * Load a single workflow from the backend database into a Java * object. The identification is based on the secondary key quadruple. * * @param basedir is the base directory * @param vogroup is the VO group identifier * @param label is the workflow label * @param run is the workflow run directory * @return the Workflow that was matched by the id, which may be null */ public WorkEntry getWorkflow( String basedir, String vogroup, String label, String run ) throws SQLException { WorkEntry result = null; Logging.instance().log("xaction", 1, "START load work sk" ); PreparedStatement ps = m_dbdriver.getPreparedStatement( "work.select.sk" ); int i = 1; ps.setString( i++, basedir ); ps.setString( i++, vogroup ); ps.setString( i++, label ); ps.setString( i++, run ); ResultSet rs = ps.executeQuery(); Logging.instance().log("xaction", 1, "INTER load work sk" ); if ( rs.next() ) { result = convertResultSet(rs,true); } else { Logging.instance().log( "wf", 0, "No workflows found" ); } rs.close(); Logging.instance().log("xaction", 1, "FINAL load work sk" ); return result; } /** * Loads all workflows that are fresh enough and returns a map of * workflows matching. The list is indexed by the primary key of * the WF table, which is the unique workflow id. * * @param mtime is the oldest last modification time. Use * <code>null</code> for all. * @return a map of workflows, indexed by their workflow id. */ public java.util.Map getWorkflows( java.util.Date mtime ) throws SQLException { java.util.Map result = new TreeMap(); Logging.instance().log("xaction", 1, "START load all work" ); PreparedStatement ps = null; if ( mtime == null ) { ps = m_dbdriver.getPreparedStatement( "work.select.all" ); } else { ps = m_dbdriver.getPreparedStatement( "work.select.mtime" ); ps.setTimestamp( 1, toStamp(mtime) ); } ResultSet rs = ps.executeQuery(); Logging.instance().log("xaction", 1, "INTER load all work" ); while ( rs.next() ) { // insert workflows without job state result.put( new Long(rs.getLong("id")), convertResultSet(rs,false) ); } rs.close(); if ( result.size() > 0 ) { // now add job state Logging.instance().log( "xaction", 1, "START load all jobs" ); if ( mtime == null ) { ps = m_dbdriver.getPreparedStatement( "job.select.all" ); } else { ps = m_dbdriver.getPreparedStatement( "job.select.mtime" ); ps.setTimestamp( 1, toStamp(mtime) ); } rs = ps.executeQuery(); Logging.instance().log( "xaction", 1, "INTER load all jobs" ); while ( rs.next() ) { Long key = new Long( rs.getLong("wfid") ); JobStateEntry job = new JobStateEntry( rs.getLong("wfid"), rs.getString("jobid") ); job.setState( rs.getString("state") ); job.setModificationTime( fromStamp(rs.getTimestamp("mtime")) ); job.setSite( rs.getString("site") ); if ( result.containsKey(key) ) { ((WorkEntry) (result.get(key))).addJob(job); } } Logging.instance().log( "xaction", 1, "FINAL load all jobs" ); } else { Logging.instance().log( "wf", 0, "No workflows found" ); } Logging.instance().log("xaction", 1, "FINAL load all work" ); return result; } }