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 java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;

import org.apache.commons.io.IOUtils;

/**
 * This class provides certain utility functions for working with the embedded derby database
 */
public class DerbyUtils 
{
	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_DB_FOLDER = "IntegritySCM";
	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(30), " +
														CM_PROJECT.OLD_REVISION + " VARCHAR(30), " +
														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 CREATE_NAME_INDEX = "CREATE INDEX MEMBER_NAME ON CM_PROJECT (" + CM_PROJECT.NAME + " ASC)";
	public static final String DROP_NAME_INDEX = "DROP INDEX MEMBER_NAME";
	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 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;
	}

	/**
	 * Utility function that sets the derby DB home
	 * @param dir
	 */
	public static void setDerbySystemDir(File dir)
	{
		System.setProperty(DERBY_SYS_HOME_PROPERTY, dir.getAbsolutePath());
	}

	/**
	 * Utility function to load the Java DB Driver
	 */
	public static void loadDerbyDriver() 
	{
	    try 
	    {
	    	Logger.debug("Loading derby driver: " + DERBY_DRIVER);
	        Class.forName(DERBY_DRIVER);
	    }
	    catch( ClassNotFoundException ex ) 
	    {
	    	Logger.error("Failed to load derby driver: " + DERBY_DRIVER);
	    	Logger.error(ex.getMessage());
	    	Logger.fatal(ex);
	    }
	}

	/**
	 * Opens a connection to the derby database represented with the File 'path'
	 * @param path Job directory where the derby db will be saved
	 * @return SQL Connection to the derby db
	 * @throws SQLException 
	 */
	public static Connection createDBConnection(File path) throws SQLException
	{
		String dbUrl = "jdbc:derby:" + path.getAbsolutePath().replace('\\', '/') + "/" + DERBY_DB_FOLDER + ";create=true;user=dbuser;password=dbuserpwd";
		Logger.debug("Attempting to open connection to database: " + path.getAbsolutePath() + IntegritySCM.FS + DERBY_DB_FOLDER);
	    return DriverManager.getConnection(dbUrl);
	}

	/**
	 * Shuts down the embedded derby database represented with the File 'path'
	 * @param path Job directory where the derby db can be located
	 */
	public static void shutdownDB(File path)
	{
		String dbUrl = "jdbc:derby:" + path.getAbsolutePath().replace('\\', '/') + "/" + DERBY_DB_FOLDER + ";shutdown=true;user=dbuser;password=dbuserpwd";
		try 
		{
			Logger.debug("Attempting to shut down database: " + path.getAbsolutePath() + IntegritySCM.FS + DERBY_DB_FOLDER);
		    Connection db = DriverManager.getConnection(dbUrl);
		    db.close();
		}
		catch( SQLException sqle )
		{
			Logger.error("Failed to shutdown database connection!");
			Logger.error(sqle.getMessage());
		    Logger.fatal(sqle);
		}		
	}
	
	/**
	 * Helper function that simply drops tables and indexes
	 * @param db Derby database connection
	 * @return true/false depending on the success of the operation
	 * @throws SQLException
	 */
	private static boolean dropTables(Connection db) throws SQLException
	{
		boolean tablesDropped = false;
		
		// First drop the Member_Name index
		Statement dropIndx = db.createStatement();
		tablesDropped = dropIndx.execute(DROP_NAME_INDEX);
		dropIndx.close();
		
		// Second drop the CM_Project table
		Statement dropTable = db.createStatement();
		tablesDropped = dropTable.execute(DROP_PROJECT_TABLE);
		dropTable.close();
		
		Logger.debug("Prior Integrity SCM cache tables successfully dropped!");		
		return tablesDropped;
	}
	
	/**
	 * Helper function that simply creates new tables and indexes
	 * @param db Derby database connection
	 * @return true/false depending on the success of the operation
	 * @throws SQLException
	 */
	private static boolean createTables(Connection db) throws SQLException
	{
		boolean tablesCreated = false;
		
		// First create the CM_Project table
		Statement createTable = db.createStatement();
		tablesCreated = createTable.execute(CREATE_PROJECT_TABLE);
		createTable.close();
		
		// Create an index on the Member Name column
		Statement createIndex = db.createStatement();
		tablesCreated = createIndex.execute(CREATE_NAME_INDEX);
		createIndex.close();
		
		Logger.debug("New Integrity SCM cache tables successfully created!");
		return tablesCreated;
		
	}

	/**
	 * 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 boolean createCMProjectTables(Connection db)
	{
		boolean tablesCreated = false;
		Statement select = null;
		try
		{
			select = db.createStatement();
			if( select.execute(SELECT_MEMBER_1) )
			{
				try
				{
					Logger.debug("A prior set of Integrity SCM cache tables detected, dropping...");
					// Close the select statement, so that we can drop the table
					select.close();
					tablesCreated = dropTables(db);
					Logger.debug("Recreating a fresh set of Integrity SCM cache tables...");
					tablesCreated = createTables(db);
				}
				catch( SQLException ex )
				{
					Logger.error("Failed to create Integrity SCM cache tables!");
					Logger.fatal(ex);
					tablesCreated = false;
				}
			}
		} 
		catch( SQLException ex ) 
		{
			Logger.debug(ex.getMessage());
			try
			{
				Logger.debug("Integrity SCM cache tables do not exist, creating...");				
				tablesCreated = createTables(db);
			}
			catch( SQLException sqlex )
			{
				Logger.error("Failed to create Integrity SCM cache tables!");
				Logger.fatal(sqlex);
				tablesCreated = false;
			}
		}
		finally
		{
			if( null != select )
			{
				try 
				{
					select.close();
				} 
				catch( SQLException ex )
				{
					Logger.error(ex.getMessage());
					Logger.fatal(ex);
					tablesCreated = false;
				}
			}
		}
		
		return tablesCreated;
	}
	
	/**
	 * 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:
					value = rs.getBlob(i);
					if( ! rs.wasNull() )
					{
						InputStream is = rs.getBlob(i).getBinaryStream();
						try
						{
							byte[] bytes = IOUtils.toByteArray(is);
							rowData.put(getEnum(rsMetaData.getColumnLabel(i)), bytes);
						}
						finally
						{
							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:
					value = rs.getClob(i);
					if( ! rs.wasNull() )
					{
						BufferedReader reader = new java.io.BufferedReader(rs.getClob(i).getCharacterStream());
						String line = null;
						StringBuilder sb = new StringBuilder();
						try
						{
							while( null != (line=reader.readLine()) ){ sb.append(line + IntegritySCM.NL); }
							rowData.put(getEnum(rsMetaData.getColumnLabel(i)), sb.toString());
						}
						finally
						{
							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:
					value = rs.getObject(i);
					if( !rs.wasNull() ){ rowData.put(getEnum(rsMetaData.getColumnLabel(i)), rs.getObject(i)); }
					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;   
	}  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy