All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.scm.DerbyUtils Maven / Gradle / Ivy

The newest version!
package hudson.scm;

import hudson.scm.IntegritySCM.DescriptorImpl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.sql.ConnectionPoolDataSource;

import org.apache.commons.io.IOUtils;
import org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource;

import com.mks.api.response.APIException;
import com.mks.api.response.Field;
import com.mks.api.response.WorkItem;
import com.mks.api.response.WorkItemIterator;
import com.mks.api.si.SIModelTypeName;

/**
 * This class provides certain utility functions for working with the embedded derby database
 */
public class DerbyUtils 
{
	private static final Logger LOGGER = Logger.getLogger("IntegritySCM");
	public static final String DERBY_DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
	public static final String DERBY_SYS_HOME_PROPERTY = "derby.system.home";
	public static final String DERBY_URL_PREFIX = "jdbc:derby:";
	private static final String DERBY_DB_NAME = "IntegritySCM";
	public static final String CREATE_INTEGRITY_SCM_REGISTRY = "CREATE TABLE INTEGRITY_SCM_REGISTRY (" +
																	"ID INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), " +
																	"JOB_NAME VARCHAR(256) NOT NULL, " +
																	"CONFIGURATION_NAME VARCHAR(50) NOT NULL, " +
																	"PROJECT_CACHE_TABLE VARCHAR(50) NOT NULL, " +
																	"BUILD_NUMBER BIGINT NOT NULL)";
	public static final String SELECT_REGISTRY_1 = "SELECT ID FROM INTEGRITY_SCM_REGISTRY WHERE ID = 1";	
	public static final String SELECT_REGISTRY_TABLE = "SELECT PROJECT_CACHE_TABLE FROM INTEGRITY_SCM_REGISTRY WHERE JOB_NAME = ? AND CONFIGURATION_NAME = ? AND BUILD_NUMBER = ?";
	public static final String INSERT_REGISTRY_ENTRY = "INSERT INTO INTEGRITY_SCM_REGISTRY (JOB_NAME, CONFIGURATION_NAME, PROJECT_CACHE_TABLE, BUILD_NUMBER) " + "VALUES (?, ?, ?, ?)";
	public static final String SELECT_REGISTRY_DISTINCT_PROJECTS = "SELECT DISTINCT JOB_NAME FROM INTEGRITY_SCM_REGISTRY";
	public static final String SELECT_REGISTRY_PROJECTS = "SELECT PROJECT_CACHE_TABLE FROM INTEGRITY_SCM_REGISTRY WHERE JOB_NAME = ? AND CONFIGURATION_NAME = ? ORDER BY BUILD_NUMBER DESC";
	public static final String SELECT_REGISTRY_PROJECT = "SELECT PROJECT_CACHE_TABLE FROM INTEGRITY_SCM_REGISTRY WHERE JOB_NAME = ?";
	public static final String DROP_REGISTRY_ENTRY = "DELETE FROM INTEGRITY_SCM_REGISTRY WHERE PROJECT_CACHE_TABLE = ?"; 
	public static final String CREATE_PROJECT_TABLE = "CREATE TABLE CM_PROJECT (" +
														CM_PROJECT.ID + " INTEGER NOT NULL " + 
														"PRIMARY KEY GENERATED ALWAYS AS IDENTITY " + 
														"(START WITH 1, INCREMENT BY 1), " +
														CM_PROJECT.TYPE + " SMALLINT NOT NULL, " +		/* 0 = File; 1 = Directory */
														CM_PROJECT.NAME + " VARCHAR(32500) NOT NULL, " +
														CM_PROJECT.MEMBER_ID + " VARCHAR(32500), " +														
														CM_PROJECT.TIMESTAMP + " TIMESTAMP, " +
														CM_PROJECT.DESCRIPTION + " CLOB(4 M), " +
														CM_PROJECT.AUTHOR + " VARCHAR(100), " +
														CM_PROJECT.CONFIG_PATH + " VARCHAR(32500), " +
														CM_PROJECT.REVISION + " VARCHAR(32500), " +
														CM_PROJECT.OLD_REVISION + " VARCHAR(32500), " +
														CM_PROJECT.RELATIVE_FILE + " VARCHAR(32500), " +
														CM_PROJECT.CHECKSUM + " VARCHAR(32), " +
														CM_PROJECT.DELTA + " SMALLINT)"; 		/* 0 = Unchanged; 1 = Added; 2 = Changed; 3 = Dropped */
	public static final String DROP_PROJECT_TABLE = "DROP TABLE CM_PROJECT";
	public static final String SELECT_MEMBER_1 = "SELECT " + CM_PROJECT.ID + " FROM CM_PROJECT WHERE " + CM_PROJECT.ID + " = 1";	
	public static final String INSERT_MEMBER_RECORD = "INSERT INTO CM_PROJECT " +
														"(" + CM_PROJECT.TYPE + ", " + CM_PROJECT.NAME + ", " + CM_PROJECT.MEMBER_ID + ", " +
														CM_PROJECT.TIMESTAMP + ", " + CM_PROJECT.DESCRIPTION + ", " + CM_PROJECT.CONFIG_PATH + ", " +
														CM_PROJECT.REVISION + ", " + CM_PROJECT.RELATIVE_FILE + ") " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
	public static final String BASELINE_SELECT = "SELECT " + CM_PROJECT.NAME + ", " + CM_PROJECT.MEMBER_ID + ", " + CM_PROJECT.TIMESTAMP + ", " +
													CM_PROJECT.DESCRIPTION + ", " + CM_PROJECT.AUTHOR + ", " + CM_PROJECT.CONFIG_PATH + ", " +
													CM_PROJECT.REVISION + ", " + CM_PROJECT.RELATIVE_FILE + ", " + CM_PROJECT.CHECKSUM +
													" FROM CM_PROJECT WHERE " + CM_PROJECT.TYPE + " = 0 AND (" + 
													CM_PROJECT.DELTA + " IS NULL OR " + CM_PROJECT.DELTA + " <> 3)";
	public static final String DELTA_SELECT = "SELECT " + CM_PROJECT.TYPE + ", " + CM_PROJECT.NAME + ", " + CM_PROJECT.MEMBER_ID + ", " +
												CM_PROJECT.TIMESTAMP + ", " + CM_PROJECT.DESCRIPTION + ", " + CM_PROJECT.AUTHOR + ", " +
												CM_PROJECT.CONFIG_PATH + ", " + CM_PROJECT.REVISION + ", " + CM_PROJECT.OLD_REVISION + ", " +
												CM_PROJECT.RELATIVE_FILE + ", " + CM_PROJECT.CHECKSUM + ", " + CM_PROJECT.DELTA +
												" FROM CM_PROJECT WHERE " + CM_PROJECT.TYPE + " = 0";
	public static final String PROJECT_SELECT = "SELECT " + CM_PROJECT.NAME + ", " + CM_PROJECT.MEMBER_ID + ", " + CM_PROJECT.TIMESTAMP + ", " +
												CM_PROJECT.DESCRIPTION + ", " + CM_PROJECT.AUTHOR + ", " + CM_PROJECT.CONFIG_PATH + ", " +
												CM_PROJECT.REVISION + ", " + CM_PROJECT.OLD_REVISION + ", " + CM_PROJECT.RELATIVE_FILE + ", " + 
												CM_PROJECT.CHECKSUM + ", " + CM_PROJECT.DELTA +
												" FROM CM_PROJECT WHERE " + CM_PROJECT.TYPE + " = 0 ORDER BY " + CM_PROJECT.NAME + " ASC";

