Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/PersistenceLauncher.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/PersistenceLauncher.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/PersistenceLauncher.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/PersistenceLauncher.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,284 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.enhancer; + +import java.util.Properties; + +import java.io.PrintWriter; + +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; + +import org.apache.jdo.impl.enhancer.util.Support; + + + +/** + * Application launcher for persistence-capable classes. + * + * @author Martin Zaun + */ +public class PersistenceLauncher { + + // chose whether to separate or join out and err channels + //static private final PrintWriter err = new PrintWriter(System.err, true); + static private final PrintWriter err = new PrintWriter(System.out, true); + static private final PrintWriter out = new PrintWriter(System.out, true); + static private final String prefix = "PersistenceLauncher.main() : "; + + /** + * Creates new PersistenceLauncher. + */ + private PersistenceLauncher() { + } + + /** + * Prints usage message. + */ + static void usage() + { + out.flush(); + err.println("PersistenceLauncher:"); + err.println(" usage: <options> ... <target class name> <args> ..."); + err.println(" options:"); + err.println(" -h | --help"); + err.println(" -n | --noEnhancement"); + err.println(" -q | --quiet"); + err.println(" -w | --warn"); + err.println(" -d | --debug"); + err.println(" -t | --timing"); + err.println(" class names have to be fully qualified"); + err.println("done."); + err.println(); + err.flush(); + } + + /** + * Creates a class loader and launches a target class. + * @param args the command line arguments + */ + public static void main(String[] args) + throws ClassNotFoundException, + NoSuchMethodException, + SecurityException, + IllegalAccessException, + IllegalArgumentException, + InvocationTargetException { +/* + message("property PersistenceExecutor.TAG_REPOSITORY = " + + System.getProperty("PersistenceExecutor.TAG_REPOSITORY")); + message("property PersistenceExecutor.TAG_CLASSPATH = " + + System.getProperty("PersistenceExecutor.TAG_CLASSPATH")); + message("property PersistenceExecutor.TAG_LIBRARY = " + + System.getProperty("PersistenceExecutor.TAG_LIBRARY")); + message("property PersistenceExecutor.TAG_CLASSNAME = " + + System.getProperty("PersistenceExecutor.TAG_CLASSNAME")); +*/ + + // get launcher options + final String classpath = System.getProperty("java.class.path"); + boolean noEnhancement = false; + boolean debug = false; + boolean timing = false; + Properties enhancerSettings = new Properties(); + String targetClassname = null; + String[] targetClassArgs = null; + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("-h") + || arg.equals("--help")) { + usage(); + + // exit gently + return; + } + if (arg.equals("-n") + || arg.equals("--noEnhancement")) { + noEnhancement = false; + continue; + } + if (arg.equals("-t") + || arg.equals("--timing")) { + timing = true; + enhancerSettings.setProperty(EnhancerClassLoader.DO_TIMING_STATISTICS, + "true"); + continue; + } + if (arg.equals("-d") + || arg.equals("--debug")) { + debug = true; + enhancerSettings.setProperty(EnhancerClassLoader.VERBOSE_LEVEL, + EnhancerClassLoader.VERBOSE_LEVEL_DEBUG); + continue; + } + if (arg.equals("-w") + || arg.equals("--warn")) { + debug = false; + enhancerSettings.setProperty(EnhancerClassLoader.VERBOSE_LEVEL, + EnhancerClassLoader.VERBOSE_LEVEL_WARN); + continue; + } + if (arg.equals("-q") + || arg.equals("--quiet")) { + debug = false; + enhancerSettings.setProperty(EnhancerClassLoader.VERBOSE_LEVEL, + EnhancerClassLoader.VERBOSE_LEVEL_QUIET); + continue; + } + + // get target class name + targetClassname = arg; + + // copy remaining arguments and leave loop + i++; + final int length = args.length - i; + targetClassArgs = new String[length]; + System.arraycopy(args, i, targetClassArgs, 0, length); + break; + } + + // debugging oputput + if (debug) { + out.println(prefix + "..."); + out.println("settings and arguments:"); + out.println(" classpath = " + classpath); + out.println(" noEnhancement = " + noEnhancement); + out.println(" debug = " + debug); + out.println(" enhancerSettings = {"); + enhancerSettings.list(out); + out.println(" }"); + out.println(" targetClassname = " + targetClassname); + out.print(" targetClassArgs = { "); + for (int i = 0; i < targetClassArgs.length; i++) { + out.print(targetClassArgs[i] + " "); + } + out.println("}"); + } + + // check options + if (targetClassname == null) { + usage(); + throw new IllegalArgumentException("targetClassname == null"); + } + + // get class loader + final ClassLoader loader; + if (noEnhancement) { + if (debug) { + out.println(prefix + "using system class loader"); + } + //out.println("using system class loader"); + loader = PersistenceLauncher.class.getClassLoader(); + } else { + if (debug) { + out.println(prefix + "creating enhancer class loader"); + } + final Properties settings = enhancerSettings; + final PrintWriter out = PersistenceLauncher.out; + loader = new EnhancerClassLoader(classpath, settings, out); + } + + // get target class' main method + Class clazz; + Method main; + try { + final String mname = "main"; + final Class[] mparams = new Class[]{ String[].class }; + final boolean init = true; + if (debug) { + out.println(prefix + "getting method " + + targetClassname + "." + mname + "(String[])"); + } + clazz = Class.forName(targetClassname, init, loader); + main = clazz.getDeclaredMethod(mname, mparams); + } catch (ClassNotFoundException e) { + // log exception only + if (debug) { + out.flush(); + err.println("PersistenceLauncher: EXCEPTION SEEN: " + e); + e.printStackTrace(err); + err.flush(); + } + throw e; + } catch (NoSuchMethodException e) { + // log exception only + if (debug) { + out.flush(); + err.println("PersistenceLauncher: EXCEPTION SEEN: " + e); + e.printStackTrace(err); + err.flush(); + } + throw e; + } catch (SecurityException e) { + // log exception only + if (debug) { + out.flush(); + err.println("PersistenceLauncher: EXCEPTION SEEN: " + e); + e.printStackTrace(err); + err.flush(); + } + throw e; + } + + // invoke target class' main method + try { + final Object[] margs = new Object[]{ targetClassArgs }; + if (debug) { + out.println("invoking method " + clazz.getName() + + "." + main.getName() + "(String[])"); + } + main.invoke(null, margs); + } catch (IllegalAccessException e) { + // log exception only + if (debug) { + out.flush(); + err.println("PersistenceLauncher: EXCEPTION SEEN: " + e); + e.printStackTrace(err); + err.flush(); + } + throw e; + } catch (IllegalArgumentException e) { + // log exception only + if (debug) { + out.flush(); + err.println("PersistenceLauncher: EXCEPTION SEEN: " + e); + e.printStackTrace(err); + err.flush(); + } + throw e; + } catch (InvocationTargetException e) { + // log exception only + if (debug) { + out.flush(); + err.println("PersistenceLauncher: EXCEPTION SEEN: " + e); + e.printStackTrace(err); + err.flush(); + } + throw e; + } finally { + if (timing) { + Support.timer.print(); + } + } + + if (debug) { + out.println(prefix + "done."); + out.flush(); + err.flush(); + } + } +}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedClassAttribute.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedClassAttribute.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedClassAttribute.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedClassAttribute.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,132 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; + +/** + * AnnotatedClassAttribute represents a class level attribute + * class file which identifies the level of annotation of the class. + */ +public class AnnotatedClassAttribute extends ClassAttribute { + + /* The expected attribute name */ + public final static String expectedAttrName = "filter.annotatedClass"; + + /* The expected attribute version */ + public final static short expectedAttrVersion = 1; + + /* Bit mask indicating that the class was filter generated */ + public final static short generatedFlag = 0x1; + + /* Bit mask indicating that the class was filter annotated */ + public final static short annotatedFlag = 0x2; + + /* Bit mask indicating that the class was "repackaged" or similarly + * modified */ + public final static short modifiedFlag = 0x4; + + /* The version of the attribute */ + private short attrVersion; + + /* Flags associated with the annotation */ + private short annotationFlags; + + /* The modification date of the class file at the time of modification */ + private long classModTime; + + /* The date of the annotation */ + private long classAnnotationTime; + + /* public accessors */ + + public short getVersion() { + return attrVersion; + } + + public void setVersion(short version) { + attrVersion = version; + } + + public short getFlags() { + return annotationFlags; + } + + public void setFlags(short flags) { + annotationFlags = flags; + } + + public long getModTime() { + return classModTime; + } + + public void setModTime(long time) { + classModTime = time; + } + + public long getAnnotationTime() { + return classAnnotationTime; + } + + public void setAnnotationTime(long time) { + classAnnotationTime = time; + } + + /** + * Constructor + */ + public AnnotatedClassAttribute( + ConstUtf8 nameAttr, short version, short annFlags, + long modTime, long annTime) { + super(nameAttr); + attrVersion = version; + annotationFlags = annFlags; + classModTime = modTime; + classAnnotationTime = annTime; + } + + /* package local methods */ + + static AnnotatedClassAttribute read( + ConstUtf8 attrName, DataInputStream data, ConstantPool pool) + throws IOException { + short version = data.readShort(); + short annFlags = data.readShort(); + long modTime = data.readLong(); + long annTime = data.readLong(); + return new AnnotatedClassAttribute(attrName, version, annFlags, + modTime, annTime); + } + + void write(DataOutputStream out) throws IOException { + out.writeShort(attrName().getIndex()); + out.writeShort(20); + out.writeShort(attrVersion); + out.writeShort(annotationFlags); + out.writeLong(classModTime); + out.writeLong(classAnnotationTime); + } + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println("version: " + attrVersion); + out.println(" flags: " + annotationFlags); + out.println(" modTime: " + classModTime); + out.println(" annTime: " + classAnnotationTime); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedMethodAttribute.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedMethodAttribute.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedMethodAttribute.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AnnotatedMethodAttribute.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,140 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; + +/** + * AnnotatedMethodAttribute represents a class level attribute + * class file which identifies the level of annotation of the class. + */ +public class AnnotatedMethodAttribute extends ClassAttribute { + + /* The expected attribute name */ + public final static String expectedAttrName = "filter.annotatedMethod"; + + /* The expected attribute version */ + public final static short expectedAttrVersion = 1; + + /* Bit mask indicating that the class was filter generated */ + public final static short generatedFlag = 0x1; + + /* Bit mask indicating that the class was filter annotated */ + public final static short annotatedFlag = 0x2; + + /* Bit mask indicating that the class was "repackaged" */ + public final static short modifiedFlag = 0x4; + + /* The version of the attribute */ + private short attrVersion; + + /* Flags associated with the annotation */ + private short annotationFlags; + + /* list of targets in the code sequence delimiting inserted instruction + * sequences. Even index targets are a range start (inclusive) and odd + * targets represent a range end (exclusive) */ + private InsnTarget annotationRanges[]; + + /* public accessors */ + + public short getVersion() { + return attrVersion; + } + + public void setVersion(short version) { + attrVersion = version; + } + + public short getFlags() { + return annotationFlags; + } + + public void setFlags(short flags) { + annotationFlags = flags; + } + + public InsnTarget[] getAnnotationRanges() { + return annotationRanges; + } + + public void setAnnotationRanges(InsnTarget[] ranges) { + annotationRanges = ranges; + } + + /** + * Constructor + */ + public AnnotatedMethodAttribute( + ConstUtf8 nameAttr, short version, short annFlags, + InsnTarget[] annRanges) { + super(nameAttr); + attrVersion = version; + annotationFlags = annFlags; + annotationRanges = annRanges; + } + + /* package local methods */ + + static AnnotatedMethodAttribute read( + ConstUtf8 attrName, DataInputStream data, CodeEnv env) + throws IOException { + short version = data.readShort(); + short annFlags = data.readShort(); + + short nRanges = data.readShort(); + + InsnTarget ranges[] = new InsnTarget[nRanges*2]; + for (int i=0; i<nRanges; i++) { + ranges[i*2] = env.getTarget(data.readShort()); + ranges[i*2+1] = env.getTarget(data.readShort()); + } + return new AnnotatedMethodAttribute(attrName, version, annFlags, ranges); + } + + void write(DataOutputStream out) throws IOException { + out.writeShort(attrName().getIndex()); + if (annotationRanges == null) + out.writeShort(2); + else + out.writeShort(4 + 2 * annotationRanges.length); + out.writeShort(attrVersion); + out.writeShort(annotationFlags); + if (annotationRanges == null) + out.writeShort(0); + else { + out.writeShort(annotationRanges.length / 2); + for (int i=0; i<annotationRanges.length; i++) + out.writeShort(annotationRanges[i].offset()); + } + } + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println("version: " + attrVersion); + out.println(" flags: " + annotationFlags); + if (annotationRanges != null) { + out.println("Annotations: "); + for (int i=0; i<annotationRanges.length/2; i++) { + ClassPrint.spaces(out, indent+2); + out.println(annotationRanges[i*2] + " to " + + annotationRanges[i*2+1]); + } + } + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AttributeVector.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AttributeVector.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AttributeVector.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/AttributeVector.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,213 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; +import java.util.Vector; +import java.util.Stack; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * A list of attributes within a class file. + * These lists occur in several places within a class file + * - at class level + * - at method level + * - at field level + * - at attribute level + */ +public class AttributeVector { + + /* Vector of ClassAttribute */ + private ClassAttribute attributes[] = null; + + /** + * Returns the i'th attribute in the array + */ + private ClassAttribute attrAt(int i) { + return attributes[i]; + } + + /** + * Construct an empty AttributeVector + */ + public AttributeVector() { } + + /** + * Add an element to the vector + */ + public void addElement(ClassAttribute attr) { + if (attributes == null) + attributes = new ClassAttribute[1]; + else { + ClassAttribute newAttributes[] = new ClassAttribute[attributes.length+1]; + System.arraycopy(attributes, 0, newAttributes, 0, attributes.length); + attributes = newAttributes; + } + attributes[attributes.length-1] = attr; + } + + public Enumeration elements() { + class AttributeVectorEnumeration implements Enumeration { + private ClassAttribute[] attributes; + private int current = 0; + + AttributeVectorEnumeration(ClassAttribute attrs[]) { + attributes = attrs; + } + + public boolean hasMoreElements() { + return attributes != null && current < attributes.length; + } + public Object nextElement() { + if (!hasMoreElements()) + throw new NoSuchElementException(); + return attributes[current++]; + } + } + + return new AttributeVectorEnumeration(attributes); + } + + /** + * Look for an attribute of a specific name + */ + public ClassAttribute findAttribute(String attrName) { + Enumeration e = elements(); + while (e.hasMoreElements()) { + ClassAttribute attr = (ClassAttribute) e.nextElement(); + if (attr.attrName().asString().equals(attrName)) + return attr; + } + return null; + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof AttributeVector)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + AttributeVector other = (AttributeVector)obj; + + if (this.attributes.length != other.attributes.length) { + msg.push("attributes.length " + + String.valueOf(other.attributes.length)); + msg.push("attributes.length " + + String.valueOf(this.attributes.length)); + return false; + } + + // sort attributes by name + class ClassAttributeComparator implements Comparator { + public int compare(Object o1, Object o2) { + ClassAttribute a1 = (ClassAttribute)o1; + ClassAttribute a2 = (ClassAttribute)o2; + String s1 = a1.attrName().asString(); + String s2 = a2.attrName().asString(); + return s1.compareTo(s2); + } + } + ClassAttributeComparator comparator = new ClassAttributeComparator(); + ClassAttribute[] thisAttributes + = (ClassAttribute[])this.attributes.clone(); + ClassAttribute[] otherAttributes + = (ClassAttribute[])other.attributes.clone(); + Arrays.sort(thisAttributes, comparator); + Arrays.sort(otherAttributes, comparator); + for (int i = 0; i < attributes.length; i++) { + ClassAttribute a1 = thisAttributes[i]; + ClassAttribute a2 = otherAttributes[i]; + if (!a1.isEqual(msg, a2)) { + msg.push("attributes[i] = " + String.valueOf(a2)); + msg.push("attributes[i] = " + String.valueOf(a1)); + return false; + } + } + return true; + } + + /** + * General attribute reader + */ + static AttributeVector readAttributes( + DataInputStream data, ConstantPool constantPool) + throws IOException { + AttributeVector attribs = new AttributeVector(); + int n_attrs = data.readUnsignedShort(); + while (n_attrs-- > 0) { + attribs.addElement(ClassAttribute.read(data, constantPool)); + } + return attribs; + } + + /** + * ClassMethod attribute reader + */ + static AttributeVector readAttributes( + DataInputStream data, CodeEnv codeEnv) + throws IOException { + AttributeVector attribs = new AttributeVector(); + int n_attrs = data.readUnsignedShort(); + while (n_attrs-- > 0) { + attribs.addElement(ClassAttribute.read(data, codeEnv)); + } + return attribs; + } + + /** + * Write the attributes to the output stream + */ + void write(DataOutputStream out) throws IOException { + if (attributes == null) { + out.writeShort(0); + } else { + out.writeShort(attributes.length); + for (int i=0; i<attributes.length; i++) + attributes[i].write(out); + } + } + + /** + * Print a description of the attributes + */ + void print(PrintStream out, int indent) { + if (attributes != null) { + for (int i=0; i<attributes.length; i++) + attributes[i].print(out, indent); + } + } + + /** + * Print a brief summary of the attributes + */ + //@olsen: added 'out' and 'indent' parameters + void summarize(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println((attributes == null ? 0 : attributes.length) + + " attributes"); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassAttribute.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassAttribute.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassAttribute.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassAttribute.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,162 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.util.Stack; +import java.util.Vector; +import java.util.Hashtable; +import java.io.*; + +/** + * An abstract base class for the attributes within a class file + */ +public abstract class ClassAttribute implements VMConstants { + + /* The name of the attribute */ + private ConstUtf8 attributeName; + + /** + * Returns the name of the attribute + */ + public ConstUtf8 attrName() { + return attributeName; + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof ClassAttribute)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + ClassAttribute other = (ClassAttribute)obj; + + if (!this.attributeName.isEqual(msg, other.attributeName)) { + msg.push(String.valueOf("attributeName = " + + other.attributeName)); + msg.push(String.valueOf("attributeName = " + + this.attributeName)); + return false; + } + return true; + } + + /** + * Constructor + */ + ClassAttribute(ConstUtf8 theAttrName) { + attributeName = theAttrName; + } + + /** + * General attribute reader + */ + static ClassAttribute read(DataInputStream data, ConstantPool pool) + throws IOException { + + ClassAttribute attr = null; + int attrNameIndex = data.readUnsignedShort(); + ConstUtf8 attrName8 = (ConstUtf8) pool.constantAt(attrNameIndex); + String attrName = attrName8.asString(); + int attrLength = data.readInt(); + + if (attrName.equals(CodeAttribute.expectedAttrName)) { + /* The old style code attribute reader uses more memory and + cpu when the instructions don't need to be examined than the + new deferred attribute reader. We may at some point decide that + we want to change the default based on the current situation + but for now we will just use the deferred reader in all cases. */ + if (true) { + attr = CodeAttribute.read(attrName8, attrLength, data, pool); + } else { + attr = CodeAttribute.read(attrName8, data, pool); + } + } + else if (attrName.equals(SourceFileAttribute.expectedAttrName)) { + attr = SourceFileAttribute.read(attrName8, data, pool); + } + else if (attrName.equals(ConstantValueAttribute.expectedAttrName)) { + attr = ConstantValueAttribute.read(attrName8, data, pool); + } + else if (attrName.equals(ExceptionsAttribute.expectedAttrName)) { + attr = ExceptionsAttribute.read(attrName8, data, pool); + } + else if (attrName.equals(AnnotatedClassAttribute.expectedAttrName)) { + attr = AnnotatedClassAttribute.read(attrName8, data, pool); + } + else { + /* Unrecognized method attribute */ + byte attrBytes[] = new byte[attrLength]; + data.readFully(attrBytes); + attr = new GenericAttribute (attrName8, attrBytes); + } + + return attr; + } + + /* + * CodeAttribute attribute reader + */ + + static ClassAttribute read(DataInputStream data, CodeEnv env) + throws IOException { + ClassAttribute attr = null; + int attrNameIndex = data.readUnsignedShort(); + ConstUtf8 attrName8 = (ConstUtf8) env.pool().constantAt(attrNameIndex); + String attrName = attrName8.asString(); + int attrLength = data.readInt(); + + if (attrName.equals(LineNumberTableAttribute.expectedAttrName)) { + attr = LineNumberTableAttribute.read(attrName8, data, env); + } + else if (attrName.equals(LocalVariableTableAttribute.expectedAttrName)) { + attr = LocalVariableTableAttribute.read(attrName8, data, env); + } + else if (attrName.equals(AnnotatedMethodAttribute.expectedAttrName)) { + attr = AnnotatedMethodAttribute.read(attrName8, data, env); + } + //@olsen: fix 4467428, added support for synthetic code attribute + else if (attrName.equals(SyntheticAttribute.expectedAttrName)) { + attr = SyntheticAttribute.read(attrName8, data, env.pool()); + } + else { + /* Unrecognized method attribute */ + byte attrBytes[] = new byte[attrLength]; + data.readFully(attrBytes); + attr = new GenericAttribute (attrName8, attrBytes); + } + + return attr; + } + + /** + * Write the attribute to the output stream + */ + abstract void write(DataOutputStream out) throws IOException; + + /** + * Print a description of the attribute to the print stream + */ + abstract void print(PrintStream out, int indent); +} + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassField.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassField.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassField.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassField.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,142 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; + +/** + * ClassField models the static and non-static fields of a class within + * a class file. + */ + +final public class ClassField extends ClassMember { + /* access flag bit mask - see VMConstants */ + private int accessFlags; + + /* The name of the field */ + private ConstUtf8 fieldName; + + /* The type signature of the field */ + private ConstUtf8 fieldSignature; + + /* The attributes associated with the field */ + private AttributeVector fieldAttributes; + + + /* public accessors */ + + /** + * Is the field transient? + */ + public boolean isTransient() { + return (accessFlags & ACCTransient) != 0; + } + + /** + * Return the access flags for the field - see VMConstants + */ + public int access() { + return accessFlags; + } + + /** + * Update the access flags for the field - see VMConstants + */ + public void setAccess(int newFlags) { + accessFlags = newFlags; + } + + /** + * Return the name of the field + */ + public ConstUtf8 name() { + return fieldName; + } + + /** + * Change the name of the field + */ + public void changeName(ConstUtf8 name) { + fieldName = name; + } + + /** + * Return the type signature of the field + */ + public ConstUtf8 signature() { + return fieldSignature; + } + + /** + * Change the type signature of the field + */ + public void changeSignature(ConstUtf8 newSig) { + fieldSignature = newSig; + } + + /** + * Return the attributes associated with the field + */ + public AttributeVector attributes() { + return fieldAttributes; + } + + /** + * Construct a class field object + */ + public ClassField(int accFlags, ConstUtf8 name, ConstUtf8 sig, + AttributeVector field_attrs) { + accessFlags = accFlags; + fieldName = name; + fieldSignature = sig; + fieldAttributes = field_attrs; + } + + /* package local methods */ + + static ClassField read(DataInputStream data, ConstantPool pool) + throws IOException { + ClassField f = null; + int accessFlags = data.readUnsignedShort(); + int name_index = data.readUnsignedShort(); + int sig_index = data.readUnsignedShort(); + AttributeVector fieldAttribs = AttributeVector.readAttributes(data, pool); + f = new ClassField(accessFlags, + (ConstUtf8) pool.constantAt(name_index), + (ConstUtf8) pool.constantAt(sig_index), + fieldAttribs); + return f; + } + + void write (DataOutputStream data) throws IOException { + data.writeShort(accessFlags); + data.writeShort(fieldName.getIndex()); + data.writeShort(fieldSignature.getIndex()); + fieldAttributes.write(data); + } + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.print("'" + fieldName.asString() + "'"); + out.print(" sig = " + fieldSignature.asString()); + out.print(" access_flags = " + Integer.toString(accessFlags)); + out.println(" attributes:"); + fieldAttributes.print(out, indent+2); + } +} + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassFile.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassFile.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassFile.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassFile.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,676 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; +import java.util.Hashtable; +import java.util.Enumeration; +import java.io.*; +import java.security.MessageDigest; +import java.security.DigestOutputStream; +import java.security.NoSuchAlgorithmException; +import java.io.DataOutputStream; + + +/** + * ClassFile models the structure of a class as represented within + * a class file. + */ +final public class ClassFile implements VMConstants, Serializable { + + /* Class file constants */ + public static final int magic = 0xcafebabe; + + /[EMAIL PROTECTED] added more flexible version checking. + */ + public static final short[] [] jdkMajorMinorVersions = new short[][] { + new short[] {45,3}, // jdk 1.1 + new short[] {46,0}, // jdk 1.2 + new short[] {47,0}, // jdk 1.3 + new short[] {48,0} // jdk 1.4 + }; + public static final List jdkVersions = + convertMajorMinorVersions(jdkMajorMinorVersions); + + public static final String supportedVersions = printSupportedVersions(); + + private int majorVersion = 0; + private int minorVersion = 0; + + /* The constant pool for the class file */ + private ConstantPool constantPool = new ConstantPool(); + + /* access flag bit mask - see VMConstants */ + private int accessFlags = 0; + + /* The name of the class */ + private ConstClass thisClassName; + + /* The name of the super class */ + private ConstClass superClassName; + + /* A list of the interfaces which the class implements + * The contents are ConstClass objects + */ + private Vector classInterfaces = new Vector(); + + /* A list of the fields which the class contains + * The contents are ClassField objects + */ + private Vector classFields = new Vector(); + + /* A list of the methods which the class defines + * The contents are ClassMethod objects + */ + private Vector classMethods = new Vector(); + + /* A list of the attributes associated with the class */ + private AttributeVector classAttributes = new AttributeVector(); + + /** Static methods + * Added for major.minor compatibility checking + */ + private static List convertMajorMinorVersions(short[][] majorMinor) { + int length = majorMinor.length; + List result = new ArrayList(length); + for (int i = 0; i < length; i++) { + result.add(new Integer(majorMinor[i][0] * 65536 + majorMinor[i][1])); + } + return result; + } + + private static boolean isSupportedVersion(short major, short minor) { + Integer version = new Integer(major*65536 + minor); + return jdkVersions.contains(version); + } + + public static final String printSupportedVersions() { + StringBuffer buf = new StringBuffer("{"); //NOI18N + int length = jdkMajorMinorVersions.length; + for (int i = 0; i < length; i++) { + int major = jdkMajorMinorVersions[i][0]; + int minor = jdkMajorMinorVersions[i][1]; + buf.append("{"); buf.append(major); buf.append(","); + buf.append(minor); buf.append("}"); //NOI18N + } + buf.append("}"); //NOI18N + return buf.toString(); + } + + /* public accessors */ + + + + /** + * Return the constant pool for the class file + */ + public ConstantPool pool() { + return constantPool; + } + + /** + * Return the access flags for the class - see VMConstants + */ + public int access() { + return accessFlags; + } + + /** + * Is the class final? + */ + final public boolean isFinal() { + return (accessFlags & ACCFinal) != 0; + } + + /** + * Is the class an interface? + */ + final public boolean isInterface() { + return (accessFlags & ACCInterface) != 0; + } + + /** + * Is the class public? + */ + final public boolean isPublic() { + return (accessFlags & ACCPublic) != 0; + } + + /** + * Is the class abstract? + */ + final public boolean isAbstract() { + return (accessFlags & ACCAbstract) != 0; + } + + + /** + * Set the access flags for the class - see VMConstants + */ + public void setAccessFlags (int flags) { + accessFlags = flags; + } + + /** + * Return the name of the class + */ + public ConstClass className() { + return thisClassName; + } + + /** + * Return the name of the class as a string + */ + //@olsen: added method + public String classNameString() { + return (thisClassName == null) ? null : thisClassName.asString(); + } + + /** + * Return the name of the super class + */ + public ConstClass superName() { + return superClassName; + } + + /** + * Return the name of the super class as a string + */ + public String superNameString() { + return (superClassName == null) ? null : superClassName.asString(); + } + + /** + * Set the name of the super class + */ + public void setSuperName(ConstClass superCl) { + superClassName = superCl; + } + + /** + * Return the list of the interfaces which the class implements + * The contents are ConstClass objects + */ + public Vector interfaces() { + return classInterfaces; + } + + /** + * Add an interface to the list of the interfaces which the class implements + */ + public void addInterface (ConstClass iface) { + classInterfaces.addElement(iface); + } + + /** + * Return the list of the fields which the class contains + * The contents are ClassField objects + */ + public Vector fields() { + return classFields; + } + + /** + * Add a field to the list of the fields which the class contains + */ + public void addField (ClassField field) { + classFields.addElement(field); + } + + /** + * Add a field to the list of the fields which the class contains, + * at the index'th position. + */ + public void addField(ClassField field, int index) { + classFields.insertElementAt(field, index); + } + + /** + * Return the list of the methods which the class defines + * The contents are ClassMethod objects + */ + public Vector methods() { + return classMethods; + } + + /** + * Look for a method with the specified name and type signature + */ + public ClassMethod findMethod(String methodName, String methodSig) { + for (Enumeration e = methods().elements(); e.hasMoreElements();) { + ClassMethod method = (ClassMethod) e.nextElement(); + if (method.name().asString().equals(methodName) && + method.signature().asString().equals(methodSig)) + return method; + } + return null; + } + + /** + * Add a method to the list of the methods which the class defines + */ + public void addMethod(ClassMethod method) { + classMethods.addElement(method); + } + + /** + * Look for a field with the specified name + */ + public ClassField findField(String fieldName) { + for (Enumeration e = fields().elements(); e.hasMoreElements();) { + ClassField field = (ClassField) e.nextElement(); + if (field.name().asString().equals(fieldName)) + return field; + } + return null; + } + + /** + * Return the list of the attributes associated with the class + */ + public AttributeVector attributes() { + return classAttributes; + } + + /** + * Returns the class name in user ('.' delimited) form. + */ + //@olsen: moved from ClassControl to ClassFile + public String userClassName() + { + return userClassFromVMClass(classNameString()); + } + + /** + * Returns the class name in user ('.' delimited) form. + */ + //@olsen: moved from ClassControl to ClassFile + static public String userClassFromVMClass(String vmName) + { + return vmName.replace('/', '.'); + } + + /** + * Returns the class name in VM ('/' delimited) form. + */ + //@olsen: moved from ClassControl to ClassFile + static public String vmClassFromUserClass(String userName) + { + return userName.replace('.', '/'); + } + + /** + * Returns the vm package name for this class. + */ + //@olsen: moved from ClassControl to ClassFile + public String pkg() + { + return packageOf(classNameString()); + } + + /** + * Returns the vm package name for the vm class name. + */ + //@olsen: moved from ClassControl to ClassFile + static public String packageOf(String vmName) + { + int last = vmName.lastIndexOf('/'); + if (last < 0) + return ""; + return vmName.substring(0, last); + } + + + /* Constructors */ + + /** + * Construct a ClassFile from an input stream + */ + public ClassFile(DataInputStream data) throws ClassFormatError { + this(data, true); + } + + public ClassFile(DataInputStream data, + boolean allowJDK12ClassFiles) throws ClassFormatError { + try { + int thisMagic = data.readInt(); + if (thisMagic != magic) + throw new ClassFormatError("Bad magic value for input"); + + short thisMinorVersion = data.readShort(); + short thisMajorVersion = data.readShort(); + /[EMAIL PROTECTED] changed checking only target 1.1 and 1.2 to more + * general check for a list of versions. + */ + if (isSupportedVersion(thisMajorVersion, thisMinorVersion)) { + minorVersion = thisMinorVersion; + majorVersion = thisMajorVersion; + } else { + throw new ClassFormatError("Bad version number: {" + + thisMajorVersion + "," + + thisMinorVersion + + "} expected one of: " + + supportedVersions); + } + + readConstants(data); + accessFlags = data.readUnsignedShort(); + thisClassName = (ConstClass) + constantPool.constantAt(data.readUnsignedShort()); + superClassName = (ConstClass) + constantPool.constantAt(data.readUnsignedShort()); + readInterfaces(data); + readFields(data); + readMethods(data); + classAttributes = AttributeVector.readAttributes(data, constantPool); + } catch (IOException e) { + throw new ClassFormatError("IOException during reading: " + + e.getMessage()); + } + //@olsen: added println() for debugging + //System.out.println("ClassFile(): new class = " + + //thisClassName.asString()); + } + + /** + * Construct a bare bones class, ready for additions + */ + public ClassFile(String cname, String supername) { + thisClassName = constantPool.addClass(cname); + superClassName = constantPool.addClass(supername); + //@olsen: added println() for debugging + //System.out.println("ClassFile(): new bare class file = " + + //thisClassName); + } + + /** + * Write the Class file to the data output stream + */ + public + void write (DataOutputStream buff) throws IOException { + buff.writeInt(magic); + buff.writeShort(minorVersion); + buff.writeShort(majorVersion); + constantPool.write(buff); + buff.writeShort(accessFlags); + buff.writeShort(thisClassName.getIndex()); + //@lars: superclass may be null (java.lang.Object); + //VMSpec 2nd ed., section 4.1 + buff.writeShort(superClassName == null ? 0 : superClassName.getIndex()); + //buff.writeShort(superClassName.getIndex()); + writeInterfaces(buff); + writeFields(buff); + writeMethods(buff); + classAttributes.write(buff); + } + + /** + * Returns a byte array representation of this class. + */ + public byte[] getBytes() throws java.io.IOException { + /* Write the class bytes to a file, for debugging. */ + + String writeClassToDirectory = + System.getProperty("filter.writeClassToDirectory"); + if (writeClassToDirectory != null) { + String filename = writeClassToDirectory + java.io.File.separator + + thisClassName.asString() + ".class"; + System.err.println("Writing class to file " + filename); + DataOutputStream stream = new DataOutputStream( + new java.io.FileOutputStream(filename)); + write(stream); + stream.close(); + } + + /* Get the class bytes and return them. */ + + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + write(new DataOutputStream(byteStream)); + + return byteStream.toByteArray(); + } + + //@olsen: added method + public void print(PrintStream out) { + print(out, 0); + } + + //@olsen: added 'indent' parameter + public void print(PrintStream out, int indent) { + constantPool.print(out, indent); + out.println(); + + ClassPrint.spaces(out, indent); + out.println("majorVersion = " + Integer.toString(majorVersion)); + ClassPrint.spaces(out, indent); + out.println("minorVersion = " + Integer.toString(minorVersion)); + ClassPrint.spaces(out, indent); + out.println("accessFlags = " + Integer.toString(accessFlags)); + ClassPrint.spaces(out, indent); + out.println("className = " + thisClassName.asString()); + ClassPrint.spaces(out, indent); + out.println("superClassName = " + superClassName.asString()); + ClassPrint.spaces(out, indent); + out.print("Interfaces ="); + for (int i=0; i<classInterfaces.size(); i++) { + out.print(" " + + ((ConstClass)classInterfaces.elementAt(i)).asString()); + } + out.println(); + + ClassPrint.spaces(out, indent); + out.println("fields ="); + for (int i=0; i<classFields.size(); i++) { + ((ClassField) classFields.elementAt(i)).print(out, indent + 3); + } + + ClassPrint.spaces(out, indent); + out.println("methods ="); + for (int i=0; i<classMethods.size(); i++) { + ((ClassMethod) classMethods.elementAt(i)).print(out, indent + 3); + } + + ClassPrint.spaces(out, indent); + out.println("attributes ="); + classAttributes.print(out, indent + 3); + + } + + //@olsen: made public + //@olsen: added 'out' and 'indent' parameters + public void summarize(PrintStream out, int indent) { + constantPool.summarize(out, indent); + int codeSize = 0; + for (int i=0; i<classMethods.size(); i++) { + codeSize += ((ClassMethod)classMethods.elementAt(i)).codeSize(); + } + ClassPrint.spaces(out, indent); + out.println(classMethods.size() + " methods in " + + codeSize + " bytes"); + ClassPrint.spaces(out, indent); + out.println(classFields.size() + " fields"); + } + + /* package local methods */ + + /* + * class file reading helpers + */ + private void readConstants (DataInputStream data) throws IOException { + constantPool = new ConstantPool(data); + } + + private void readInterfaces(DataInputStream data) throws IOException { + int nInterfaces = data.readUnsignedShort(); + while (nInterfaces-- > 0) { + int interfaceIndex = data.readUnsignedShort(); + ConstClass ci = null; + if (interfaceIndex != 0) + ci = (ConstClass) constantPool.constantAt(interfaceIndex); + classInterfaces.addElement(ci); + } + } + + private void writeInterfaces(DataOutputStream data) throws IOException { + data.writeShort(classInterfaces.size()); + for (int i=0; i<classInterfaces.size(); i++) { + ConstClass ci = (ConstClass) classInterfaces.elementAt(i); + int interfaceIndex = 0; + if (ci != null) + interfaceIndex = ci.getIndex(); + data.writeShort(interfaceIndex); + } + } + + private void readFields(DataInputStream data) throws IOException { + int nFields = data.readUnsignedShort(); + while (nFields-- > 0) { + classFields.addElement (ClassField.read(data, constantPool)); + } + } + + private void writeFields (DataOutputStream data) throws IOException { + data.writeShort(classFields.size()); + for (int i=0; i<classFields.size(); i++) + ((ClassField)classFields.elementAt(i)).write(data); + } + + private void readMethods (DataInputStream data) throws IOException { + int nMethods = data.readUnsignedShort(); + while (nMethods-- > 0) { + classMethods.addElement (ClassMethod.read(data, constantPool)); + } + } + + private void writeMethods (DataOutputStream data) throws IOException { + data.writeShort(classMethods.size()); + for (int i=0; i<classMethods.size(); i++) + ((ClassMethod)classMethods.elementAt(i)).write(data); + } + +} + +abstract class ArraySorter { + protected ArraySorter() {} + + /* return the size of the array being sorted */ + abstract int size(); + + /* return -1 if o1 < o2, 0 if o1 == o2, 1 if o1 > o2 */ + abstract int compare(int o1Index, int o2Index); + + /* Swap the elements at index o1Index and o2Index */ + abstract void swap(int o1Index, int o2Index); + + void sortArray() { + sortArray(0, size()-1); + } + + private void sortArray(int start, int end) { + if (end > start) { + swap(start, (start+end)/2); + int last = start; + for (int i = start+1; i<=end; i++) { + if (compare(i, start) < 0) + swap (++last, i); + } + swap(start, last); + sortArray(start, last-1); + sortArray(last+1, end); + } + } +} + +class InterfaceArraySorter extends ArraySorter { + private ConstClass theArray[]; + + InterfaceArraySorter(ConstClass[] interfaces) { + theArray = interfaces; + } + + /* return the size of the array being sorted */ + int size() { return theArray.length; } + + /* return -1 if o1 < o2, 0 if o1 == o2, 1 if o1 > o2 */ + int compare(int o1Index, int o2Index) { + return theArray[o1Index].asString().compareTo( + theArray[o2Index].asString()); + } + + /* Swap the elements at index o1Index and o2Index */ + void swap(int o1Index, int o2Index) { + ConstClass tmp = theArray[o1Index]; + theArray[o1Index] = theArray[o2Index]; + theArray[o2Index] = tmp; + } +} + +class FieldArraySorter extends ArraySorter { + private ClassField theArray[]; + + FieldArraySorter(ClassField[] fields) { + theArray = fields; + } + + /* return the size of the array being sorted */ + int size() { return theArray.length; } + + /* return -1 if o1 < o2, 0 if o1 == o2, 1 if o1 > o2 */ + int compare(int o1Index, int o2Index) { + return theArray[o1Index].name().asString().compareTo( + theArray[o2Index].name().asString()); + } + + /* Swap the elements at index o1Index and o2Index */ + void swap(int o1Index, int o2Index) { + ClassField tmp = theArray[o1Index]; + theArray[o1Index] = theArray[o2Index]; + theArray[o2Index] = tmp; + } +} + +class MethodArraySorter extends ArraySorter { + private ClassMethod theArray[]; + + MethodArraySorter(ClassMethod[] methods) { + theArray = methods; + } + + /* return the size of the array being sorted */ + int size() { return theArray.length; } + + /* return -1 if o1 < o2, 0 if o1 == o2, 1 if o1 > o2 */ + int compare(int o1Index, int o2Index) { + int cmp = theArray[o1Index].name().asString().compareTo( + theArray[o2Index].name().asString()); + if (cmp == 0) { + cmp = theArray[o1Index].signature().asString().compareTo( + theArray[o2Index].signature().asString()); + } + return cmp; + } + + /* Swap the elements at index o1Index and o2Index */ + void swap(int o1Index, int o2Index) { + ClassMethod tmp = theArray[o1Index]; + theArray[o1Index] = theArray[o2Index]; + theArray[o2Index] = tmp; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMember.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMember.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMember.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMember.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,116 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; +import java.util.Stack; + +/** + * ClassMember is a common base class for ClassMethod and ClassField + */ +abstract public class ClassMember implements VMConstants { + + /* public accessors */ + + /** + * Is the member static? + */ + final public boolean isStatic() { + return (access() & ACCStatic) != 0; + } + + /** + * Is the member final? + */ + final public boolean isFinal() { + return (access() & ACCFinal) != 0; + } + + /** + * Turn on or off the final qualifier for the member. + */ + public void setIsFinal(boolean newFinal) { + if (newFinal) + setAccess(access() | ACCFinal); + else + setAccess(access() & ~ACCFinal); + } + + /** + * Is the member private? + */ + final public boolean isPrivate() { + return (access() & ACCPrivate) != 0; + } + + /** + * Is the member protected? + */ + final public boolean isProtected() { + return (access() & ACCProtected) != 0; + } + + /** + * Is the member public? + */ + final public boolean isPublic() { + return (access() & ACCPublic) != 0; + } + + /* These are expected to be implemented by subtypes */ + + /** + * Return the access flags for the method - see VMConstants + */ + abstract public int access(); + + /** + * Set the access flags for the method - see VMConstants + */ + abstract public void setAccess(int newAccess); + + /** + * Return the name of the member + */ + abstract public ConstUtf8 name(); + + /** + * Return the type signature of the method + */ + abstract public ConstUtf8 signature(); + + /** + * Return the attributes associated with the member + */ + abstract public AttributeVector attributes(); + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof ClassMember)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + ClassMember other = (ClassMember)obj; + + return true; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMethod.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMethod.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMethod.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassMethod.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,246 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; +import java.util.Vector; +import java.util.Stack; +import java.util.Enumeration; + +/** + * ClassMethod models the static and non-static methods of a class within + * a class file. This includes constructors and initializer code. + */ +public class ClassMethod extends ClassMember { + /* The name of the constructor code */ + public final static String intializerName = "<init>"; + + /* The name of the static initializer code */ + public final static String staticIntializerName = "<clinit>"; + + /* access flag bit mask - see VMConstants */ + private int accessFlags; + + /* The name of the method */ + private ConstUtf8 methodName; + + /* The type signature of the method */ + private ConstUtf8 methodSignature; + + /* The attributes associated with the field */ + private AttributeVector methodAttributes; + + + /* public accessors */ + + /** + * Return the access flags for the method - see VMConstants + */ + public int access() { + return accessFlags; + } + + /** + * Update the access flags for the field - see VMConstants + */ + public void setAccess(int newFlags) { + accessFlags = newFlags; + } + + /** + * Is the method abstract? + */ + public boolean isAbstract() { + return (accessFlags & ACCAbstract) != 0; + } + + /** + * Is the method native? + */ + public boolean isNative() { + return (accessFlags & ACCNative) != 0; + } + + /** + * Return the name of the method + */ + public ConstUtf8 name() { + return methodName; + } + + /** + * Change the name of the method + */ + public void changeName(ConstUtf8 name) { + methodName = name; + } + + /** + * Return the type signature of the method + */ + public ConstUtf8 signature() { + return methodSignature; + } + + /** + * Change the type signature of the method + */ + public void changeSignature(ConstUtf8 newSig) { + methodSignature = newSig; + } + + /** + * Return the attributes associated with the method + */ + public AttributeVector attributes() { + return methodAttributes; + } + + /** + * Construct a class method object + */ + + public ClassMethod(int accFlags, ConstUtf8 name, ConstUtf8 sig, + AttributeVector methodAttrs) { + accessFlags = accFlags; + methodName = name; + methodSignature = sig; + methodAttributes = methodAttrs; + } + + /** + * Returns the size of the method byteCode (if any) + */ + int codeSize() { + CodeAttribute codeAttr = codeAttribute(); + return (codeAttr == null) ? 0 : codeAttr.codeSize(); + } + + /** + * Returns the CodeAttribute associated with this method (if any) + */ + public CodeAttribute codeAttribute() { + Enumeration e = methodAttributes.elements(); + while (e.hasMoreElements()) { + ClassAttribute attr = (ClassAttribute) e.nextElement(); + if (attr instanceof CodeAttribute) + return (CodeAttribute) attr; + } + return null; + } + + /** + * Returns the ExceptionsAttribute associated with this method (if any) + */ + //@olsen: added method + public ExceptionsAttribute exceptionsAttribute() { + Enumeration e = methodAttributes.elements(); + while (e.hasMoreElements()) { + ClassAttribute attr = (ClassAttribute) e.nextElement(); + if (attr instanceof ExceptionsAttribute) + return (ExceptionsAttribute) attr; + } + return null; + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof ClassMethod)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + ClassMethod other = (ClassMethod)obj; + + if (!super.isEqual(msg, other)) { + return false; + } + + if (this.accessFlags != other.accessFlags) { + msg.push(String.valueOf("accessFlags = 0x" + + Integer.toHexString(other.accessFlags))); + msg.push(String.valueOf("accessFlags = 0x" + + Integer.toHexString(this.accessFlags))); + return false; + } + if (!this.methodName.isEqual(msg, other.methodName)) { + msg.push(String.valueOf("methodName = " + + other.methodName)); + msg.push(String.valueOf("methodName = " + + this.methodName)); + return false; + } + if (!this.methodSignature.isEqual(msg, other.methodSignature)) { + msg.push(String.valueOf("methodSignature = " + + other.methodSignature)); + msg.push(String.valueOf("methodSignature = " + + this.methodSignature)); + return false; + } + if (!this.methodAttributes.isEqual(msg, other.methodAttributes)) { + msg.push(String.valueOf("methodAttributes = " + + other.methodAttributes)); + msg.push(String.valueOf("methodAttributes = " + + this.methodAttributes)); + return false; + } + return true; + } + + //@olsen: made public + public void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.print("'" + methodName.asString() + "'"); + out.print(" sig = " + methodSignature.asString()); + out.print(" accessFlags = " + Integer.toString(accessFlags)); + out.println(" attributes:"); + methodAttributes.print(out, indent+2); + } + + /* package local methods */ + + static ClassMethod read(DataInputStream data, ConstantPool pool) + throws IOException { + int accessFlags = data.readUnsignedShort(); + int nameIndex = data.readUnsignedShort(); + int sigIndex = data.readUnsignedShort(); + ClassMethod f = + new ClassMethod(accessFlags, + (ConstUtf8) pool.constantAt(nameIndex), + (ConstUtf8) pool.constantAt(sigIndex), + null); + + f.methodAttributes = AttributeVector.readAttributes(data, pool); + return f; + } + + void write(DataOutputStream data) throws IOException { + CodeAttribute codeAttr = codeAttribute(); + data.writeShort(accessFlags); + data.writeShort(methodName.getIndex()); + data.writeShort(methodSignature.getIndex()); + methodAttributes.write(data); + } +} + + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassPrint.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassPrint.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassPrint.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ClassPrint.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,34 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; + +/** + * A really simple class with printing utilities + */ + +class ClassPrint { + /** + * Print 'nspaces' spaces to the print stream + */ + public static void spaces(PrintStream ps, int nspaces) { + while (nspaces-- > 0) + ps.print(' '); + } +}