//package oracle.aurora.jaccelerator.server; package oracle.jaccelerator.server; import java.io.*; import java.util.Hashtable; import java.util.Enumeration; import java.sql.SQLException; import oracle.aurora.rdbms.Handle; import oracle.aurora.rdbms.ClassHandle; import oracle.aurora.rdbms.ResourceHandle; import oracle.aurora.rdbms.Schema; import oracle.aurora.rdbms.ObjectTypeChangedException; import oracle.sql.BLOB; /** * load me to the server this way: * * loadjava -verbose -oci8 -resolve -user scott/tiger TransitiveClosureDumper.java * * call me from SQL this way: * * connect $1/$2 * create or replace package jaccelerator as * function DUMP_TRANSITIVE_CLOSURE (name varchar2, schema varchar2) * return VARCHAR2; * pragma restrict_references(DUMP_TRANSITIVE_CLOSURE, wnds); * end; * / * show errors; * create or replace package body jaccelerator as * function DUMP_TRANSITIVE_CLOSURE (name varchar2, schema varchar2) * return VARCHAR2 as * language java name * 'oracle.jaccelerator.server.TransitiveClosureDumper.traverseReferences(java.lang.String, java.lang.String) return java.lang.String'; * end; * / * show errors; * select JACCELERATOR.DUMP_TRANSITIVE_CLOSURE('java/lang/String', 'SYS') from dual; * * */ public class TransitiveClosureDumper extends Dumper { public TransitiveClosureDumper (String serverSideFileName) throws IOException { needServerSideDump = true; classAttributesWriter = openFileWriter(serverSideFileName); } public TransitiveClosureDumper () throws IOException { needServerSideDump = true; classAttributesWriter = new PrintWriter(System.out); } public TransitiveClosureDumper (BLOB classAttributesListBlob) throws SQLException, IOException { needServerSideDump = false; classAttributesWriter = new PrintWriter(classAttributesListBlob.setBinaryStream(0L)); System.out.println("-- classAttributesListBlob: " + classAttributesListBlob); } public static String traverseReferences (String root, String schema) throws SQLException, IOException { String[] roots = { root }; TransitiveClosureDumper visitor = new TransitiveClosureDumper(); return visitor.traverseReferences(roots, schema); } // public String traverseReferences (String[] roots, String schema, BLOB attributes) // throws SQLException, IOException // { // String result = traverseReferences(roots, schema); // FileInputStream classAttributesListFile = // new FileInputStream(classAttributesListFileName); // copy(classAttributesListFile, attributes.getBinaryOutputStream()); // return result; // } protected boolean needServerSideDump = true; public String traverseReferences (String[] roots, String schemaName) throws SQLException, IOException { Schema schema = Schema.lookup(schemaName); for (int i = 0; i < roots.length; i++) { String name = roots[i]; ClassHandle h = Handle.lookupClass(name, schema); if (h == null) throw new SQLException("class to translate not found: " + name + " in " + schema); if (h.status() == Handle.INVALID) throw new SQLException("class to translate is invalid: " + name + " in " + schema); rootSet.put(name, h); traverseReferences(h); } return dumpClasses(); } // String offset = "trace4"; int systemClassesCount = 0; public void traverseReferences (ClassHandle handle) { // System.out.println("//" + handle); // *** handle.status() on the server is extremely slow. Let's just // *** assume that TC of valid classes is always valid. // if (handle.status() == Handle.INVALID) return; String name = handle.name(); String schema = handle.schema().toString(); boolean alreadyVisited = visit(handle, name, schema); if (alreadyVisited) ; else { boolean sysClass = schema.equals("SYS"); // boolean sysTieBraker = sysClass // ? (name.startsWith("oracle/aurora") || // name.startsWith("java/security") || // name.startsWith("sun/security") || // name.startsWith("java/net") || // name.startsWith("java/awt")) // : false; //if (sysTieBraker) ; //else { if (sysClass) systemClassesCount++; visitedSchemas.put(schema, schema); // System.out.println("//" + offset + name); try { ClassHandle[] references = handle.referencedClassHandles(); // String offset_saved = offset; // offset = offset + " "; for (int i = 0; i < references.length; i++) { traverseReferences(references[i]); } // offset = offset_saved; } catch (ObjectTypeChangedException e) { System.out.println("-- TransitiveClosureDumper.traverseReferences: " + e); } } } } protected Hashtable visitedClasses = new Hashtable(); protected Hashtable visitedSchemas = new Hashtable(); protected Hashtable rootSet = new Hashtable(); public boolean visit (ClassHandle handle, String name, String schema) { boolean alreadyVisited = false; Object prev = visitedClasses.get(name); if (prev == null) { visitedClasses.put(name, handle); } if (prev instanceof ClassHandle) { ClassHandle prevHandle = (ClassHandle)prev; if (prevHandle == handle) { alreadyVisited = true; } else { Hashtable bag = new Hashtable(); bag.put(prevHandle, prevHandle); bag.put(handle, handle); visitedClasses.put(name, bag); } } if (prev instanceof Hashtable) { Hashtable conflicts = ((Hashtable)prev); Object val = conflicts.get(handle); if (conflicts != null) alreadyVisited = true; else conflicts.put(handle, handle); } return alreadyVisited; } String classAttributesListFileName = "class_attributes.txt"; protected PrintWriter classAttributesWriter; protected void dumpClass (ClassHandle h) throws SQLException, IOException { dumpClassAttributes(h); if (needServerSideDump) dumpClass(h, h.name(), h.schema().toString()); } protected void dumpClassAttributes (ClassHandle h) throws SQLException, IOException { String digest = ClassProperties.digest(h); try { String definers = h.definers() ? "true" : "false"; if (classAttributesWriter!= null) { String name = h.name(); classAttributesWriter.println(name + " " + (rootSet.get(name) != null ? "ROOT" : "REF") + " " + h.schema() + " " + "D_" + digest + " " + definers); } } catch (ObjectTypeChangedException e) { System.out.println("-- TransitiveClosureDumper.dumpClassAttributes: " + e); } } public String dumpClasses () throws SQLException, IOException { dumpClasses_before(); int totalCount = 0; int multidefNames = 0; if (visitedClasses.size() > 0) { classAttributesWriter.println("# Attributes of classes related to modules that must be re-ncomped "); Enumeration e = visitedClasses.elements(); while(e.hasMoreElements()) { Object elt = e.nextElement(); if (elt instanceof ClassHandle) { ClassHandle h = (ClassHandle)elt; ++totalCount; dumpClass(h); } if (elt instanceof Hashtable) { ++multidefNames; Enumeration ee = ((Hashtable)elt).elements(); while (ee.hasMoreElements()) { ClassHandle hh = (ClassHandle)ee.nextElement(); ++totalCount; dumpClass(hh); } } } } dumpClasses_after(); classAttributesWriter.close(); StringBuffer schemas = new StringBuffer("schemas:"); Enumeration e = visitedSchemas.keys(); while (e.hasMoreElements()) schemas.append(" " + e.nextElement()); return "total: " + totalCount + " multidefs: " + multidefNames + " " + schemas; } protected void dumpClasses_after () throws SQLException, IOException {} protected void dumpClasses_before () throws SQLException, IOException {} }