	public static final String SUB_PROJECT_SELECT = "SELECT " + CM_PROJECT.NAME + ", " + CM_PROJECT.CONFIG_PATH + ", " +  CM_PROJECT.REVISION +
												" FROM CM_PROJECT WHERE " + CM_PROJECT.TYPE + " = 1 ORDER BY " + CM_PROJECT.CONFIG_PATH + " ASC";	
	
	public static final String AUTHOR_SELECT = "SELECT " + CM_PROJECT.NAME + ", " + CM_PROJECT.MEMBER_ID + ", " + CM_PROJECT.AUTHOR + ", " +
												CM_PROJECT.CONFIG_PATH + ", " + CM_PROJECT.REVISION + " FROM CM_PROJECT WHERE " + 
												CM_PROJECT.TYPE + " = 0 AND (" + CM_PROJECT.DELTA + " IS NULL OR " + CM_PROJECT.DELTA + " <> 3)";
	public static final String DIR_SELECT = "SELECT DISTINCT " + CM_PROJECT.RELATIVE_FILE + " FROM CM_PROJECT WHERE " + 
												CM_PROJECT.TYPE + " = 1 ORDER BY " + CM_PROJECT.RELATIVE_FILE + " ASC";
	public static final String CHECKSUM_UPDATE = "SELECT " + CM_PROJECT.NAME + ", " + CM_PROJECT.CHECKSUM + " FROM CM_PROJECT WHERE " + 
													CM_PROJECT.TYPE + " = 0 AND (" + CM_PROJECT.DELTA + " IS NULL OR " + CM_PROJECT.DELTA + " <> 3)";	
	
	/**
	 * Returns the CM_PROJECT column name for the string column name
	 * @param name
	 * @return
	 */
	public static final CM_PROJECT getEnum(String name)
	{
		CM_PROJECT[] values = CM_PROJECT.values();
		for( int i = 0; i < values.length; i++ )
		{
			if( name.equals(values[i].toString()) )
			{
				return values[i];
			}
		}
		return CM_PROJECT.UNDEFINED;
	}

	/**
	 * Random unique id generator for cache table names
	 * @return
	 */
	public static final String getUUIDTableName()
	{
		return "SCM_" + UUID.randomUUID().toString().replace('-', '_');
	}
	
	/**
	 * Utility function to load the Java DB Driver
	 */
	public static void loadDerbyDriver() 
	{
	    try 
	    {
	    	LOGGER.fine("Loading derby driver: " + DERBY_DRIVER);
	        Class.forName(DERBY_DRIVER);
	    }
	    catch( ClassNotFoundException ex ) 
	    {
	    	LOGGER.severe("Failed to load derby driver: " + DERBY_DRIVER);
	    	LOGGER.severe(ex.getMessage());
	    	LOGGER.log(Level.SEVERE, "ClassNotFoundException", ex);
	    }
	}

	/**
	 * Creates a pooled connection data source for the derby database
	 * @return
	 */
	public static ConnectionPoolDataSource createConnectionPoolDataSource(String derbyHome)
	{
		EmbeddedConnectionPoolDataSource dataSource = new EmbeddedConnectionPoolDataSource();
		dataSource.setCreateDatabase("create");
		dataSource.setDataSourceName(DERBY_URL_PREFIX + derbyHome.replace('\\',  '/') + "/" + DERBY_DB_NAME);
		dataSource.setDatabaseName(derbyHome.replace('\\',  '/') + "/" + DERBY_DB_NAME);

		return dataSource;
		
	}

	/**
	 * Generic SQL statement execution function
	 * @param dataSource A pooled connection data source
	 * @param sql String sql statement
	 * @return
	 * @throws SQLException
	 */
	public static synchronized boolean executeStmt(ConnectionPoolDataSource dataSource, String sql) throws SQLException
	{
		boolean success = false;
		Connection db = null;
		Statement stmt = null;
		try
		{
			LOGGER.fine("Preparing to execute " + sql);
			db = dataSource.getPooledConnection().getConnection();
			stmt = db.createStatement();
			success = stmt.execute(sql);
			LOGGER.fine("Executed...!");
		}
		catch(SQLException sqlex)
		{
			throw sqlex;
		}
		finally
		{
			if( null != stmt )
			{
				stmt.close();
			}
			
			if( null != db )
			{
				db.close();
			}
		}
		
		return success;
	}

	/**
	 * Creates the Integrity SCM cache registry table
	 * @param dataSource
	 * @return
	 */
	public static synchronized boolean createRegistry(ConnectionPoolDataSource dataSource)
	{
		boolean tableCreated = false;
		try
		{
			if( executeStmt(dataSource, SELECT_REGISTRY_1) )
			{
				LOGGER.fine("Integrity SCM cache registry table exists...");
				tableCreated = true;
			}
		} 
		catch( SQLException ex ) 
		{
			LOGGER.fine(ex.getMessage());
			try
			{
				LOGGER.fine("Integrity SCM cache registry doesn't exist, creating...");				
				tableCreated = executeStmt(dataSource, CREATE_INTEGRITY_SCM_REGISTRY);
			}
			catch( SQLException sqlex )
			{
				LOGGER.fine("Failed to create Integrity SCM cache registry table!");
				LOGGER.log(Level.SEVERE, "SQLException", sqlex);
				tableCreated = false;
			}
		}
		
		return tableCreated;
	}	
	
