in src/main/java/org/apache/bsf/util/event/generator/EventAdapterGenerator.java [202:554]
public static Class makeEventAdapterClass(final Class listenerType, final boolean writeClassFile) {
logger.debug("EventAdapterGenerator");
if (EVENTLISTENER.isAssignableFrom(listenerType)) {
boolean exceptionable = false;
boolean nonExceptionable = false;
byte[] constantPool = null;
short cpBaseIndex;
short cpCount = 0;
short cpExceptionBaseIndex;
short exceptionableCount;
short nonExceptionableCount;
/* Derive Names */
final String listenerTypeName = listenerType.getName();
logger.debug("ListenerTypeName: " + listenerTypeName);
final String adapterClassName = CLASSPACKAGE
+ (listenerTypeName.endsWith("Listener") ? listenerTypeName.substring(0, listenerTypeName.length() - 8) : listenerTypeName).replace('.',
'_')
+ "Adapter";
String finalAdapterClassName = adapterClassName;
Class cached = null;
int suffixIndex = 0;
do {
if (null != (cached = ldr.getLoadedClass(finalAdapterClassName))) {
logger.debug("cached: " + cached);
try {
if (!listenerType.isAssignableFrom(cached)) {
finalAdapterClassName = adapterClassName + "_" + suffixIndex++;
} else {
return cached;
}
} catch (final VerifyError ex) {
System.err.println(ex.getMessage());
ex.printStackTrace();
return cached;
}
}
} while (cached != null);
final String eventListenerName = listenerTypeName.replace('.', '/');
/* method stuff */
final java.lang.reflect.Method[] lms = listenerType.getMethods();
/* ****************************************************************************************** */
// Listener interface
// Class name
cpCount += 4;
// cp item 17
constantPool = Bytecode.addUtf8(constantPool, eventListenerName);
// cp item 18
constantPool = Bytecode.addUtf8(constantPool, finalAdapterClassName);
// cp item 19
constantPool = Bytecode.addClass(constantPool, (short) 17);
// cp item 20
constantPool = Bytecode.addClass(constantPool, (short) 18);
// do we have nonExceptionalble event, exceptionable or both
for (int i = 0; i < lms.length; ++i) {
final Class[] exceptionTypes = lms[i].getExceptionTypes();
if (0 < exceptionTypes.length) {
exceptionable = true;
} else {
nonExceptionable = true;
}
} /* End for */
/* ****************************************************************************************** */
// optional inclusion of nonexceptional events affects exceptional events indices
nonExceptionableCount = 0;
if (nonExceptionable) {
nonExceptionableCount = 3;
cpCount += nonExceptionableCount;
// cp item 21
constantPool = Bytecode.addUtf8(constantPool, "processEvent");
// cp item 22
constantPool = Bytecode.addNameAndType(constantPool, (short) 21, (short) 8);
// cp item 23
constantPool = Bytecode.addInterfaceMethodRef(constantPool, (short) 12, (short) 22);
}
/* ****************************************************************************************** */
// optional inclusion of exceptional events affects CP Items which follow for specific methods
exceptionableCount = 0;
if (exceptionable) {
final int classIndex = BASECPCOUNT + cpCount + 1;
final int nameIndex = BASECPCOUNT + cpCount + 0;
final int natIndex = BASECPCOUNT + cpCount + 3;
exceptionableCount = 5;
cpCount += exceptionableCount;
// cp item 24 or 21
constantPool = Bytecode.addUtf8(constantPool, "processExceptionableEvent");
// cp item 25 or 22
constantPool = Bytecode.addUtf8(constantPool, "java/lang/Exception");
// cp item 26 or 23
constantPool = Bytecode.addClass(constantPool, (short) classIndex);
// cp item 27 or 24
constantPool = Bytecode.addNameAndType(constantPool, (short) nameIndex, (short) 8);
// cp item 28 or 25
constantPool = Bytecode.addInterfaceMethodRef(constantPool, (short) 12, (short) natIndex);
}
// base index for method cp references
cpBaseIndex = (short) (BASECPCOUNT + cpCount);
logger.debug("cpBaseIndex: " + cpBaseIndex);
for (int i = 0; i < lms.length; ++i) {
final String eventMethodName = lms[i].getName();
final String eventName = lms[i].getParameterTypes()[0].getName().replace('.', '/');
cpCount += 3;
// cp items for event methods
constantPool = Bytecode.addUtf8(constantPool, eventMethodName);
constantPool = Bytecode.addUtf8(constantPool, ("(L" + eventName + ";)V"));
constantPool = Bytecode.addString(constantPool, (short) (BASECPCOUNT + cpCount - 3));
} /* End for */
final boolean[] propertyChangeFlag = new boolean[lms.length];
int cpIndexPCE = 0;
for (int i = 0; i < lms.length; ++i) {
final String eventName = lms[i].getParameterTypes()[0].getName().replace('.', '/');
// cp items for PropertyChangeEvent special handling
if (eventName.equalsIgnoreCase("java/beans/PropertyChangeEvent")) {
propertyChangeFlag[i] = true;
if (0 == cpIndexPCE) {
constantPool = Bytecode.addUtf8(constantPool, eventName);
constantPool = Bytecode.addUtf8(constantPool, "getPropertyName");
constantPool = Bytecode.addUtf8(constantPool, "()Ljava/lang/String;");
constantPool = Bytecode.addClass(constantPool, (short) (BASECPCOUNT + cpCount));
constantPool = Bytecode.addNameAndType(constantPool, (short) (BASECPCOUNT + cpCount + 1), (short) (BASECPCOUNT + cpCount + 2));
constantPool = Bytecode.addMethodRef(constantPool, (short) (BASECPCOUNT + cpCount + 3), (short) (BASECPCOUNT + cpCount + 4));
cpCount += 6;
cpIndexPCE = BASECPCOUNT + cpCount - 1;
}
} else {
propertyChangeFlag[i] = false;
}
} /* End for */
cpExceptionBaseIndex = (short) (BASECPCOUNT + cpCount);
logger.debug("cpExceptionBaseIndex: " + cpExceptionBaseIndex);
final int excpIndex[][] = new int[lms.length][];
for (int i = 0; i < lms.length; ++i) {
final Class[] exceptionTypes = lms[i].getExceptionTypes();
excpIndex[i] = new int[exceptionTypes.length];
for (int j = 0; j < exceptionTypes.length; j++) {
constantPool = Bytecode.addUtf8(constantPool, exceptionTypes[j].getName().replace('.', '/'));
constantPool = Bytecode.addClass(constantPool, (short) (BASECPCOUNT + cpCount));
excpIndex[i][j] = BASECPCOUNT + cpCount + 1;
cpCount += 2;
}
} /* End for */
/* end constant pool */
/* ************************************************************************************************ */
// put the Class byte array together
/* start */
byte[] newClass = CLASSHEADER; // magic, version (fixed)
final short count = (short) (BASECPCOUNT + cpCount);
newClass = ByteUtility.addBytes(newClass, count); // constant_pool_count (variable)
newClass = ByteUtility.addBytes(newClass, BASECP); // constant_pool (fixed)
newClass = ByteUtility.addBytes(newClass, constantPool); // constant_pool (variable)
newClass = ByteUtility.addBytes(newClass, FIXEDCLASSBYTES); // see FIXEDCLASSBYTES (fixed)
newClass = ByteUtility.addBytes(newClass, (short) (lms.length + 1)); // method_count (variable)
newClass = ByteUtility.addBytes(newClass, INITMETHOD); // constructor <init> (fixed)
// methods
/* ****************************************************************************************** */
/* loop over listener methods from listenerType */
for (int i = 0; i < lms.length; ++i) {
newClass = ByteUtility.addBytes(newClass, (short) 1); // access_flags (fixed)
newClass = ByteUtility.addBytes(newClass, (short) (cpBaseIndex + 3 * i + 0)); // name_index (variable)
newClass = ByteUtility.addBytes(newClass, (short) (cpBaseIndex + 3 * i + 1)); // descriptor_index (variable)
newClass = ByteUtility.addBytes(newClass, (short) 1); // attribute_count (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 3); // attribute_name_index code(fixed)
// Code Attribute Length
int length = 32;
if (0 < excpIndex[i].length) {
length += 5 + 8 * (1 + excpIndex[i].length);
}
if (propertyChangeFlag[i]) {
length += 2;
}
newClass = ByteUtility.addBytes(newClass, (long) length); // attribute_length (variable)
// start code attribute
newClass = ByteUtility.addBytes(newClass, (short) 6); // max_stack (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 3); // max_locals (fixed)
// Code Length
length = 20;
if (exceptionable && 0 < excpIndex[i].length) {
length += 5;
}
if (propertyChangeFlag[i]) {
length += 2;
}
newClass = ByteUtility.addBytes(newClass, (long) length); // code_length (variable)
// start code
newClass = ByteUtility.addBytes(newClass, (byte) 0x2A); // aload_0 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0xB4); // getfield (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 15); // index (fixed)
if (propertyChangeFlag[i]) { // the propertyName is passed as the first parameter
newClass = ByteUtility.addBytes(newClass, (byte) 0x2B); // aload_1 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0xB6); // invokevirtual (fixed)
newClass = ByteUtility.addBytes(newClass, (short) cpIndexPCE); // methodref (variable)
} else { // the eventMethodName is passed as the first parameter
// Target for method invocation.
newClass = ByteUtility.addBytes(newClass, (byte) 0x12); // ldc (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) (cpBaseIndex + 3 * i + 2)); // index (byte) (variable)
}
newClass = ByteUtility.addBytes(newClass, (byte) 0x04); // iconst_1 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0xBD); // anewarray (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 10); // Class java/lang/Object (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0x59); // dup (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0x03); // iconst_0 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0x2B); // aload_1 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0x53); // aastore (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0xB9); // invokeinterface (fixed)
// index to processEvent or processExceptionableEvent method
length = 23; // actually an index into cp
if (exceptionable && nonExceptionable) { // interface method index
if (0 < lms[i].getExceptionTypes().length) {
length += 5;
}
} else if (exceptionable) {
length += 2;
}
newClass = ByteUtility.addBytes(newClass, (short) length); // index (process??????...) (variable)
newClass = ByteUtility.addBytes(newClass, (byte) 0x03); // iconst_0 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0x00); // noop (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0xB1); // return (fixed)
if (exceptionable && 0 < excpIndex[i].length) { // exception code
newClass = ByteUtility.addBytes(newClass, (byte) 0x4D); // astore_2 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0x2C); // aload_2 (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0xBF); // athrow (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0x57); // pop (fixed)
newClass = ByteUtility.addBytes(newClass, (byte) 0xB1); // return (fixed)
// end code
// exception table
length = excpIndex[i].length;
newClass = ByteUtility.addBytes(newClass, (short) (1 + length)); // exception_table_length (variable)
for (int j = 0; j < length; j++) { // catch exception types and rethrow
newClass = ByteUtility.addBytes(newClass, (short) 0); // start_pc (fixed)
if (propertyChangeFlag[i]) {
newClass = ByteUtility.addBytes(newClass, (short) 21); // end_pc (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 22); // handler_pc (fixed)
} else {
newClass = ByteUtility.addBytes(newClass, (short) 19); // end_pc (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 20); // handler_pc (fixed)
}
newClass = ByteUtility.addBytes(newClass, (short) excpIndex[i][j]); // catch_type (variable)
}
// catch "exception" and trap it
newClass = ByteUtility.addBytes(newClass, (short) 0); // start_pc (fixed)
if (propertyChangeFlag[i]) {
newClass = ByteUtility.addBytes(newClass, (short) 21); // end_pc (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 25); // handler_pc (fixed)
} else {
newClass = ByteUtility.addBytes(newClass, (short) 19); // end_pc (fixed)
newClass = ByteUtility.addBytes(newClass, (short) 23); // handler_pc (fixed)
}
if (nonExceptionable) {
newClass = ByteUtility.addBytes(newClass, (short) 26);
} // catch_type (fixed)
else // or
{
newClass = ByteUtility.addBytes(newClass, (short) 23);
} // catch_type (fixed)
} else {
newClass = ByteUtility.addBytes(newClass, (short) 0);
} // exception_table_length (fixed)
// attributes on the code attribute (none)
newClass = ByteUtility.addBytes(newClass, (short) 0); // attribute_count (fixed)
// end code attribute
} /* End for */
// Class Attributes (none for this)
newClass = ByteUtility.addBytes(newClass, (short) 0); // attribute_count (fixed)
/* done */
logger.debug("adapterName: " + finalAdapterClassName);
logger.debug("cpCount: " + count + " = " + BASECPCOUNT + " + " + cpCount);
logger.debug("methodCount: " + (lms.length + 1));
// output to disk class file
/* ****************************************************************************************** */
// now create the class and load it
// return the Class.
if (writeClassFile) {
try {
// removed "WRITEDIRECTORY+", as this path is already part of 'finalAdapterClassName'
final FileOutputStream fos = new FileOutputStream(finalAdapterClassName + ".class");
fos.write(newClass);
fos.close();
} catch (final IOException ex) {
System.err.println(ex.getMessage());
ex.printStackTrace();
}
try {
final Class ret = ldr.loadClass(finalAdapterClassName);
logger.debug("EventAdapterGenerator: " + ret.getName() + " dynamically generated");
return ret;
} catch (final ClassNotFoundException ex) {
System.err.println(ex.getMessage());
ex.printStackTrace();
}
}
try {
final Class ret = ldr.defineClass(finalAdapterClassName, newClass);
logger.debug("EventAdapterGenerator: " + ret.getName() + " dynamically generated");
return ret;
}
catch (final Throwable ex) // rgf, 2012-01-15
{
System.err.println(ex.getMessage());
ex.printStackTrace();
}
}
return null;
}