/**Installer for module */ package oracle.jaccelerator.server; import oracle.aurora.rdbms.Schema; import oracle.aurora.rdbms.ClassHandle; import oracle.aurora.rdbms.Handle; import oracle.aurora.rdbms.ResourceHandle; import oracle.aurora.rdbms.ObjectTypeChangedException; import oracle.sql.CHAR; import java.io.*; import java.util.Date; import java.sql.*; import oracle.jdbc.*; /** * DLL Installer * * drop java source "oracle/jaccelerator/server/Installer"; */ public abstract class Installer { /** * * To run: Installer("project"), where project is the name of a * deployment jar. * * */ public static void main(String argv[]) throws SQLException, IOException { if (argv.length == 0) System.out.println("usage: Installer jar1 jar2 ..."); for (int i = 0; i < argv.length; i++) System.out.println(run(argv[i])); } public static String run (String jarName) throws SQLException, IOException { String bundleInstallerName = "oracle.aurora.deploy." + jarName + "_BundleInstaller"; Class bundleInstallerClass = null; try { bundleInstallerClass = Class.forName(bundleInstallerName); } catch (Exception e) { throw new SQLException("failed to find the DLL bundle installer class " + bundleInstallerName + " " + e); } try { OracleDriver driver = new OracleDriver(); Connection connection = driver.defaultConnection(); Messages messages = new Messages(connection, null); messages.prepareInfoTables(); Installer installer = (Installer)bundleInstallerClass.newInstance(); String status = installer.runAndReport(); messages.finishInfoTables(); return status; } catch (Exception e) { throw new SQLException("failed to install DLLs " + bundleInstallerName + " " + e); } } public static void show (String s) { System.out.println("-- " + s); } public static boolean verbose = false; public static void showVerbose (String s) { if (verbose) show(s); } public abstract String runAndReport () throws Exception; static int checkClasses (Messages messages, String[] list) throws SQLException { int mismatchCount = 0; int length = list.length; int i = 0; while (i < length) { String className = list[i++]; String schema = list[i++]; String digest = list[i++]; String definers = list[i++]; ClassHandle h = Handle.lookupClass(className, Schema.lookup(schema)); if (h == null) { mismatchCount++; messages.makeErrorRecord(className, "no such class in " + schema, new Date()); } else if (digest_equal(h, digest) == false) { mismatchCount++; messages.makeErrorRecord(className, "class MD5 digest mismatch", new Date()); } else if (definersStatus_equal(h, definers) == false) { mismatchCount++; messages.makeErrorRecord(className, "was definers=" + definers + ", now otherwise", new Date()); } } return mismatchCount; } static boolean digest_equal (ClassHandle h, String digest) throws SQLException { return ClassProperties.digest(h).equals(digest); } /** * * In many cases, this check matters for module classes * only. However, any code motion or inlining should preserve * definers semantics, and therefore we apply this test to the * entire fragile set. * * */ static boolean definersStatus_equal (ClassHandle h, String definers) { boolean equals = false; try { boolean isDefiners = h.definers(); equals = (definers.equals("false") && isDefiners == false) || (definers.equals("true") && isDefiners == true) ; } catch (ObjectTypeChangedException e) {} return equals; } static void setAttributes (String[] list, String schema) { int length = list.length; int i = 0; while (i < length) { String className = list[i++]; String lib = list[i++]; String entry = list[i++]; ClassHandle h = Handle.lookupClass(className, Schema.lookup(schema)); setLibName(h,lib); setEntry(h,entry); h.setNcompIsEnabled(true); h.setNcompIsAllowed(true); showVerbose("ncomp_handle: " + className + " " + "dll=" + h.getNcompDllNameAsCHAR() + " " + "allowed=" + h.getNcompIsAllowed() + " " + "enabled=" + h.getNcompIsEnabled() + " " + "lib=" + h.getNcompLibNameAsCHAR() + " " + "func=" + h.getNcompFunctionNameAsCHAR()); } } static void setLibName (ClassHandle h, String name) { h.setNcompLibName(new CHAR(name.getBytes(), null)); } static void setEntry (ClassHandle h, String entry) { h.setNcompFunctionName(new CHAR(entry.getBytes(), null)); } static boolean checkPlatform (String platformDescription) { String oracle_home = (String)System.getProperty("oracle.aurora.rdbms.oracle_home"); if (!oracle_home.endsWith(File.separator)) oracle_home += File.separator; String jtc_h_fname = oracle_home + "javavm" + File.separator + "jahome" + File.separator + "jtc.h"; String jtc_h_checksum = Dumper.parseKeywordValuePair(jtc_h_fname, "JTC_CHECKSUM_NCOMP_H"); return platformDescription.equals(System.getProperty("os.name") + " " + System.getProperty("os.arch") + " " + jtc_h_checksum); } public static String successMessage = "installed"; public boolean installedSuccessfully (String status) { return status.equals(successMessage); } public static String run (String packageName, String schema, String libraryName, String platformDescription, String[] fragileSetCheckList, String[] moduleClassAttributes) throws SQLException, IOException { return run(packageName, schema, libraryName, platformDescription, fragileSetCheckList, moduleClassAttributes, false); } static String deploymentDirName = "oracle/aurora/deploy/"; public static String run (String packageName, String schema, String libraryName, String platformDescription, String[] fragileSetCheckList, String[] moduleClassAttributes, boolean abortIfNoResource) throws SQLException, IOException { OracleDriver driver = new OracleDriver(); Connection connection = driver.defaultConnection(); Messages messages = new Messages(connection, libraryName); if (schema != null) schema = schema.toUpperCase(); if (checkPlatform(platformDescription) == false) { show("-- wrong OS/platform/checksum: " + platformDescription); return report(messages, "not installed, incompatibe binaries: " + platformDescription); } ResourceHandle h = Handle.lookupResource(libraryName, Schema.lookup(schema)); if (h == null) { if (abortIfNoResource) { return report(messages, "not installed, no such DLL:"); } else { // report(messages, "DLL is not a resource:"); } } int mismatchCount = checkClasses(messages, fragileSetCheckList); showVerbose("mismatchCount: " + mismatchCount); if (mismatchCount != 0) { if (h != null) dropResource(h); return abortIfNoResource ? report(messages, "not installed, class mismatch") : report(messages, "not enabled, class mismatch") ; } ClassProcessor disabler = new PackageDisableNcomp(packageName, schema); ForEachClass.inPackage(packageName, schema).apply(disabler); setAttributes(moduleClassAttributes, schema); int baseNameIdx = libraryName.lastIndexOf('/'); String libraryBaseName = (baseNameIdx < 0) ? libraryName : libraryName.substring(baseNameIdx); String chmod_command = (String)System.getProperty("oracle.aurora.ncomp.lib.permission"); String oracle_home = (String)System.getProperty("oracle.aurora.rdbms.oracle_home"); if (!oracle_home.endsWith(File.separator)) oracle_home += File.separator; String libPath = oracle_home + "javavm" + File.separator + "admin" + File.separator + libraryBaseName; String result = null; if (h != null) { FileOutputStream file = Dumper.openFileOutputStream(libPath); Dumper.copy(h, file); file.close(); showVerbose("dumped dll: " + h); if (chmod_command.equals("") == true) { showVerbose("No need to invoke chmod on:" + libPath); } else { showVerbose("Invoking chmod on:" +libPath); try { Process p = Runtime.getRuntime().exec(chmod_command + libPath); p.waitFor(); p.destroy(); } catch (Exception e) { throw new SQLException ("Error: " + e + " while trying to set +x permission on " + libPath); } } dropResource(h); result = report(messages, successMessage + " from java resource"); } else { if (libraryName.startsWith(deploymentDirName)) { String deployedFileName = libraryName.substring(deploymentDirName.length()); showVerbose("copying: " + deployedFileName); FileInputStream deployedFile = Dumper.openFileInputStream(oracle_home + "javavm" + File.separator + "deploy" + File.separator + deployedFileName); FileOutputStream file = Dumper.openFileOutputStream(libPath); Dumper.copy(deployedFile, file); deployedFile.close(); file.close(); showVerbose("copied from deploy to admin: " + deployedFileName); if (chmod_command.equals("") == true) { showVerbose("No need to invoke chmod on:" + libPath); } else { try { showVerbose("Setting execute permission on: " + libPath); Process p = Runtime.getRuntime().exec(chmod_command + libPath); p.waitFor(); p.destroy(); } catch (Exception e) { throw new SQLException ("Error: " + e + " while trying to set +x permission on " + libPath); } } result = report(messages, successMessage); } else { showVerbose("enabling: " + libraryBaseName); result = report(messages, "enabled"); } } finishRun(connection, libraryName); return result; } static void finishRun (Connection connection, String libraryName) throws SQLException { try { connection.commit(); } catch (Exception e) { String text = "got error at commit when installing " + libraryName + " : " + e; show(text); throw new SQLException(text); } } protected static void dropResource (ResourceHandle h) throws SQLException { try { if (h != null) h.drop(); } catch (Exception e) { throw new SQLException("dropResource exception: " + e); } } protected static String report (Messages messages, String message) throws SQLException { messages.makeInfoRecord(message, new Date()); return message; } public static String report (String schemaAndName) throws SQLException { int colonIdx = schemaAndName.indexOf(':'); String name = schemaAndName.substring(colonIdx + 1); String schema = schemaAndName.substring(0, colonIdx); String result; System.out.println("TryHandle " + name); ClassHandle h = Handle.lookupClass(name, Schema.lookup(schema)); if (h == null) { result = "Handle " + name + " is NULL"; } else { result = ("enabled=" + h.getNcompIsEnabled() + " " + "allowed=" + h.getNcompIsAllowed() + " " + "lib=" + h.getNcompLibNameAsCHAR() + " " + "func=" + h.getNcompFunctionNameAsCHAR() + " " + "dll=" + h.getNcompDllNameAsCHAR() + " " + "source=" + h.getNcompSourceNameAsCHAR()); } System.out.println("Handle " + name + " " + new Date() + " " + result); return result; } } class Messages { public static void show (String s) { System.out.println(s); } public static java.text.SimpleDateFormat dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); public static String format(Date date) { return dateFormatter.format(date); } Connection connection; String libraryName; public Messages (Connection connection, String libraryName) { this.connection = connection; if (libraryName != null) { int baseNameIdx = libraryName.lastIndexOf('/'); libraryName = baseNameIdx > 0 ? libraryName.substring(baseNameIdx) : libraryName; } this.libraryName = libraryName; } static String libraryInfoTableName = "jaccelerator$dlls"; static String libraryErrorsTableName = "jaccelerator$dll_errors"; static String statusTableName = "jaccelerator$status"; static int dll_name_length = 200; static int status_length = 30; static int timestamp_length = Messages.format(new Date()).length(); static int problem_length = 30; static int class_name_length = 200; static boolean prepareInfoTables_done = false; void prepareInfoTables () throws SQLException { if (!prepareInfoTables_done) { Statement stmt = null; try { try { stmt = connection.createStatement(); String command = null; if (!tableIsDefined(stmt, libraryInfoTableName)) { String[] columns = { SQL.makeVarchar2Column("dll_name", dll_name_length), SQL.makeVarchar2Column("status", status_length), SQL.makeVarchar2Column("timestamp", timestamp_length) }; command = "create table " + libraryInfoTableName + SQL.makeColumns(columns); // show("-- command: " + command); stmt.execute(command); connection.commit(); } if (!tableIsDefined(stmt, libraryErrorsTableName)) { String[] columns = { SQL.makeVarchar2Column("dll_name", dll_name_length), SQL.makeVarchar2Column("problem", problem_length), SQL.makeVarchar2Column("class_name", class_name_length), SQL.makeVarchar2Column("timestamp", timestamp_length) }; command = "create table " + libraryErrorsTableName + SQL.makeColumns(columns); // show("-- command: " + command); stmt.execute(command); connection.commit(); } if (!tableIsDefined(stmt, statusTableName)) { String[] columns = { SQL.makeVarchar2Column("class_name", dll_name_length), SQL.makeVarchar2Column("status", problem_length), SQL.makeVarchar2Column("timestamp", timestamp_length) }; command = "create table " + statusTableName + SQL.makeColumns(columns); // show("-- command: " + command); stmt.execute(command); connection.commit(); } } finally { if (stmt != null) stmt.close(); } } catch (Exception e) { String text = "got error at create jaccelerator tables " + e; show(text); throw new SQLException(text); } prepareInfoTables_done = true; } } static String truncate (String value, int length) { return (value.length() > length) ? value.substring(0, length) : value ; } void makeInfoRecord (String message, Date date) throws SQLException { prepareInfoTables(); PreparedStatement pstmt = null; try { try { /* First delete an existing row */ // pstmt = connection.prepareStatement("DELETE FROM " + libraryInfoTableName + " WHERE dll_name = ? "); // pstmt.setString( 1, truncate(libraryName, dll_name_length)); // pstmt.executeUpdate(); // pstmt.close(); /* Now insert new values */ pstmt = connection.prepareStatement("INSERT INTO " + libraryInfoTableName + " (dll_name, status, timestamp) VALUES(?, ?, ?)"); int fidx = 1; pstmt.setString(fidx++, truncate(libraryName, dll_name_length)); pstmt.setString(fidx++, truncate(message, status_length)); pstmt.setString(fidx++, Messages.format(date)); pstmt.executeUpdate(); // connection.commit(); } finally { if (pstmt != null) pstmt.close(); } } catch (SQLException e) { String text = "got error at insert into jaccelerator$dlls " + e; show(text); throw new SQLException(text); } } void makeErrorRecord (String objectName, String message, Date date) throws SQLException { prepareInfoTables(); PreparedStatement pstmt = null; try { try { pstmt = connection.prepareStatement("INSERT INTO " + libraryErrorsTableName + " (dll_name, class_name, problem, timestamp) VALUES(?, ?, ?, ?)"); int fidx = 1; pstmt.setString(fidx++, truncate(libraryName, dll_name_length)); pstmt.setString(fidx++, truncate(objectName, class_name_length)); pstmt.setString(fidx++, truncate(message, problem_length)); pstmt.setString(fidx++, Messages.format(date)); pstmt.executeUpdate(); // connection.commit(); } finally { if (pstmt != null) pstmt.close(); } } catch (SQLException e) { String text = "got error at insert into " + libraryErrorsTableName + " " + e; show(text); throw new SQLException(text); } } void clearStatusRecords () throws SQLException { prepareInfoTables(); PreparedStatement pstmt = null; try { try { pstmt = connection.prepareStatement("DELETE FROM " + statusTableName + " "); pstmt.executeUpdate(); pstmt.close(); // connection.commit(); } finally { if (pstmt != null) pstmt.close(); } } catch (SQLException e) { String text = "got error at delete from " + statusTableName + " " + e; show(text); throw new SQLException(text); } } void makeStatusRecord (String className, String status, Date date, boolean shouldDelete) throws SQLException { prepareInfoTables(); PreparedStatement pstmt = null; try { try { if (shouldDelete) { /* First delete existing rows */ pstmt = connection.prepareStatement("DELETE FROM " + statusTableName + " WHERE class_name = ? "); pstmt.setString( 1, truncate(className, class_name_length)); pstmt.executeUpdate(); pstmt.close(); } /* Now insert new values */ pstmt = connection.prepareStatement("INSERT INTO " + statusTableName + " (class_name, status, timestamp) VALUES(?, ?, ?)"); int fidx = 1; pstmt.setString(fidx++, truncate(className, class_name_length)); pstmt.setString(fidx++, truncate(status, status_length)); pstmt.setString(fidx++, Messages.format(date)); pstmt.executeUpdate(); // connection.commit(); } finally { if (pstmt != null) pstmt.close(); } } catch (SQLException e) { String text = "got error at insert into " + statusTableName + " " + e; show(text); throw new SQLException(text); } } public static boolean tableIsDefined (Statement stmt, String tableName) throws SQLException { int counter = 0; try { String cmd; cmd = "select table_name from user_tables where " + SQL.makeEqlValueExpr("table_name", tableName.toUpperCase()); ResultSet rset = stmt.executeQuery(cmd); while (rset.next()) { String className = rset.getString(1); // show("-- className: " + className); counter++; } return (counter == 1); } catch (SQLException e) { String text = "got error at select from user_tables " + e; show(text); throw new SQLException(text); } } void finishInfoTables () throws SQLException { try { connection.commit(); } catch (Exception e) { String text = "got error at commit for jaccelerator installer's tables" + e; show(text); throw new SQLException(text); } } }