	/**
	 * Creates a single Integrity SCM Project/Configuration cache table
	 * @param dataSource
	 * @param jobName
	 * @param configurationName
	 * @param buildNumber
	 * @return
	 * @throws SQLException
	 */
	public static synchronized String registerProjectCache(ConnectionPoolDataSource dataSource, String jobName, String configurationName, long buildNumber) throws SQLException
	{
		String cacheTableName = "";
		Connection db = null;
		PreparedStatement select = null;
		PreparedStatement insert = null;
		ResultSet rs = null;
		
		try
		{
			// First Check to see if the current project registry exists
			db = dataSource.getPooledConnection().getConnection();
			cacheTableName = getProjectCache(dataSource, jobName, configurationName, buildNumber);
			if( null == cacheTableName || cacheTableName.length() == 0 )
			{
				// Insert a new row in the registry
				String uuid = getUUIDTableName();
				insert = db.prepareStatement(INSERT_REGISTRY_ENTRY);
				insert.clearParameters();
				insert.setString(1, jobName);			// JOB_NAME
				insert.setString(2, configurationName);	// CONFIGURATION_NAME
				insert.setString(3, uuid);				// PROJECT_CACHE_TABLE
				insert.setLong(4, buildNumber);			// BUILD_NUMBER
				insert.executeUpdate();
				cacheTableName = uuid;
			}
		}
		catch( SQLException sqlex )
		{
			LOGGER.fine(String.format("Failed to create Integrity SCM cache registry entry for %s/%s/%d!", jobName, configurationName, buildNumber));
			LOGGER.log(Level.SEVERE, "SQLException", sqlex);
		}
		finally
		{
			if( null != select ){ select.close(); }
			if( null != rs ){ rs.close(); }
			if( null != insert ){ insert.close(); }
			if( null != db ){ db.close(); }
		}	
		
		return cacheTableName;
	}
	
	/**
	 * Returns the name of the project cache table for the specified job/configuration and build
	 * @param dataSource
	 * @param jobName
	 * @param configurationName
	 * @param buildNumber
	 * @return
	 * @throws SQLException
	 */
	public static synchronized String getProjectCache(ConnectionPoolDataSource dataSource, String jobName, String configurationName, long buildNumber) throws SQLException
	{
		String cacheTableName = "";
		Connection db = null;
		PreparedStatement select = null;
		PreparedStatement insert = null;
		ResultSet rs = null;
		
		try
		{
			db = dataSource.getPooledConnection().getConnection();
			select = db.prepareStatement(SELECT_REGISTRY_TABLE, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
			select.setString(1, jobName);
			select.setString(2, configurationName);
			select.setLong(3, buildNumber);
			rs = select.executeQuery();
			if( getRowCount(rs) > 0 )
			{
				rs.next();
				cacheTableName = rs.getString("PROJECT_CACHE_TABLE");	
			}
		}
		catch( SQLException sqlex )
		{
			LOGGER.fine(String.format("Failed to get Integrity SCM cache registry entry for %s/%s/%d!", jobName, configurationName, buildNumber));
			LOGGER.log(Level.SEVERE, "SQLException", sqlex);	
		}
		finally
		{
			if( null != select ){ select.close(); }
			if( null != rs ){ rs.close(); }
			if( null != insert ){ insert.close(); }
			if( null != db ){ db.close(); }
		}	
		
		return cacheTableName;
	}	
	
	/**
	 * Maintenance function that returns a list of distinct job names 
	 * for additional checking to see which ones are inactive
	 * @param dataSource
	 * @return
	 * @throws SQLException
	 */
	public static synchronized List getDistinctJobNames(ConnectionPoolDataSource dataSource) throws SQLException
	{
		List jobsList = new ArrayList();
		Connection db = null;
		PreparedStatement select = null;
		PreparedStatement delete = null;
		ResultSet rs = null;
		
		try
		{
			// Get a connection from the pool
			db = dataSource.getPooledConnection().getConnection();
			// First Check to see if the current project registry exists
			LOGGER.fine("Preparing to execute " + SELECT_REGISTRY_DISTINCT_PROJECTS);
			select = db.prepareStatement(SELECT_REGISTRY_DISTINCT_PROJECTS);
			rs = select.executeQuery();
			LOGGER.fine("Executed!");
			while( rs.next() )
			{
				String job = rs.getString("JOB_NAME");
				jobsList.add(job);
				LOGGER.fine(String.format("Adding job '%s' from the list of registered projects cache",  job));
			}
		}
		catch( SQLException sqlex )
		{
			LOGGER.fine("Failed to run distinct jobs query!");
			LOGGER.log(Level.SEVERE, "SQLException", sqlex);
		}
		finally
		{
			if( null != select ){ select.close(); }
			if( null != rs ){ rs.close(); }
			if( null != delete ){ delete.close(); }
			if( null != db ){ db.close(); }
		}
		
		return jobsList;
	}
	
	/**
	 * Maintenance function to delete all inactive project cache tables
	 * @param dataSource
	 * @param jobName
	 * @throws SQLException
	 */
	public static synchronized void deleteProjectCache(ConnectionPoolDataSource dataSource, String jobName) throws SQLException
	{
		Connection db = null;
		PreparedStatement select = null;
		PreparedStatement delete = null;
		ResultSet rs = null;
		
		try
		{
			// Get a connection from the pool
			db = dataSource.getPooledConnection().getConnection();
			// First Check to see if the current project registry exists
			select = db.prepareStatement(SELECT_REGISTRY_PROJECT, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
			select.setString(1, jobName);
			delete = db.prepareStatement(DROP_REGISTRY_ENTRY);
			rs = select.executeQuery();
			if( getRowCount(rs) > 0 )
			{
				while( rs.next() )
				{
					String cacheTableName = rs.getString("PROJECT_CACHE_TABLE");	
					executeStmt(dataSource, DROP_PROJECT_TABLE.replaceFirst("CM_PROJECT", cacheTableName));
					delete.setString(1, cacheTableName);
					delete.addBatch();
				}
				
				delete.executeBatch();
			}
		}
		catch( SQLException sqlex )
		{
			LOGGER.fine("Failed to purge project '" + jobName + "' from Integrity SCM cache registry!");
			LOGGER.log(Level.SEVERE, "SQLException", sqlex);
		}
		finally
		{
			if( null != select ){ select.close(); }
			if( null != rs ){ rs.close(); }
			if( null != delete ){ delete.close(); }
			if( null != db ){ db.close(); }
		}
	}
	
	/**
	 * Maintenance function to limit project cache to the most recent two builds
	 * @param dataSource
	 * @param jobName
	 * @param configurationName
	 * @throws SQLException
	 */
	public static synchronized void cleanupProjectCache(ConnectionPoolDataSource dataSource, String jobName, String configurationName) throws SQLException
	{
		Connection db = null;
		PreparedStatement select = null;
		PreparedStatement delete = null;
		ResultSet rs = null;
		
		try
		{
			// Get a connection from the pool			
			db = dataSource.getPooledConnection().getConnection();
			
			// First Check to see if the current project registry exists
			select = db.prepareStatement(SELECT_REGISTRY_PROJECTS, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
			select.setString(1, jobName);
			select.setString(2, configurationName);
			delete = db.prepareStatement(DROP_REGISTRY_ENTRY);
			rs = select.executeQuery();
			int rowCount = getRowCount(rs);
			LOGGER.fine("Cache entries for " + jobName + "/" + configurationName + " = " + rowCount);
			if( rowCount > 2 )
			{
				int deleteCount = 0;
				// Keeping only two cached records
				rs.next();
				rs.next(); 
				while( rs.next() )
				{
					deleteCount++;
					String cacheTableName = rs.getString("PROJECT_CACHE_TABLE");	
					executeStmt(dataSource, DROP_PROJECT_TABLE.replaceFirst("CM_PROJECT", cacheTableName));
					LOGGER.fine(String.format("Deleting old cache entry for %s/%s/%s", jobName, configurationName, cacheTableName));
					delete.setString(1, cacheTableName);
					delete.addBatch();
				}
				
				if( deleteCount > 0 )
				{
					delete.executeBatch();
				}
			}
		}
		catch( SQLException sqlex )
		{
			LOGGER.fine(String.format("Failed to clear old cache for project '%s' from Integrity SCM cache registry!", jobName));
			LOGGER.log(Level.SEVERE, "SQLException", sqlex);
		}
		finally
		{
			if( null != select ){ select.close(); }
			if( null != rs ){ rs.close(); }
			if( null != delete ){ delete.close(); }
			if( null != db ){ db.close(); }
		}
	}
	
	/**
	 * Establishes a fresh set of Integrity SCM cache tables
	 * @param db Derby database connection
	 * @return true/false depending on the success of the operation
	 */
	public static synchronized boolean createCMProjectTables(ConnectionPoolDataSource dataSource, String tableName)
	{
		boolean tableCreated = false;
		try
		{
			if( executeStmt(dataSource, SELECT_MEMBER_1.replaceFirst("CM_PROJECT", tableName)) )
			{
				try
				{
					LOGGER.fine("A prior set of Integrity SCM cache tables detected, dropping...");
					tableCreated = executeStmt(dataSource, DROP_PROJECT_TABLE.replaceFirst("CM_PROJECT", tableName));
					LOGGER.fine("Recreating a fresh set of Integrity SCM cache tables...");
					tableCreated = executeStmt(dataSource, CREATE_PROJECT_TABLE.replaceFirst("CM_PROJECT", tableName));
				}
				catch( SQLException ex )
				{
					LOGGER.fine(String.format("Failed to create Integrity SCM project cache table '%s'", tableName));
					LOGGER.log(Level.SEVERE, "SQLException", ex);
					tableCreated = false;
				}
			}
		} 
		catch( SQLException ex ) 
		{
			LOGGER.fine(ex.getMessage());
			try
			{
				LOGGER.fine(String.format("Integrity SCM cache table '%s' does not exist, creating...", tableName));				
				tableCreated = executeStmt(dataSource, CREATE_PROJECT_TABLE.replaceFirst("CM_PROJECT", tableName));
			}
			catch( SQLException sqlex )
			{
				LOGGER.fine(String.format("Failed to create Integrity SCM project cache table '%s'", tableName));
				LOGGER.log(Level.SEVERE, "SQLException", sqlex);
				tableCreated = false;
			}
		}
		
		return tableCreated;
	}
	
	/**
	 * Convenience function that converts a result set row into a Hashtable for easy access
	 * @param rs ResultSet row object
	 * @return Hashtable containing the non-null values for each column
	 * @throws SQLException
	 * @throws IOException
	 */
	public static Hashtable getRowData(ResultSet rs) throws SQLException, IOException
	{
		Hashtable rowData = new Hashtable();
		ResultSetMetaData rsMetaData = rs.getMetaData();
		int columns = rsMetaData.getColumnCount();
		for( int i = 1; i <= columns; i++ )
		{
			int columnType = rsMetaData.getColumnType(i);
			@SuppressWarnings("unused")
			Object value = null;
			switch(columnType)
			{
				case java.sql.Types.ARRAY:
					value = rs.getArray(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getArray(i)); }
					break;
					
				case java.sql.Types.BIGINT:
				case java.sql.Types.NUMERIC:
				case java.sql.Types.REAL:					
					value = rs.getLong(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getLong(i)); }					
					break;
					
				case java.sql.Types.BLOB:
					InputStream is = null;
					try
					{
						is = rs.getBlob(i).getBinaryStream();
						byte[] bytes = IOUtils.toByteArray(is);
						rowData.put(getEnum(rsMetaData.getColumnLabel(i)), bytes);
					}
					finally
					{
						if( null != is ){ is.close(); }
					}
					break;
					
				case java.sql.Types.BOOLEAN:
					value = rs.getBoolean(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getBoolean(i)); }
					break;
					
				case java.sql.Types.CLOB:
					BufferedReader reader = null;
					try
					{
						reader = new java.io.BufferedReader(rs.getClob(i).getCharacterStream());
						String line = null;
						StringBuilder sb = new StringBuilder();
						while( null != (line=reader.readLine()) ){ sb.append(line + IntegritySCM.NL); }
						rowData.put(getEnum(rsMetaData.getColumnLabel(i)), sb.toString());
					}
					finally
					{
						if( null != reader ){ reader.close(); }
					}
					break;
					
				case java.sql.Types.DATE:
					value = rs.getDate(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getDate(i)); }
					break;
					
				case java.sql.Types.DECIMAL:
					value = rs.getBigDecimal(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getBigDecimal(i)); }
					break;
					
				case java.sql.Types.DOUBLE:
					value = rs.getDouble(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getDouble(i)); }
					break;
					
				case java.sql.Types.FLOAT:
					value = rs.getFloat(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getFloat(i)); }
					break;
					
				case java.sql.Types.INTEGER:
					value = rs.getInt(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getInt(i)); }
					break;
					
				case java.sql.Types.JAVA_OBJECT:
					try
					{
						rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getObject(i));
					}
					finally
					{
						
					}
					break;
					
				case java.sql.Types.SMALLINT:
				case java.sql.Types.TINYINT:
					value = rs.getShort(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getShort(i)); }
					break;

				case java.sql.Types.TIME:
					value = rs.getTime(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getTime(i)); }
					break;
					
				case java.sql.Types.TIMESTAMP:					
					value = rs.getTimestamp(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getTimestamp(i)); }
					break;
										
				default:
					value = rs.getString(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getString(i)); }
			}

		}

		return rowData;
	}

	/**
	 * This function provides a count of the total number of rows in the ResultSet
	 * @param set
	 * @return
	 * @throws SQLException
	 */
	public static int getRowCount(ResultSet rs) throws SQLException   
	{   
		int rowCount = 0;   
		int currentRow = rs.getRow();   
		rowCount = rs.last() ? rs.getRow() : rowCount;   
		if( currentRow == 0 )
		{
			rs.beforeFirst();
		}
		else
		{   
			rs.absolute(currentRow);
		}
		
		return rowCount;   
	}	
	
	/**
	 * Attempts to fix known issues with characters that can potentially break the change log xml
	 * @param desc Input comment string for the revision
	 * @return Sanitized string that can be embedded within a CDATA tag
	 */
	public static String fixDescription(String desc)
	{
		// Char 8211 which is a long dash causes problems for the change log XML, need to fix it!
		String description = desc.replace((char)8211, '-');
		return description.replaceAll("", "] ] >");
	}
	
	/**
	 * Compares this version of the project to a previous/new version to determine what are the updates and what was deleted
	 * @param baselineProjectCache The previous baseline (build) for this Integrity CM Project
	 * @param api The current Integrity API Session to obtain the author information
	 * @param return The total number of changes found in the comparison
	 * @throws SQLException 
	 * @throws IOException 
	 */
	public static synchronized int compareBaseline(String baselineProjectCache, String projectCacheTable, boolean skipAuthorInfo, APISession api) throws SQLException, IOException
	{
		// Re-initialize our return variable
		int changeCount = 0;
		
		Connection db = null;
		Statement baselineSelect = null;
		Statement pjSelect = null;
		ResultSet baselineRS = null;
		ResultSet rs = null;
		
		try
		{			
			// Get a connection from our pool
			db = DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource().getPooledConnection().getConnection();				
			// Create the select statement for the previous baseline
			baselineSelect = db.createStatement();
			String baselineSelectSql = DerbyUtils.BASELINE_SELECT.replaceFirst("CM_PROJECT", baselineProjectCache);
			LOGGER.fine("Attempting to execute query " + baselineSelectSql);
			baselineRS = baselineSelect.executeQuery(baselineSelectSql);
		
			// Create a hashtable to hold the old baseline for easy comparison
			Hashtable> baselinePJ = new Hashtable>();
			while( baselineRS.next() )
			{
				Hashtable rowHash = DerbyUtils.getRowData(baselineRS);
				Hashtable memberInfo = new Hashtable();
				memberInfo.put(CM_PROJECT.MEMBER_ID, (null == rowHash.get(CM_PROJECT.MEMBER_ID) ? "" : rowHash.get(CM_PROJECT.MEMBER_ID).toString()));
				memberInfo.put(CM_PROJECT.TIMESTAMP, (null == rowHash.get(CM_PROJECT.TIMESTAMP) ? "" : (Date)rowHash.get(CM_PROJECT.TIMESTAMP)));
				memberInfo.put(CM_PROJECT.DESCRIPTION, (null == rowHash.get(CM_PROJECT.DESCRIPTION) ? "" : rowHash.get(CM_PROJECT.DESCRIPTION).toString()));
				memberInfo.put(CM_PROJECT.AUTHOR, (null == rowHash.get(CM_PROJECT.AUTHOR) ? "" : rowHash.get(CM_PROJECT.AUTHOR).toString()));
				memberInfo.put(CM_PROJECT.CONFIG_PATH, (null == rowHash.get(CM_PROJECT.CONFIG_PATH) ? "" : rowHash.get(CM_PROJECT.CONFIG_PATH).toString()));
				memberInfo.put(CM_PROJECT.REVISION, (null == rowHash.get(CM_PROJECT.REVISION) ? "" : rowHash.get(CM_PROJECT.REVISION).toString()));
				memberInfo.put(CM_PROJECT.RELATIVE_FILE, (null == rowHash.get(CM_PROJECT.RELATIVE_FILE) ? "" : rowHash.get(CM_PROJECT.RELATIVE_FILE).toString()));
				memberInfo.put(CM_PROJECT.CHECKSUM, (null == rowHash.get(CM_PROJECT.CHECKSUM) ? "" : rowHash.get(CM_PROJECT.CHECKSUM).toString()));
				baselinePJ.put(rowHash.get(CM_PROJECT.NAME).toString(), memberInfo);
			}
			
			// Create the select statement for the current project
			pjSelect = db.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
			String pjSelectSql = DerbyUtils.DELTA_SELECT.replaceFirst("CM_PROJECT", projectCacheTable);
			LOGGER.fine("Attempting to execute query " + pjSelectSql);
			rs = pjSelect.executeQuery(pjSelectSql);
			
			// Now we will compare the adds and updates between the current project and the baseline
			for( int i = 1; i <= DerbyUtils.getRowCount(rs); i++ )
			{
				// Move the cursor to the current record
				rs.absolute(i);
				Hashtable rowHash = DerbyUtils.getRowData(rs);
				// Obtain the member we're working with
				String memberName = rowHash.get(CM_PROJECT.NAME).toString();
				// Get the baseline project information for this member
				LOGGER.fine("Comparing file against baseline " + memberName);
				Hashtable baselineMemberInfo = baselinePJ.get(memberName);
				// This file was in the previous baseline as well...
				if( null != baselineMemberInfo )
				{
					// Did it change? Either by an update or roll back (update member revision)?
					String oldRevision = baselineMemberInfo.get(CM_PROJECT.REVISION).toString();
					if( ! rowHash.get(CM_PROJECT.REVISION).toString().equals(oldRevision) )
					{
						// Initialize the prior revision
						rs.updateString(CM_PROJECT.OLD_REVISION.toString(), oldRevision);
						// Initialize the author information as requested
						if( ! skipAuthorInfo ){ rs.updateString(CM_PROJECT.AUTHOR.toString(), 
													IntegrityCMMember.getAuthor(api, 
													rowHash.get(CM_PROJECT.CONFIG_PATH).toString(),
													rowHash.get(CM_PROJECT.MEMBER_ID).toString(),
													rowHash.get(CM_PROJECT.REVISION).toString())); }
						// Initialize the delta flag for this member
						rs.updateShort(CM_PROJECT.DELTA.toString(), (short)2);
						LOGGER.fine("... " + memberName + " revision changed - new revision is " + rowHash.get(CM_PROJECT.REVISION).toString());
						changeCount++;
					}
					else
					{
						// This member did not change, so lets copy its old author information
						if( null != baselineMemberInfo.get(CM_PROJECT.AUTHOR) )
						{
							rs.updateString(CM_PROJECT.AUTHOR.toString(), baselineMemberInfo.get(CM_PROJECT.AUTHOR).toString());
						}
						// Also, lets copy over the previous MD5 checksum
						if( null != baselineMemberInfo.get(CM_PROJECT.CHECKSUM) )
						{
							rs.updateString(CM_PROJECT.CHECKSUM.toString(), baselineMemberInfo.get(CM_PROJECT.CHECKSUM).toString());
						}
						// Initialize the delta flag
						rs.updateShort(CM_PROJECT.DELTA.toString(), (short)0);
					}
					
					// Remove this member from the baseline project hashtable, so we'll be left with items that are dropped
					baselinePJ.remove(memberName);
				}
				else // We've found a new file
				{
					// Initialize the author information as requested
					if( ! skipAuthorInfo ){ rs.updateString(CM_PROJECT.AUTHOR.toString(), 
												IntegrityCMMember.getAuthor(api, 
												rowHash.get(CM_PROJECT.CONFIG_PATH).toString(),
												rowHash.get(CM_PROJECT.MEMBER_ID).toString(),
												rowHash.get(CM_PROJECT.REVISION).toString())); }				
					// Initialize the delta flag for this member
					rs.updateShort(CM_PROJECT.DELTA.toString(), (short)1);
					LOGGER.fine("... " + memberName + " new file - revision is " + rowHash.get(CM_PROJECT.REVISION).toString());					
					changeCount++;
				}
				
				// Update this row in the data source
				rs.updateRow();				
			}
			
			// Now, we should be left with the drops.  Exist only in the old baseline and not the current one.
			Enumeration deletedMembers = baselinePJ.keys();
			while( deletedMembers.hasMoreElements() )
			{
				changeCount++;
				String memberName = deletedMembers.nextElement();
				Hashtable memberInfo = baselinePJ.get(memberName);
				
				// Add the deleted members to the database
				rs.moveToInsertRow();
				rs.updateShort(CM_PROJECT.TYPE.toString(), (short)0);
				rs.updateString(CM_PROJECT.NAME.toString(), memberName);
				rs.updateString(CM_PROJECT.MEMBER_ID.toString(), memberInfo.get(CM_PROJECT.MEMBER_ID).toString());
				if( memberInfo.get(CM_PROJECT.TIMESTAMP) instanceof java.util.Date )
				{
					Timestamp ts = new Timestamp(((Date)memberInfo.get(CM_PROJECT.TIMESTAMP)).getTime());
					rs.updateTimestamp(CM_PROJECT.TIMESTAMP.toString(), ts);
				}
				rs.updateString(CM_PROJECT.DESCRIPTION.toString(), memberInfo.get(CM_PROJECT.DESCRIPTION).toString());
				rs.updateString(CM_PROJECT.AUTHOR.toString(), memberInfo.get(CM_PROJECT.AUTHOR).toString());
				rs.updateString(CM_PROJECT.CONFIG_PATH.toString(), memberInfo.get(CM_PROJECT.CONFIG_PATH).toString());
				rs.updateString(CM_PROJECT.REVISION.toString(), memberInfo.get(CM_PROJECT.REVISION).toString());
				rs.updateString(CM_PROJECT.RELATIVE_FILE.toString(), memberInfo.get(CM_PROJECT.RELATIVE_FILE).toString());
				rs.updateShort(CM_PROJECT.DELTA.toString(), (short)3);
				rs.insertRow();
				rs.moveToCurrentRow();
				
				LOGGER.fine("... " + memberName + " file dropped - revision was " + memberInfo.get(CM_PROJECT.REVISION).toString());
			}

			// Commit changes to the database...
			db.commit();
		}
		finally
		{
			// Close the result set and select statements
			if( null != baselineRS ){ baselineRS.close(); }
			if( null != rs ){ rs.close(); }			
			if( null != baselineSelect ){ baselineSelect.close(); }
			if( null != pjSelect ){ pjSelect.close(); }			
			
			// Close DB connection
			if( null != db ){ db.close(); }			
		}
		
		return changeCount;
	}	
	
	/**
	 * Parses the output from the si viewproject command to get a list of members
	 * @param wit WorkItemIterator
	 * @throws APIException 
	 * @throws SQLException 
	 */
	public static synchronized void parseProject(IntegrityCMProject siProject, WorkItemIterator wit) throws APIException, SQLException
	{
		// Setup the Derby DB for this Project
		Connection db = null;
		PreparedStatement insert = null;
		try
		{
			// Get a connection from our pool
			db = DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource().getPooledConnection().getConnection();
			// Create a fresh set of tables for this project
			DerbyUtils.createCMProjectTables(DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource(), siProject.getProjectCacheTable());
			// Initialize the project config hash
			Hashtable pjConfigHash = new Hashtable();
			// Add the mapping for the current project
			pjConfigHash.put(siProject.getProjectName(), siProject.getConfigurationPath());
			// Compute the project root directory
			String projectRoot = siProject.getProjectName().substring(0, siProject.getProjectName().lastIndexOf('/'));
	
			// Iterate through the list of members returned by the API
			String insertSQL = DerbyUtils.INSERT_MEMBER_RECORD.replaceFirst("CM_PROJECT", siProject.getProjectCacheTable());
			LOGGER.fine("Attempting to execute query " + insertSQL);
			insert = db.prepareStatement(insertSQL);
			
			
			while( wit.hasNext() )
			{
				WorkItem wi = wit.next();
				String entryType = (null != wi.getField("type") ? wi.getField("type").getValueAsString() : "");
				
				if( wi.getModelType().equals(SIModelTypeName.SI_SUBPROJECT) )
				{
					// Ignore pending subprojects in the tree...
					if( entryType.equalsIgnoreCase("pending-sharesubproject") )
					{
						LOGGER.warning("Skipping " + entryType + " " + wi.getId());
					}
					else
					{
						// Save the configuration path for the current subproject, using the canonical path name
						pjConfigHash.put(wi.getField("name").getValueAsString(), wi.getId());
						// Save the relative directory path for this subproject
						String pjDir = wi.getField("name").getValueAsString().substring(projectRoot.length());
						pjDir = pjDir.substring(0, pjDir.lastIndexOf('/'));				
						// Save this directory entry
						insert.clearParameters();
						insert.setShort(1, (short)1);														// Type
						insert.setString(2, wi.getField("name").getValueAsString());						// Name
						insert.setString(3, wi.getId());													// MemberID
						insert.setTimestamp(4, new Timestamp(Calendar.getInstance().getTimeInMillis()));	// Timestamp
						insert.setClob(5, new StringReader(""));											// Description
						insert.setString(6, wi.getId());													// ConfigPath
						
						String subProjectRev = "";
						if (wi.contains("memberrev")) 
						{
							subProjectRev = wi.getField("memberrev").getItem().getId();
						}						
						insert.setString(7, subProjectRev);													// Revision
						insert.setString(8, pjDir);															// RelativeFile
						insert.executeUpdate();
						
					}
				}
				else if( wi.getModelType().equals(SIModelTypeName.MEMBER) )
				{
					// Ignore certain pending operations
					if( entryType.endsWith("in-pending-sub") ||
							entryType.equalsIgnoreCase("pending-add") ||
							entryType.equalsIgnoreCase("pending-move-to-update") || 
							entryType.equalsIgnoreCase("pending-rename-update") )
					{
						LOGGER.warning("Skipping " + entryType + " " + wi.getId());
					}
					else
					{
						// Figure out this member's parent project's canonical path name
						String parentProject = wi.getField("parent").getValueAsString();				
						// Save this member entry
						String memberName = wi.getField("name").getValueAsString();
						// Figure out the full member path
						LOGGER.fine("Member context: " + wi.getContext());
						LOGGER.fine("Member parent: " + parentProject);
						LOGGER.fine("Member name: " + memberName);
						
						// Process this member only if we can figure out where to put it in the workspace
						if( memberName.startsWith(projectRoot) )
						{
							String description = "";
							// Per JENKINS-19791 some users are getting an exception when attempting 
							// to read the 'memberdescription' field in the API response. This is an
							// attempt to catch the exception and ignore it...!
							try
							{
								if( null != wi.getField("memberdescription") && null != wi.getField("memberdescription").getValueAsString() )
								{
									description = fixDescription(wi.getField("memberdescription").getValueAsString());
								}
							}
							catch( NoSuchElementException e ) 
							{
								// Ignore exception
								LOGGER.warning("Cannot obtain the value for 'memberdescription' in API response for member: "+ memberName);
								LOGGER.info("API Response has the following fields available: ");
								for( @SuppressWarnings("unchecked")
								final Iterator fieldsIterator = wi.getFields(); fieldsIterator.hasNext(); )
								{
									Field apiField = fieldsIterator.next();
									LOGGER.info("Name: " + apiField.getName() + ", Value: "+ apiField.getValueAsString());
								}
							}
							
							Date timestamp = new Date();
							// Per JENKINS-25068 some users are getting a null pointer exception when attempting 
							// to read the 'membertimestamp' field in the API response. This is an attempt to work around it!							
							try
							{
								Field timeFld = wi.getField("membertimestamp");
								if( null != timeFld && null != timeFld.getDateTime() )
								{
									timestamp = timeFld.getDateTime();
								}
							}
							catch( Exception e )
							{
								// Ignore exception
								LOGGER.warning("Cannot obtain the value for 'membertimestamp' in API response for member: "+ memberName);
								LOGGER.warning("Defaulting 'membertimestamp' to now - " + timestamp);
							}
							
							insert.clearParameters();
							insert.setShort(1, (short)0);										// Type
							insert.setString(2, memberName);									// Name
							insert.setString(3, wi.getId());									// MemberID
							insert.setTimestamp(4, new Timestamp(timestamp.getTime()));			// Timestamp
							insert.setClob(5, new StringReader(description));					// Description
							insert.setString(6, pjConfigHash.get(parentProject));				// ConfigPath
							insert.setString(7, wi.getField("memberrev").getItem().getId());	// Revision 
							insert.setString(8, memberName.substring(projectRoot.length()));	// RelativeFile (for workspace)
							insert.executeUpdate();
						}
						else
						{
							// Issue warning...
							LOGGER.warning("Skipping " + memberName + " it doesn't appear to exist within this project " + projectRoot + "!");
						}
					}
				}
				else
				{
					LOGGER.warning("View project output contains an invalid model type: " + wi.getModelType());
				}
			}
			
			// Commit to the database
			db.commit();
		}
		finally
		{
			// Close the insert statement
			if( null != insert ){ insert.close(); }
			
			// Close the database connection
			if( null != db ){ db.close(); }
		}

		// Log the completion of this operation
		LOGGER.fine("Parsing project " + siProject.getConfigurationPath() + " complete!");		
	}	
	
	/**
	 * Updates the author information for all the members in the project
	 * @param api
	 * @throws SQLException
	 * @throws IOException
	 */
	public static synchronized void primeAuthorInformation(String projectCacheTable, APISession api) throws SQLException, IOException
	{
		Connection db = null;
		Statement authSelect = null;
		ResultSet rs = null;
		try
		{
			// Get a connection from our pool
			db = DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource().getPooledConnection().getConnection();			
			// Create the select statement for the current project
			authSelect = db.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
			rs = authSelect.executeQuery(DerbyUtils.AUTHOR_SELECT.replaceFirst("CM_PROJECT", projectCacheTable));
			while( rs.next() )
			{
				Hashtable rowHash = DerbyUtils.getRowData(rs);
				rs.updateString(CM_PROJECT.AUTHOR.toString(), 
						IntegrityCMMember.getAuthor(api, 
											rowHash.get(CM_PROJECT.CONFIG_PATH).toString(),
											rowHash.get(CM_PROJECT.MEMBER_ID).toString(),
											rowHash.get(CM_PROJECT.REVISION).toString()));
				rs.updateRow();
			}
			
			// Commit the updates
			db.commit();
		}
		finally
		{
			// Release the result set
			if( null != rs ){ rs.close(); }
			
			// Release the statement
			if( null != authSelect ){ authSelect.close(); }
			
			// Close project db connections
			if( null != db ){ db.close(); }
		}
	}	
	
	/**
	 * Updates the underlying Integrity SCM Project table cache with the new checksum information
	 * @param checksumHash Checksum hashtable generated from a checkout operation
	 * @throws SQLException
	 * @throws IOException
	 */
	public static synchronized void updateChecksum(String projectCacheTable, ConcurrentHashMap checksumHash) throws SQLException, IOException
	{
		Connection db = null;
		Statement checksumSelect = null;
		ResultSet rs = null;
		try
		{
			// Get a connection from our pool
			db = DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource().getPooledConnection().getConnection();				
			// Create the select statement for the current project
			checksumSelect = db.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
			rs = checksumSelect.executeQuery(DerbyUtils.CHECKSUM_UPDATE.replaceFirst("CM_PROJECT", projectCacheTable));
			while( rs.next() )
			{
				Hashtable rowHash = DerbyUtils.getRowData(rs);
				String newChecksum = checksumHash.get(rowHash.get(CM_PROJECT.NAME).toString());
				if( null != newChecksum && newChecksum.length() > 0 )
				{
					rs.updateString(CM_PROJECT.CHECKSUM.toString(), newChecksum);
					rs.updateRow();
				}
			}
			
			// Commit the updates
			db.commit();
		}
		finally
		{
			// Release the result set
			if( null != rs ){ rs.close(); }
			
			// Release the statement
			if( null != checksumSelect ){ checksumSelect.close(); }
			
			// Close project db connections
			if( null != db ){ db.close(); }
		}
	}
	
	/**
	 * Project access function that returns the state of the current project
	 * NOTE: For maximum efficiency, this should be called only once and after the compareBasline() has been invoked!
	 * @return A List containing every member in this project, including any dropped artifacts
	 * @throws SQLException
	 * @throws IOException
	 */
	public static synchronized List> viewProject(String projectCacheTable) throws SQLException, IOException
	{
		// Initialize our return variable
		List> projectMembersList = new ArrayList>();
		
		// Initialize our db connection
		Connection db = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		try
		{
			// Get a connection from our pool
			db = DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource().getPooledConnection().getConnection();				
			stmt = db.createStatement();
			rs = stmt.executeQuery(DerbyUtils.PROJECT_SELECT.replaceFirst("CM_PROJECT", projectCacheTable));
			while( rs.next() )
			{
				projectMembersList.add(DerbyUtils.getRowData(rs));
			}
		}
		finally
		{
			// Close the database resources
			if( null != rs ){ rs.close(); }
			if( null != stmt ){ stmt.close(); }
			if( null != db ){ db.close(); }
		}
		
		return projectMembersList;
	}	
	
	/**
	 * Project access function that returns the state of the current project
	 * NOTE: For maximum efficiency, this should be called only once and after the compareBasline() has been invoked!
	 * @return A List containing every subproject in this project
	 * @throws SQLException
	 * @throws IOException
	 */
	public static synchronized List> viewSubProjects(String projectCacheTable) throws SQLException, IOException
	{
		// Initialize our return variable
		List> subprojectsList = new ArrayList>();
		
		// Initialize our db connection
		Connection db = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		try
		{
			// Get a connection from our pool
			db = DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource().getPooledConnection().getConnection();			
			stmt = db.createStatement();
			rs = stmt.executeQuery(DerbyUtils.SUB_PROJECT_SELECT.replaceFirst("CM_PROJECT", projectCacheTable));
			while( rs.next() )
			{
				subprojectsList.add(DerbyUtils.getRowData(rs));
			}
		}
		finally
		{
			// Close the database resources
			if( null != rs ){ rs.close(); }
			if( null != stmt ){ stmt.close(); }
			if( null != db ){ db.close(); }
		}
		
		return subprojectsList;
	}	
	
	/**
	 * Returns a string list of relative paths to all directories in this project
	 * @return
	 * @throws SQLException 
	 * @throws IOException 
	 */
	public static synchronized List getDirList(String projectCacheTable) throws SQLException, IOException
	{
		// Initialize our return variable
		List dirList = new ArrayList();
		
		// Initialize our db connection
		Connection db = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		try
		{
			// Get a connection from our pool
			db = DescriptorImpl.INTEGRITY_DESCRIPTOR.getDataSource().getPooledConnection().getConnection();			
			stmt = db.createStatement();
			rs = stmt.executeQuery(DerbyUtils.DIR_SELECT.replaceFirst("CM_PROJECT", projectCacheTable));
			while( rs.next() )
			{
				Hashtable rowData = DerbyUtils.getRowData(rs); 
				dirList.add(rowData.get(CM_PROJECT.RELATIVE_FILE).toString());
			}
		}
		finally
		{
			// Close the database resources
			if( null != rs ){ rs.close(); }
			if( null != stmt ){ stmt.close(); }
			if( null != db ){ db.close(); }
		}
		
		return dirList;
	}	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy