";
+ public static final String SUID_FIELD_NAME = "serialVersionUID";
+
+ public static final int PRIVATE_FINAL_STATIC = ACC_PRIVATE | ACC_FINAL | ACC_STATIC;
+
+ public static final int SWITCH_STYLE_TRIE = 0;
+ public static final int SWITCH_STYLE_HASH = 1;
+ public static final int SWITCH_STYLE_HASHONLY = 2;
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/Converter.java b/blade-aop/src/main/java/net/sf/cglib/core/Converter.java
new file mode 100644
index 000000000..00414358d
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/Converter.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+public interface Converter {
+ Object convert(Object value, Class target, Object context);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/Customizer.java b/blade-aop/src/main/java/net/sf/cglib/core/Customizer.java
new file mode 100644
index 000000000..4297b163a
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/Customizer.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import org.objectweb.asm.Type;
+
+/**
+ * Customizes key types for {@link KeyFactory} when building equals, hashCode, and toString.
+ * For customization of field types, use {@link FieldTypeCustomizer}
+ *
+ * @see KeyFactory#CLASS_BY_NAME
+ */
+public interface Customizer extends KeyFactoryCustomizer {
+ void customize(CodeEmitter e, Type type);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/DebuggingClassWriter.java b/blade-aop/src/main/java/net/sf/cglib/core/DebuggingClassWriter.java
new file mode 100644
index 000000000..78f1ae7d4
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/DebuggingClassWriter.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.io.*;
+import java.lang.reflect.Constructor;
+
+public class DebuggingClassWriter extends ClassVisitor {
+
+ public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation";
+
+ private static String debugLocation;
+ private static Constructor traceCtor;
+
+ private String className;
+ private String superName;
+
+ static {
+ debugLocation = System.getProperty(DEBUG_LOCATION_PROPERTY);
+ if (debugLocation != null) {
+ System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'");
+ try {
+ Class clazz = Class.forName("org.objectweb.asm.util.TraceClassVisitor");
+ traceCtor = clazz.getConstructor(new Class[]{ClassVisitor.class, PrintWriter.class});
+ } catch (Throwable ignore) {
+ }
+ }
+ }
+
+ public DebuggingClassWriter(int flags) {
+ super(Opcodes.ASM5, new ClassWriter(flags));
+ }
+
+ public void visit(int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ className = name.replace('/', '.');
+ this.superName = superName.replace('/', '.');
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public String getSuperName() {
+ return superName;
+ }
+
+ public byte[] toByteArray() {
+
+ return (byte[]) java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Object run() {
+
+
+ byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray();
+ if (debugLocation != null) {
+ String dirs = className.replace('.', File.separatorChar);
+ try {
+ new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
+
+ File file = new File(new File(debugLocation), dirs + ".class");
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
+ try {
+ out.write(b);
+ } finally {
+ out.close();
+ }
+
+ if (traceCtor != null) {
+ file = new File(new File(debugLocation), dirs + ".asm");
+ out = new BufferedOutputStream(new FileOutputStream(file));
+ try {
+ ClassReader cr = new ClassReader(b);
+ PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
+ ClassVisitor tcv = (ClassVisitor)traceCtor.newInstance(new Object[]{null, pw});
+ cr.accept(tcv, 0);
+ pw.flush();
+ } finally {
+ out.close();
+ }
+ }
+ } catch (Exception e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+ return b;
+ }
+ });
+
+ }
+ }
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/DefaultGeneratorStrategy.java b/blade-aop/src/main/java/net/sf/cglib/core/DefaultGeneratorStrategy.java
new file mode 100644
index 000000000..dd876c760
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/DefaultGeneratorStrategy.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import org.objectweb.asm.ClassWriter;
+
+public class DefaultGeneratorStrategy implements GeneratorStrategy {
+ public static final DefaultGeneratorStrategy INSTANCE = new DefaultGeneratorStrategy();
+
+ public byte[] generate(ClassGenerator cg) throws Exception {
+ DebuggingClassWriter cw = getClassVisitor();
+ transform(cg).generateClass(cw);
+ return transform(cw.toByteArray());
+ }
+
+ protected DebuggingClassWriter getClassVisitor() throws Exception {
+ return new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES);
+ }
+
+ protected final ClassWriter getClassWriter() {
+ // Cause compile / runtime errors for people who implemented the old
+ // interface without using @Override
+ throw new UnsupportedOperationException("You are calling " +
+ "getClassWriter, which no longer exists in this cglib version.");
+ }
+
+ protected byte[] transform(byte[] b) throws Exception {
+ return b;
+ }
+
+ protected ClassGenerator transform(ClassGenerator cg) throws Exception {
+ return cg;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/DefaultNamingPolicy.java b/blade-aop/src/main/java/net/sf/cglib/core/DefaultNamingPolicy.java
new file mode 100644
index 000000000..dfdb6ab63
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/DefaultNamingPolicy.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import java.util.Set;
+
+/**
+ * The default policy used by {@link AbstractClassGenerator}.
+ * Generates names such as
+ * net.sf.cglib.Foo$$EnhancerByCGLIB$$38272841
+ * This is composed of a prefix based on the name of the superclass, a fixed
+ * string incorporating the CGLIB class responsible for generation, and a
+ * hashcode derived from the parameters used to create the object. If the same
+ * name has been previously been used in the same ClassLoader, a
+ * suffix is added to ensure uniqueness.
+ */
+public class DefaultNamingPolicy implements NamingPolicy {
+ public static final DefaultNamingPolicy INSTANCE = new DefaultNamingPolicy();
+
+ /**
+ * This allows to test collisions of {@code key.hashCode()}.
+ */
+ private final static boolean STRESS_HASH_CODE = Boolean.getBoolean("net.sf.cglib.test.stressHashCodes");
+
+ public String getClassName(String prefix, String source, Object key, Predicate names) {
+ if (prefix == null) {
+ prefix = "net.sf.cglib.empty.Object";
+ } else if (prefix.startsWith("java")) {
+ prefix = "$" + prefix;
+ }
+ String base =
+ prefix + "$$" +
+ source.substring(source.lastIndexOf('.') + 1) +
+ getTag() + "$$" +
+ Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode());
+ String attempt = base;
+ int index = 2;
+ while (names.evaluate(attempt))
+ attempt = base + "_" + index++;
+ return attempt;
+ }
+
+ /**
+ * Returns a string which is incorporated into every generated class name.
+ * By default returns "ByCGLIB"
+ */
+ protected String getTag() {
+ return "ByCGLIB";
+ }
+
+ public int hashCode() {
+ return getTag().hashCode();
+ }
+
+ public boolean equals(Object o) {
+ return (o instanceof DefaultNamingPolicy) && ((DefaultNamingPolicy) o).getTag().equals(getTag());
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/DuplicatesPredicate.java b/blade-aop/src/main/java/net/sf/cglib/core/DuplicatesPredicate.java
new file mode 100644
index 000000000..6ebee2c35
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/DuplicatesPredicate.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+public class DuplicatesPredicate implements Predicate {
+ private Set unique = new HashSet();
+
+ public boolean evaluate(Object arg) {
+ return unique.add(MethodWrapper.create((Method)arg));
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/EmitUtils.java b/blade-aop/src/main/java/net/sf/cglib/core/EmitUtils.java
new file mode 100644
index 000000000..07bdab156
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/EmitUtils.java
@@ -0,0 +1,960 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.*;
+
+import net.sf.cglib.core.internal.CustomizerRegistry;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+public class EmitUtils {
+ private static final Signature CSTRUCT_NULL =
+ TypeUtils.parseConstructor("");
+ private static final Signature CSTRUCT_THROWABLE =
+ TypeUtils.parseConstructor("Throwable");
+
+ private static final Signature GET_NAME =
+ TypeUtils.parseSignature("String getName()");
+ private static final Signature HASH_CODE =
+ TypeUtils.parseSignature("int hashCode()");
+ private static final Signature EQUALS =
+ TypeUtils.parseSignature("boolean equals(Object)");
+ private static final Signature STRING_LENGTH =
+ TypeUtils.parseSignature("int length()");
+ private static final Signature STRING_CHAR_AT =
+ TypeUtils.parseSignature("char charAt(int)");
+ private static final Signature FOR_NAME =
+ TypeUtils.parseSignature("Class forName(String)");
+ private static final Signature DOUBLE_TO_LONG_BITS =
+ TypeUtils.parseSignature("long doubleToLongBits(double)");
+ private static final Signature FLOAT_TO_INT_BITS =
+ TypeUtils.parseSignature("int floatToIntBits(float)");
+ private static final Signature TO_STRING =
+ TypeUtils.parseSignature("String toString()");
+ private static final Signature APPEND_STRING =
+ TypeUtils.parseSignature("StringBuffer append(String)");
+ private static final Signature APPEND_INT =
+ TypeUtils.parseSignature("StringBuffer append(int)");
+ private static final Signature APPEND_DOUBLE =
+ TypeUtils.parseSignature("StringBuffer append(double)");
+ private static final Signature APPEND_FLOAT =
+ TypeUtils.parseSignature("StringBuffer append(float)");
+ private static final Signature APPEND_CHAR =
+ TypeUtils.parseSignature("StringBuffer append(char)");
+ private static final Signature APPEND_LONG =
+ TypeUtils.parseSignature("StringBuffer append(long)");
+ private static final Signature APPEND_BOOLEAN =
+ TypeUtils.parseSignature("StringBuffer append(boolean)");
+ private static final Signature LENGTH =
+ TypeUtils.parseSignature("int length()");
+ private static final Signature SET_LENGTH =
+ TypeUtils.parseSignature("void setLength(int)");
+ private static final Signature GET_DECLARED_METHOD =
+ TypeUtils.parseSignature("java.lang.reflect.Method getDeclaredMethod(String, Class[])");
+
+
+
+ public static final ArrayDelimiters DEFAULT_DELIMITERS = new ArrayDelimiters("{", ", ", "}");
+
+ private EmitUtils() {
+ }
+
+ public static void factory_method(ClassEmitter ce, Signature sig) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, sig, null);
+ e.new_instance_this();
+ e.dup();
+ e.load_args();
+ e.invoke_constructor_this(TypeUtils.parseConstructor(sig.getArgumentTypes()));
+ e.return_value();
+ e.end_method();
+ }
+
+ public static void null_constructor(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_NULL, null);
+ e.load_this();
+ e.super_invoke_constructor();
+ e.return_value();
+ e.end_method();
+ }
+
+ /**
+ * Process an array on the stack. Assumes the top item on the stack
+ * is an array of the specified type. For each element in the array,
+ * puts the element on the stack and triggers the callback.
+ * @param type the type of the array (type.isArray() must be true)
+ * @param callback the callback triggered for each element
+ */
+ public static void process_array(CodeEmitter e, Type type, ProcessArrayCallback callback) {
+ Type componentType = TypeUtils.getComponentType(type);
+ Local array = e.make_local();
+ Local loopvar = e.make_local(Type.INT_TYPE);
+ Label loopbody = e.make_label();
+ Label checkloop = e.make_label();
+ e.store_local(array);
+ e.push(0);
+ e.store_local(loopvar);
+ e.goTo(checkloop);
+
+ e.mark(loopbody);
+ e.load_local(array);
+ e.load_local(loopvar);
+ e.array_load(componentType);
+ callback.processElement(componentType);
+ e.iinc(loopvar, 1);
+
+ e.mark(checkloop);
+ e.load_local(loopvar);
+ e.load_local(array);
+ e.arraylength();
+ e.if_icmp(e.LT, loopbody);
+ }
+
+ /**
+ * Process two arrays on the stack in parallel. Assumes the top two items on the stack
+ * are arrays of the specified class. The arrays must be the same length. For each pair
+ * of elements in the arrays, puts the pair on the stack and triggers the callback.
+ * @param type the type of the arrays (type.isArray() must be true)
+ * @param callback the callback triggered for each pair of elements
+ */
+ public static void process_arrays(CodeEmitter e, Type type, ProcessArrayCallback callback) {
+ Type componentType = TypeUtils.getComponentType(type);
+ Local array1 = e.make_local();
+ Local array2 = e.make_local();
+ Local loopvar = e.make_local(Type.INT_TYPE);
+ Label loopbody = e.make_label();
+ Label checkloop = e.make_label();
+ e.store_local(array1);
+ e.store_local(array2);
+ e.push(0);
+ e.store_local(loopvar);
+ e.goTo(checkloop);
+
+ e.mark(loopbody);
+ e.load_local(array1);
+ e.load_local(loopvar);
+ e.array_load(componentType);
+ e.load_local(array2);
+ e.load_local(loopvar);
+ e.array_load(componentType);
+ callback.processElement(componentType);
+ e.iinc(loopvar, 1);
+
+ e.mark(checkloop);
+ e.load_local(loopvar);
+ e.load_local(array1);
+ e.arraylength();
+ e.if_icmp(e.LT, loopbody);
+ }
+
+ public static void string_switch(CodeEmitter e, String[] strings, int switchStyle, ObjectSwitchCallback callback) {
+ try {
+ switch (switchStyle) {
+ case Constants.SWITCH_STYLE_TRIE:
+ string_switch_trie(e, strings, callback);
+ break;
+ case Constants.SWITCH_STYLE_HASH:
+ string_switch_hash(e, strings, callback, false);
+ break;
+ case Constants.SWITCH_STYLE_HASHONLY:
+ string_switch_hash(e, strings, callback, true);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown switch style " + switchStyle);
+ }
+ } catch (RuntimeException ex) {
+ throw ex;
+ } catch (Error ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new CodeGenerationException(ex);
+ }
+ }
+
+ private static void string_switch_trie(final CodeEmitter e,
+ String[] strings,
+ final ObjectSwitchCallback callback) throws Exception {
+ final Label def = e.make_label();
+ final Label end = e.make_label();
+ final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
+ public Object transform(Object value) {
+ return new Integer(((String)value).length());
+ }
+ });
+ e.dup();
+ e.invoke_virtual(Constants.TYPE_STRING, STRING_LENGTH);
+ e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
+ public void processCase(int key, Label ignore_end) throws Exception {
+ List bucket = (List)buckets.get(new Integer(key));
+ stringSwitchHelper(e, bucket, callback, def, end, 0);
+ }
+ public void processDefault() {
+ e.goTo(def);
+ }
+ });
+ e.mark(def);
+ e.pop();
+ callback.processDefault();
+ e.mark(end);
+ }
+
+ private static void stringSwitchHelper(final CodeEmitter e,
+ List strings,
+ final ObjectSwitchCallback callback,
+ final Label def,
+ final Label end,
+ final int index) throws Exception {
+ final int len = ((String)strings.get(0)).length();
+ final Map buckets = CollectionUtils.bucket(strings, new Transformer() {
+ public Object transform(Object value) {
+ return new Integer(((String)value).charAt(index));
+ }
+ });
+ e.dup();
+ e.push(index);
+ e.invoke_virtual(Constants.TYPE_STRING, STRING_CHAR_AT);
+ e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
+ public void processCase(int key, Label ignore_end) throws Exception {
+ List bucket = (List)buckets.get(new Integer(key));
+ if (index + 1 == len) {
+ e.pop();
+ callback.processCase(bucket.get(0), end);
+ } else {
+ stringSwitchHelper(e, bucket, callback, def, end, index + 1);
+ }
+ }
+ public void processDefault() {
+ e.goTo(def);
+ }
+ });
+ }
+
+ static int[] getSwitchKeys(Map buckets) {
+ int[] keys = new int[buckets.size()];
+ int index = 0;
+ for (Iterator it = buckets.keySet().iterator(); it.hasNext();) {
+ keys[index++] = ((Integer)it.next()).intValue();
+ }
+ Arrays.sort(keys);
+ return keys;
+ }
+
+ private static void string_switch_hash(final CodeEmitter e,
+ final String[] strings,
+ final ObjectSwitchCallback callback,
+ final boolean skipEquals) throws Exception {
+ final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
+ public Object transform(Object value) {
+ return new Integer(value.hashCode());
+ }
+ });
+ final Label def = e.make_label();
+ final Label end = e.make_label();
+ e.dup();
+ e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
+ e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
+ public void processCase(int key, Label ignore_end) throws Exception {
+ List bucket = (List)buckets.get(new Integer(key));
+ Label next = null;
+ if (skipEquals && bucket.size() == 1) {
+ if (skipEquals)
+ e.pop();
+ callback.processCase((String)bucket.get(0), end);
+ } else {
+ for (Iterator it = bucket.iterator(); it.hasNext();) {
+ String string = (String)it.next();
+ if (next != null) {
+ e.mark(next);
+ }
+ if (it.hasNext()) {
+ e.dup();
+ }
+ e.push(string);
+ e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
+ if (it.hasNext()) {
+ e.if_jump(e.EQ, next = e.make_label());
+ e.pop();
+ } else {
+ e.if_jump(e.EQ, def);
+ }
+ callback.processCase(string, end);
+ }
+ }
+ }
+ public void processDefault() {
+ e.pop();
+ }
+ });
+ e.mark(def);
+ callback.processDefault();
+ e.mark(end);
+ }
+
+ public static void load_class_this(CodeEmitter e) {
+ load_class_helper(e, e.getClassEmitter().getClassType());
+ }
+
+ public static void load_class(CodeEmitter e, Type type) {
+ if (TypeUtils.isPrimitive(type)) {
+ if (type == Type.VOID_TYPE) {
+ throw new IllegalArgumentException("cannot load void type");
+ }
+ e.getstatic(TypeUtils.getBoxedType(type), "TYPE", Constants.TYPE_CLASS);
+ } else {
+ load_class_helper(e, type);
+ }
+ }
+
+ private static void load_class_helper(CodeEmitter e, final Type type) {
+ if (e.isStaticHook()) {
+ // have to fall back on non-optimized load
+ e.push(TypeUtils.emulateClassGetName(type));
+ e.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
+ } else {
+ ClassEmitter ce = e.getClassEmitter();
+ String typeName = TypeUtils.emulateClassGetName(type);
+
+ // TODO: can end up with duplicated field names when using chained transformers; incorporate static hook # somehow
+ String fieldName = "CGLIB$load_class$" + TypeUtils.escapeType(typeName);
+ if (!ce.isFieldDeclared(fieldName)) {
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, fieldName, Constants.TYPE_CLASS, null);
+ CodeEmitter hook = ce.getStaticHook();
+ hook.push(typeName);
+ hook.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
+ hook.putstatic(ce.getClassType(), fieldName, Constants.TYPE_CLASS);
+ }
+ e.getfield(fieldName);
+ }
+ }
+
+ public static void push_array(CodeEmitter e, Object[] array) {
+ e.push(array.length);
+ e.newarray(Type.getType(remapComponentType(array.getClass().getComponentType())));
+ for (int i = 0; i < array.length; i++) {
+ e.dup();
+ e.push(i);
+ push_object(e, array[i]);
+ e.aastore();
+ }
+ }
+
+ private static Class remapComponentType(Class componentType) {
+ if (componentType.equals(Type.class))
+ return Class.class;
+ return componentType;
+ }
+
+ public static void push_object(CodeEmitter e, Object obj) {
+ if (obj == null) {
+ e.aconst_null();
+ } else {
+ Class type = obj.getClass();
+ if (type.isArray()) {
+ push_array(e, (Object[])obj);
+ } else if (obj instanceof String) {
+ e.push((String)obj);
+ } else if (obj instanceof Type) {
+ load_class(e, (Type)obj);
+ } else if (obj instanceof Class) {
+ load_class(e, Type.getType((Class)obj));
+ } else if (obj instanceof BigInteger) {
+ e.new_instance(Constants.TYPE_BIG_INTEGER);
+ e.dup();
+ e.push(obj.toString());
+ e.invoke_constructor(Constants.TYPE_BIG_INTEGER);
+ } else if (obj instanceof BigDecimal) {
+ e.new_instance(Constants.TYPE_BIG_DECIMAL);
+ e.dup();
+ e.push(obj.toString());
+ e.invoke_constructor(Constants.TYPE_BIG_DECIMAL);
+ } else {
+ throw new IllegalArgumentException("unknown type: " + obj.getClass());
+ }
+ }
+ }
+
+ /**
+ * @deprecated use {@link #hash_code(CodeEmitter, Type, int, CustomizerRegistry)} instead
+ */
+ @Deprecated
+ public static void hash_code(CodeEmitter e, Type type, int multiplier, final Customizer customizer) {
+ hash_code(e, type, multiplier, CustomizerRegistry.singleton(customizer));
+ }
+
+ public static void hash_code(CodeEmitter e, Type type, int multiplier, final CustomizerRegistry registry) {
+ if (TypeUtils.isArray(type)) {
+ hash_array(e, type, multiplier, registry);
+ } else {
+ e.swap(Type.INT_TYPE, type);
+ e.push(multiplier);
+ e.math(e.MUL, Type.INT_TYPE);
+ e.swap(type, Type.INT_TYPE);
+ if (TypeUtils.isPrimitive(type)) {
+ hash_primitive(e, type);
+ } else {
+ hash_object(e, type, registry);
+ }
+ e.math(e.ADD, Type.INT_TYPE);
+ }
+ }
+
+ private static void hash_array(final CodeEmitter e, Type type, final int multiplier, final CustomizerRegistry registry) {
+ Label skip = e.make_label();
+ Label end = e.make_label();
+ e.dup();
+ e.ifnull(skip);
+ EmitUtils.process_array(e, type, new ProcessArrayCallback() {
+ public void processElement(Type type) {
+ hash_code(e, type, multiplier, registry);
+ }
+ });
+ e.goTo(end);
+ e.mark(skip);
+ e.pop();
+ e.mark(end);
+ }
+
+ private static void hash_object(CodeEmitter e, Type type, CustomizerRegistry registry) {
+ // (f == null) ? 0 : f.hashCode();
+ Label skip = e.make_label();
+ Label end = e.make_label();
+ e.dup();
+ e.ifnull(skip);
+ boolean customHashCode = false;
+ for (HashCodeCustomizer customizer : registry.get(HashCodeCustomizer.class)) {
+ if (customizer.customize(e, type)) {
+ customHashCode = true;
+ break;
+ }
+ }
+ if (!customHashCode) {
+ for (Customizer customizer : registry.get(Customizer.class)) {
+ customizer.customize(e, type);
+ }
+ e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
+ }
+ e.goTo(end);
+ e.mark(skip);
+ e.pop();
+ e.push(0);
+ e.mark(end);
+ }
+
+ private static void hash_primitive(CodeEmitter e, Type type) {
+ switch (type.getSort()) {
+ case Type.BOOLEAN:
+ // f ? 0 : 1
+ e.push(1);
+ e.math(e.XOR, Type.INT_TYPE);
+ break;
+ case Type.FLOAT:
+ // Float.floatToIntBits(f)
+ e.invoke_static(Constants.TYPE_FLOAT, FLOAT_TO_INT_BITS);
+ break;
+ case Type.DOUBLE:
+ // Double.doubleToLongBits(f), hash_code(Long.TYPE)
+ e.invoke_static(Constants.TYPE_DOUBLE, DOUBLE_TO_LONG_BITS);
+ // fall through
+ case Type.LONG:
+ hash_long(e);
+ }
+ }
+
+ private static void hash_long(CodeEmitter e) {
+ // (int)(f ^ (f >>> 32))
+ e.dup2();
+ e.push(32);
+ e.math(e.USHR, Type.LONG_TYPE);
+ e.math(e.XOR, Type.LONG_TYPE);
+ e.cast_numeric(Type.LONG_TYPE, Type.INT_TYPE);
+ }
+
+// public static void not_equals(CodeEmitter e, Type type, Label notEquals) {
+// not_equals(e, type, notEquals, null);
+// }
+
+ /**
+ * @deprecated use {@link #not_equals(CodeEmitter, Type, Label, CustomizerRegistry)} instead
+ */
+ @Deprecated
+ public static void not_equals(CodeEmitter e, Type type, final Label notEquals, final Customizer customizer) {
+ not_equals(e, type, notEquals, CustomizerRegistry.singleton(customizer));
+ }
+
+ /**
+ * Branches to the specified label if the top two items on the stack
+ * are not equal. The items must both be of the specified
+ * class. Equality is determined by comparing primitive values
+ * directly and by invoking the equals method for
+ * Objects. Arrays are recursively processed in the same manner.
+ */
+ public static void not_equals(final CodeEmitter e, Type type, final Label notEquals, final CustomizerRegistry registry) {
+ (new ProcessArrayCallback() {
+ public void processElement(Type type) {
+ not_equals_helper(e, type, notEquals, registry, this);
+ }
+ }).processElement(type);
+ }
+
+ private static void not_equals_helper(CodeEmitter e,
+ Type type,
+ Label notEquals,
+ CustomizerRegistry registry,
+ ProcessArrayCallback callback) {
+ if (TypeUtils.isPrimitive(type)) {
+ e.if_cmp(type, e.NE, notEquals);
+ } else {
+ Label end = e.make_label();
+ nullcmp(e, notEquals, end);
+ if (TypeUtils.isArray(type)) {
+ Label checkContents = e.make_label();
+ e.dup2();
+ e.arraylength();
+ e.swap();
+ e.arraylength();
+ e.if_icmp(e.EQ, checkContents);
+ e.pop2();
+ e.goTo(notEquals);
+ e.mark(checkContents);
+ EmitUtils.process_arrays(e, type, callback);
+ } else {
+ List customizers = registry.get(Customizer.class);
+ if (!customizers.isEmpty()) {
+ for (Customizer customizer : customizers) {
+ customizer.customize(e, type);
+ }
+ e.swap();
+ for (Customizer customizer : customizers) {
+ customizer.customize(e, type);
+ }
+ }
+ e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
+ e.if_jump(e.EQ, notEquals);
+ }
+ e.mark(end);
+ }
+ }
+
+ /**
+ * If both objects on the top of the stack are non-null, does nothing.
+ * If one is null, or both are null, both are popped off and execution
+ * branches to the respective label.
+ * @param oneNull label to branch to if only one of the objects is null
+ * @param bothNull label to branch to if both of the objects are null
+ */
+ private static void nullcmp(CodeEmitter e, Label oneNull, Label bothNull) {
+ e.dup2();
+ Label nonNull = e.make_label();
+ Label oneNullHelper = e.make_label();
+ Label end = e.make_label();
+ e.ifnonnull(nonNull);
+ e.ifnonnull(oneNullHelper);
+ e.pop2();
+ e.goTo(bothNull);
+
+ e.mark(nonNull);
+ e.ifnull(oneNullHelper);
+ e.goTo(end);
+
+ e.mark(oneNullHelper);
+ e.pop2();
+ e.goTo(oneNull);
+
+ e.mark(end);
+ }
+
+ /*
+ public static void to_string(CodeEmitter e,
+ Type type,
+ ArrayDelimiters delims,
+ CustomizerRegistry registry) {
+ e.new_instance(Constants.TYPE_STRING_BUFFER);
+ e.dup();
+ e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
+ e.swap();
+ append_string(e, type, delims, registry);
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
+ }
+ */
+
+ /**
+ * @deprecated use {@link #append_string(CodeEmitter, Type, ArrayDelimiters, CustomizerRegistry)} instead
+ */
+ @Deprecated
+ public static void append_string(final CodeEmitter e,
+ Type type,
+ final ArrayDelimiters delims,
+ final Customizer customizer) {
+ append_string(e, type, delims, CustomizerRegistry.singleton(customizer));
+ }
+
+ public static void append_string(final CodeEmitter e,
+ Type type,
+ final ArrayDelimiters delims,
+ final CustomizerRegistry registry) {
+ final ArrayDelimiters d = (delims != null) ? delims : DEFAULT_DELIMITERS;
+ ProcessArrayCallback callback = new ProcessArrayCallback() {
+ public void processElement(Type type) {
+ append_string_helper(e, type, d, registry, this);
+ e.push(d.inside);
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
+ }
+ };
+ append_string_helper(e, type, d, registry, callback);
+ }
+
+ private static void append_string_helper(CodeEmitter e,
+ Type type,
+ ArrayDelimiters delims,
+ CustomizerRegistry registry,
+ ProcessArrayCallback callback) {
+ Label skip = e.make_label();
+ Label end = e.make_label();
+ if (TypeUtils.isPrimitive(type)) {
+ switch (type.getSort()) {
+ case Type.INT:
+ case Type.SHORT:
+ case Type.BYTE:
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_INT);
+ break;
+ case Type.DOUBLE:
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_DOUBLE);
+ break;
+ case Type.FLOAT:
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_FLOAT);
+ break;
+ case Type.LONG:
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_LONG);
+ break;
+ case Type.BOOLEAN:
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_BOOLEAN);
+ break;
+ case Type.CHAR:
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_CHAR);
+ break;
+ }
+ } else if (TypeUtils.isArray(type)) {
+ e.dup();
+ e.ifnull(skip);
+ e.swap();
+ if (delims != null && delims.before != null && !"".equals(delims.before)) {
+ e.push(delims.before);
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
+ e.swap();
+ }
+ EmitUtils.process_array(e, type, callback);
+ shrinkStringBuffer(e, 2);
+ if (delims != null && delims.after != null && !"".equals(delims.after)) {
+ e.push(delims.after);
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
+ }
+ } else {
+ e.dup();
+ e.ifnull(skip);
+ for (Customizer customizer : registry.get(Customizer.class)) {
+ customizer.customize(e, type);
+ }
+ e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
+ }
+ e.goTo(end);
+ e.mark(skip);
+ e.pop();
+ e.push("null");
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
+ e.mark(end);
+ }
+
+ private static void shrinkStringBuffer(CodeEmitter e, int amt) {
+ e.dup();
+ e.dup();
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, LENGTH);
+ e.push(amt);
+ e.math(e.SUB, Type.INT_TYPE);
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, SET_LENGTH);
+ }
+
+ public static class ArrayDelimiters {
+ private String before;
+ private String inside;
+ private String after;
+
+ public ArrayDelimiters(String before, String inside, String after) {
+ this.before = before;
+ this.inside = inside;
+ this.after = after;
+ }
+ }
+
+ public static void load_method(CodeEmitter e, MethodInfo method) {
+ load_class(e, method.getClassInfo().getType());
+ e.push(method.getSignature().getName());
+ push_object(e, method.getSignature().getArgumentTypes());
+ e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHOD);
+ }
+
+ private interface ParameterTyper {
+ Type[] getParameterTypes(MethodInfo member);
+ }
+
+ public static void method_switch(CodeEmitter e,
+ List methods,
+ ObjectSwitchCallback callback) {
+ member_switch_helper(e, methods, callback, true);
+ }
+
+ public static void constructor_switch(CodeEmitter e,
+ List constructors,
+ ObjectSwitchCallback callback) {
+ member_switch_helper(e, constructors, callback, false);
+ }
+
+ private static void member_switch_helper(final CodeEmitter e,
+ List members,
+ final ObjectSwitchCallback callback,
+ boolean useName) {
+ try {
+ final Map cache = new HashMap();
+ final ParameterTyper cached = new ParameterTyper() {
+ public Type[] getParameterTypes(MethodInfo member) {
+ Type[] types = (Type[])cache.get(member);
+ if (types == null) {
+ cache.put(member, types = member.getSignature().getArgumentTypes());
+ }
+ return types;
+ }
+ };
+ final Label def = e.make_label();
+ final Label end = e.make_label();
+ if (useName) {
+ e.swap();
+ final Map buckets = CollectionUtils.bucket(members, new Transformer() {
+ public Object transform(Object value) {
+ return ((MethodInfo)value).getSignature().getName();
+ }
+ });
+ String[] names = (String[])buckets.keySet().toArray(new String[buckets.size()]);
+ EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
+ public void processCase(Object key, Label dontUseEnd) throws Exception {
+ member_helper_size(e, (List)buckets.get(key), callback, cached, def, end);
+ }
+ public void processDefault() throws Exception {
+ e.goTo(def);
+ }
+ });
+ } else {
+ member_helper_size(e, members, callback, cached, def, end);
+ }
+ e.mark(def);
+ e.pop();
+ callback.processDefault();
+ e.mark(end);
+ } catch (RuntimeException ex) {
+ throw ex;
+ } catch (Error ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new CodeGenerationException(ex);
+ }
+ }
+
+ private static void member_helper_size(final CodeEmitter e,
+ List members,
+ final ObjectSwitchCallback callback,
+ final ParameterTyper typer,
+ final Label def,
+ final Label end) throws Exception {
+ final Map buckets = CollectionUtils.bucket(members, new Transformer() {
+ public Object transform(Object value) {
+ return new Integer(typer.getParameterTypes((MethodInfo)value).length);
+ }
+ });
+ e.dup();
+ e.arraylength();
+ e.process_switch(EmitUtils.getSwitchKeys(buckets), new ProcessSwitchCallback() {
+ public void processCase(int key, Label dontUseEnd) throws Exception {
+ List bucket = (List)buckets.get(new Integer(key));
+ member_helper_type(e, bucket, callback, typer, def, end, new BitSet());
+ }
+ public void processDefault() throws Exception {
+ e.goTo(def);
+ }
+ });
+ }
+
+ private static void member_helper_type(final CodeEmitter e,
+ List members,
+ final ObjectSwitchCallback callback,
+ final ParameterTyper typer,
+ final Label def,
+ final Label end,
+ final BitSet checked) throws Exception {
+ if (members.size() == 1) {
+ MethodInfo member = (MethodInfo)members.get(0);
+ Type[] types = typer.getParameterTypes(member);
+ // need to check classes that have not already been checked via switches
+ for (int i = 0; i < types.length; i++) {
+ if (checked == null || !checked.get(i)) {
+ e.dup();
+ e.aaload(i);
+ e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
+ e.push(TypeUtils.emulateClassGetName(types[i]));
+ e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
+ e.if_jump(e.EQ, def);
+ }
+ }
+ e.pop();
+ callback.processCase(member, end);
+ } else {
+ // choose the index that has the best chance of uniquely identifying member
+ Type[] example = typer.getParameterTypes((MethodInfo)members.get(0));
+ Map buckets = null;
+ int index = -1;
+ for (int i = 0; i < example.length; i++) {
+ final int j = i;
+ Map test = CollectionUtils.bucket(members, new Transformer() {
+ public Object transform(Object value) {
+ return TypeUtils.emulateClassGetName(typer.getParameterTypes((MethodInfo)value)[j]);
+ }
+ });
+ if (buckets == null || test.size() > buckets.size()) {
+ buckets = test;
+ index = i;
+ }
+ }
+ if (buckets == null || buckets.size() == 1) {
+ // TODO: switch by returnType
+ // must have two methods with same name, types, and different return types
+ e.goTo(def);
+ } else {
+ checked.set(index);
+
+ e.dup();
+ e.aaload(index);
+ e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
+
+ final Map fbuckets = buckets;
+ String[] names = (String[])buckets.keySet().toArray(new String[buckets.size()]);
+ EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
+ public void processCase(Object key, Label dontUseEnd) throws Exception {
+ member_helper_type(e, (List)fbuckets.get(key), callback, typer, def, end, checked);
+ }
+ public void processDefault() throws Exception {
+ e.goTo(def);
+ }
+ });
+ }
+ }
+ }
+
+ public static void wrap_throwable(Block block, Type wrapper) {
+ CodeEmitter e = block.getCodeEmitter();
+ e.catch_exception(block, Constants.TYPE_THROWABLE);
+ e.new_instance(wrapper);
+ e.dup_x1();
+ e.swap();
+ e.invoke_constructor(wrapper, CSTRUCT_THROWABLE);
+ e.athrow();
+ }
+
+ public static void add_properties(ClassEmitter ce, String[] names, Type[] types) {
+ for (int i = 0; i < names.length; i++) {
+ String fieldName = "$cglib_prop_" + names[i];
+ ce.declare_field(Constants.ACC_PRIVATE, fieldName, types[i], null);
+ EmitUtils.add_property(ce, names[i], types[i], fieldName);
+ }
+ }
+
+ public static void add_property(ClassEmitter ce, String name, Type type, String fieldName) {
+ String property = TypeUtils.upperFirst(name);
+ CodeEmitter e;
+ e = ce.begin_method(Constants.ACC_PUBLIC,
+ new Signature("get" + property,
+ type,
+ Constants.TYPES_EMPTY),
+ null);
+ e.load_this();
+ e.getfield(fieldName);
+ e.return_value();
+ e.end_method();
+
+ e = ce.begin_method(Constants.ACC_PUBLIC,
+ new Signature("set" + property,
+ Type.VOID_TYPE,
+ new Type[]{ type }),
+ null);
+ e.load_this();
+ e.load_arg(0);
+ e.putfield(fieldName);
+ e.return_value();
+ e.end_method();
+ }
+
+ /* generates:
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Error e) {
+ throw e;
+ } catch ( e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new (e);
+ }
+ */
+ public static void wrap_undeclared_throwable(CodeEmitter e, Block handler, Type[] exceptions, Type wrapper) {
+ Set set = (exceptions == null) ? Collections.EMPTY_SET : new HashSet(Arrays.asList(exceptions));
+
+ if (set.contains(Constants.TYPE_THROWABLE))
+ return;
+
+ boolean needThrow = exceptions != null;
+ if (!set.contains(Constants.TYPE_RUNTIME_EXCEPTION)) {
+ e.catch_exception(handler, Constants.TYPE_RUNTIME_EXCEPTION);
+ needThrow = true;
+ }
+ if (!set.contains(Constants.TYPE_ERROR)) {
+ e.catch_exception(handler, Constants.TYPE_ERROR);
+ needThrow = true;
+ }
+ if (exceptions != null) {
+ for (int i = 0; i < exceptions.length; i++) {
+ e.catch_exception(handler, exceptions[i]);
+ }
+ }
+ if (needThrow) {
+ e.athrow();
+ }
+ // e -> eo -> oeo -> ooe -> o
+ e.catch_exception(handler, Constants.TYPE_THROWABLE);
+ e.new_instance(wrapper);
+ e.dup_x1();
+ e.swap();
+ e.invoke_constructor(wrapper, CSTRUCT_THROWABLE);
+ e.athrow();
+ }
+
+ public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method) {
+ return begin_method(e, method, method.getModifiers());
+ }
+
+ public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method, int access) {
+ return e.begin_method(access,
+ method.getSignature(),
+ method.getExceptionTypes());
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/FieldTypeCustomizer.java b/blade-aop/src/main/java/net/sf/cglib/core/FieldTypeCustomizer.java
new file mode 100644
index 000000000..1caa076b7
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/FieldTypeCustomizer.java
@@ -0,0 +1,23 @@
+package net.sf.cglib.core;
+
+import org.objectweb.asm.Type;
+
+/**
+ * Customizes key types for {@link KeyFactory} right in constructor.
+ */
+public interface FieldTypeCustomizer extends KeyFactoryCustomizer {
+ /**
+ * Customizes {@code this.FIELD_0 = ?} assignment in key constructor
+ * @param e code emitter
+ * @param index parameter index
+ * @param type parameter type
+ */
+ void customize(CodeEmitter e, int index, Type type);
+
+ /**
+ * Computes type of field for storing given parameter
+ * @param index parameter index
+ * @param type parameter type
+ */
+ Type getOutType(int index, Type type);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/GeneratorStrategy.java b/blade-aop/src/main/java/net/sf/cglib/core/GeneratorStrategy.java
new file mode 100644
index 000000000..8d5ee694f
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/GeneratorStrategy.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+/**
+ * The GeneratorStrategyClass. By providing your
+ * own strategy you may examine or modify the generated class before
+ * it is loaded. Typically this will be accomplished by subclassing
+ * {@link DefaultGeneratorStrategy} and overriding the appropriate
+ * protected method.
+ * @see AbstractClassGenerator#setStrategy
+ */
+public interface GeneratorStrategy {
+ /**
+ * Generate the class.
+ * @param cg a class generator on which you can call {@link ClassGenerator#generateClass}
+ * @return a byte array containing the bits of a valid Class
+ */
+ byte[] generate(ClassGenerator cg) throws Exception;
+
+ /**
+ * The GeneratorStrategy in use does not currently, but may
+ * in the future, affect the caching of classes generated by {@link
+ * AbstractClassGenerator}, so this is a reminder that you should
+ * correctly implement equals and hashCode
+ * to avoid generating too many classes.
+ */
+ boolean equals(Object o);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/HashCodeCustomizer.java b/blade-aop/src/main/java/net/sf/cglib/core/HashCodeCustomizer.java
new file mode 100644
index 000000000..b66b791cb
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/HashCodeCustomizer.java
@@ -0,0 +1,12 @@
+package net.sf.cglib.core;
+
+import org.objectweb.asm.Type;
+
+public interface HashCodeCustomizer extends KeyFactoryCustomizer {
+ /**
+ * Customizes calculation of hashcode
+ * @param e code emitter
+ * @param type parameter type
+ */
+ boolean customize(CodeEmitter e, Type type);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/KeyFactory.java b/blade-aop/src/main/java/net/sf/cglib/core/KeyFactory.java
new file mode 100644
index 000000000..b9ea79851
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/KeyFactory.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import net.sf.cglib.core.internal.CustomizerRegistry;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
+ * Code for equals and hashCode methods follow the
+ * the rules laid out in Effective Java by Joshua Bloch.
+ *
+ * To generate a KeyFactory, you need to supply an interface which
+ * describes the structure of the key. The interface should have a
+ * single method named newInstance, which returns an
+ * Object. The arguments array can be
+ * anything --Objects, primitive values, or single or
+ * multi-dimension arrays of either. For example:
+ *
+ * private interface IntStringKey {
+ * public Object newInstance(int i, String s);
+ * }
+ *
+ * Once you have made a KeyFactory, you generate a new key by calling
+ * the newInstance method defined by your interface.
+ *
+ * IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
+ * Object key1 = factory.newInstance(4, "Hello");
+ * Object key2 = factory.newInstance(4, "World");
+ *
+ * Note:
+ * hashCode equality between two keys key1 and key2 is only guaranteed if
+ * key1.equals(key2) and the keys were produced by the same factory.
+ *
+ * @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $
+ */
+abstract public class KeyFactory {
+ private static final Signature GET_NAME =
+ TypeUtils.parseSignature("String getName()");
+ private static final Signature GET_CLASS =
+ TypeUtils.parseSignature("Class getClass()");
+ private static final Signature HASH_CODE =
+ TypeUtils.parseSignature("int hashCode()");
+ private static final Signature EQUALS =
+ TypeUtils.parseSignature("boolean equals(Object)");
+ private static final Signature TO_STRING =
+ TypeUtils.parseSignature("String toString()");
+ private static final Signature APPEND_STRING =
+ TypeUtils.parseSignature("StringBuffer append(String)");
+ private static final Type KEY_FACTORY =
+ TypeUtils.parseType("net.sf.cglib.core.KeyFactory");
+ private static final Signature GET_SORT =
+ TypeUtils.parseSignature("int getSort()");
+
+ //generated numbers:
+ private final static int PRIMES[] = {
+ 11, 73, 179, 331,
+ 521, 787, 1213, 1823,
+ 2609, 3691, 5189, 7247,
+ 10037, 13931, 19289, 26627,
+ 36683, 50441, 69403, 95401,
+ 131129, 180179, 247501, 340057,
+ 467063, 641371, 880603, 1209107,
+ 1660097, 2279161, 3129011, 4295723,
+ 5897291, 8095873, 11114263, 15257791,
+ 20946017, 28754629, 39474179, 54189869,
+ 74391461, 102123817, 140194277, 192456917,
+ 264202273, 362693231, 497900099, 683510293,
+ 938313161, 1288102441, 1768288259 };
+
+
+ public static final Customizer CLASS_BY_NAME = new Customizer() {
+ public void customize(CodeEmitter e, Type type) {
+ if (type.equals(Constants.TYPE_CLASS)) {
+ e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
+ }
+ }
+ };
+
+ public static final FieldTypeCustomizer STORE_CLASS_AS_STRING = new FieldTypeCustomizer() {
+ public void customize(CodeEmitter e, int index, Type type) {
+ if (type.equals(Constants.TYPE_CLASS)) {
+ e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
+ }
+ }
+
+ public Type getOutType(int index, Type type) {
+ if (type.equals(Constants.TYPE_CLASS)) {
+ return Constants.TYPE_STRING;
+ }
+ return type;
+ }
+ };
+
+ /**
+ * {@link Type#hashCode()} is very expensive as it traverses full descriptor to calculate hash code.
+ * This customizer uses {@link Type#getSort()} as a hash code.
+ */
+ public static final HashCodeCustomizer HASH_ASM_TYPE = new HashCodeCustomizer() {
+ public boolean customize(CodeEmitter e, Type type) {
+ if (Constants.TYPE_TYPE.equals(type)) {
+ e.invoke_virtual(type, GET_SORT);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ /**
+ * @deprecated this customizer might result in unexpected class leak since key object still holds a strong reference to the Object and class.
+ * It is recommended to have pre-processing method that would strip Objects and represent Classes as Strings
+ */
+ @Deprecated
+ public static final Customizer OBJECT_BY_CLASS = new Customizer() {
+ public void customize(CodeEmitter e, Type type) {
+ e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
+ }
+ };
+
+ protected KeyFactory() {
+ }
+
+ public static KeyFactory create(Class keyInterface) {
+ return create(keyInterface, null);
+ }
+
+ public static KeyFactory create(Class keyInterface, Customizer customizer) {
+ return create(keyInterface.getClassLoader(), keyInterface, customizer);
+ }
+
+ public static KeyFactory create(Class keyInterface, KeyFactoryCustomizer first, List next) {
+ return create(keyInterface.getClassLoader(), keyInterface, first, next);
+ }
+
+ public static KeyFactory create(ClassLoader loader, Class keyInterface, Customizer customizer) {
+ return create(loader, keyInterface, customizer, Collections.emptyList());
+ }
+
+ public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer,
+ List next) {
+ Generator gen = new Generator();
+ gen.setInterface(keyInterface);
+
+ if (customizer != null) {
+ gen.addCustomizer(customizer);
+ }
+ if (next != null && !next.isEmpty()) {
+ for (KeyFactoryCustomizer keyFactoryCustomizer : next) {
+ gen.addCustomizer(keyFactoryCustomizer);
+ }
+ }
+ gen.setClassLoader(loader);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(KeyFactory.class.getName());
+ private static final Class[] KNOWN_CUSTOMIZER_TYPES = new Class[]{Customizer.class, FieldTypeCustomizer.class};
+
+ private Class keyInterface;
+ // TODO: Make me final when deprecated methods are removed
+ private CustomizerRegistry customizers = new CustomizerRegistry(KNOWN_CUSTOMIZER_TYPES);
+ private int constant;
+ private int multiplier;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return keyInterface.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(keyInterface);
+ }
+
+ /**
+ * @deprecated Use {@link #addCustomizer(KeyFactoryCustomizer)} instead.
+ */
+ @Deprecated
+ public void setCustomizer(Customizer customizer) {
+ customizers = CustomizerRegistry.singleton(customizer);
+ }
+
+ public void addCustomizer(KeyFactoryCustomizer customizer) {
+ customizers.add(customizer);
+ }
+
+ public List getCustomizers(Class klass) {
+ return customizers.get(klass);
+ }
+
+ public void setInterface(Class keyInterface) {
+ this.keyInterface = keyInterface;
+ }
+
+ public KeyFactory create() {
+ setNamePrefix(keyInterface.getName());
+ return (KeyFactory)super.create(keyInterface.getName());
+ }
+
+ public void setHashConstant(int constant) {
+ this.constant = constant;
+ }
+
+ public void setHashMultiplier(int multiplier) {
+ this.multiplier = multiplier;
+ }
+
+ protected Object firstInstance(Class type) {
+ return ReflectUtils.newInstance(type);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return instance;
+ }
+
+ public void generateClass(ClassVisitor v) {
+ ClassEmitter ce = new ClassEmitter(v);
+
+ Method newInstance = ReflectUtils.findNewInstance(keyInterface);
+ if (!newInstance.getReturnType().equals(Object.class)) {
+ throw new IllegalArgumentException("newInstance method must return Object");
+ }
+
+ Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
+ ce.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ KEY_FACTORY,
+ new Type[]{ Type.getType(keyInterface) },
+ Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(ce);
+ EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
+
+ int seed = 0;
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
+ TypeUtils.parseConstructor(parameterTypes),
+ null);
+ e.load_this();
+ e.super_invoke_constructor();
+ e.load_this();
+ List fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Type parameterType = parameterTypes[i];
+ Type fieldType = parameterType;
+ for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
+ fieldType = customizer.getOutType(i, fieldType);
+ }
+ seed += fieldType.hashCode();
+ ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
+ getFieldName(i),
+ fieldType,
+ null);
+ e.dup();
+ e.load_arg(i);
+ for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
+ customizer.customize(e, i, parameterType);
+ }
+ e.putfield(getFieldName(i));
+ }
+ e.return_value();
+ e.end_method();
+
+ // hash code
+ e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);
+ int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)];
+ int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)];
+ e.push(hc);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ e.load_this();
+ e.getfield(getFieldName(i));
+ EmitUtils.hash_code(e, parameterTypes[i], hm, customizers);
+ }
+ e.return_value();
+ e.end_method();
+
+ // equals
+ e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);
+ Label fail = e.make_label();
+ e.load_arg(0);
+ e.instance_of_this();
+ e.if_jump(e.EQ, fail);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ e.load_this();
+ e.getfield(getFieldName(i));
+ e.load_arg(0);
+ e.checkcast_this();
+ e.getfield(getFieldName(i));
+ EmitUtils.not_equals(e, parameterTypes[i], fail, customizers);
+ }
+ e.push(1);
+ e.return_value();
+ e.mark(fail);
+ e.push(0);
+ e.return_value();
+ e.end_method();
+
+ // toString
+ e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);
+ e.new_instance(Constants.TYPE_STRING_BUFFER);
+ e.dup();
+ e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (i > 0) {
+ e.push(", ");
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
+ }
+ e.load_this();
+ e.getfield(getFieldName(i));
+ EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizers);
+ }
+ e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
+ e.return_value();
+ e.end_method();
+
+ ce.end_class();
+ }
+
+ private String getFieldName(int arg) {
+ return "FIELD_" + arg;
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/KeyFactoryCustomizer.java b/blade-aop/src/main/java/net/sf/cglib/core/KeyFactoryCustomizer.java
new file mode 100644
index 000000000..e6a5f2c56
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/KeyFactoryCustomizer.java
@@ -0,0 +1,7 @@
+package net.sf.cglib.core;
+
+/**
+ * Marker interface for customizers of {@link KeyFactory}
+ */
+public interface KeyFactoryCustomizer {
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/Local.java b/blade-aop/src/main/java/net/sf/cglib/core/Local.java
new file mode 100644
index 000000000..f39a1e298
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/Local.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import org.objectweb.asm.Type;
+
+public class Local
+{
+ private Type type;
+ private int index;
+
+ public Local(int index, Type type) {
+ this.type = type;
+ this.index = index;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public Type getType() {
+ return type;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/LocalVariablesSorter.java b/blade-aop/src/main/java/net/sf/cglib/core/LocalVariablesSorter.java
new file mode 100644
index 000000000..6846d15b7
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/LocalVariablesSorter.java
@@ -0,0 +1,158 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2005 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.sf.cglib.core;
+
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * A {@link MethodVisitor} that renumbers local variables in their order of
+ * appearance. This adapter allows one to easily add new local variables to a
+ * method.
+ *
+ * @author Chris Nokleberg
+ * @author Eric Bruneton
+ */
+public class LocalVariablesSorter extends MethodVisitor {
+
+ /**
+ * Mapping from old to new local variable indexes. A local variable at index
+ * i of size 1 is remapped to 'mapping[2*i]', while a local variable at
+ * index i of size 2 is remapped to 'mapping[2*i+1]'.
+ */
+ private static class State
+ {
+ int[] mapping = new int[40];
+ int nextLocal;
+ }
+
+ protected final int firstLocal;
+ private final State state;
+
+ public LocalVariablesSorter(
+ final int access,
+ final String desc,
+ final MethodVisitor mv)
+ {
+ super(Opcodes.ASM5, mv);
+ state = new State();
+ Type[] args = Type.getArgumentTypes(desc);
+ state.nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1;
+ for (int i = 0; i < args.length; i++) {
+ state.nextLocal += args[i].getSize();
+ }
+ firstLocal = state.nextLocal;
+ }
+
+ public LocalVariablesSorter(LocalVariablesSorter lvs) {
+ super(Opcodes.ASM5, lvs.mv);
+ state = lvs.state;
+ firstLocal = lvs.firstLocal;
+ }
+
+ public void visitVarInsn(final int opcode, final int var) {
+ int size;
+ switch (opcode) {
+ case Opcodes.LLOAD:
+ case Opcodes.LSTORE:
+ case Opcodes.DLOAD:
+ case Opcodes.DSTORE:
+ size = 2;
+ break;
+ default:
+ size = 1;
+ }
+ mv.visitVarInsn(opcode, remap(var, size));
+ }
+
+ public void visitIincInsn(final int var, final int increment) {
+ mv.visitIincInsn(remap(var, 1), increment);
+ }
+
+ public void visitMaxs(final int maxStack, final int maxLocals) {
+ mv.visitMaxs(maxStack, state.nextLocal);
+ }
+
+ public void visitLocalVariable(
+ final String name,
+ final String desc,
+ final String signature,
+ final Label start,
+ final Label end,
+ final int index)
+ {
+ mv.visitLocalVariable(name, desc, signature, start, end, remap(index));
+ }
+
+ // -------------
+
+ protected int newLocal(final int size) {
+ int var = state.nextLocal;
+ state.nextLocal += size;
+ return var;
+ }
+
+ private int remap(final int var, final int size) {
+ if (var < firstLocal) {
+ return var;
+ }
+ int key = 2 * var + size - 1;
+ int length = state.mapping.length;
+ if (key >= length) {
+ int[] newMapping = new int[Math.max(2 * length, key + 1)];
+ System.arraycopy(state.mapping, 0, newMapping, 0, length);
+ state.mapping = newMapping;
+ }
+ int value = state.mapping[key];
+ if (value == 0) {
+ value = state.nextLocal + 1;
+ state.mapping[key] = value;
+ state.nextLocal += size;
+ }
+ return value - 1;
+ }
+
+ private int remap(final int var) {
+ if (var < firstLocal) {
+ return var;
+ }
+ int key = 2 * var;
+ int value = key < state.mapping.length ? state.mapping[key] : 0;
+ if (value == 0) {
+ value = key + 1 < state.mapping.length ? state.mapping[key + 1] : 0;
+ }
+ if (value == 0) {
+ throw new IllegalStateException("Unknown local variable " + var);
+ }
+ return value - 1;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/MethodInfo.java b/blade-aop/src/main/java/net/sf/cglib/core/MethodInfo.java
new file mode 100644
index 000000000..dfaacd821
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/MethodInfo.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.core;
+
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Type;
+
+abstract public class MethodInfo {
+
+ protected MethodInfo() {
+ }
+
+ abstract public ClassInfo getClassInfo();
+ abstract public int getModifiers();
+ abstract public Signature getSignature();
+ abstract public Type[] getExceptionTypes();
+
+ public boolean equals(Object o) {
+ if (o == null)
+ return false;
+ if (!(o instanceof MethodInfo))
+ return false;
+ return getSignature().equals(((MethodInfo)o).getSignature());
+ }
+
+ public int hashCode() {
+ return getSignature().hashCode();
+ }
+
+ public String toString() {
+ // TODO: include modifiers, exceptions
+ return getSignature().toString();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/MethodInfoTransformer.java b/blade-aop/src/main/java/net/sf/cglib/core/MethodInfoTransformer.java
new file mode 100644
index 000000000..7b3a8fc3c
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/MethodInfoTransformer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.core;
+
+import java.lang.reflect.*;
+
+public class MethodInfoTransformer implements Transformer
+{
+ private static final MethodInfoTransformer INSTANCE = new MethodInfoTransformer();
+
+ public static MethodInfoTransformer getInstance() {
+ return INSTANCE;
+ }
+
+ public Object transform(Object value) {
+ if (value instanceof Method) {
+ return ReflectUtils.getMethodInfo((Method)value);
+ } else if (value instanceof Constructor) {
+ return ReflectUtils.getMethodInfo((Constructor)value);
+ } else {
+ throw new IllegalArgumentException("cannot get method info for " + value);
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/MethodWrapper.java b/blade-aop/src/main/java/net/sf/cglib/core/MethodWrapper.java
new file mode 100644
index 000000000..5bea1acbe
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/MethodWrapper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+public class MethodWrapper {
+ private static final MethodWrapperKey KEY_FACTORY =
+ (MethodWrapperKey)KeyFactory.create(MethodWrapperKey.class);
+
+ /** Internal interface, only public due to ClassLoader issues. */
+ public interface MethodWrapperKey {
+ public Object newInstance(String name, String[] parameterTypes, String returnType);
+ }
+
+ private MethodWrapper() {
+ }
+
+ public static Object create(Method method) {
+ return KEY_FACTORY.newInstance(method.getName(),
+ ReflectUtils.getNames(method.getParameterTypes()),
+ method.getReturnType().getName());
+ }
+
+ public static Set createSet(Collection methods) {
+ Set set = new HashSet();
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ set.add(create((Method)it.next()));
+ }
+ return set;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/NamingPolicy.java b/blade-aop/src/main/java/net/sf/cglib/core/NamingPolicy.java
new file mode 100644
index 000000000..d7dc68e3a
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/NamingPolicy.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import java.util.Set;
+
+/**
+ * Customize the generated class name for {@link AbstractClassGenerator}-based utilities.
+ */
+public interface NamingPolicy {
+ /**
+ * Choose a name for a generated class.
+ * @param prefix a dotted-name chosen by the generating class (possibly to put the generated class in a particular package)
+ * @param source the fully-qualified class name of the generating class (for example "net.sf.cglib.Enhancer")
+ * @param key A key object representing the state of the parameters; for caching to work properly, equal keys should result
+ * in the same generated class name. The default policy incorporates key.hashCode() into the class name.
+ * @param names a predicate that returns true if the given classname has already been used in the same ClassLoader.
+ * @return the fully-qualified class name
+ */
+ String getClassName(String prefix, String source, Object key, Predicate names);
+
+ /**
+ * The NamingPolicy in use does not currently, but may
+ * in the future, affect the caching of classes generated by {@link
+ * AbstractClassGenerator}, so this is a reminder that you should
+ * correctly implement equals and hashCode
+ * to avoid generating too many classes.
+ */
+ boolean equals(Object o);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/ObjectSwitchCallback.java b/blade-aop/src/main/java/net/sf/cglib/core/ObjectSwitchCallback.java
new file mode 100644
index 000000000..df179e015
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/ObjectSwitchCallback.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import org.objectweb.asm.Label;
+
+public interface ObjectSwitchCallback {
+ void processCase(Object key, Label end) throws Exception;
+ void processDefault() throws Exception;
+}
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/Predicate.java b/blade-aop/src/main/java/net/sf/cglib/core/Predicate.java
new file mode 100644
index 000000000..ab367a83d
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/Predicate.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+public interface Predicate {
+ boolean evaluate(Object arg);
+}
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/ProcessArrayCallback.java b/blade-aop/src/main/java/net/sf/cglib/core/ProcessArrayCallback.java
new file mode 100644
index 000000000..bb2a79712
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/ProcessArrayCallback.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import org.objectweb.asm.Type;
+
+public interface ProcessArrayCallback {
+ void processElement(Type type);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/ProcessSwitchCallback.java b/blade-aop/src/main/java/net/sf/cglib/core/ProcessSwitchCallback.java
new file mode 100644
index 000000000..cac098562
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/ProcessSwitchCallback.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import org.objectweb.asm.Label;
+
+public interface ProcessSwitchCallback {
+ void processCase(int key, Label end) throws Exception;
+ void processDefault() throws Exception;
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/ReflectUtils.java b/blade-aop/src/main/java/net/sf/cglib/core/ReflectUtils.java
new file mode 100644
index 000000000..df9579a0a
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/ReflectUtils.java
@@ -0,0 +1,492 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import java.beans.*;
+import java.lang.reflect.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.*;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Type;
+
+/**
+ * @version $Id: ReflectUtils.java,v 1.30 2009/01/11 19:47:49 herbyderby Exp $
+ */
+public class ReflectUtils {
+ private ReflectUtils() { }
+
+ private static final Map primitives = new HashMap(8);
+ private static final Map transforms = new HashMap(8);
+ private static final ClassLoader defaultLoader = ReflectUtils.class.getClassLoader();
+ private static Method DEFINE_CLASS;
+ private static final ProtectionDomain PROTECTION_DOMAIN;
+
+ private static final List OBJECT_METHODS = new ArrayList();
+
+ static {
+ PROTECTION_DOMAIN = getProtectionDomain(ReflectUtils.class);
+
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ try {
+ Class loader = Class.forName("java.lang.ClassLoader"); // JVM crash w/o this
+ DEFINE_CLASS = loader.getDeclaredMethod("defineClass",
+ new Class[]{ String.class,
+ byte[].class,
+ Integer.TYPE,
+ Integer.TYPE,
+ ProtectionDomain.class });
+ DEFINE_CLASS.setAccessible(true);
+ } catch (ClassNotFoundException e) {
+ throw new CodeGenerationException(e);
+ } catch (NoSuchMethodException e) {
+ throw new CodeGenerationException(e);
+ }
+ return null;
+ }
+ });
+ Method[] methods = Object.class.getDeclaredMethods();
+ for (Method method : methods) {
+ if ("finalize".equals(method.getName())
+ || (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) {
+ continue;
+ }
+ OBJECT_METHODS.add(method);
+ }
+ }
+
+ private static final String[] CGLIB_PACKAGES = {
+ "java.lang",
+ };
+
+ static {
+ primitives.put("byte", Byte.TYPE);
+ primitives.put("char", Character.TYPE);
+ primitives.put("double", Double.TYPE);
+ primitives.put("float", Float.TYPE);
+ primitives.put("int", Integer.TYPE);
+ primitives.put("long", Long.TYPE);
+ primitives.put("short", Short.TYPE);
+ primitives.put("boolean", Boolean.TYPE);
+
+ transforms.put("byte", "B");
+ transforms.put("char", "C");
+ transforms.put("double", "D");
+ transforms.put("float", "F");
+ transforms.put("int", "I");
+ transforms.put("long", "J");
+ transforms.put("short", "S");
+ transforms.put("boolean", "Z");
+ }
+
+ public static ProtectionDomain getProtectionDomain(final Class source) {
+ if(source == null) {
+ return null;
+ }
+ return (ProtectionDomain)AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return source.getProtectionDomain();
+ }
+ });
+ }
+
+ public static Type[] getExceptionTypes(Member member) {
+ if (member instanceof Method) {
+ return TypeUtils.getTypes(((Method)member).getExceptionTypes());
+ } else if (member instanceof Constructor) {
+ return TypeUtils.getTypes(((Constructor)member).getExceptionTypes());
+ } else {
+ throw new IllegalArgumentException("Cannot get exception types of a field");
+ }
+ }
+
+ public static Signature getSignature(Member member) {
+ if (member instanceof Method) {
+ return new Signature(member.getName(), Type.getMethodDescriptor((Method)member));
+ } else if (member instanceof Constructor) {
+ Type[] types = TypeUtils.getTypes(((Constructor)member).getParameterTypes());
+ return new Signature(Constants.CONSTRUCTOR_NAME,
+ Type.getMethodDescriptor(Type.VOID_TYPE, types));
+
+ } else {
+ throw new IllegalArgumentException("Cannot get signature of a field");
+ }
+ }
+
+ public static Constructor findConstructor(String desc) {
+ return findConstructor(desc, defaultLoader);
+ }
+
+ public static Constructor findConstructor(String desc, ClassLoader loader) {
+ try {
+ int lparen = desc.indexOf('(');
+ String className = desc.substring(0, lparen).trim();
+ return getClass(className, loader).getConstructor(parseTypes(desc, loader));
+ } catch (ClassNotFoundException e) {
+ throw new CodeGenerationException(e);
+ } catch (NoSuchMethodException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ public static Method findMethod(String desc) {
+ return findMethod(desc, defaultLoader);
+ }
+
+ public static Method findMethod(String desc, ClassLoader loader) {
+ try {
+ int lparen = desc.indexOf('(');
+ int dot = desc.lastIndexOf('.', lparen);
+ String className = desc.substring(0, dot).trim();
+ String methodName = desc.substring(dot + 1, lparen).trim();
+ return getClass(className, loader).getDeclaredMethod(methodName, parseTypes(desc, loader));
+ } catch (ClassNotFoundException e) {
+ throw new CodeGenerationException(e);
+ } catch (NoSuchMethodException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ private static Class[] parseTypes(String desc, ClassLoader loader) throws ClassNotFoundException {
+ int lparen = desc.indexOf('(');
+ int rparen = desc.indexOf(')', lparen);
+ List params = new ArrayList();
+ int start = lparen + 1;
+ for (;;) {
+ int comma = desc.indexOf(',', start);
+ if (comma < 0) {
+ break;
+ }
+ params.add(desc.substring(start, comma).trim());
+ start = comma + 1;
+ }
+ if (start < rparen) {
+ params.add(desc.substring(start, rparen).trim());
+ }
+ Class[] types = new Class[params.size()];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = getClass((String)params.get(i), loader);
+ }
+ return types;
+ }
+
+ private static Class getClass(String className, ClassLoader loader) throws ClassNotFoundException {
+ return getClass(className, loader, CGLIB_PACKAGES);
+ }
+
+ private static Class getClass(String className, ClassLoader loader, String[] packages) throws ClassNotFoundException {
+ String save = className;
+ int dimensions = 0;
+ int index = 0;
+ while ((index = className.indexOf("[]", index) + 1) > 0) {
+ dimensions++;
+ }
+ StringBuffer brackets = new StringBuffer(className.length() - dimensions);
+ for (int i = 0; i < dimensions; i++) {
+ brackets.append('[');
+ }
+ className = className.substring(0, className.length() - 2 * dimensions);
+
+ String prefix = (dimensions > 0) ? brackets + "L" : "";
+ String suffix = (dimensions > 0) ? ";" : "";
+ try {
+ return Class.forName(prefix + className + suffix, false, loader);
+ } catch (ClassNotFoundException ignore) { }
+ for (int i = 0; i < packages.length; i++) {
+ try {
+ return Class.forName(prefix + packages[i] + '.' + className + suffix, false, loader);
+ } catch (ClassNotFoundException ignore) { }
+ }
+ if (dimensions == 0) {
+ Class c = (Class)primitives.get(className);
+ if (c != null) {
+ return c;
+ }
+ } else {
+ String transform = (String)transforms.get(className);
+ if (transform != null) {
+ try {
+ return Class.forName(brackets + transform, false, loader);
+ } catch (ClassNotFoundException ignore) { }
+ }
+ }
+ throw new ClassNotFoundException(save);
+ }
+
+
+ public static Object newInstance(Class type) {
+ return newInstance(type, Constants.EMPTY_CLASS_ARRAY, null);
+ }
+
+ public static Object newInstance(Class type, Class[] parameterTypes, Object[] args) {
+ return newInstance(getConstructor(type, parameterTypes), args);
+ }
+
+ public static Object newInstance(final Constructor cstruct, final Object[] args) {
+
+ boolean flag = cstruct.isAccessible();
+ try {
+ if (!flag) {
+ cstruct.setAccessible(true);
+ }
+ Object result = cstruct.newInstance(args);
+ return result;
+ } catch (InstantiationException e) {
+ throw new CodeGenerationException(e);
+ } catch (IllegalAccessException e) {
+ throw new CodeGenerationException(e);
+ } catch (InvocationTargetException e) {
+ throw new CodeGenerationException(e.getTargetException());
+ } finally {
+ if (!flag) {
+ cstruct.setAccessible(flag);
+ }
+ }
+
+ }
+
+ public static Constructor getConstructor(Class type, Class[] parameterTypes) {
+ try {
+ Constructor constructor = type.getDeclaredConstructor(parameterTypes);
+ constructor.setAccessible(true);
+ return constructor;
+ } catch (NoSuchMethodException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ public static String[] getNames(Class[] classes)
+ {
+ if (classes == null)
+ return null;
+ String[] names = new String[classes.length];
+ for (int i = 0; i < names.length; i++) {
+ names[i] = classes[i].getName();
+ }
+ return names;
+ }
+
+ public static Class[] getClasses(Object[] objects) {
+ Class[] classes = new Class[objects.length];
+ for (int i = 0; i < objects.length; i++) {
+ classes[i] = objects[i].getClass();
+ }
+ return classes;
+ }
+
+ public static Method findNewInstance(Class iface) {
+ Method m = findInterfaceMethod(iface);
+ if (!m.getName().equals("newInstance")) {
+ throw new IllegalArgumentException(iface + " missing newInstance method");
+ }
+ return m;
+ }
+
+ public static Method[] getPropertyMethods(PropertyDescriptor[] properties, boolean read, boolean write) {
+ Set methods = new HashSet();
+ for (int i = 0; i < properties.length; i++) {
+ PropertyDescriptor pd = properties[i];
+ if (read) {
+ methods.add(pd.getReadMethod());
+ }
+ if (write) {
+ methods.add(pd.getWriteMethod());
+ }
+ }
+ methods.remove(null);
+ return (Method[])methods.toArray(new Method[methods.size()]);
+ }
+
+ public static PropertyDescriptor[] getBeanProperties(Class type) {
+ return getPropertiesHelper(type, true, true);
+ }
+
+ public static PropertyDescriptor[] getBeanGetters(Class type) {
+ return getPropertiesHelper(type, true, false);
+ }
+
+ public static PropertyDescriptor[] getBeanSetters(Class type) {
+ return getPropertiesHelper(type, false, true);
+ }
+
+ private static PropertyDescriptor[] getPropertiesHelper(Class type, boolean read, boolean write) {
+ try {
+ BeanInfo info = Introspector.getBeanInfo(type, Object.class);
+ PropertyDescriptor[] all = info.getPropertyDescriptors();
+ if (read && write) {
+ return all;
+ }
+ List properties = new ArrayList(all.length);
+ for (int i = 0; i < all.length; i++) {
+ PropertyDescriptor pd = all[i];
+ if ((read && pd.getReadMethod() != null) ||
+ (write && pd.getWriteMethod() != null)) {
+ properties.add(pd);
+ }
+ }
+ return (PropertyDescriptor[])properties.toArray(new PropertyDescriptor[properties.size()]);
+ } catch (IntrospectionException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+
+
+ public static Method findDeclaredMethod(final Class type,
+ final String methodName, final Class[] parameterTypes)
+ throws NoSuchMethodException {
+
+ Class cl = type;
+ while (cl != null) {
+ try {
+ return cl.getDeclaredMethod(methodName, parameterTypes);
+ } catch (NoSuchMethodException e) {
+ cl = cl.getSuperclass();
+ }
+ }
+ throw new NoSuchMethodException(methodName);
+
+ }
+
+ public static List addAllMethods(final Class type, final List list) {
+
+
+ if (type == Object.class) {
+ list.addAll(OBJECT_METHODS);
+ } else
+ list.addAll(java.util.Arrays.asList(type.getDeclaredMethods()));
+
+ Class superclass = type.getSuperclass();
+ if (superclass != null) {
+ addAllMethods(superclass, list);
+ }
+ Class[] interfaces = type.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ addAllMethods(interfaces[i], list);
+ }
+
+ return list;
+ }
+
+ public static List addAllInterfaces(Class type, List list) {
+ Class superclass = type.getSuperclass();
+ if (superclass != null) {
+ list.addAll(Arrays.asList(type.getInterfaces()));
+ addAllInterfaces(superclass, list);
+ }
+ return list;
+ }
+
+
+ public static Method findInterfaceMethod(Class iface) {
+ if (!iface.isInterface()) {
+ throw new IllegalArgumentException(iface + " is not an interface");
+ }
+ Method[] methods = iface.getDeclaredMethods();
+ if (methods.length != 1) {
+ throw new IllegalArgumentException("expecting exactly 1 method in " + iface);
+ }
+ return methods[0];
+ }
+
+ public static Class defineClass(String className, byte[] b, ClassLoader loader) throws Exception {
+ return defineClass(className, b, loader, PROTECTION_DOMAIN);
+ }
+
+ public static Class defineClass(String className, byte[] b, ClassLoader loader, ProtectionDomain protectionDomain) throws Exception {
+ Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), protectionDomain };
+ Class c = (Class)DEFINE_CLASS.invoke(loader, args);
+ // Force static initializers to run.
+ Class.forName(className, true, loader);
+ return c;
+ }
+
+ public static int findPackageProtected(Class[] classes) {
+ for (int i = 0; i < classes.length; i++) {
+ if (!Modifier.isPublic(classes[i].getModifiers())) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ public static MethodInfo getMethodInfo(final Member member, final int modifiers) {
+ final Signature sig = getSignature(member);
+ return new MethodInfo() {
+ private ClassInfo ci;
+ public ClassInfo getClassInfo() {
+ if (ci == null)
+ ci = ReflectUtils.getClassInfo(member.getDeclaringClass());
+ return ci;
+ }
+ public int getModifiers() {
+ return modifiers;
+ }
+ public Signature getSignature() {
+ return sig;
+ }
+ public Type[] getExceptionTypes() {
+ return ReflectUtils.getExceptionTypes(member);
+ }
+ public Attribute getAttribute() {
+ return null;
+ }
+ };
+ }
+
+ public static MethodInfo getMethodInfo(Member member) {
+ return getMethodInfo(member, member.getModifiers());
+ }
+
+ public static ClassInfo getClassInfo(final Class clazz) {
+ final Type type = Type.getType(clazz);
+ final Type sc = (clazz.getSuperclass() == null) ? null : Type.getType(clazz.getSuperclass());
+ return new ClassInfo() {
+ public Type getType() {
+ return type;
+ }
+ public Type getSuperType() {
+ return sc;
+ }
+ public Type[] getInterfaces() {
+ return TypeUtils.getTypes(clazz.getInterfaces());
+ }
+ public int getModifiers() {
+ return clazz.getModifiers();
+ }
+ };
+ }
+
+ // used by MethodInterceptorGenerated generated code
+ public static Method[] findMethods(String[] namesAndDescriptors, Method[] methods)
+ {
+ Map map = new HashMap();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ map.put(method.getName() + Type.getMethodDescriptor(method), method);
+ }
+ Method[] result = new Method[namesAndDescriptors.length / 2];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = (Method)map.get(namesAndDescriptors[i * 2] + namesAndDescriptors[i * 2 + 1]);
+ if (result[i] == null) {
+ // TODO: error?
+ }
+ }
+ return result;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/RejectModifierPredicate.java b/blade-aop/src/main/java/net/sf/cglib/core/RejectModifierPredicate.java
new file mode 100644
index 000000000..5ad7758a8
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/RejectModifierPredicate.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.core;
+
+import java.lang.reflect.*;
+
+public class RejectModifierPredicate implements Predicate {
+ private int rejectMask;
+
+ public RejectModifierPredicate(int rejectMask) {
+ this.rejectMask = rejectMask;
+ }
+
+ public boolean evaluate(Object arg) {
+ return (((Member)arg).getModifiers() & rejectMask) == 0;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/Signature.java b/blade-aop/src/main/java/net/sf/cglib/core/Signature.java
new file mode 100644
index 000000000..6a176e898
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/Signature.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+import org.objectweb.asm.Type;
+
+/**
+ * A representation of a method signature, containing the method name,
+ * return type, and parameter types.
+ */
+public class Signature {
+ private String name;
+ private String desc;
+
+ public Signature(String name, String desc) {
+ // TODO: better error checking
+ if (name.indexOf('(') >= 0) {
+ throw new IllegalArgumentException("Name '" + name + "' is invalid");
+ }
+ this.name = name;
+ this.desc = desc;
+ }
+
+ public Signature(String name, Type returnType, Type[] argumentTypes) {
+ this(name, Type.getMethodDescriptor(returnType, argumentTypes));
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescriptor() {
+ return desc;
+ }
+
+ public Type getReturnType() {
+ return Type.getReturnType(desc);
+ }
+
+ public Type[] getArgumentTypes() {
+ return Type.getArgumentTypes(desc);
+ }
+
+ public String toString() {
+ return name + desc;
+ }
+
+ public boolean equals(Object o) {
+ if (o == null)
+ return false;
+ if (!(o instanceof Signature))
+ return false;
+ Signature other = (Signature)o;
+ return name.equals(other.name) && desc.equals(other.desc);
+ }
+
+ public int hashCode() {
+ return name.hashCode() ^ desc.hashCode();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/TinyBitSet.java b/blade-aop/src/main/java/net/sf/cglib/core/TinyBitSet.java
new file mode 100644
index 000000000..993456e40
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/TinyBitSet.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+public class TinyBitSet {
+ private static int[] T = new int[256];
+ private int value = 0;
+
+ private static int gcount(int x) {
+ int c = 0;
+ while (x != 0) {
+ c++;
+ x &= (x - 1);
+ }
+ return c;
+ }
+
+ static {
+ for(int j = 0; j < 256; j++) {
+ T[j] = gcount(j);
+ }
+ }
+
+ private static int topbit(int i) {
+ int j;
+ for (j = 0; i != 0; i ^= j) {
+ j = i & -i;
+ }
+ return j;
+ }
+
+ private static int log2(int i) {
+ int j = 0;
+ for (j = 0; i != 0; i >>= 1) {
+ j++;
+ }
+ return j;
+ }
+
+ public int length() {
+ return log2(topbit(value));
+ }
+
+ public int cardinality() {
+ int w = value;
+ int c = 0;
+ while (w != 0) {
+ c += T[w & 255];
+ w >>= 8;
+ }
+ return c;
+ }
+
+ public boolean get(int index) {
+ return (value & (1 << index)) != 0;
+ }
+
+ public void set(int index) {
+ value |= (1 << index);
+ }
+
+ public void clear(int index) {
+ value &= ~(1 << index);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/Transformer.java b/blade-aop/src/main/java/net/sf/cglib/core/Transformer.java
new file mode 100644
index 000000000..fc7afe6b0
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/Transformer.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.core;
+
+public interface Transformer {
+ Object transform(Object value);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/TypeUtils.java b/blade-aop/src/main/java/net/sf/cglib/core/TypeUtils.java
new file mode 100644
index 000000000..960eb04d4
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/TypeUtils.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import java.util.*;
+import org.objectweb.asm.Type;
+
+public class TypeUtils {
+ private static final Map transforms = new HashMap();
+ private static final Map rtransforms = new HashMap();
+
+ private TypeUtils() {
+ }
+
+ static {
+ transforms.put("void", "V");
+ transforms.put("byte", "B");
+ transforms.put("char", "C");
+ transforms.put("double", "D");
+ transforms.put("float", "F");
+ transforms.put("int", "I");
+ transforms.put("long", "J");
+ transforms.put("short", "S");
+ transforms.put("boolean", "Z");
+
+ CollectionUtils.reverse(transforms, rtransforms);
+ }
+
+ public static Type getType(String className) {
+ return Type.getType("L" + className.replace('.', '/') + ";");
+ }
+
+ public static boolean isFinal(int access) {
+ return (Constants.ACC_FINAL & access) != 0;
+ }
+
+ public static boolean isStatic(int access) {
+ return (Constants.ACC_STATIC & access) != 0;
+ }
+
+ public static boolean isProtected(int access) {
+ return (Constants.ACC_PROTECTED & access) != 0;
+ }
+
+ public static boolean isPublic(int access) {
+ return (Constants.ACC_PUBLIC & access) != 0;
+ }
+
+ public static boolean isAbstract(int access) {
+ return (Constants.ACC_ABSTRACT & access) != 0;
+ }
+
+ public static boolean isInterface(int access) {
+ return (Constants.ACC_INTERFACE & access) != 0;
+ }
+
+ public static boolean isPrivate(int access) {
+ return (Constants.ACC_PRIVATE & access) != 0;
+ }
+
+ public static boolean isSynthetic(int access) {
+ return (Constants.ACC_SYNTHETIC & access) != 0;
+ }
+
+ public static boolean isBridge(int access) {
+ return (Constants.ACC_BRIDGE & access) != 0;
+ }
+
+ // getPackage returns null on JDK 1.2
+ public static String getPackageName(Type type) {
+ return getPackageName(getClassName(type));
+ }
+
+ public static String getPackageName(String className) {
+ int idx = className.lastIndexOf('.');
+ return (idx < 0) ? "" : className.substring(0, idx);
+ }
+
+ public static String upperFirst(String s) {
+ if (s == null || s.length() == 0) {
+ return s;
+ }
+ return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+ }
+
+ public static String getClassName(Type type) {
+ if (isPrimitive(type)) {
+ return (String)rtransforms.get(type.getDescriptor());
+ } else if (isArray(type)) {
+ return getClassName(getComponentType(type)) + "[]";
+ } else {
+ return type.getClassName();
+ }
+ }
+
+ public static Type[] add(Type[] types, Type extra) {
+ if (types == null) {
+ return new Type[]{ extra };
+ } else {
+ List list = Arrays.asList(types);
+ if (list.contains(extra)) {
+ return types;
+ }
+ Type[] copy = new Type[types.length + 1];
+ System.arraycopy(types, 0, copy, 0, types.length);
+ copy[types.length] = extra;
+ return copy;
+ }
+ }
+
+ public static Type[] add(Type[] t1, Type[] t2) {
+ // TODO: set semantics?
+ Type[] all = new Type[t1.length + t2.length];
+ System.arraycopy(t1, 0, all, 0, t1.length);
+ System.arraycopy(t2, 0, all, t1.length, t2.length);
+ return all;
+ }
+
+ public static Type fromInternalName(String name) {
+ // TODO; primitives?
+ return Type.getType("L" + name + ";");
+ }
+
+ public static Type[] fromInternalNames(String[] names) {
+ if (names == null) {
+ return null;
+ }
+ Type[] types = new Type[names.length];
+ for (int i = 0; i < names.length; i++) {
+ types[i] = fromInternalName(names[i]);
+ }
+ return types;
+ }
+
+ public static int getStackSize(Type[] types) {
+ int size = 0;
+ for (int i = 0; i < types.length; i++) {
+ size += types[i].getSize();
+ }
+ return size;
+ }
+
+ public static String[] toInternalNames(Type[] types) {
+ if (types == null) {
+ return null;
+ }
+ String[] names = new String[types.length];
+ for (int i = 0; i < types.length; i++) {
+ names[i] = types[i].getInternalName();
+ }
+ return names;
+ }
+
+ public static Signature parseSignature(String s) {
+ int space = s.indexOf(' ');
+ int lparen = s.indexOf('(', space);
+ int rparen = s.indexOf(')', lparen);
+ String returnType = s.substring(0, space);
+ String methodName = s.substring(space + 1, lparen);
+ StringBuffer sb = new StringBuffer();
+ sb.append('(');
+ for (Iterator it = parseTypes(s, lparen + 1, rparen).iterator(); it.hasNext();) {
+ sb.append(it.next());
+ }
+ sb.append(')');
+ sb.append(map(returnType));
+ return new Signature(methodName, sb.toString());
+ }
+
+ public static Type parseType(String s) {
+ return Type.getType(map(s));
+ }
+
+ public static Type[] parseTypes(String s) {
+ List names = parseTypes(s, 0, s.length());
+ Type[] types = new Type[names.size()];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = Type.getType((String)names.get(i));
+ }
+ return types;
+ }
+
+ public static Signature parseConstructor(Type[] types) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("(");
+ for (int i = 0; i < types.length; i++) {
+ sb.append(types[i].getDescriptor());
+ }
+ sb.append(")");
+ sb.append("V");
+ return new Signature(Constants.CONSTRUCTOR_NAME, sb.toString());
+ }
+
+ public static Signature parseConstructor(String sig) {
+ return parseSignature("void (" + sig + ")"); // TODO
+ }
+
+ private static List parseTypes(String s, int mark, int end) {
+ List types = new ArrayList(5);
+ for (;;) {
+ int next = s.indexOf(',', mark);
+ if (next < 0) {
+ break;
+ }
+ types.add(map(s.substring(mark, next).trim()));
+ mark = next + 1;
+ }
+ types.add(map(s.substring(mark, end).trim()));
+ return types;
+ }
+
+ private static String map(String type) {
+ if (type.equals("")) {
+ return type;
+ }
+ String t = (String)transforms.get(type);
+ if (t != null) {
+ return t;
+ } else if (type.indexOf('.') < 0) {
+ return map("java.lang." + type);
+ } else {
+ StringBuffer sb = new StringBuffer();
+ int index = 0;
+ while ((index = type.indexOf("[]", index) + 1) > 0) {
+ sb.append('[');
+ }
+ type = type.substring(0, type.length() - sb.length() * 2);
+ sb.append('L').append(type.replace('.', '/')).append(';');
+ return sb.toString();
+ }
+ }
+
+ public static Type getBoxedType(Type type) {
+ switch (type.getSort()) {
+ case Type.CHAR:
+ return Constants.TYPE_CHARACTER;
+ case Type.BOOLEAN:
+ return Constants.TYPE_BOOLEAN;
+ case Type.DOUBLE:
+ return Constants.TYPE_DOUBLE;
+ case Type.FLOAT:
+ return Constants.TYPE_FLOAT;
+ case Type.LONG:
+ return Constants.TYPE_LONG;
+ case Type.INT:
+ return Constants.TYPE_INTEGER;
+ case Type.SHORT:
+ return Constants.TYPE_SHORT;
+ case Type.BYTE:
+ return Constants.TYPE_BYTE;
+ default:
+ return type;
+ }
+ }
+
+ public static Type getUnboxedType(Type type) {
+ if (Constants.TYPE_INTEGER.equals(type)) {
+ return Type.INT_TYPE;
+ } else if (Constants.TYPE_BOOLEAN.equals(type)) {
+ return Type.BOOLEAN_TYPE;
+ } else if (Constants.TYPE_DOUBLE.equals(type)) {
+ return Type.DOUBLE_TYPE;
+ } else if (Constants.TYPE_LONG.equals(type)) {
+ return Type.LONG_TYPE;
+ } else if (Constants.TYPE_CHARACTER.equals(type)) {
+ return Type.CHAR_TYPE;
+ } else if (Constants.TYPE_BYTE.equals(type)) {
+ return Type.BYTE_TYPE;
+ } else if (Constants.TYPE_FLOAT.equals(type)) {
+ return Type.FLOAT_TYPE;
+ } else if (Constants.TYPE_SHORT.equals(type)) {
+ return Type.SHORT_TYPE;
+ } else {
+ return type;
+ }
+ }
+
+ public static boolean isArray(Type type) {
+ return type.getSort() == Type.ARRAY;
+ }
+
+ public static Type getComponentType(Type type) {
+ if (!isArray(type)) {
+ throw new IllegalArgumentException("Type " + type + " is not an array");
+ }
+ return Type.getType(type.getDescriptor().substring(1));
+ }
+
+ public static boolean isPrimitive(Type type) {
+ switch (type.getSort()) {
+ case Type.ARRAY:
+ case Type.OBJECT:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ public static String emulateClassGetName(Type type) {
+ if (isArray(type)) {
+ return type.getDescriptor().replace('/', '.');
+ } else {
+ return getClassName(type);
+ }
+ }
+
+ public static boolean isConstructor(MethodInfo method) {
+ return method.getSignature().getName().equals(Constants.CONSTRUCTOR_NAME);
+ }
+
+ public static Type[] getTypes(Class[] classes) {
+ if (classes == null) {
+ return null;
+ }
+ Type[] types = new Type[classes.length];
+ for (int i = 0; i < classes.length; i++) {
+ types[i] = Type.getType(classes[i]);
+ }
+ return types;
+ }
+
+ public static int ICONST(int value) {
+ switch (value) {
+ case -1: return Constants.ICONST_M1;
+ case 0: return Constants.ICONST_0;
+ case 1: return Constants.ICONST_1;
+ case 2: return Constants.ICONST_2;
+ case 3: return Constants.ICONST_3;
+ case 4: return Constants.ICONST_4;
+ case 5: return Constants.ICONST_5;
+ }
+ return -1; // error
+ }
+
+ public static int LCONST(long value) {
+ if (value == 0L) {
+ return Constants.LCONST_0;
+ } else if (value == 1L) {
+ return Constants.LCONST_1;
+ } else {
+ return -1; // error
+ }
+ }
+
+ public static int FCONST(float value) {
+ if (value == 0f) {
+ return Constants.FCONST_0;
+ } else if (value == 1f) {
+ return Constants.FCONST_1;
+ } else if (value == 2f) {
+ return Constants.FCONST_2;
+ } else {
+ return -1; // error
+ }
+ }
+
+ public static int DCONST(double value) {
+ if (value == 0d) {
+ return Constants.DCONST_0;
+ } else if (value == 1d) {
+ return Constants.DCONST_1;
+ } else {
+ return -1; // error
+ }
+ }
+
+ public static int NEWARRAY(Type type) {
+ switch (type.getSort()) {
+ case Type.BYTE:
+ return Constants.T_BYTE;
+ case Type.CHAR:
+ return Constants.T_CHAR;
+ case Type.DOUBLE:
+ return Constants.T_DOUBLE;
+ case Type.FLOAT:
+ return Constants.T_FLOAT;
+ case Type.INT:
+ return Constants.T_INT;
+ case Type.LONG:
+ return Constants.T_LONG;
+ case Type.SHORT:
+ return Constants.T_SHORT;
+ case Type.BOOLEAN:
+ return Constants.T_BOOLEAN;
+ default:
+ return -1; // error
+ }
+ }
+
+ public static String escapeType(String s) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, len = s.length(); i < len; i++) {
+ char c = s.charAt(i);
+ switch (c) {
+ case '$': sb.append("$24"); break;
+ case '.': sb.append("$2E"); break;
+ case '[': sb.append("$5B"); break;
+ case ';': sb.append("$3B"); break;
+ case '(': sb.append("$28"); break;
+ case ')': sb.append("$29"); break;
+ case '/': sb.append("$2F"); break;
+ default:
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/VisibilityPredicate.java b/blade-aop/src/main/java/net/sf/cglib/core/VisibilityPredicate.java
new file mode 100644
index 000000000..fbefab121
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/VisibilityPredicate.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.core;
+
+import java.lang.reflect.*;
+import org.objectweb.asm.Type;
+
+public class VisibilityPredicate implements Predicate {
+ private boolean protectedOk;
+ private String pkg;
+ private boolean samePackageOk;
+
+ public VisibilityPredicate(Class source, boolean protectedOk) {
+ this.protectedOk = protectedOk;
+ // same package is not ok for the bootstrap loaded classes. In all other cases we are
+ // generating classes in the same classloader
+ this.samePackageOk = source.getClassLoader() != null;
+ pkg = TypeUtils.getPackageName(Type.getType(source));
+ }
+
+ public boolean evaluate(Object arg) {
+ Member member = (Member)arg;
+ int mod = member.getModifiers();
+ if (Modifier.isPrivate(mod)) {
+ return false;
+ } else if (Modifier.isPublic(mod)) {
+ return true;
+ } else if (Modifier.isProtected(mod) && protectedOk) {
+ // protected is fine if 'protectedOk' is true (for subclasses)
+ return true;
+ } else {
+ // protected/package private if the member is in the same package as the source class
+ // and we are generating into the same classloader.
+ return samePackageOk
+ && pkg.equals(TypeUtils.getPackageName(Type.getType(member.getDeclaringClass())));
+ }
+ }
+}
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/WeakCacheKey.java b/blade-aop/src/main/java/net/sf/cglib/core/WeakCacheKey.java
new file mode 100644
index 000000000..ebbb23b04
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/WeakCacheKey.java
@@ -0,0 +1,42 @@
+package net.sf.cglib.core;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Allows to check for object equality, yet the class does not keep strong reference to the target.
+ * {@link #equals(Object)} returns true if and only if the reference is not yet expired and target
+ * objects are equal in terms of {@link #equals(Object)}.
+ *
+ * This an internal class, thus it might disappear in future cglib releases.
+ *
+ * @param type of the reference
+ */
+public class WeakCacheKey extends WeakReference {
+ private final int hash;
+
+ public WeakCacheKey(T referent) {
+ super(referent);
+ this.hash = referent.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof WeakCacheKey)) {
+ return false;
+ }
+ Object ours = get();
+ Object theirs = ((WeakCacheKey) obj).get();
+ return ours != null && theirs != null && ours.equals(theirs);
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ T t = get();
+ return t == null ? "Clean WeakIdentityKey, hash: " + hash : t.toString();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/internal/CustomizerRegistry.java b/blade-aop/src/main/java/net/sf/cglib/core/internal/CustomizerRegistry.java
new file mode 100644
index 000000000..e04206b65
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/internal/CustomizerRegistry.java
@@ -0,0 +1,48 @@
+package net.sf.cglib.core.internal;
+
+import net.sf.cglib.core.Customizer;
+import net.sf.cglib.core.FieldTypeCustomizer;
+import net.sf.cglib.core.KeyFactoryCustomizer;
+
+import java.util.*;
+
+public class CustomizerRegistry {
+ private final Class[] customizerTypes;
+ private Map> customizers = new HashMap>();
+
+ public CustomizerRegistry(Class[] customizerTypes) {
+ this.customizerTypes = customizerTypes;
+ }
+
+ public void add(KeyFactoryCustomizer customizer) {
+ Class extends KeyFactoryCustomizer> klass = customizer.getClass();
+ for (Class type : customizerTypes) {
+ if (type.isAssignableFrom(klass)) {
+ List list = customizers.get(type);
+ if (list == null) {
+ customizers.put(type, list = new ArrayList());
+ }
+ list.add(customizer);
+ }
+ }
+ }
+
+ public List get(Class klass) {
+ List list = customizers.get(klass);
+ if (list == null) {
+ return Collections.emptyList();
+ }
+ return (List) list;
+ }
+
+ /**
+ * @deprecated Only to keep backward compatibility.
+ */
+ @Deprecated
+ public static CustomizerRegistry singleton(Customizer customizer)
+ {
+ CustomizerRegistry registry = new CustomizerRegistry(new Class[]{Customizer.class});
+ registry.add(customizer);
+ return registry;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/internal/Function.java b/blade-aop/src/main/java/net/sf/cglib/core/internal/Function.java
new file mode 100644
index 000000000..5da759c61
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/internal/Function.java
@@ -0,0 +1,5 @@
+package net.sf.cglib.core.internal;
+
+public interface Function {
+ V apply(K key);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/core/internal/LoadingCache.java b/blade-aop/src/main/java/net/sf/cglib/core/internal/LoadingCache.java
new file mode 100644
index 000000000..24cd9e418
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/core/internal/LoadingCache.java
@@ -0,0 +1,86 @@
+package net.sf.cglib.core.internal;
+
+import java.util.concurrent.*;
+
+public class LoadingCache {
+ protected final ConcurrentMap map;
+ protected final Function loader;
+ protected final Function keyMapper;
+
+ public static final Function IDENTITY = new Function() {
+ public Object apply(Object key) {
+ return key;
+ }
+ };
+
+ public LoadingCache(Function keyMapper, Function loader) {
+ this.keyMapper = keyMapper;
+ this.loader = loader;
+ this.map = new ConcurrentHashMap();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Function identity() {
+ return IDENTITY;
+ }
+
+ public V get(K key) {
+ final KK cacheKey = keyMapper.apply(key);
+ Object v = map.get(cacheKey);
+ if (v != null && !(v instanceof FutureTask)) {
+ return (V) v;
+ }
+
+ return createEntry(key, cacheKey, v);
+ }
+
+ /**
+ * Loads entry to the cache.
+ * If entry is missing, put {@link FutureTask} first so other competing thread might wait for the result.
+ * @param key original key that would be used to load the instance
+ * @param cacheKey key that would be used to store the entry in internal map
+ * @param v null or {@link FutureTask}
+ * @return newly created instance
+ */
+ protected V createEntry(final K key, KK cacheKey, Object v) {
+ FutureTask task;
+ boolean creator = false;
+ if (v != null) {
+ // Another thread is already loading an instance
+ task = (FutureTask) v;
+ } else {
+ task = new FutureTask(new Callable() {
+ public V call() throws Exception {
+ return loader.apply(key);
+ }
+ });
+ Object prevTask = map.putIfAbsent(cacheKey, task);
+ if (prevTask == null) {
+ // creator does the load
+ creator = true;
+ task.run();
+ } else if (prevTask instanceof FutureTask) {
+ task = (FutureTask) prevTask;
+ } else {
+ return (V) prevTask;
+ }
+ }
+
+ V result;
+ try {
+ result = task.get();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException("Interrupted while loading cache item", e);
+ } catch (ExecutionException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw ((RuntimeException) cause);
+ }
+ throw new IllegalStateException("Unable to load cache item", cause);
+ }
+ if (creator) {
+ map.put(cacheKey, result);
+ }
+ return result;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/BridgeMethodResolver.java b/blade-aop/src/main/java/net/sf/cglib/proxy/BridgeMethodResolver.java
new file mode 100644
index 000000000..574857c1c
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/BridgeMethodResolver.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2011 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 net.sf.cglib.proxy;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import net.sf.cglib.core.Signature;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Uses bytecode reflection to figure out the targets of all bridge methods
+ * that use invokespecial, so that we can later rewrite them to use invokevirtual.
+ *
+ * @author sberlin@gmail.com (Sam Berlin)
+ */
+class BridgeMethodResolver {
+
+ private final Map/* */declToBridge;
+
+ public BridgeMethodResolver(Map declToBridge) {
+ this.declToBridge = declToBridge;
+ }
+
+ /**
+ * Finds all bridge methods that are being called with invokespecial &
+ * returns them.
+ */
+ public Map/**/resolveAll() {
+ Map resolved = new HashMap();
+ for (Iterator entryIter = declToBridge.entrySet().iterator(); entryIter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry)entryIter.next();
+ Class owner = (Class)entry.getKey();
+ Set bridges = (Set)entry.getValue();
+ try {
+ new ClassReader(owner.getName())
+ .accept(new BridgedFinder(bridges, resolved),
+ ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
+ } catch(IOException ignored) {}
+ }
+ return resolved;
+ }
+
+ private static class BridgedFinder extends ClassVisitor {
+ private Map/**/ resolved;
+ private Set/**/ eligableMethods;
+
+ private Signature currentMethod = null;
+
+ BridgedFinder(Set eligableMethods, Map resolved) {
+ super(Opcodes.ASM5);
+ this.resolved = resolved;
+ this.eligableMethods = eligableMethods;
+ }
+
+ public void visit(int version, int access, String name,
+ String signature, String superName, String[] interfaces) {
+ }
+
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ Signature sig = new Signature(name, desc);
+ if (eligableMethods.remove(sig)) {
+ currentMethod = sig;
+ return new MethodVisitor(Opcodes.ASM5) {
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (opcode == Opcodes.INVOKESPECIAL && currentMethod != null) {
+ Signature target = new Signature(name, desc);
+ // If the target signature is the same as the current,
+ // we shouldn't change our bridge becaues invokespecial
+ // is the only way to make progress (otherwise we'll
+ // get infinite recursion). This would typically
+ // only happen when a bridge method is created to widen
+ // the visibility of a superclass' method.
+ if (!target.equals(currentMethod)) {
+ resolved.put(currentMethod, target);
+ }
+ currentMethod = null;
+ }
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+ }
+
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/Callback.java b/blade-aop/src/main/java/net/sf/cglib/proxy/Callback.java
new file mode 100644
index 000000000..bcd7f5dd7
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/Callback.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+/**
+ * All callback interfaces used by {@link Enhancer} extend this interface.
+ * @see MethodInterceptor
+ * @see NoOp
+ * @see LazyLoader
+ * @see Dispatcher
+ * @see InvocationHandler
+ * @see FixedValue
+ */
+public interface Callback
+{
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackFilter.java b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackFilter.java
new file mode 100644
index 000000000..21f001926
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackFilter.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.Method;
+
+/**
+ * Map methods of subclasses generated by {@link Enhancer} to a particular
+ * callback. The type of the callbacks chosen for each method affects
+ * the bytecode generated for that method in the subclass, and cannot
+ * change for the life of the class.
+ * Note: {@link CallbackFilter} implementations are supposed to be
+ * lightweight as cglib might keep {@link CallbackFilter} objects
+ * alive to enable caching of generated classes. Prefer using {@code static}
+ * classes for implementation of {@link CallbackFilter}.
+ */
+public interface CallbackFilter {
+ /**
+ * Map a method to a callback.
+ * @param method the intercepted method
+ * @return the index into the array of callbacks (as specified by {@link Enhancer#setCallbacks}) to use for the method,
+ */
+ int accept(Method method);
+
+ /**
+ * The CallbackFilter in use affects which cached class
+ * the Enhancer will use, so this is a reminder that
+ * you should correctly implement equals and
+ * hashCode for custom CallbackFilter
+ * implementations in order to improve performance.
+ */
+ boolean equals(Object o);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackGenerator.java b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackGenerator.java
new file mode 100644
index 000000000..283f22ac7
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackGenerator.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.util.List;
+import net.sf.cglib.core.*;
+
+interface CallbackGenerator
+{
+ void generate(ClassEmitter ce, Context context, List methods) throws Exception;
+ void generateStatic(CodeEmitter e, Context context, List methods) throws Exception;
+
+ interface Context
+ {
+ ClassLoader getClassLoader();
+ CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method);
+ int getOriginalModifiers(MethodInfo method);
+ int getIndex(MethodInfo method);
+ void emitCallback(CodeEmitter ce, int index);
+ Signature getImplSignature(MethodInfo method);
+ void emitInvoke(CodeEmitter e, MethodInfo method);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackHelper.java b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackHelper.java
new file mode 100644
index 000000000..b2e7e3039
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackHelper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.proxy;
+
+import net.sf.cglib.core.ReflectUtils;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * @version $Id: CallbackHelper.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $
+ */
+abstract public class CallbackHelper
+implements CallbackFilter
+{
+ private Map methodMap = new HashMap();
+ private List callbacks = new ArrayList();
+
+ public CallbackHelper(Class superclass, Class[] interfaces)
+ {
+ List methods = new ArrayList();
+ Enhancer.getMethods(superclass, interfaces, methods);
+ Map indexes = new HashMap();
+ for (int i = 0, size = methods.size(); i < size; i++) {
+ Method method = (Method)methods.get(i);
+ Object callback = getCallback(method);
+ if (callback == null)
+ throw new IllegalStateException("getCallback cannot return null");
+ boolean isCallback = callback instanceof Callback;
+ if (!(isCallback || (callback instanceof Class)))
+ throw new IllegalStateException("getCallback must return a Callback or a Class");
+ if (i > 0 && ((callbacks.get(i - 1) instanceof Callback) ^ isCallback))
+ throw new IllegalStateException("getCallback must return a Callback or a Class consistently for every Method");
+ Integer index = (Integer)indexes.get(callback);
+ if (index == null) {
+ index = new Integer(callbacks.size());
+ indexes.put(callback, index);
+ }
+ methodMap.put(method, index);
+ callbacks.add(callback);
+ }
+ }
+
+ abstract protected Object getCallback(Method method);
+
+ public Callback[] getCallbacks()
+ {
+ if (callbacks.size() == 0)
+ return new Callback[0];
+ if (callbacks.get(0) instanceof Callback) {
+ return (Callback[])callbacks.toArray(new Callback[callbacks.size()]);
+ } else {
+ throw new IllegalStateException("getCallback returned classes, not callbacks; call getCallbackTypes instead");
+ }
+ }
+
+ public Class[] getCallbackTypes()
+ {
+ if (callbacks.size() == 0)
+ return new Class[0];
+ if (callbacks.get(0) instanceof Callback) {
+ return ReflectUtils.getClasses(getCallbacks());
+ } else {
+ return (Class[])callbacks.toArray(new Class[callbacks.size()]);
+ }
+ }
+
+ public int accept(Method method)
+ {
+ return ((Integer)methodMap.get(method)).intValue();
+ }
+
+ public int hashCode()
+ {
+ return methodMap.hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == null)
+ return false;
+ if (!(o instanceof CallbackHelper))
+ return false;
+ return methodMap.equals(((CallbackHelper)o).methodMap);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackInfo.java b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackInfo.java
new file mode 100644
index 000000000..2fcece882
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/CallbackInfo.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.proxy;
+
+import org.objectweb.asm.Type;
+
+class CallbackInfo
+{
+ public static Type[] determineTypes(Class[] callbackTypes) {
+ return determineTypes(callbackTypes, true);
+ }
+
+ public static Type[] determineTypes(Class[] callbackTypes, boolean checkAll) {
+ Type[] types = new Type[callbackTypes.length];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = determineType(callbackTypes[i], checkAll);
+ }
+ return types;
+ }
+
+ public static Type[] determineTypes(Callback[] callbacks) {
+ return determineTypes(callbacks, true);
+ }
+
+ public static Type[] determineTypes(Callback[] callbacks, boolean checkAll) {
+ Type[] types = new Type[callbacks.length];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = determineType(callbacks[i], checkAll);
+ }
+ return types;
+ }
+
+ public static CallbackGenerator[] getGenerators(Type[] callbackTypes) {
+ CallbackGenerator[] generators = new CallbackGenerator[callbackTypes.length];
+ for (int i = 0; i < generators.length; i++) {
+ generators[i] = getGenerator(callbackTypes[i]);
+ }
+ return generators;
+ }
+
+ //////////////////// PRIVATE ////////////////////
+
+ private Class cls;
+ private CallbackGenerator generator;
+ private Type type;
+
+ private static final CallbackInfo[] CALLBACKS = {
+ new CallbackInfo(NoOp.class, NoOpGenerator.INSTANCE),
+ new CallbackInfo(MethodInterceptor.class, MethodInterceptorGenerator.INSTANCE),
+ new CallbackInfo(InvocationHandler.class, InvocationHandlerGenerator.INSTANCE),
+ new CallbackInfo(LazyLoader.class, LazyLoaderGenerator.INSTANCE),
+ new CallbackInfo(Dispatcher.class, DispatcherGenerator.INSTANCE),
+ new CallbackInfo(FixedValue.class, FixedValueGenerator.INSTANCE),
+ new CallbackInfo(ProxyRefDispatcher.class, DispatcherGenerator.PROXY_REF_INSTANCE),
+ };
+
+ private CallbackInfo(Class cls, CallbackGenerator generator) {
+ this.cls = cls;
+ this.generator = generator;
+ type = Type.getType(cls);
+ }
+
+ private static Type determineType(Callback callback, boolean checkAll) {
+ if (callback == null) {
+ throw new IllegalStateException("Callback is null");
+ }
+ return determineType(callback.getClass(), checkAll);
+ }
+
+ private static Type determineType(Class callbackType, boolean checkAll) {
+ Class cur = null;
+ Type type = null;
+ for (int i = 0; i < CALLBACKS.length; i++) {
+ CallbackInfo info = CALLBACKS[i];
+ if (info.cls.isAssignableFrom(callbackType)) {
+ if (cur != null) {
+ throw new IllegalStateException("Callback implements both " + cur + " and " + info.cls);
+ }
+ cur = info.cls;
+ type = info.type;
+ if (!checkAll) {
+ break;
+ }
+ }
+ }
+ if (cur == null) {
+ throw new IllegalStateException("Unknown callback type " + callbackType);
+ }
+ return type;
+ }
+
+ private static CallbackGenerator getGenerator(Type callbackType) {
+ for (int i = 0; i < CALLBACKS.length; i++) {
+ CallbackInfo info = CALLBACKS[i];
+ if (info.type.equals(callbackType)) {
+ return info.generator;
+ }
+ }
+ throw new IllegalStateException("Unknown callback type " + callbackType);
+ }
+}
+
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/Dispatcher.java b/blade-aop/src/main/java/net/sf/cglib/proxy/Dispatcher.java
new file mode 100644
index 000000000..374a06efd
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/Dispatcher.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+/**
+ * Dispatching {@link Enhancer} callback. This is identical to the
+ * {@link LazyLoader} interface but needs to be separate so that Enhancer
+ * knows which type of code to generate.
+ */
+public interface Dispatcher extends Callback {
+ /**
+ * Return the object which the original method invocation should
+ * be dispatched. This method is called for every method invocation.
+ * @return an object that can invoke the method
+ */
+ Object loadObject() throws Exception;
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/DispatcherGenerator.java b/blade-aop/src/main/java/net/sf/cglib/proxy/DispatcherGenerator.java
new file mode 100644
index 000000000..3a337ad72
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/DispatcherGenerator.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Type;
+
+class DispatcherGenerator implements CallbackGenerator {
+ public static final DispatcherGenerator INSTANCE =
+ new DispatcherGenerator(false);
+ public static final DispatcherGenerator PROXY_REF_INSTANCE =
+ new DispatcherGenerator(true);
+
+ private static final Type DISPATCHER =
+ TypeUtils.parseType("net.sf.cglib.proxy.Dispatcher");
+ private static final Type PROXY_REF_DISPATCHER =
+ TypeUtils.parseType("net.sf.cglib.proxy.ProxyRefDispatcher");
+ private static final Signature LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject()");
+ private static final Signature PROXY_REF_LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject(Object)");
+
+ private boolean proxyRef;
+
+ private DispatcherGenerator(boolean proxyRef) {
+ this.proxyRef = proxyRef;
+ }
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ if (!TypeUtils.isProtected(method.getModifiers())) {
+ CodeEmitter e = context.beginMethod(ce, method);
+ context.emitCallback(e, context.getIndex(method));
+ if (proxyRef) {
+ e.load_this();
+ e.invoke_interface(PROXY_REF_DISPATCHER, PROXY_REF_LOAD_OBJECT);
+ } else {
+ e.invoke_interface(DISPATCHER, LOAD_OBJECT);
+ }
+ e.checkcast(method.getClassInfo().getType());
+ e.load_args();
+ e.invoke(method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/Enhancer.java b/blade-aop/src/main/java/net/sf/cglib/proxy/Enhancer.java
new file mode 100644
index 000000000..7e7d831bc
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/Enhancer.java
@@ -0,0 +1,1315 @@
+/*
+ * Copyright 2002,2003,2004 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 net.sf.cglib.proxy;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import java.util.*;
+
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.Label;
+
+/**
+ * Generates dynamic subclasses to enable method interception. This
+ * class started as a substitute for the standard Dynamic Proxy support
+ * included with JDK 1.3, but one that allowed the proxies to extend a
+ * concrete base class, in addition to implementing interfaces. The dynamically
+ * generated subclasses override the non-final methods of the superclass and
+ * have hooks which callback to user-defined interceptor
+ * implementations.
+ *
+ * The original and most general callback type is the {@link MethodInterceptor}, which
+ * in AOP terms enables "around advice"--that is, you can invoke custom code both before
+ * and after the invocation of the "super" method. In addition you can modify the
+ * arguments before calling the super method, or not call it at all.
+ *
+ * Although MethodInterceptor is generic enough to meet any
+ * interception need, it is often overkill. For simplicity and performance, additional
+ * specialized callback types, such as {@link LazyLoader} are also available.
+ * Often a single callback will be used per enhanced class, but you can control
+ * which callback is used on a per-method basis with a {@link CallbackFilter}.
+ *
+ * The most common uses of this class are embodied in the static helper methods. For
+ * advanced needs, such as customizing the ClassLoader to use, you should create
+ * a new instance of Enhancer. Other classes within CGLIB follow a similar pattern.
+ *
+ * All enhanced objects implement the {@link Factory} interface, unless {@link #setUseFactory} is
+ * used to explicitly disable this feature. The Factory interface provides an API
+ * to change the callbacks of an existing object, as well as a faster and easier way to create
+ * new instances of the same type.
+ *
+ * For an almost drop-in replacement for
+ * java.lang.reflect.Proxy, see the {@link Proxy} class.
+ */
+public class Enhancer extends AbstractClassGenerator
+{
+ private static final CallbackFilter ALL_ZERO = new CallbackFilter(){
+ public int accept(Method method) {
+ return 0;
+ }
+ };
+
+ private static final Source SOURCE = new Source(Enhancer.class.getName());
+ private static final EnhancerKey KEY_FACTORY =
+ (EnhancerKey)KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null);
+
+ private static final String BOUND_FIELD = "CGLIB$BOUND";
+ private static final String FACTORY_DATA_FIELD = "CGLIB$FACTORY_DATA";
+ private static final String THREAD_CALLBACKS_FIELD = "CGLIB$THREAD_CALLBACKS";
+ private static final String STATIC_CALLBACKS_FIELD = "CGLIB$STATIC_CALLBACKS";
+ private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS";
+ private static final String SET_STATIC_CALLBACKS_NAME = "CGLIB$SET_STATIC_CALLBACKS";
+ private static final String CONSTRUCTED_FIELD = "CGLIB$CONSTRUCTED";
+ /**
+ * {@link net.sf.cglib.core.AbstractClassGenerator.ClassLoaderData#generatedClasses} requires to keep cache key
+ * in a good shape (the keys should be up and running if the proxy class is alive), and one of the cache keys is
+ * {@link CallbackFilter}. That is why the generated class contains static field that keeps strong reference to
+ * the {@link #filter}.
+ *
This dance achieves two goals: ensures generated class is reusable and available through generatedClasses
+ * cache, and it enables to unload classloader and the related {@link CallbackFilter} in case user does not need
+ * that
+ */
+ private static final String CALLBACK_FILTER_FIELD = "CGLIB$CALLBACK_FILTER";
+
+ private static final Type OBJECT_TYPE =
+ TypeUtils.parseType("Object");
+ private static final Type FACTORY =
+ TypeUtils.parseType("net.sf.cglib.proxy.Factory");
+ private static final Type ILLEGAL_STATE_EXCEPTION =
+ TypeUtils.parseType("IllegalStateException");
+ private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
+ TypeUtils.parseType("IllegalArgumentException");
+ private static final Type THREAD_LOCAL =
+ TypeUtils.parseType("ThreadLocal");
+ private static final Type CALLBACK =
+ TypeUtils.parseType("net.sf.cglib.proxy.Callback");
+ private static final Type CALLBACK_ARRAY =
+ Type.getType(Callback[].class);
+ private static final Signature CSTRUCT_NULL =
+ TypeUtils.parseConstructor("");
+ private static final Signature SET_THREAD_CALLBACKS =
+ new Signature(SET_THREAD_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY });
+ private static final Signature SET_STATIC_CALLBACKS =
+ new Signature(SET_STATIC_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY });
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ CALLBACK_ARRAY });
+ private static final Signature MULTIARG_NEW_INSTANCE =
+ new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{
+ Constants.TYPE_CLASS_ARRAY,
+ Constants.TYPE_OBJECT_ARRAY,
+ CALLBACK_ARRAY,
+ });
+ private static final Signature SINGLE_NEW_INSTANCE =
+ new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ CALLBACK });
+ private static final Signature SET_CALLBACK =
+ new Signature("setCallback", Type.VOID_TYPE, new Type[]{ Type.INT_TYPE, CALLBACK });
+ private static final Signature GET_CALLBACK =
+ new Signature("getCallback", CALLBACK, new Type[]{ Type.INT_TYPE });
+ private static final Signature SET_CALLBACKS =
+ new Signature("setCallbacks", Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY });
+ private static final Signature GET_CALLBACKS =
+ new Signature("getCallbacks", CALLBACK_ARRAY, new Type[0]);
+ private static final Signature THREAD_LOCAL_GET =
+ TypeUtils.parseSignature("Object get()");
+ private static final Signature THREAD_LOCAL_SET =
+ TypeUtils.parseSignature("void set(Object)");
+ private static final Signature BIND_CALLBACKS =
+ TypeUtils.parseSignature("void CGLIB$BIND_CALLBACKS(Object)");
+
+ private EnhancerFactoryData currentData;
+ private Object currentKey;
+
+ /** Internal interface, only public due to ClassLoader issues. */
+ public interface EnhancerKey {
+ public Object newInstance(String type,
+ String[] interfaces,
+ WeakCacheKey filter,
+ Type[] callbackTypes,
+ boolean useFactory,
+ boolean interceptDuringConstruction,
+ Long serialVersionUID);
+ }
+
+ private Class[] interfaces;
+ private CallbackFilter filter;
+ private Callback[] callbacks;
+ private Type[] callbackTypes;
+ private boolean validateCallbackTypes;
+ private boolean classOnly;
+ private Class superclass;
+ private Class[] argumentTypes;
+ private Object[] arguments;
+ private boolean useFactory = true;
+ private Long serialVersionUID;
+ private boolean interceptDuringConstruction = true;
+
+ /**
+ * Create a new Enhancer. A new Enhancer
+ * object should be used for each generated object, and should not
+ * be shared across threads. To create additional instances of a
+ * generated class, use the Factory interface.
+ * @see Factory
+ */
+ public Enhancer() {
+ super(SOURCE);
+ }
+
+ /**
+ * Set the class which the generated class will extend. As a convenience,
+ * if the supplied superclass is actually an interface, setInterfaces
+ * will be called with the appropriate argument instead.
+ * A non-interface argument must not be declared as final, and must have an
+ * accessible constructor.
+ * @param superclass class to extend or interface to implement
+ * @see #setInterfaces(Class[])
+ */
+ public void setSuperclass(Class superclass) {
+ if (superclass != null && superclass.isInterface()) {
+ setInterfaces(new Class[]{ superclass });
+ } else if (superclass != null && superclass.equals(Object.class)) {
+ // affects choice of ClassLoader
+ this.superclass = null;
+ } else {
+ this.superclass = superclass;
+ }
+ }
+
+ /**
+ * Set the interfaces to implement. The Factory interface will
+ * always be implemented regardless of what is specified here.
+ * @param interfaces array of interfaces to implement, or null
+ * @see Factory
+ */
+ public void setInterfaces(Class[] interfaces) {
+ this.interfaces = interfaces;
+ }
+
+ /**
+ * Set the {@link CallbackFilter} used to map the generated class' methods
+ * to a particular callback index.
+ * New object instances will always use the same mapping, but may use different
+ * actual callback objects.
+ * @param filter the callback filter to use when generating a new class
+ * @see #setCallbacks
+ */
+ public void setCallbackFilter(CallbackFilter filter) {
+ this.filter = filter;
+ }
+
+
+ /**
+ * Set the single {@link Callback} to use.
+ * Ignored if you use {@link #createClass}.
+ * @param callback the callback to use for all methods
+ * @see #setCallbacks
+ */
+ public void setCallback(final Callback callback) {
+ setCallbacks(new Callback[]{ callback });
+ }
+
+ /**
+ * Set the array of callbacks to use.
+ * Ignored if you use {@link #createClass}.
+ * You must use a {@link CallbackFilter} to specify the index into this
+ * array for each method in the proxied class.
+ * @param callbacks the callback array
+ * @see #setCallbackFilter
+ * @see #setCallback
+ */
+ public void setCallbacks(Callback[] callbacks) {
+ if (callbacks != null && callbacks.length == 0) {
+ throw new IllegalArgumentException("Array cannot be empty");
+ }
+ this.callbacks = callbacks;
+ }
+
+ /**
+ * Set whether the enhanced object instances should implement
+ * the {@link Factory} interface.
+ * This was added for tools that need for proxies to be more
+ * indistinguishable from their targets. Also, in some cases it may
+ * be necessary to disable the Factory interface to
+ * prevent code from changing the underlying callbacks.
+ * @param useFactory whether to implement Factory; default is true
+ */
+ public void setUseFactory(boolean useFactory) {
+ this.useFactory = useFactory;
+ }
+
+ /**
+ * Set whether methods called from within the proxy's constructer
+ * will be intercepted. The default value is true. Unintercepted methods
+ * will call the method of the proxy's base class, if it exists.
+ * @param interceptDuringConstruction whether to intercept methods called from the constructor
+ */
+ public void setInterceptDuringConstruction(boolean interceptDuringConstruction) {
+ this.interceptDuringConstruction = interceptDuringConstruction;
+ }
+
+ /**
+ * Set the single type of {@link Callback} to use.
+ * This may be used instead of {@link #setCallback} when calling
+ * {@link #createClass}, since it may not be possible to have
+ * an array of actual callback instances.
+ * @param callbackType the type of callback to use for all methods
+ * @see #setCallbackTypes
+ */
+ public void setCallbackType(Class callbackType) {
+ setCallbackTypes(new Class[]{ callbackType });
+ }
+
+ /**
+ * Set the array of callback types to use.
+ * This may be used instead of {@link #setCallbacks} when calling
+ * {@link #createClass}, since it may not be possible to have
+ * an array of actual callback instances.
+ * You must use a {@link CallbackFilter} to specify the index into this
+ * array for each method in the proxied class.
+ * @param callbackTypes the array of callback types
+ */
+ public void setCallbackTypes(Class[] callbackTypes) {
+ if (callbackTypes != null && callbackTypes.length == 0) {
+ throw new IllegalArgumentException("Array cannot be empty");
+ }
+ this.callbackTypes = CallbackInfo.determineTypes(callbackTypes);
+ }
+
+ /**
+ * Generate a new class if necessary and uses the specified
+ * callbacks (if any) to create a new object instance.
+ * Uses the no-arg constructor of the superclass.
+ * @return a new instance
+ */
+ public Object create() {
+ classOnly = false;
+ argumentTypes = null;
+ return createHelper();
+ }
+
+ /**
+ * Generate a new class if necessary and uses the specified
+ * callbacks (if any) to create a new object instance.
+ * Uses the constructor of the superclass matching the argumentTypes
+ * parameter, with the given arguments.
+ * @param argumentTypes constructor signature
+ * @param arguments compatible wrapped arguments to pass to constructor
+ * @return a new instance
+ */
+ public Object create(Class[] argumentTypes, Object[] arguments) {
+ classOnly = false;
+ if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) {
+ throw new IllegalArgumentException("Arguments must be non-null and of equal length");
+ }
+ this.argumentTypes = argumentTypes;
+ this.arguments = arguments;
+ return createHelper();
+ }
+
+ /**
+ * Generate a new class if necessary and return it without creating a new instance.
+ * This ignores any callbacks that have been set.
+ * To create a new instance you will have to use reflection, and methods
+ * called during the constructor will not be intercepted. To avoid this problem,
+ * use the multi-arg create method.
+ * @see #create(Class[], Object[])
+ */
+ public Class createClass() {
+ classOnly = true;
+ return (Class)createHelper();
+ }
+
+ /**
+ * Insert a static serialVersionUID field into the generated class.
+ * @param sUID the field value, or null to avoid generating field.
+ */
+ public void setSerialVersionUID(Long sUID) {
+ serialVersionUID = sUID;
+ }
+
+ private void preValidate() {
+ if (callbackTypes == null) {
+ callbackTypes = CallbackInfo.determineTypes(callbacks, false);
+ validateCallbackTypes = true;
+ }
+ if (filter == null) {
+ if (callbackTypes.length > 1) {
+ throw new IllegalStateException("Multiple callback types possible but no filter specified");
+ }
+ filter = ALL_ZERO;
+ }
+ }
+
+ private void validate() {
+ if (classOnly ^ (callbacks == null)) {
+ if (classOnly) {
+ throw new IllegalStateException("createClass does not accept callbacks");
+ } else {
+ throw new IllegalStateException("Callbacks are required");
+ }
+ }
+ if (classOnly && (callbackTypes == null)) {
+ throw new IllegalStateException("Callback types are required");
+ }
+ if (validateCallbackTypes) {
+ callbackTypes = null;
+ }
+ if (callbacks != null && callbackTypes != null) {
+ if (callbacks.length != callbackTypes.length) {
+ throw new IllegalStateException("Lengths of callback and callback types array must be the same");
+ }
+ Type[] check = CallbackInfo.determineTypes(callbacks);
+ for (int i = 0; i < check.length; i++) {
+ if (!check[i].equals(callbackTypes[i])) {
+ throw new IllegalStateException("Callback " + check[i] + " is not assignable to " + callbackTypes[i]);
+ }
+ }
+ } else if (callbacks != null) {
+ callbackTypes = CallbackInfo.determineTypes(callbacks);
+ }
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; i++) {
+ if (interfaces[i] == null) {
+ throw new IllegalStateException("Interfaces cannot be null");
+ }
+ if (!interfaces[i].isInterface()) {
+ throw new IllegalStateException(interfaces[i] + " is not an interface");
+ }
+ }
+ }
+ }
+
+ /**
+ * The idea of the class is to cache relevant java.lang.reflect instances so
+ * proxy-class can be instantiated faster that when using {@link ReflectUtils#newInstance(Class, Class[], Object[])}
+ * and {@link Enhancer#setThreadCallbacks(Class, Callback[])}
+ */
+ static class EnhancerFactoryData {
+ public final Class generatedClass;
+ private final Method setThreadCallbacks;
+ private final Class[] primaryConstructorArgTypes;
+ private final Constructor primaryConstructor;
+
+ public EnhancerFactoryData(Class generatedClass, Class[] primaryConstructorArgTypes, boolean classOnly) {
+ this.generatedClass = generatedClass;
+ try {
+ setThreadCallbacks = getCallbacksSetter(generatedClass, SET_THREAD_CALLBACKS_NAME);
+ if (classOnly) {
+ this.primaryConstructorArgTypes = null;
+ this.primaryConstructor = null;
+ } else {
+ this.primaryConstructorArgTypes = primaryConstructorArgTypes;
+ this.primaryConstructor = ReflectUtils.getConstructor(generatedClass, primaryConstructorArgTypes);
+ }
+ } catch (NoSuchMethodException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ /**
+ * Creates proxy instance for given argument types, and assigns the callbacks.
+ * Ideally, for each proxy class, just one set of argument types should be used,
+ * otherwise it would have to spend time on constructor lookup.
+ * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
+ * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
+ *
+ * @see #createUsingReflection(Class)
+ * @param argumentTypes constructor argument types
+ * @param arguments constructor arguments
+ * @param callbacks callbacks to set for the new instance
+ * @return newly created proxy
+ */
+ public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
+ setThreadCallbacks(callbacks);
+ try {
+ // Explicit reference equality is added here just in case Arrays.equals does not have one
+ if (primaryConstructorArgTypes == argumentTypes ||
+ Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
+ // If we have relevant Constructor instance at hand, just call it
+ // This skips "get constructors" machinery
+ return ReflectUtils.newInstance(primaryConstructor, arguments);
+ }
+ // Take a slow path if observing unexpected argument types
+ return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
+ } finally {
+ // clear thread callbacks to allow them to be gc'd
+ setThreadCallbacks(null);
+ }
+
+ }
+
+ private void setThreadCallbacks(Callback[] callbacks) {
+ try {
+ setThreadCallbacks.invoke(generatedClass, (Object) callbacks);
+ } catch (IllegalAccessException e) {
+ throw new CodeGenerationException(e);
+ } catch (InvocationTargetException e) {
+ throw new CodeGenerationException(e.getTargetException());
+ }
+ }
+ }
+
+ private Object createHelper() {
+ preValidate();
+ Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
+ ReflectUtils.getNames(interfaces),
+ filter == ALL_ZERO ? null : new WeakCacheKey(filter),
+ callbackTypes,
+ useFactory,
+ interceptDuringConstruction,
+ serialVersionUID);
+ this.currentKey = key;
+ Object result = super.create(key);
+ return result;
+ }
+
+ @Override
+ protected Class generate(ClassLoaderData data) {
+ validate();
+ if (superclass != null) {
+ setNamePrefix(superclass.getName());
+ } else if (interfaces != null) {
+ setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
+ }
+ return super.generate(data);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ if (superclass != null) {
+ return superclass.getClassLoader();
+ } else if (interfaces != null) {
+ return interfaces[0].getClassLoader();
+ } else {
+ return null;
+ }
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ if (superclass != null) {
+ return ReflectUtils.getProtectionDomain(superclass);
+ } else if (interfaces != null) {
+ return ReflectUtils.getProtectionDomain(interfaces[0]);
+ } else {
+ return null;
+ }
+ }
+
+ private Signature rename(Signature sig, int index) {
+ return new Signature("CGLIB$" + sig.getName() + "$" + index,
+ sig.getDescriptor());
+ }
+
+ /**
+ * Finds all of the methods that will be extended by an
+ * Enhancer-generated class using the specified superclass and
+ * interfaces. This can be useful in building a list of Callback
+ * objects. The methods are added to the end of the given list. Due
+ * to the subclassing nature of the classes generated by Enhancer,
+ * the methods are guaranteed to be non-static, non-final, and
+ * non-private. Each method signature will only occur once, even if
+ * it occurs in multiple classes.
+ * @param superclass the class that will be extended, or null
+ * @param interfaces the list of interfaces that will be implemented, or null
+ * @param methods the list into which to copy the applicable methods
+ */
+ public static void getMethods(Class superclass, Class[] interfaces, List methods)
+ {
+ getMethods(superclass, interfaces, methods, null, null);
+ }
+
+ private static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic)
+ {
+ ReflectUtils.addAllMethods(superclass, methods);
+ List target = (interfaceMethods != null) ? interfaceMethods : methods;
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; i++) {
+ if (interfaces[i] != Factory.class) {
+ ReflectUtils.addAllMethods(interfaces[i], target);
+ }
+ }
+ }
+ if (interfaceMethods != null) {
+ if (forcePublic != null) {
+ forcePublic.addAll(MethodWrapper.createSet(interfaceMethods));
+ }
+ methods.addAll(interfaceMethods);
+ }
+ CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_STATIC));
+ CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true));
+ CollectionUtils.filter(methods, new DuplicatesPredicate());
+ CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_FINAL));
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ Class sc = (superclass == null) ? Object.class : superclass;
+
+ if (TypeUtils.isFinal(sc.getModifiers()))
+ throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
+ List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
+ filterConstructors(sc, constructors);
+
+ // Order is very important: must add superclass, then
+ // its superclass chain, then each interface and
+ // its superinterfaces.
+ List actualMethods = new ArrayList();
+ List interfaceMethods = new ArrayList();
+ final Set forcePublic = new HashSet();
+ getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);
+
+ List methods = CollectionUtils.transform(actualMethods, new Transformer() {
+ public Object transform(Object value) {
+ Method method = (Method)value;
+ int modifiers = Constants.ACC_FINAL
+ | (method.getModifiers()
+ & ~Constants.ACC_ABSTRACT
+ & ~Constants.ACC_NATIVE
+ & ~Constants.ACC_SYNCHRONIZED);
+ if (forcePublic.contains(MethodWrapper.create(method))) {
+ modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
+ }
+ return ReflectUtils.getMethodInfo(method, modifiers);
+ }
+ });
+
+ ClassEmitter e = new ClassEmitter(v);
+ if (currentData == null) {
+ e.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ Type.getType(sc),
+ (useFactory ?
+ TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) :
+ TypeUtils.getTypes(interfaces)),
+ Constants.SOURCE_FILE);
+ } else {
+ e.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ null,
+ new Type[]{FACTORY},
+ Constants.SOURCE_FILE);
+ }
+ List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
+
+ e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
+ e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null);
+ if (!interceptDuringConstruction) {
+ e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
+ }
+ e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
+ e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
+ if (serialVersionUID != null) {
+ e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
+ }
+
+ for (int i = 0; i < callbackTypes.length; i++) {
+ e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
+ }
+ // This is declared private to avoid "public field" pollution
+ e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null);
+
+ if (currentData == null) {
+ emitMethods(e, methods, actualMethods);
+ emitConstructors(e, constructorInfo);
+ } else {
+ emitDefaultConstructor(e);
+ }
+ emitSetThreadCallbacks(e);
+ emitSetStaticCallbacks(e);
+ emitBindCallbacks(e);
+
+ if (useFactory || currentData != null) {
+ int[] keys = getCallbackKeys();
+ emitNewInstanceCallbacks(e);
+ emitNewInstanceCallback(e);
+ emitNewInstanceMultiarg(e, constructorInfo);
+ emitGetCallback(e, keys);
+ emitSetCallback(e, keys);
+ emitGetCallbacks(e);
+ emitSetCallbacks(e);
+ }
+
+ e.end_class();
+ }
+
+ /**
+ * Filter the list of constructors from the superclass. The
+ * constructors which remain will be included in the generated
+ * class. The default implementation is to filter out all private
+ * constructors, but subclasses may extend Enhancer to override this
+ * behavior.
+ * @param sc the superclass
+ * @param constructors the list of all declared constructors from the superclass
+ * @throws IllegalArgumentException if there are no non-private constructors
+ */
+ protected void filterConstructors(Class sc, List constructors) {
+ CollectionUtils.filter(constructors, new VisibilityPredicate(sc, true));
+ if (constructors.size() == 0)
+ throw new IllegalArgumentException("No visible constructors in " + sc);
+ }
+
+ /**
+ * This method should not be called in regular flow.
+ * Technically speaking {@link #wrapCachedClass(Class)} uses {@link EnhancerFactoryData} as a cache value,
+ * and the latter enables faster instantiation than plain old reflection lookup and invoke.
+ * This method is left intact for backward compatibility reasons: just in case it was ever used.
+ *
+ * @param type class to instantiate
+ * @return newly created proxy instance
+ * @throws Exception if something goes wrong
+ */
+ protected Object firstInstance(Class type) throws Exception {
+ if (classOnly) {
+ return type;
+ } else {
+ return createUsingReflection(type);
+ }
+ }
+
+ protected Object nextInstance(Object instance) {
+ EnhancerFactoryData data = (EnhancerFactoryData) instance;
+
+ if (classOnly) {
+ return data.generatedClass;
+ }
+
+ Class[] argumentTypes = this.argumentTypes;
+ Object[] arguments = this.arguments;
+ if (argumentTypes == null) {
+ argumentTypes = Constants.EMPTY_CLASS_ARRAY;
+ arguments = null;
+ }
+ return data.newInstance(argumentTypes, arguments, callbacks);
+ }
+
+ @Override
+ protected Object wrapCachedClass(Class klass) {
+ Class[] argumentTypes = this.argumentTypes;
+ if (argumentTypes == null) {
+ argumentTypes = Constants.EMPTY_CLASS_ARRAY;
+ }
+ EnhancerFactoryData factoryData = new EnhancerFactoryData(klass, argumentTypes, classOnly);
+ Field factoryDataField = null;
+ try {
+ // The subsequent dance is performed just once for each class,
+ // so it does not matter much how fast it goes
+ factoryDataField = klass.getField(FACTORY_DATA_FIELD);
+ factoryDataField.set(null, factoryData);
+ Field callbackFilterField = klass.getDeclaredField(CALLBACK_FILTER_FIELD);
+ callbackFilterField.setAccessible(true);
+ callbackFilterField.set(null, this.filter);
+ } catch (NoSuchFieldException e) {
+ throw new CodeGenerationException(e);
+ } catch (IllegalAccessException e) {
+ throw new CodeGenerationException(e);
+ }
+ return new WeakReference(factoryData);
+ }
+
+ @Override
+ protected Object unwrapCachedValue(Object cached) {
+ if (currentKey instanceof EnhancerKey) {
+ EnhancerFactoryData data = ((WeakReference) cached).get();
+ return data;
+ }
+ return super.unwrapCachedValue(cached);
+ }
+
+ /**
+ * Call this method to register the {@link Callback} array to use before
+ * creating a new instance of the generated class via reflection. If you are using
+ * an instance of Enhancer or the {@link Factory} interface to create
+ * new instances, this method is unnecessary. Its primary use is for when you want to
+ * cache and reuse a generated class yourself, and the generated class does
+ * not implement the {@link Factory} interface.
+ *
+ * Note that this method only registers the callbacks on the current thread.
+ * If you want to register callbacks for instances created by multiple threads,
+ * use {@link #registerStaticCallbacks}.
+ *
+ * The registered callbacks are overwritten and subsequently cleared
+ * when calling any of the create methods (such as
+ * {@link #create}), or any {@link Factory} newInstance method.
+ * Otherwise they are not cleared, and you should be careful to set them
+ * back to null after creating new instances via reflection if
+ * memory leakage is a concern.
+ * @param generatedClass a class previously created by {@link Enhancer}
+ * @param callbacks the array of callbacks to use when instances of the generated
+ * class are created
+ * @see #setUseFactory
+ */
+ public static void registerCallbacks(Class generatedClass, Callback[] callbacks) {
+ setThreadCallbacks(generatedClass, callbacks);
+ }
+
+ /**
+ * Similar to {@link #registerCallbacks}, but suitable for use
+ * when multiple threads will be creating instances of the generated class.
+ * The thread-level callbacks will always override the static callbacks.
+ * Static callbacks are never cleared.
+ * @param generatedClass a class previously created by {@link Enhancer}
+ * @param callbacks the array of callbacks to use when instances of the generated
+ * class are created
+ */
+ public static void registerStaticCallbacks(Class generatedClass, Callback[] callbacks) {
+ setCallbacksHelper(generatedClass, callbacks, SET_STATIC_CALLBACKS_NAME);
+ }
+
+ /**
+ * Determine if a class was generated using Enhancer.
+ * @param type any class
+ * @return whether the class was generated using Enhancer
+ */
+ public static boolean isEnhanced(Class type) {
+ try {
+ getCallbacksSetter(type, SET_THREAD_CALLBACKS_NAME);
+ return true;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
+ private static void setThreadCallbacks(Class type, Callback[] callbacks) {
+ setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME);
+ }
+
+ private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
+ // TODO: optimize
+ try {
+ Method setter = getCallbacksSetter(type, methodName);
+ setter.invoke(null, new Object[]{ callbacks });
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException(type + " is not an enhanced class");
+ } catch (IllegalAccessException e) {
+ throw new CodeGenerationException(e);
+ } catch (InvocationTargetException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException {
+ return type.getDeclaredMethod(methodName, new Class[]{ Callback[].class });
+ }
+
+ /**
+ * Instantiates a proxy instance and assigns callback values.
+ * Implementation detail: java.lang.reflect instances are not cached, so this method should not
+ * be used on a hot path.
+ * This method is used when {@link #setUseCache(boolean)} is set to {@code false}.
+ *
+ * @param type class to instantiate
+ * @return newly created instance
+ */
+ private Object createUsingReflection(Class type) {
+ setThreadCallbacks(type, callbacks);
+ try{
+
+ if (argumentTypes != null) {
+
+ return ReflectUtils.newInstance(type, argumentTypes, arguments);
+
+ } else {
+
+ return ReflectUtils.newInstance(type);
+
+ }
+ }finally{
+ // clear thread callbacks to allow them to be gc'd
+ setThreadCallbacks(type, null);
+ }
+ }
+
+ /**
+ * Helper method to create an intercepted object.
+ * For finer control over the generated instance, use a new instance of Enhancer
+ * instead of this static method.
+ * @param type class to extend or interface to implement
+ * @param callback the callback to use for all methods
+ */
+ public static Object create(Class type, Callback callback) {
+ Enhancer e = new Enhancer();
+ e.setSuperclass(type);
+ e.setCallback(callback);
+ return e.create();
+ }
+
+ /**
+ * Helper method to create an intercepted object.
+ * For finer control over the generated instance, use a new instance of Enhancer
+ * instead of this static method.
+ * @param superclass class to extend or interface to implement
+ * @param interfaces array of interfaces to implement, or null
+ * @param callback the callback to use for all methods
+ */
+ public static Object create(Class superclass, Class interfaces[], Callback callback) {
+ Enhancer e = new Enhancer();
+ e.setSuperclass(superclass);
+ e.setInterfaces(interfaces);
+ e.setCallback(callback);
+ return e.create();
+ }
+
+ /**
+ * Helper method to create an intercepted object.
+ * For finer control over the generated instance, use a new instance of Enhancer
+ * instead of this static method.
+ * @param superclass class to extend or interface to implement
+ * @param interfaces array of interfaces to implement, or null
+ * @param filter the callback filter to use when generating a new class
+ * @param callbacks callback implementations to use for the enhanced object
+ */
+ public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) {
+ Enhancer e = new Enhancer();
+ e.setSuperclass(superclass);
+ e.setInterfaces(interfaces);
+ e.setCallbackFilter(filter);
+ e.setCallbacks(callbacks);
+ return e.create();
+ }
+
+ private void emitDefaultConstructor(ClassEmitter ce) {
+ Constructor declaredConstructor;
+ try {
+ declaredConstructor = Object.class.getDeclaredConstructor();
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException("Object should have default constructor ", e);
+ }
+ MethodInfo constructor = (MethodInfo) MethodInfoTransformer.getInstance().transform(declaredConstructor);
+ CodeEmitter e = EmitUtils.begin_method(ce, constructor, Constants.ACC_PUBLIC);
+ e.load_this();
+ e.dup();
+ Signature sig = constructor.getSignature();
+ e.super_invoke_constructor(sig);
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitConstructors(ClassEmitter ce, List constructors) {
+ boolean seenNull = false;
+ for (Iterator it = constructors.iterator(); it.hasNext();) {
+ MethodInfo constructor = (MethodInfo)it.next();
+ if (currentData != null && !"()V".equals(constructor.getSignature().getDescriptor())) {
+ continue;
+ }
+ CodeEmitter e = EmitUtils.begin_method(ce, constructor, Constants.ACC_PUBLIC);
+ e.load_this();
+ e.dup();
+ e.load_args();
+ Signature sig = constructor.getSignature();
+ seenNull = seenNull || sig.getDescriptor().equals("()V");
+ e.super_invoke_constructor(sig);
+ if (currentData == null) {
+ e.invoke_static_this(BIND_CALLBACKS);
+ if (!interceptDuringConstruction) {
+ e.load_this();
+ e.push(1);
+ e.putfield(CONSTRUCTED_FIELD);
+ }
+ }
+ e.return_value();
+ e.end_method();
+ }
+ if (!classOnly && !seenNull && arguments == null)
+ throw new IllegalArgumentException("Superclass has no null constructors but no arguments were given");
+ }
+
+ private int[] getCallbackKeys() {
+ int[] keys = new int[callbackTypes.length];
+ for (int i = 0; i < callbackTypes.length; i++) {
+ keys[i] = i;
+ }
+ return keys;
+ }
+
+ private void emitGetCallback(ClassEmitter ce, int[] keys) {
+ final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACK, null);
+ e.load_this();
+ e.invoke_static_this(BIND_CALLBACKS);
+ e.load_this();
+ e.load_arg(0);
+ e.process_switch(keys, new ProcessSwitchCallback() {
+ public void processCase(int key, Label end) {
+ e.getfield(getCallbackField(key));
+ e.goTo(end);
+ }
+ public void processDefault() {
+ e.pop(); // stack height
+ e.aconst_null();
+ }
+ });
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitSetCallback(ClassEmitter ce, int[] keys) {
+ final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACK, null);
+ e.load_arg(0);
+ e.process_switch(keys, new ProcessSwitchCallback() {
+ public void processCase(int key, Label end) {
+ e.load_this();
+ e.load_arg(1);
+ e.checkcast(callbackTypes[key]);
+ e.putfield(getCallbackField(key));
+ e.goTo(end);
+ }
+ public void processDefault() {
+ // TODO: error?
+ }
+ });
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitSetCallbacks(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACKS, null);
+ e.load_this();
+ e.load_arg(0);
+ for (int i = 0; i < callbackTypes.length; i++) {
+ e.dup2();
+ e.aaload(i);
+ e.checkcast(callbackTypes[i]);
+ e.putfield(getCallbackField(i));
+ }
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitGetCallbacks(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACKS, null);
+ e.load_this();
+ e.invoke_static_this(BIND_CALLBACKS);
+ e.load_this();
+ e.push(callbackTypes.length);
+ e.newarray(CALLBACK);
+ for (int i = 0; i < callbackTypes.length; i++) {
+ e.dup();
+ e.push(i);
+ e.load_this();
+ e.getfield(getCallbackField(i));
+ e.aastore();
+ }
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitNewInstanceCallbacks(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
+ Type thisType = getThisType(e);
+ e.load_arg(0);
+ e.invoke_static(thisType, SET_THREAD_CALLBACKS);
+ emitCommonNewInstance(e);
+ }
+
+ private Type getThisType(CodeEmitter e) {
+ if (currentData == null) {
+ return e.getClassEmitter().getClassType();
+ } else {
+ return Type.getType(currentData.generatedClass);
+ }
+ }
+
+ private void emitCommonNewInstance(CodeEmitter e) {
+ Type thisType = getThisType(e);
+ e.new_instance(thisType);
+ e.dup();
+ e.invoke_constructor(thisType);
+ e.aconst_null();
+ e.invoke_static(thisType, SET_THREAD_CALLBACKS);
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitNewInstanceCallback(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SINGLE_NEW_INSTANCE, null);
+ switch (callbackTypes.length) {
+ case 0:
+ // TODO: make sure Callback is null
+ break;
+ case 1:
+ // for now just make a new array; TODO: optimize
+ e.push(1);
+ e.newarray(CALLBACK);
+ e.dup();
+ e.push(0);
+ e.load_arg(0);
+ e.aastore();
+ e.invoke_static(getThisType(e), SET_THREAD_CALLBACKS);
+ break;
+ default:
+ e.throw_exception(ILLEGAL_STATE_EXCEPTION, "More than one callback object required");
+ }
+ emitCommonNewInstance(e);
+ }
+
+ private void emitNewInstanceMultiarg(ClassEmitter ce, List constructors) {
+ final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, MULTIARG_NEW_INSTANCE, null);
+ final Type thisType = getThisType(e);
+ e.load_arg(2);
+ e.invoke_static(thisType, SET_THREAD_CALLBACKS);
+ e.new_instance(thisType);
+ e.dup();
+ e.load_arg(0);
+ EmitUtils.constructor_switch(e, constructors, new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ MethodInfo constructor = (MethodInfo)key;
+ Type types[] = constructor.getSignature().getArgumentTypes();
+ for (int i = 0; i < types.length; i++) {
+ e.load_arg(1);
+ e.push(i);
+ e.aaload();
+ e.unbox(types[i]);
+ }
+ e.invoke_constructor(thisType, constructor.getSignature());
+ e.goTo(end);
+ }
+ public void processDefault() {
+ e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Constructor not found");
+ }
+ });
+ e.aconst_null();
+ e.invoke_static(thisType, SET_THREAD_CALLBACKS);
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitMethods(final ClassEmitter ce, List methods, List actualMethods) {
+ CallbackGenerator[] generators = CallbackInfo.getGenerators(callbackTypes);
+
+ Map groups = new HashMap();
+ final Map indexes = new HashMap();
+ final Map originalModifiers = new HashMap();
+ final Map positions = CollectionUtils.getIndexMap(methods);
+ final Map declToBridge = new HashMap();
+
+ Iterator it1 = methods.iterator();
+ Iterator it2 = (actualMethods != null) ? actualMethods.iterator() : null;
+
+ while (it1.hasNext()) {
+ MethodInfo method = (MethodInfo)it1.next();
+ Method actualMethod = (it2 != null) ? (Method)it2.next() : null;
+ int index = filter.accept(actualMethod);
+ if (index >= callbackTypes.length) {
+ throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index);
+ }
+ originalModifiers.put(method, new Integer((actualMethod != null) ? actualMethod.getModifiers() : method.getModifiers()));
+ indexes.put(method, new Integer(index));
+ List group = (List)groups.get(generators[index]);
+ if (group == null) {
+ groups.put(generators[index], group = new ArrayList(methods.size()));
+ }
+ group.add(method);
+
+ // Optimization: build up a map of Class -> bridge methods in class
+ // so that we can look up all the bridge methods in one pass for a class.
+ if (TypeUtils.isBridge(actualMethod.getModifiers())) {
+ Set bridges = (Set)declToBridge.get(actualMethod.getDeclaringClass());
+ if (bridges == null) {
+ bridges = new HashSet();
+ declToBridge.put(actualMethod.getDeclaringClass(), bridges);
+ }
+ bridges.add(method.getSignature());
+ }
+ }
+
+ final Map bridgeToTarget = new BridgeMethodResolver(declToBridge).resolveAll();
+
+ Set seenGen = new HashSet();
+ CodeEmitter se = ce.getStaticHook();
+ se.new_instance(THREAD_LOCAL);
+ se.dup();
+ se.invoke_constructor(THREAD_LOCAL, CSTRUCT_NULL);
+ se.putfield(THREAD_CALLBACKS_FIELD);
+
+ final Object[] state = new Object[1];
+ CallbackGenerator.Context context = new CallbackGenerator.Context() {
+ public ClassLoader getClassLoader() {
+ return Enhancer.this.getClassLoader();
+ }
+ public int getOriginalModifiers(MethodInfo method) {
+ return ((Integer)originalModifiers.get(method)).intValue();
+ }
+ public int getIndex(MethodInfo method) {
+ return ((Integer)indexes.get(method)).intValue();
+ }
+ public void emitCallback(CodeEmitter e, int index) {
+ emitCurrentCallback(e, index);
+ }
+ public Signature getImplSignature(MethodInfo method) {
+ return rename(method.getSignature(), ((Integer)positions.get(method)).intValue());
+ }
+ public void emitInvoke(CodeEmitter e, MethodInfo method) {
+ // If this is a bridge and we know the target was called from invokespecial,
+ // then we need to invoke_virtual w/ the bridge target instead of doing
+ // a super, because super may itself be using super, which would bypass
+ // any proxies on the target.
+ Signature bridgeTarget = (Signature)bridgeToTarget.get(method.getSignature());
+ if (bridgeTarget != null) {
+ // TODO: this assumes that the target has wider or the same type
+ // parameters than the current.
+ // In reality this should always be true because otherwise we wouldn't
+ // have had a bridge doing an invokespecial.
+ // If it isn't true, we would need to checkcast each argument
+ // against the target's argument types
+ e.invoke_virtual_this(bridgeTarget);
+
+ Type retType = method.getSignature().getReturnType();
+ // Not necessary to cast if the target & bridge have
+ // the same return type.
+ // (This conveniently includes void and primitive types,
+ // which would fail if casted. It's not possible to
+ // covariant from boxed to unbox (or vice versa), so no having
+ // to box/unbox for bridges).
+ // TODO: It also isn't necessary to checkcast if the return is
+ // assignable from the target. (This would happen if a subclass
+ // used covariant returns to narrow the return type within a bridge
+ // method.)
+ if (!retType.equals(bridgeTarget.getReturnType())) {
+ e.checkcast(retType);
+ }
+ } else {
+ e.super_invoke(method.getSignature());
+ }
+ }
+ public CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method) {
+ CodeEmitter e = EmitUtils.begin_method(ce, method);
+ if (!interceptDuringConstruction &&
+ !TypeUtils.isAbstract(method.getModifiers())) {
+ Label constructed = e.make_label();
+ e.load_this();
+ e.getfield(CONSTRUCTED_FIELD);
+ e.if_jump(e.NE, constructed);
+ e.load_this();
+ e.load_args();
+ e.super_invoke();
+ e.return_value();
+ e.mark(constructed);
+ }
+ return e;
+ }
+ };
+ for (int i = 0; i < callbackTypes.length; i++) {
+ CallbackGenerator gen = generators[i];
+ if (!seenGen.contains(gen)) {
+ seenGen.add(gen);
+ final List fmethods = (List)groups.get(gen);
+ if (fmethods != null) {
+ try {
+ gen.generate(ce, context, fmethods);
+ gen.generateStatic(se, context, fmethods);
+ } catch (RuntimeException x) {
+ throw x;
+ } catch (Exception x) {
+ throw new CodeGenerationException(x);
+ }
+ }
+ }
+ }
+ se.return_value();
+ se.end_method();
+ }
+
+ private void emitSetThreadCallbacks(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
+ SET_THREAD_CALLBACKS,
+ null);
+ e.getfield(THREAD_CALLBACKS_FIELD);
+ e.load_arg(0);
+ e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET);
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitSetStaticCallbacks(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
+ SET_STATIC_CALLBACKS,
+ null);
+ e.load_arg(0);
+ e.putfield(STATIC_CALLBACKS_FIELD);
+ e.return_value();
+ e.end_method();
+ }
+
+ private void emitCurrentCallback(CodeEmitter e, int index) {
+ e.load_this();
+ e.getfield(getCallbackField(index));
+ e.dup();
+ Label end = e.make_label();
+ e.ifnonnull(end);
+ e.pop(); // stack height
+ e.load_this();
+ e.invoke_static_this(BIND_CALLBACKS);
+ e.load_this();
+ e.getfield(getCallbackField(index));
+ e.mark(end);
+ }
+
+ private void emitBindCallbacks(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.PRIVATE_FINAL_STATIC,
+ BIND_CALLBACKS,
+ null);
+ Local me = e.make_local();
+ e.load_arg(0);
+ e.checkcast_this();
+ e.store_local(me);
+
+ Label end = e.make_label();
+ e.load_local(me);
+ e.getfield(BOUND_FIELD);
+ e.if_jump(e.NE, end);
+ e.load_local(me);
+ e.push(1);
+ e.putfield(BOUND_FIELD);
+
+ e.getfield(THREAD_CALLBACKS_FIELD);
+ e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_GET);
+ e.dup();
+ Label found_callback = e.make_label();
+ e.ifnonnull(found_callback);
+ e.pop();
+
+ e.getfield(STATIC_CALLBACKS_FIELD);
+ e.dup();
+ e.ifnonnull(found_callback);
+ e.pop();
+ e.goTo(end);
+
+ e.mark(found_callback);
+ e.checkcast(CALLBACK_ARRAY);
+ e.load_local(me);
+ e.swap();
+ for (int i = callbackTypes.length - 1; i >= 0; i--) {
+ if (i != 0) {
+ e.dup2();
+ }
+ e.aaload(i);
+ e.checkcast(callbackTypes[i]);
+ e.putfield(getCallbackField(i));
+ }
+
+ e.mark(end);
+ e.return_value();
+ e.end_method();
+ }
+
+ private static String getCallbackField(int index) {
+ return "CGLIB$CALLBACK_" + index;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/Factory.java b/blade-aop/src/main/java/net/sf/cglib/proxy/Factory.java
new file mode 100644
index 000000000..437f6ae13
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/Factory.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2002,2003 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 net.sf.cglib.proxy;
+
+/**
+ * All enhanced instances returned by the {@link Enhancer} class implement this interface.
+ * Using this interface for new instances is faster than going through the Enhancer
+ * interface or using reflection. In addition, to intercept methods called during
+ * object construction you must use these methods instead of reflection.
+ * @author Juozas Baliuka baliuka@mwm.lt
+ * @version $Id: Factory.java,v 1.13 2004/06/24 21:15:20 herbyderby Exp $
+ */
+public interface Factory {
+ /**
+ * Creates new instance of the same type, using the no-arg constructor.
+ * The class of this object must have been created using a single Callback type.
+ * If multiple callbacks are required an exception will be thrown.
+ * @param callback the new interceptor to use
+ * @return new instance of the same type
+ */
+ Object newInstance(Callback callback);
+
+ /**
+ * Creates new instance of the same type, using the no-arg constructor.
+ * @param callbacks the new callbacks(s) to use
+ * @return new instance of the same type
+ */
+ Object newInstance(Callback[] callbacks);
+
+ /**
+ * Creates a new instance of the same type, using the constructor
+ * matching the given signature.
+ * @param types the constructor argument types
+ * @param args the constructor arguments
+ * @param callbacks the new interceptor(s) to use
+ * @return new instance of the same type
+ */
+ Object newInstance(Class[] types, Object[] args, Callback[] callbacks);
+
+ /**
+ * Return the Callback implementation at the specified index.
+ * @param index the callback index
+ * @return the callback implementation
+ */
+ Callback getCallback(int index);
+
+ /**
+ * Set the callback for this object for the given type.
+ * @param index the callback index to replace
+ * @param callback the new callback
+ */
+ void setCallback(int index, Callback callback);
+
+ /**
+ * Replace all of the callbacks for this object at once.
+ * @param callbacks the new callbacks(s) to use
+ */
+ void setCallbacks(Callback[] callbacks);
+
+ /**
+ * Get the current set of callbacks for ths object.
+ * @return a new array instance
+ */
+ Callback[] getCallbacks();
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/FixedValue.java b/blade-aop/src/main/java/net/sf/cglib/proxy/FixedValue.java
new file mode 100644
index 000000000..06afdba8b
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/FixedValue.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+/**
+ * {@link Enhancer} callback that simply returns the value to return
+ * from the proxied method. No information about what method
+ * is being called is available to the callback, and the type of
+ * the returned object must be compatible with the return type of
+ * the proxied method. This makes this callback primarily useful
+ * for forcing a particular method (through the use of a {@link CallbackFilter}
+ * to return a fixed value with little overhead.
+ */
+public interface FixedValue extends Callback {
+ /**
+ * Return the object which the original method invocation should
+ * return. This method is called for every method invocation.
+ * @return an object matching the type of the return value for every
+ * method this callback is mapped to
+ */
+ Object loadObject() throws Exception;
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/FixedValueGenerator.java b/blade-aop/src/main/java/net/sf/cglib/proxy/FixedValueGenerator.java
new file mode 100644
index 000000000..1cd6e92e2
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/FixedValueGenerator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Type;
+
+class FixedValueGenerator implements CallbackGenerator {
+ public static final FixedValueGenerator INSTANCE = new FixedValueGenerator();
+ private static final Type FIXED_VALUE =
+ TypeUtils.parseType("net.sf.cglib.proxy.FixedValue");
+ private static final Signature LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject()");
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ CodeEmitter e = context.beginMethod(ce, method);
+ context.emitCallback(e, context.getIndex(method));
+ e.invoke_interface(FIXED_VALUE, LOAD_OBJECT);
+ e.unbox_or_zero(e.getReturnType());
+ e.return_value();
+ e.end_method();
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/InterfaceMaker.java b/blade-aop/src/main/java/net/sf/cglib/proxy/InterfaceMaker.java
new file mode 100644
index 000000000..f4f8b71f2
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/InterfaceMaker.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.*;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+
+/**
+ * Generates new interfaces at runtime.
+ * By passing a generated interface to the Enhancer's list of interfaces to
+ * implement, you can make your enhanced classes handle an arbitrary set
+ * of method signatures.
+ * @author Chris Nokleberg
+ * @version $Id: InterfaceMaker.java,v 1.4 2006/03/05 02:43:19 herbyderby Exp $
+ */
+public class InterfaceMaker extends AbstractClassGenerator
+{
+ private static final Source SOURCE = new Source(InterfaceMaker.class.getName());
+ private Map signatures = new HashMap();
+
+ /**
+ * Create a new InterfaceMaker. A new InterfaceMaker
+ * object should be used for each generated interface, and should not
+ * be shared across threads.
+ */
+ public InterfaceMaker() {
+ super(SOURCE);
+ }
+
+ /**
+ * Add a method signature to the interface.
+ * @param sig the method signature to add to the interface
+ * @param exceptions an array of exception types to declare for the method
+ */
+ public void add(Signature sig, Type[] exceptions) {
+ signatures.put(sig, exceptions);
+ }
+
+ /**
+ * Add a method signature to the interface. The method modifiers are ignored,
+ * since interface methods are by definition abstract and public.
+ * @param method the method to add to the interface
+ */
+ public void add(Method method) {
+ add(ReflectUtils.getSignature(method),
+ ReflectUtils.getExceptionTypes(method));
+ }
+
+ /**
+ * Add all the public methods in the specified class.
+ * Methods from superclasses are included, except for methods declared in the base
+ * Object class (e.g. getClass, equals, hashCode).
+ * @param class the class containing the methods to add to the interface
+ */
+ public void add(Class clazz) {
+ Method[] methods = clazz.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ if (!m.getDeclaringClass().getName().equals("java.lang.Object")) {
+ add(m);
+ }
+ }
+ }
+
+ /**
+ * Create an interface using the current set of method signatures.
+ */
+ public Class create() {
+ setUseCache(false);
+ return (Class)super.create(this);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return null;
+ }
+
+ protected Object firstInstance(Class type) {
+ return type;
+ }
+
+ protected Object nextInstance(Object instance) {
+ throw new IllegalStateException("InterfaceMaker does not cache");
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ ClassEmitter ce = new ClassEmitter(v);
+ ce.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC | Constants.ACC_INTERFACE,
+ getClassName(),
+ null,
+ null,
+ Constants.SOURCE_FILE);
+ for (Iterator it = signatures.keySet().iterator(); it.hasNext();) {
+ Signature sig = (Signature)it.next();
+ Type[] exceptions = (Type[])signatures.get(sig);
+ ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT,
+ sig,
+ exceptions).end_method();
+ }
+ ce.end_class();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/InvocationHandler.java b/blade-aop/src/main/java/net/sf/cglib/proxy/InvocationHandler.java
new file mode 100644
index 000000000..4307a6d19
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/InvocationHandler.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.Method;
+
+/**
+ * {@link java.lang.reflect.InvocationHandler} replacement (unavailable under JDK 1.2).
+ * This callback type is primarily for use by the {@link Proxy} class but
+ * may be used with {@link Enhancer} as well.
+ * @author Neeme Praks neeme@apache.org
+ * @version $Id: InvocationHandler.java,v 1.3 2004/06/24 21:15:20 herbyderby Exp $
+ */
+public interface InvocationHandler
+extends Callback
+{
+ /**
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
+ */
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
+
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/InvocationHandlerGenerator.java b/blade-aop/src/main/java/net/sf/cglib/proxy/InvocationHandlerGenerator.java
new file mode 100644
index 000000000..dcb028fcd
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/InvocationHandlerGenerator.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import net.sf.cglib.core.*;
+import java.util.*;
+import org.objectweb.asm.Type;
+
+class InvocationHandlerGenerator
+implements CallbackGenerator
+{
+ public static final InvocationHandlerGenerator INSTANCE = new InvocationHandlerGenerator();
+
+ private static final Type INVOCATION_HANDLER =
+ TypeUtils.parseType("net.sf.cglib.proxy.InvocationHandler");
+ private static final Type UNDECLARED_THROWABLE_EXCEPTION =
+ TypeUtils.parseType("net.sf.cglib.proxy.UndeclaredThrowableException");
+ private static final Type METHOD =
+ TypeUtils.parseType("java.lang.reflect.Method");
+ private static final Signature INVOKE =
+ TypeUtils.parseSignature("Object invoke(Object, java.lang.reflect.Method, Object[])");
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ Signature impl = context.getImplSignature(method);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, impl.getName(), METHOD, null);
+
+ CodeEmitter e = context.beginMethod(ce, method);
+ Block handler = e.begin_block();
+ context.emitCallback(e, context.getIndex(method));
+ e.load_this();
+ e.getfield(impl.getName());
+ e.create_arg_array();
+ e.invoke_interface(INVOCATION_HANDLER, INVOKE);
+ e.unbox(method.getSignature().getReturnType());
+ e.return_value();
+ handler.end();
+ EmitUtils.wrap_undeclared_throwable(e, handler, method.getExceptionTypes(), UNDECLARED_THROWABLE_EXCEPTION);
+ e.end_method();
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ EmitUtils.load_method(e, method);
+ e.putfield(context.getImplSignature(method).getName());
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/LazyLoader.java b/blade-aop/src/main/java/net/sf/cglib/proxy/LazyLoader.java
new file mode 100644
index 000000000..874c2a396
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/LazyLoader.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+/**
+ * Lazy-loading {@link Enhancer} callback.
+ */
+public interface LazyLoader extends Callback {
+ /**
+ * Return the object which the original method invocation should be
+ * dispatched. Called as soon as the first lazily-loaded method in
+ * the enhanced instance is invoked. The same object is then used
+ * for every future method call to the proxy instance.
+ * @return an object that can invoke the method
+ */
+ Object loadObject() throws Exception;
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/LazyLoaderGenerator.java b/blade-aop/src/main/java/net/sf/cglib/proxy/LazyLoaderGenerator.java
new file mode 100644
index 000000000..b7f92c1ca
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/LazyLoaderGenerator.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+class LazyLoaderGenerator implements CallbackGenerator {
+ public static final LazyLoaderGenerator INSTANCE = new LazyLoaderGenerator();
+
+ private static final Signature LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject()");
+ private static final Type LAZY_LOADER =
+ TypeUtils.parseType("net.sf.cglib.proxy.LazyLoader");
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ Set indexes = new HashSet();
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ if (TypeUtils.isProtected(method.getModifiers())) {
+ // ignore protected methods
+ } else {
+ int index = context.getIndex(method);
+ indexes.add(new Integer(index));
+ CodeEmitter e = context.beginMethod(ce, method);
+ e.load_this();
+ e.dup();
+ e.invoke_virtual_this(loadMethod(index));
+ e.checkcast(method.getClassInfo().getType());
+ e.load_args();
+ e.invoke(method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+
+ for (Iterator it = indexes.iterator(); it.hasNext();) {
+ int index = ((Integer)it.next()).intValue();
+
+ String delegate = "CGLIB$LAZY_LOADER_" + index;
+ ce.declare_field(Constants.ACC_PRIVATE, delegate, Constants.TYPE_OBJECT, null);
+
+ CodeEmitter e = ce.begin_method(Constants.ACC_PRIVATE |
+ Constants.ACC_SYNCHRONIZED |
+ Constants.ACC_FINAL,
+ loadMethod(index),
+ null);
+ e.load_this();
+ e.getfield(delegate);
+ e.dup();
+ Label end = e.make_label();
+ e.ifnonnull(end);
+ e.pop();
+ e.load_this();
+ context.emitCallback(e, index);
+ e.invoke_interface(LAZY_LOADER, LOAD_OBJECT);
+ e.dup_x1();
+ e.putfield(delegate);
+ e.mark(end);
+ e.return_value();
+ e.end_method();
+
+ }
+ }
+
+ private Signature loadMethod(int index) {
+ return new Signature("CGLIB$LOAD_PRIVATE_" + index,
+ Constants.TYPE_OBJECT,
+ Constants.TYPES_EMPTY);
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/MethodInterceptor.java b/blade-aop/src/main/java/net/sf/cglib/proxy/MethodInterceptor.java
new file mode 100644
index 000000000..c0a24429d
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/MethodInterceptor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002,2003 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 net.sf.cglib.proxy;
+
+/**
+ * General-purpose {@link Enhancer} callback which provides for "around advice".
+ * @author Juozas Baliuka baliuka@mwm.lt
+ * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
+ */
+public interface MethodInterceptor
+extends Callback
+{
+ /**
+ * All generated proxied methods call this method instead of the original method.
+ * The original method may either be invoked by normal reflection using the Method object,
+ * or by using the MethodProxy (faster).
+ * @param obj "this", the enhanced object
+ * @param method intercepted Method
+ * @param args argument array; primitive types are wrapped
+ * @param proxy used to invoke super (non-intercepted method); may be called
+ * as many times as needed
+ * @throws Throwable any exception may be thrown; if so, super method will not be invoked
+ * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
+ * @see MethodProxy
+ */
+ public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
+ MethodProxy proxy) throws Throwable;
+
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/MethodInterceptorGenerator.java b/blade-aop/src/main/java/net/sf/cglib/proxy/MethodInterceptorGenerator.java
new file mode 100644
index 000000000..b0e00a9da
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/MethodInterceptorGenerator.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.Method;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+class MethodInterceptorGenerator
+implements CallbackGenerator
+{
+ public static final MethodInterceptorGenerator INSTANCE = new MethodInterceptorGenerator();
+
+ static final String EMPTY_ARGS_NAME = "CGLIB$emptyArgs";
+ static final String FIND_PROXY_NAME = "CGLIB$findMethodProxy";
+ static final Class[] FIND_PROXY_TYPES = { Signature.class };
+
+ private static final Type ABSTRACT_METHOD_ERROR =
+ TypeUtils.parseType("AbstractMethodError");
+ private static final Type METHOD =
+ TypeUtils.parseType("java.lang.reflect.Method");
+ private static final Type REFLECT_UTILS =
+ TypeUtils.parseType("net.sf.cglib.core.ReflectUtils");
+ private static final Type METHOD_PROXY =
+ TypeUtils.parseType("net.sf.cglib.proxy.MethodProxy");
+ private static final Type METHOD_INTERCEPTOR =
+ TypeUtils.parseType("net.sf.cglib.proxy.MethodInterceptor");
+ private static final Signature GET_DECLARED_METHODS =
+ TypeUtils.parseSignature("java.lang.reflect.Method[] getDeclaredMethods()");
+ private static final Signature GET_DECLARING_CLASS =
+ TypeUtils.parseSignature("Class getDeclaringClass()");
+ private static final Signature FIND_METHODS =
+ TypeUtils.parseSignature("java.lang.reflect.Method[] findMethods(String[], java.lang.reflect.Method[])");
+ private static final Signature MAKE_PROXY =
+ new Signature("create", METHOD_PROXY, new Type[]{
+ Constants.TYPE_CLASS,
+ Constants.TYPE_CLASS,
+ Constants.TYPE_STRING,
+ Constants.TYPE_STRING,
+ Constants.TYPE_STRING
+ });
+ private static final Signature INTERCEPT =
+ new Signature("intercept", Constants.TYPE_OBJECT, new Type[]{
+ Constants.TYPE_OBJECT,
+ METHOD,
+ Constants.TYPE_OBJECT_ARRAY,
+ METHOD_PROXY
+ });
+ private static final Signature FIND_PROXY =
+ new Signature(FIND_PROXY_NAME, METHOD_PROXY, new Type[]{ Constants.TYPE_SIGNATURE });
+ private static final Signature TO_STRING =
+ TypeUtils.parseSignature("String toString()");
+ private static final Transformer METHOD_TO_CLASS = new Transformer(){
+ public Object transform(Object value) {
+ return ((MethodInfo)value).getClassInfo();
+ }
+ };
+ private static final Signature CSTRUCT_SIGNATURE =
+ TypeUtils.parseConstructor("String, String");
+
+ private String getMethodField(Signature impl) {
+ return impl.getName() + "$Method";
+ }
+ private String getMethodProxyField(Signature impl) {
+ return impl.getName() + "$Proxy";
+ }
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ Map sigMap = new HashMap();
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ Signature sig = method.getSignature();
+ Signature impl = context.getImplSignature(method);
+
+ String methodField = getMethodField(impl);
+ String methodProxyField = getMethodProxyField(impl);
+
+ sigMap.put(sig.toString(), methodProxyField);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodField, METHOD, null);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodProxyField, METHOD_PROXY, null);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, EMPTY_ARGS_NAME, Constants.TYPE_OBJECT_ARRAY, null);
+ CodeEmitter e;
+
+ // access method
+ e = ce.begin_method(Constants.ACC_FINAL,
+ impl,
+ method.getExceptionTypes());
+ superHelper(e, method, context);
+ e.return_value();
+ e.end_method();
+
+ // around method
+ e = context.beginMethod(ce, method);
+ Label nullInterceptor = e.make_label();
+ context.emitCallback(e, context.getIndex(method));
+ e.dup();
+ e.ifnull(nullInterceptor);
+
+ e.load_this();
+ e.getfield(methodField);
+
+ if (sig.getArgumentTypes().length == 0) {
+ e.getfield(EMPTY_ARGS_NAME);
+ } else {
+ e.create_arg_array();
+ }
+
+ e.getfield(methodProxyField);
+ e.invoke_interface(METHOD_INTERCEPTOR, INTERCEPT);
+ e.unbox_or_zero(sig.getReturnType());
+ e.return_value();
+
+ e.mark(nullInterceptor);
+ superHelper(e, method, context);
+ e.return_value();
+ e.end_method();
+ }
+ generateFindProxy(ce, sigMap);
+ }
+
+ private static void superHelper(CodeEmitter e, MethodInfo method, Context context)
+ {
+ if (TypeUtils.isAbstract(method.getModifiers())) {
+ e.throw_exception(ABSTRACT_METHOD_ERROR, method.toString() + " is abstract" );
+ } else {
+ e.load_this();
+ e.load_args();
+ context.emitInvoke(e, method);
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) throws Exception {
+ /* generates:
+ static {
+ Class thisClass = Class.forName("NameOfThisClass");
+ Class cls = Class.forName("java.lang.Object");
+ String[] sigs = new String[]{ "toString", "()Ljava/lang/String;", ... };
+ Method[] methods = cls.getDeclaredMethods();
+ methods = ReflectUtils.findMethods(sigs, methods);
+ METHOD_0 = methods[0];
+ CGLIB$ACCESS_0 = MethodProxy.create(cls, thisClass, "()Ljava/lang/String;", "toString", "CGLIB$ACCESS_0");
+ ...
+ }
+ */
+
+ e.push(0);
+ e.newarray();
+ e.putfield(EMPTY_ARGS_NAME);
+
+ Local thisclass = e.make_local();
+ Local declaringclass = e.make_local();
+ EmitUtils.load_class_this(e);
+ e.store_local(thisclass);
+
+ Map methodsByClass = CollectionUtils.bucket(methods, METHOD_TO_CLASS);
+ for (Iterator i = methodsByClass.keySet().iterator(); i.hasNext();) {
+ ClassInfo classInfo = (ClassInfo)i.next();
+
+ List classMethods = (List)methodsByClass.get(classInfo);
+ e.push(2 * classMethods.size());
+ e.newarray(Constants.TYPE_STRING);
+ for (int index = 0; index < classMethods.size(); index++) {
+ MethodInfo method = (MethodInfo)classMethods.get(index);
+ Signature sig = method.getSignature();
+ e.dup();
+ e.push(2 * index);
+ e.push(sig.getName());
+ e.aastore();
+ e.dup();
+ e.push(2 * index + 1);
+ e.push(sig.getDescriptor());
+ e.aastore();
+ }
+
+ EmitUtils.load_class(e, classInfo.getType());
+ e.dup();
+ e.store_local(declaringclass);
+ e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHODS);
+ e.invoke_static(REFLECT_UTILS, FIND_METHODS);
+
+ for (int index = 0; index < classMethods.size(); index++) {
+ MethodInfo method = (MethodInfo)classMethods.get(index);
+ Signature sig = method.getSignature();
+ Signature impl = context.getImplSignature(method);
+ e.dup();
+ e.push(index);
+ e.array_load(METHOD);
+ e.putfield(getMethodField(impl));
+
+ e.load_local(declaringclass);
+ e.load_local(thisclass);
+ e.push(sig.getDescriptor());
+ e.push(sig.getName());
+ e.push(impl.getName());
+ e.invoke_static(METHOD_PROXY, MAKE_PROXY);
+ e.putfield(getMethodProxyField(impl));
+ }
+ e.pop();
+ }
+ }
+
+ public void generateFindProxy(ClassEmitter ce, final Map sigMap) {
+ final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
+ FIND_PROXY,
+ null);
+ e.load_arg(0);
+ e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
+ ObjectSwitchCallback callback = new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ e.getfield((String)sigMap.get(key));
+ e.return_value();
+ }
+ public void processDefault() {
+ e.aconst_null();
+ e.return_value();
+ }
+ };
+ EmitUtils.string_switch(e,
+ (String[])sigMap.keySet().toArray(new String[0]),
+ Constants.SWITCH_STYLE_HASH,
+ callback);
+ e.end_method();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/MethodProxy.java b/blade-aop/src/main/java/net/sf/cglib/proxy/MethodProxy.java
new file mode 100644
index 000000000..c8bc95f9a
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/MethodProxy.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import net.sf.cglib.core.AbstractClassGenerator;
+import net.sf.cglib.core.CodeGenerationException;
+import net.sf.cglib.core.GeneratorStrategy;
+import net.sf.cglib.core.NamingPolicy;
+import net.sf.cglib.core.Signature;
+import net.sf.cglib.reflect.FastClass;
+
+/**
+ * Classes generated by {@link Enhancer} pass this object to the
+ * registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can
+ * be used to either invoke the original method, or call the same method on a different
+ * object of the same type.
+ * @version $Id: MethodProxy.java,v 1.16 2009/01/11 20:09:48 herbyderby Exp $
+ */
+public class MethodProxy {
+ private Signature sig1;
+ private Signature sig2;
+ private CreateInfo createInfo;
+
+ private final Object initLock = new Object();
+ private volatile FastClassInfo fastClassInfo;
+
+ /**
+ * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
+ * for similar functionality.
+ */
+ public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
+ MethodProxy proxy = new MethodProxy();
+ proxy.sig1 = new Signature(name1, desc);
+ proxy.sig2 = new Signature(name2, desc);
+ proxy.createInfo = new CreateInfo(c1, c2);
+ return proxy;
+ }
+
+ private void init()
+ {
+ /*
+ * Using a volatile invariant allows us to initialize the FastClass and
+ * method index pairs atomically.
+ *
+ * Double-checked locking is safe with volatile in Java 5. Before 1.5 this
+ * code could allow fastClassInfo to be instantiated more than once, which
+ * appears to be benign.
+ */
+ if (fastClassInfo == null)
+ {
+ synchronized (initLock)
+ {
+ if (fastClassInfo == null)
+ {
+ CreateInfo ci = createInfo;
+
+ FastClassInfo fci = new FastClassInfo();
+ fci.f1 = helper(ci, ci.c1);
+ fci.f2 = helper(ci, ci.c2);
+ fci.i1 = fci.f1.getIndex(sig1);
+ fci.i2 = fci.f2.getIndex(sig2);
+ fastClassInfo = fci;
+ createInfo = null;
+ }
+ }
+ }
+ }
+
+ private static class FastClassInfo
+ {
+ FastClass f1;
+ FastClass f2;
+ int i1;
+ int i2;
+ }
+
+ private static class CreateInfo
+ {
+ Class c1;
+ Class c2;
+ NamingPolicy namingPolicy;
+ GeneratorStrategy strategy;
+ boolean attemptLoad;
+
+ public CreateInfo(Class c1, Class c2)
+ {
+ this.c1 = c1;
+ this.c2 = c2;
+ AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
+ if (fromEnhancer != null) {
+ namingPolicy = fromEnhancer.getNamingPolicy();
+ strategy = fromEnhancer.getStrategy();
+ attemptLoad = fromEnhancer.getAttemptLoad();
+ }
+ }
+ }
+
+ private static FastClass helper(CreateInfo ci, Class type) {
+ FastClass.Generator g = new FastClass.Generator();
+ g.setType(type);
+ g.setClassLoader(ci.c2.getClassLoader());
+ g.setNamingPolicy(ci.namingPolicy);
+ g.setStrategy(ci.strategy);
+ g.setAttemptLoad(ci.attemptLoad);
+ return g.create();
+ }
+
+ private MethodProxy() {
+ }
+
+ /**
+ * Return the signature of the proxied method.
+ */
+ public Signature getSignature() {
+ return sig1;
+ }
+
+ /**
+ * Return the name of the synthetic method created by CGLIB which is
+ * used by {@link #invokeSuper} to invoke the superclass
+ * (non-intercepted) method implementation. The parameter types are
+ * the same as the proxied method.
+ */
+ public String getSuperName() {
+ return sig2.getName();
+ }
+
+ /**
+ * Return the {@link net.sf.cglib.reflect.FastClass} method index
+ * for the method used by {@link #invokeSuper}. This index uniquely
+ * identifies the method within the generated proxy, and therefore
+ * can be useful to reference external metadata.
+ * @see #getSuperName
+ */
+ public int getSuperIndex() {
+ init();
+ return fastClassInfo.i2;
+ }
+
+ // For testing
+ FastClass getFastClass() {
+ init();
+ return fastClassInfo.f1;
+ }
+
+ // For testing
+ FastClass getSuperFastClass() {
+ init();
+ return fastClassInfo.f2;
+ }
+
+ /**
+ * Return the MethodProxy used when intercepting the method
+ * matching the given signature.
+ * @param type the class generated by Enhancer
+ * @param sig the signature to match
+ * @return the MethodProxy instance, or null if no applicable matching method is found
+ * @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor
+ */
+ public static MethodProxy find(Class type, Signature sig) {
+ try {
+ Method m = type.getDeclaredMethod(MethodInterceptorGenerator.FIND_PROXY_NAME,
+ MethodInterceptorGenerator.FIND_PROXY_TYPES);
+ return (MethodProxy)m.invoke(null, new Object[]{ sig });
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
+ } catch (IllegalAccessException e) {
+ throw new CodeGenerationException(e);
+ } catch (InvocationTargetException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ /**
+ * Invoke the original method, on a different object of the same type.
+ * @param obj the compatible object; recursion will result if you use the object passed as the first
+ * argument to the MethodInterceptor (usually not what you want)
+ * @param args the arguments passed to the intercepted method; you may substitute a different
+ * argument array as long as the types are compatible
+ * @see MethodInterceptor#intercept
+ * @throws Throwable the bare exceptions thrown by the called method are passed through
+ * without wrapping in an InvocationTargetException
+ */
+ public Object invoke(Object obj, Object[] args) throws Throwable {
+ try {
+ init();
+ FastClassInfo fci = fastClassInfo;
+ return fci.f1.invoke(fci.i1, obj, args);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ } catch (IllegalArgumentException e) {
+ if (fastClassInfo.i1 < 0)
+ throw new IllegalArgumentException("Protected method: " + sig1);
+ throw e;
+ }
+ }
+
+ /**
+ * Invoke the original (super) method on the specified object.
+ * @param obj the enhanced object, must be the object passed as the first
+ * argument to the MethodInterceptor
+ * @param args the arguments passed to the intercepted method; you may substitute a different
+ * argument array as long as the types are compatible
+ * @see MethodInterceptor#intercept
+ * @throws Throwable the bare exceptions thrown by the called method are passed through
+ * without wrapping in an InvocationTargetException
+ */
+ public Object invokeSuper(Object obj, Object[] args) throws Throwable {
+ try {
+ init();
+ FastClassInfo fci = fastClassInfo;
+ return fci.f2.invoke(fci.i2, obj, args);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/Mixin.java b/blade-aop/src/main/java/net/sf/cglib/proxy/Mixin.java
new file mode 100644
index 000000000..821bbc47d
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/Mixin.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.security.ProtectionDomain;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+
+
+
+/**
+ * Mixin allows
+ * multiple objects to be combined into a single larger object. The
+ * methods in the generated object simply call the original methods in the
+ * underlying "delegate" objects.
+ * @author Chris Nokleberg
+ * @version $Id: Mixin.java,v 1.7 2005/09/27 11:42:27 baliuka Exp $
+ */
+abstract public class Mixin {
+ private static final MixinKey KEY_FACTORY =
+ (MixinKey)KeyFactory.create(MixinKey.class, KeyFactory.CLASS_BY_NAME);
+ private static final Map ROUTE_CACHE = Collections.synchronizedMap(new HashMap());
+
+ public static final int STYLE_INTERFACES = 0;
+ public static final int STYLE_BEANS = 1;
+ public static final int STYLE_EVERYTHING = 2;
+
+ interface MixinKey {
+ public Object newInstance(int style, String[] classes, int[] route);
+ }
+
+ abstract public Mixin newInstance(Object[] delegates);
+
+ /**
+ * Helper method to create an interface mixin. For finer control over the
+ * generated instance, use a new instance of Mixin
+ * instead of this static method.
+ * TODO
+ */
+ public static Mixin create(Object[] delegates) {
+ Generator gen = new Generator();
+ gen.setDelegates(delegates);
+ return gen.create();
+ }
+
+ /**
+ * Helper method to create an interface mixin. For finer control over the
+ * generated instance, use a new instance of Mixin
+ * instead of this static method.
+ * TODO
+ */
+ public static Mixin create(Class[] interfaces, Object[] delegates) {
+ Generator gen = new Generator();
+ gen.setClasses(interfaces);
+ gen.setDelegates(delegates);
+ return gen.create();
+ }
+
+
+ public static Mixin createBean(Object[] beans) {
+
+ return createBean(null, beans);
+
+ }
+ /**
+ * Helper method to create a bean mixin. For finer control over the
+ * generated instance, use a new instance of Mixin
+ * instead of this static method.
+ * TODO
+ */
+ public static Mixin createBean(ClassLoader loader,Object[] beans) {
+ Generator gen = new Generator();
+ gen.setStyle(STYLE_BEANS);
+ gen.setDelegates(beans);
+ gen.setClassLoader(loader);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(Mixin.class.getName());
+
+ private Class[] classes;
+ private Object[] delegates;
+ private int style = STYLE_INTERFACES;
+
+ private int[] route;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return classes[0].getClassLoader(); // is this right?
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(classes[0]);
+ }
+
+ public void setStyle(int style) {
+ switch (style) {
+ case STYLE_INTERFACES:
+ case STYLE_BEANS:
+ case STYLE_EVERYTHING:
+ this.style = style;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown mixin style: " + style);
+ }
+ }
+
+ public void setClasses(Class[] classes) {
+ this.classes = classes;
+ }
+
+ public void setDelegates(Object[] delegates) {
+ this.delegates = delegates;
+ }
+
+ public Mixin create() {
+ if (classes == null && delegates == null) {
+ throw new IllegalStateException("Either classes or delegates must be set");
+ }
+ switch (style) {
+ case STYLE_INTERFACES:
+ if (classes == null) {
+ Route r = route(delegates);
+ classes = r.classes;
+ route = r.route;
+ }
+ break;
+ case STYLE_BEANS:
+ // fall-through
+ case STYLE_EVERYTHING:
+ if (classes == null) {
+ classes = ReflectUtils.getClasses(delegates);
+ } else {
+ if (delegates != null) {
+ Class[] temp = ReflectUtils.getClasses(delegates);
+ if (classes.length != temp.length) {
+ throw new IllegalStateException("Specified classes are incompatible with delegates");
+ }
+ for (int i = 0; i < classes.length; i++) {
+ if (!classes[i].isAssignableFrom(temp[i])) {
+ throw new IllegalStateException("Specified class " + classes[i] + " is incompatible with delegate class " + temp[i] + " (index " + i + ")");
+ }
+ }
+ }
+ }
+ }
+ setNamePrefix(classes[ReflectUtils.findPackageProtected(classes)].getName());
+
+ return (Mixin)super.create(KEY_FACTORY.newInstance(style, ReflectUtils.getNames( classes ), route));
+ }
+
+ public void generateClass(ClassVisitor v) {
+ switch (style) {
+ case STYLE_INTERFACES:
+ new MixinEmitter(v, getClassName(), classes, route);
+ break;
+ case STYLE_BEANS:
+ new MixinBeanEmitter(v, getClassName(), classes);
+ break;
+ case STYLE_EVERYTHING:
+ new MixinEverythingEmitter(v, getClassName(), classes);
+ break;
+ }
+ }
+
+ protected Object firstInstance(Class type) {
+ return ((Mixin)ReflectUtils.newInstance(type)).newInstance(delegates);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((Mixin)instance).newInstance(delegates);
+ }
+ }
+
+ public static Class[] getClasses(Object[] delegates) {
+ return (Class[])route(delegates).classes.clone();
+ }
+
+// public static int[] getRoute(Object[] delegates) {
+// return (int[])route(delegates).route.clone();
+// }
+
+ private static Route route(Object[] delegates) {
+ Object key = ClassesKey.create(delegates);
+ Route route = (Route)ROUTE_CACHE.get(key);
+ if (route == null) {
+ ROUTE_CACHE.put(key, route = new Route(delegates));
+ }
+ return route;
+ }
+
+ private static class Route
+ {
+ private Class[] classes;
+ private int[] route;
+
+ Route(Object[] delegates) {
+ Map map = new HashMap();
+ ArrayList collect = new ArrayList();
+ for (int i = 0; i < delegates.length; i++) {
+ Class delegate = delegates[i].getClass();
+ collect.clear();
+ ReflectUtils.addAllInterfaces(delegate, collect);
+ for (Iterator it = collect.iterator(); it.hasNext();) {
+ Class iface = (Class)it.next();
+ if (!map.containsKey(iface)) {
+ map.put(iface, new Integer(i));
+ }
+ }
+ }
+ classes = new Class[map.size()];
+ route = new int[map.size()];
+ int index = 0;
+ for (Iterator it = map.keySet().iterator(); it.hasNext();) {
+ Class key = (Class)it.next();
+ classes[index] = key;
+ route[index] = ((Integer)map.get(key)).intValue();
+ index++;
+ }
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/MixinBeanEmitter.java b/blade-aop/src/main/java/net/sf/cglib/proxy/MixinBeanEmitter.java
new file mode 100644
index 000000000..c48cc9209
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/MixinBeanEmitter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.Method;
+import net.sf.cglib.core.ReflectUtils;
+import org.objectweb.asm.ClassVisitor;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: MixinBeanEmitter.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $
+ */
+class MixinBeanEmitter extends MixinEmitter {
+ public MixinBeanEmitter(ClassVisitor v, String className, Class[] classes) {
+ super(v, className, classes, null);
+ }
+
+ protected Class[] getInterfaces(Class[] classes) {
+ return null;
+ }
+
+ protected Method[] getMethods(Class type) {
+ return ReflectUtils.getPropertyMethods(ReflectUtils.getBeanProperties(type), true, true);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/MixinEmitter.java b/blade-aop/src/main/java/net/sf/cglib/proxy/MixinEmitter.java
new file mode 100644
index 000000000..b5cfc6d97
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/MixinEmitter.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.Method;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: MixinEmitter.java,v 1.9 2006/08/27 21:04:37 herbyderby Exp $
+ */
+class MixinEmitter extends ClassEmitter {
+ private static final String FIELD_NAME = "CGLIB$DELEGATES";
+ private static final Signature CSTRUCT_OBJECT_ARRAY =
+ TypeUtils.parseConstructor("Object[]");
+ private static final Type MIXIN =
+ TypeUtils.parseType("net.sf.cglib.proxy.Mixin");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", MIXIN, new Type[]{ Constants.TYPE_OBJECT_ARRAY });
+
+ public MixinEmitter(ClassVisitor v, String className, Class[] classes, int[] route) {
+ super(v);
+
+ begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ className,
+ MIXIN,
+ TypeUtils.getTypes(getInterfaces(classes)),
+ Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(this);
+ EmitUtils.factory_method(this, NEW_INSTANCE);
+
+ declare_field(Constants.ACC_PRIVATE, FIELD_NAME, Constants.TYPE_OBJECT_ARRAY, null);
+
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT_ARRAY, null);
+ e.load_this();
+ e.super_invoke_constructor();
+ e.load_this();
+ e.load_arg(0);
+ e.putfield(FIELD_NAME);
+ e.return_value();
+ e.end_method();
+
+ Set unique = new HashSet();
+ for (int i = 0; i < classes.length; i++) {
+ Method[] methods = getMethods(classes[i]);
+ for (int j = 0; j < methods.length; j++) {
+ if (unique.add(MethodWrapper.create(methods[j]))) {
+ MethodInfo method = ReflectUtils.getMethodInfo(methods[j]);
+ int modifiers = Constants.ACC_PUBLIC;
+ if ((method.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
+ modifiers |= Constants.ACC_VARARGS;
+ }
+ e = EmitUtils.begin_method(this, method, modifiers);
+ e.load_this();
+ e.getfield(FIELD_NAME);
+ e.aaload((route != null) ? route[i] : i);
+ e.checkcast(method.getClassInfo().getType());
+ e.load_args();
+ e.invoke(method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+ }
+
+ end_class();
+ }
+
+ protected Class[] getInterfaces(Class[] classes) {
+ return classes;
+ }
+
+ protected Method[] getMethods(Class type) {
+ return type.getMethods();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/MixinEverythingEmitter.java b/blade-aop/src/main/java/net/sf/cglib/proxy/MixinEverythingEmitter.java
new file mode 100644
index 000000000..ffb45700b
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/MixinEverythingEmitter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.proxy;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import net.sf.cglib.core.CollectionUtils;
+import net.sf.cglib.core.ReflectUtils;
+import net.sf.cglib.core.RejectModifierPredicate;
+import org.objectweb.asm.ClassVisitor;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: MixinEverythingEmitter.java,v 1.3 2004/06/24 21:15:19 herbyderby Exp $
+ */
+class MixinEverythingEmitter extends MixinEmitter {
+
+ public MixinEverythingEmitter(ClassVisitor v, String className, Class[] classes) {
+ super(v, className, classes, null);
+ }
+
+ protected Class[] getInterfaces(Class[] classes) {
+ List list = new ArrayList();
+ for (int i = 0; i < classes.length; i++) {
+ ReflectUtils.addAllInterfaces(classes[i], list);
+ }
+ return (Class[])list.toArray(new Class[list.size()]);
+ }
+
+ protected Method[] getMethods(Class type) {
+ List methods = new ArrayList(Arrays.asList(type.getMethods()));
+ CollectionUtils.filter(methods, new RejectModifierPredicate(Modifier.FINAL | Modifier.STATIC));
+ return (Method[])methods.toArray(new Method[methods.size()]);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/NoOp.java b/blade-aop/src/main/java/net/sf/cglib/proxy/NoOp.java
new file mode 100644
index 000000000..227617590
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/NoOp.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+/**
+ * Methods using this {@link Enhancer} callback will delegate directly to the
+ * default (super) implementation in the base class.
+ */
+public interface NoOp extends Callback
+{
+ /**
+ * A thread-safe singleton instance of the NoOp callback.
+ */
+ public static final NoOp INSTANCE = new NoOp() { };
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/NoOpGenerator.java b/blade-aop/src/main/java/net/sf/cglib/proxy/NoOpGenerator.java
new file mode 100644
index 000000000..84920be6b
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/NoOpGenerator.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.util.Iterator;
+import java.util.List;
+import net.sf.cglib.core.*;
+
+class NoOpGenerator
+implements CallbackGenerator
+{
+ public static final NoOpGenerator INSTANCE = new NoOpGenerator();
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ if (TypeUtils.isBridge(method.getModifiers()) || (
+ TypeUtils.isProtected(context.getOriginalModifiers(method)) &&
+ TypeUtils.isPublic(method.getModifiers()))) {
+ CodeEmitter e = EmitUtils.begin_method(ce, method);
+ e.load_this();
+ e.load_args();
+ context.emitInvoke(e, method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/Proxy.java b/blade-aop/src/main/java/net/sf/cglib/proxy/Proxy.java
new file mode 100644
index 000000000..fe5f4f93e
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/Proxy.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.proxy;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Member;
+import net.sf.cglib.core.CodeGenerationException;
+
+/**
+ * This class is meant to be used as replacement for
+ * java.lang.reflect.Proxy under JDK 1.2. There are some known
+ * subtle differences:
+ *
+ * The exceptions returned by invoking getExceptionTypes
+ * on the Method passed to the invoke method
+ * are the exact set that can be thrown without resulting in an
+ * UndeclaredThrowableException being thrown.
+ * {@link UndeclaredThrowableException} is used instead
+ * of java.lang.reflect.UndeclaredThrowableException.
+ *
+ *
+ * @version $Id: Proxy.java,v 1.6 2004/06/24 21:15:19 herbyderby Exp $
+ */
+public class Proxy implements Serializable {
+ protected InvocationHandler h;
+
+ private static final CallbackFilter BAD_OBJECT_METHOD_FILTER = new CallbackFilter() {
+ public int accept(Method method) {
+ if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
+ String name = method.getName();
+ if (!(name.equals("hashCode") ||
+ name.equals("equals") ||
+ name.equals("toString"))) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+ };
+
+ protected Proxy(InvocationHandler h) {
+ Enhancer.registerCallbacks(getClass(), new Callback[]{ h, null });
+ this.h = h;
+ }
+
+ // private for security of isProxyClass
+ private static class ProxyImpl extends Proxy {
+ protected ProxyImpl(InvocationHandler h) {
+ super(h);
+ }
+ }
+
+ public static InvocationHandler getInvocationHandler(Object proxy) {
+ if (!(proxy instanceof ProxyImpl)) {
+ throw new IllegalArgumentException("Object is not a proxy");
+ }
+ return ((Proxy)proxy).h;
+ }
+
+ public static Class getProxyClass(ClassLoader loader, Class[] interfaces) {
+ Enhancer e = new Enhancer();
+ e.setSuperclass(ProxyImpl.class);
+ e.setInterfaces(interfaces);
+ e.setCallbackTypes(new Class[]{
+ InvocationHandler.class,
+ NoOp.class,
+ });
+ e.setCallbackFilter(BAD_OBJECT_METHOD_FILTER);
+ e.setUseFactory(false);
+ return e.createClass();
+ }
+
+ public static boolean isProxyClass(Class cl) {
+ return cl.getSuperclass().equals(ProxyImpl.class);
+ }
+
+ public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) {
+ try {
+ Class clazz = getProxyClass(loader, interfaces);
+ return clazz.getConstructor(new Class[]{ InvocationHandler.class }).newInstance(new Object[]{ h });
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/ProxyRefDispatcher.java b/blade-aop/src/main/java/net/sf/cglib/proxy/ProxyRefDispatcher.java
new file mode 100644
index 000000000..701088590
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/ProxyRefDispatcher.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.proxy;
+
+/**
+ * Dispatching {@link Enhancer} callback. This is the same as the
+ * {@link Dispatcher} except for the addition of an argument
+ * which references the proxy object.
+ */
+public interface ProxyRefDispatcher extends Callback {
+ /**
+ * Return the object which the original method invocation should
+ * be dispatched. This method is called for every method invocation.
+ * @param proxy a reference to the proxy (generated) object
+ * @return an object that can invoke the method
+ */
+ Object loadObject(Object proxy) throws Exception;
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/proxy/UndeclaredThrowableException.java b/blade-aop/src/main/java/net/sf/cglib/proxy/UndeclaredThrowableException.java
new file mode 100644
index 000000000..09f8db5a1
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/proxy/UndeclaredThrowableException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002,2003 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 net.sf.cglib.proxy;
+
+import net.sf.cglib.core.CodeGenerationException;
+
+/**
+ * Used by {@link Proxy} as a replacement for java.lang.reflect.UndeclaredThrowableException.
+ * @author Juozas Baliuka
+ */
+public class UndeclaredThrowableException extends CodeGenerationException {
+ /**
+ * Creates a new instance of UndeclaredThrowableException without detail message.
+ */
+ public UndeclaredThrowableException(Throwable t) {
+ super(t);
+ }
+
+ public Throwable getUndeclaredThrowable() {
+ return getCause();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/ConstructorDelegate.java b/blade-aop/src/main/java/net/sf/cglib/reflect/ConstructorDelegate.java
new file mode 100644
index 000000000..ae302c6a7
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/ConstructorDelegate.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.reflect;
+
+import java.lang.reflect.*;
+import java.security.ProtectionDomain;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: ConstructorDelegate.java,v 1.20 2006/03/05 02:43:19 herbyderby Exp $
+ */
+abstract public class ConstructorDelegate {
+ private static final ConstructorKey KEY_FACTORY =
+ (ConstructorKey)KeyFactory.create(ConstructorKey.class, KeyFactory.CLASS_BY_NAME);
+
+ interface ConstructorKey {
+ public Object newInstance(String declaring, String iface);
+ }
+
+ protected ConstructorDelegate() {
+ }
+
+ public static ConstructorDelegate create(Class targetClass, Class iface) {
+ Generator gen = new Generator();
+ gen.setTargetClass(targetClass);
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(ConstructorDelegate.class.getName());
+ private static final Type CONSTRUCTOR_DELEGATE =
+ TypeUtils.parseType("net.sf.cglib.reflect.ConstructorDelegate");
+
+ private Class iface;
+ private Class targetClass;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ public void setInterface(Class iface) {
+ this.iface = iface;
+ }
+
+ public void setTargetClass(Class targetClass) {
+ this.targetClass = targetClass;
+ }
+
+ public ConstructorDelegate create() {
+ setNamePrefix(targetClass.getName());
+ Object key = KEY_FACTORY.newInstance(iface.getName(), targetClass.getName());
+ return (ConstructorDelegate)super.create(key);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return targetClass.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(targetClass);
+ }
+
+ public void generateClass(ClassVisitor v) {
+ setNamePrefix(targetClass.getName());
+
+ final Method newInstance = ReflectUtils.findNewInstance(iface);
+ if (!newInstance.getReturnType().isAssignableFrom(targetClass)) {
+ throw new IllegalArgumentException("incompatible return type");
+ }
+ final Constructor constructor;
+ try {
+ constructor = targetClass.getDeclaredConstructor(newInstance.getParameterTypes());
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("interface does not match any known constructor");
+ }
+
+ ClassEmitter ce = new ClassEmitter(v);
+ ce.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ CONSTRUCTOR_DELEGATE,
+ new Type[]{ Type.getType(iface) },
+ Constants.SOURCE_FILE);
+ Type declaring = Type.getType(constructor.getDeclaringClass());
+ EmitUtils.null_constructor(ce);
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
+ ReflectUtils.getSignature(newInstance),
+ ReflectUtils.getExceptionTypes(newInstance));
+ e.new_instance(declaring);
+ e.dup();
+ e.load_args();
+ e.invoke_constructor(declaring, ReflectUtils.getSignature(constructor));
+ e.return_value();
+ e.end_method();
+ ce.end_class();
+ }
+
+ protected Object firstInstance(Class type) {
+ return ReflectUtils.newInstance(type);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return instance;
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/FastClass.java b/blade-aop/src/main/java/net/sf/cglib/reflect/FastClass.java
new file mode 100644
index 000000000..ce9026ad2
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/FastClass.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.reflect;
+
+import net.sf.cglib.core.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+
+abstract public class FastClass
+{
+ private Class type;
+
+ protected FastClass() {
+ throw new Error("Using the FastClass empty constructor--please report to the cglib-devel mailing list");
+ }
+
+ protected FastClass(Class type) {
+ this.type = type;
+ }
+
+ public static FastClass create(Class type) {
+
+ return create(type.getClassLoader(),type);
+
+ }
+ public static FastClass create(ClassLoader loader, Class type) {
+ Generator gen = new Generator();
+ gen.setType(type);
+ gen.setClassLoader(loader);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator
+ {
+ private static final Source SOURCE = new Source(FastClass.class.getName());
+ private Class type;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ public void setType(Class type) {
+ this.type = type;
+ }
+
+ public FastClass create() {
+ setNamePrefix(type.getName());
+ return (FastClass)super.create(type.getName());
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return type.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(type);
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ new FastClassEmitter(v, getClassName(), type);
+ }
+
+ protected Object firstInstance(Class type) {
+ return ReflectUtils.newInstance(type,
+ new Class[]{ Class.class },
+ new Object[]{ this.type });
+ }
+
+ protected Object nextInstance(Object instance) {
+ return instance;
+ }
+ }
+
+ public Object invoke(String name, Class[] parameterTypes, Object obj, Object[] args) throws InvocationTargetException {
+ return invoke(getIndex(name, parameterTypes), obj, args);
+ }
+
+ public Object newInstance() throws InvocationTargetException {
+ return newInstance(getIndex(Constants.EMPTY_CLASS_ARRAY), null);
+ }
+
+ public Object newInstance(Class[] parameterTypes, Object[] args) throws InvocationTargetException {
+ return newInstance(getIndex(parameterTypes), args);
+ }
+
+ public FastMethod getMethod(Method method) {
+ return new FastMethod(this, method);
+ }
+
+ public FastConstructor getConstructor(Constructor constructor) {
+ return new FastConstructor(this, constructor);
+ }
+
+ public FastMethod getMethod(String name, Class[] parameterTypes) {
+ try {
+ return getMethod(type.getMethod(name, parameterTypes));
+ } catch (NoSuchMethodException e) {
+ throw new NoSuchMethodError(e.getMessage());
+ }
+ }
+
+ public FastConstructor getConstructor(Class[] parameterTypes) {
+ try {
+ return getConstructor(type.getConstructor(parameterTypes));
+ } catch (NoSuchMethodException e) {
+ throw new NoSuchMethodError(e.getMessage());
+ }
+ }
+
+ public String getName() {
+ return type.getName();
+ }
+
+ public Class getJavaClass() {
+ return type;
+ }
+
+ public String toString() {
+ return type.toString();
+ }
+
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof FastClass)) {
+ return false;
+ }
+ return type.equals(((FastClass)o).type);
+ }
+
+ /**
+ * Return the index of the matching method. The index may be used
+ * later to invoke the method with less overhead. If more than one
+ * method matches (i.e. they differ by return type only), one is
+ * chosen arbitrarily.
+ * @see #invoke(int, Object, Object[])
+ * @param name the method name
+ * @param parameterTypes the parameter array
+ * @return the index, or -1 if none is found.
+ */
+ abstract public int getIndex(String name, Class[] parameterTypes);
+
+ /**
+ * Return the index of the matching constructor. The index may be used
+ * later to create a new instance with less overhead.
+ * @see #newInstance(int, Object[])
+ * @param parameterTypes the parameter array
+ * @return the constructor index, or -1 if none is found.
+ */
+ abstract public int getIndex(Class[] parameterTypes);
+
+ /**
+ * Invoke the method with the specified index.
+ * @see getIndex(name, Class[])
+ * @param index the method index
+ * @param obj the object the underlying method is invoked from
+ * @param args the arguments used for the method call
+ * @throws java.lang.reflect.InvocationTargetException if the underlying method throws an exception
+ */
+ abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;
+
+ /**
+ * Create a new instance using the specified constructor index and arguments.
+ * @see getIndex(Class[])
+ * @param index the constructor index
+ * @param args the arguments passed to the constructor
+ * @throws java.lang.reflect.InvocationTargetException if the constructor throws an exception
+ */
+ abstract public Object newInstance(int index, Object[] args) throws InvocationTargetException;
+
+ abstract public int getIndex(Signature sig);
+
+ /**
+ * Returns the maximum method index for this class.
+ */
+ abstract public int getMaxIndex();
+
+ protected static String getSignatureWithoutReturnType(String name, Class[] parameterTypes) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(name);
+ sb.append('(');
+ for (int i = 0; i < parameterTypes.length; i++) {
+ sb.append(Type.getDescriptor(parameterTypes[i]));
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/FastClassEmitter.java b/blade-aop/src/main/java/net/sf/cglib/reflect/FastClassEmitter.java
new file mode 100644
index 000000000..61990e28f
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/FastClassEmitter.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.reflect;
+
+import java.lang.reflect.*;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+class FastClassEmitter extends ClassEmitter {
+ private static final Signature CSTRUCT_CLASS =
+ TypeUtils.parseConstructor("Class");
+ private static final Signature METHOD_GET_INDEX =
+ TypeUtils.parseSignature("int getIndex(String, Class[])");
+ private static final Signature SIGNATURE_GET_INDEX =
+ new Signature("getIndex", Type.INT_TYPE, new Type[]{ Constants.TYPE_SIGNATURE });
+ private static final Signature TO_STRING =
+ TypeUtils.parseSignature("String toString()");
+ private static final Signature CONSTRUCTOR_GET_INDEX =
+ TypeUtils.parseSignature("int getIndex(Class[])");
+ private static final Signature INVOKE =
+ TypeUtils.parseSignature("Object invoke(int, Object, Object[])");
+ private static final Signature NEW_INSTANCE =
+ TypeUtils.parseSignature("Object newInstance(int, Object[])");
+ private static final Signature GET_MAX_INDEX =
+ TypeUtils.parseSignature("int getMaxIndex()");
+ private static final Signature GET_SIGNATURE_WITHOUT_RETURN_TYPE =
+ TypeUtils.parseSignature("String getSignatureWithoutReturnType(String, Class[])");
+ private static final Type FAST_CLASS =
+ TypeUtils.parseType("net.sf.cglib.reflect.FastClass");
+ private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
+ TypeUtils.parseType("IllegalArgumentException");
+ private static final Type INVOCATION_TARGET_EXCEPTION =
+ TypeUtils.parseType("java.lang.reflect.InvocationTargetException");
+ private static final Type[] INVOCATION_TARGET_EXCEPTION_ARRAY = { INVOCATION_TARGET_EXCEPTION };
+
+ public FastClassEmitter(ClassVisitor v, String className, Class type) {
+ super(v);
+
+ Type base = Type.getType(type);
+ begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE);
+
+ // constructor
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_CLASS, null);
+ e.load_this();
+ e.load_args();
+ e.super_invoke_constructor(CSTRUCT_CLASS);
+ e.return_value();
+ e.end_method();
+
+ VisibilityPredicate vp = new VisibilityPredicate(type, false);
+ List methods = ReflectUtils.addAllMethods(type, new ArrayList());
+ CollectionUtils.filter(methods, vp);
+ CollectionUtils.filter(methods, new DuplicatesPredicate());
+ List constructors = new ArrayList(Arrays.asList(type.getDeclaredConstructors()));
+ CollectionUtils.filter(constructors, vp);
+
+ // getIndex(String)
+ emitIndexBySignature(methods);
+
+ // getIndex(String, Class[])
+ emitIndexByClassArray(methods);
+
+ // getIndex(Class[])
+ e = begin_method(Constants.ACC_PUBLIC, CONSTRUCTOR_GET_INDEX, null);
+ e.load_args();
+ List info = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
+ EmitUtils.constructor_switch(e, info, new GetIndexCallback(e, info));
+ e.end_method();
+
+ // invoke(int, Object, Object[])
+ e = begin_method(Constants.ACC_PUBLIC, INVOKE, INVOCATION_TARGET_EXCEPTION_ARRAY);
+ e.load_arg(1);
+ e.checkcast(base);
+ e.load_arg(0);
+ invokeSwitchHelper(e, methods, 2, base);
+ e.end_method();
+
+ // newInstance(int, Object[])
+ e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, INVOCATION_TARGET_EXCEPTION_ARRAY);
+ e.new_instance(base);
+ e.dup();
+ e.load_arg(0);
+ invokeSwitchHelper(e, constructors, 1, base);
+ e.end_method();
+
+ // getMaxIndex()
+ e = begin_method(Constants.ACC_PUBLIC, GET_MAX_INDEX, null);
+ e.push(methods.size() - 1);
+ e.return_value();
+ e.end_method();
+
+ end_class();
+ }
+
+ // TODO: support constructor indices ("")
+ private void emitIndexBySignature(List methods) {
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SIGNATURE_GET_INDEX, null);
+ List signatures = CollectionUtils.transform(methods, new Transformer() {
+ public Object transform(Object obj) {
+ return ReflectUtils.getSignature((Method)obj).toString();
+ }
+ });
+ e.load_arg(0);
+ e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
+ signatureSwitchHelper(e, signatures);
+ e.end_method();
+ }
+
+ private static final int TOO_MANY_METHODS = 100; // TODO
+ private void emitIndexByClassArray(List methods) {
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, METHOD_GET_INDEX, null);
+ if (methods.size() > TOO_MANY_METHODS) {
+ // hack for big classes
+ List signatures = CollectionUtils.transform(methods, new Transformer() {
+ public Object transform(Object obj) {
+ String s = ReflectUtils.getSignature((Method)obj).toString();
+ return s.substring(0, s.lastIndexOf(')') + 1);
+ }
+ });
+ e.load_args();
+ e.invoke_static(FAST_CLASS, GET_SIGNATURE_WITHOUT_RETURN_TYPE);
+ signatureSwitchHelper(e, signatures);
+ } else {
+ e.load_args();
+ List info = CollectionUtils.transform(methods, MethodInfoTransformer.getInstance());
+ EmitUtils.method_switch(e, info, new GetIndexCallback(e, info));
+ }
+ e.end_method();
+ }
+
+ private void signatureSwitchHelper(final CodeEmitter e, final List signatures) {
+ ObjectSwitchCallback callback = new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ // TODO: remove linear indexOf
+ e.push(signatures.indexOf(key));
+ e.return_value();
+ }
+ public void processDefault() {
+ e.push(-1);
+ e.return_value();
+ }
+ };
+ EmitUtils.string_switch(e,
+ (String[])signatures.toArray(new String[signatures.size()]),
+ Constants.SWITCH_STYLE_HASH,
+ callback);
+ }
+
+ private static void invokeSwitchHelper(final CodeEmitter e, List members, final int arg, final Type base) {
+ final List info = CollectionUtils.transform(members, MethodInfoTransformer.getInstance());
+ final Label illegalArg = e.make_label();
+ Block block = e.begin_block();
+ e.process_switch(getIntRange(info.size()), new ProcessSwitchCallback() {
+ public void processCase(int key, Label end) {
+ MethodInfo method = (MethodInfo)info.get(key);
+ Type[] types = method.getSignature().getArgumentTypes();
+ for (int i = 0; i < types.length; i++) {
+ e.load_arg(arg);
+ e.aaload(i);
+ e.unbox(types[i]);
+ }
+ // TODO: change method lookup process so MethodInfo will already reference base
+ // instead of superclass when superclass method is inaccessible
+ e.invoke(method, base);
+ if (!TypeUtils.isConstructor(method)) {
+ e.box(method.getSignature().getReturnType());
+ }
+ e.return_value();
+ }
+ public void processDefault() {
+ e.goTo(illegalArg);
+ }
+ });
+ block.end();
+ EmitUtils.wrap_throwable(block, INVOCATION_TARGET_EXCEPTION);
+ e.mark(illegalArg);
+ e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Cannot find matching method/constructor");
+ }
+
+ private static class GetIndexCallback implements ObjectSwitchCallback {
+ private CodeEmitter e;
+ private Map indexes = new HashMap();
+
+ public GetIndexCallback(CodeEmitter e, List methods) {
+ this.e = e;
+ int index = 0;
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ indexes.put(it.next(), new Integer(index++));
+ }
+ }
+
+ public void processCase(Object key, Label end) {
+ e.push(((Integer)indexes.get(key)).intValue());
+ e.return_value();
+ }
+
+ public void processDefault() {
+ e.push(-1);
+ e.return_value();
+ }
+ }
+
+ private static int[] getIntRange(int length) {
+ int[] range = new int[length];
+ for (int i = 0; i < length; i++) {
+ range[i] = i;
+ }
+ return range;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/FastConstructor.java b/blade-aop/src/main/java/net/sf/cglib/reflect/FastConstructor.java
new file mode 100644
index 000000000..7b25697c2
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/FastConstructor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+public class FastConstructor extends FastMember
+{
+ FastConstructor(FastClass fc, Constructor constructor) {
+ super(fc, constructor, fc.getIndex(constructor.getParameterTypes()));
+ }
+
+ public Class[] getParameterTypes() {
+ return ((Constructor)member).getParameterTypes();
+ }
+
+ public Class[] getExceptionTypes() {
+ return ((Constructor)member).getExceptionTypes();
+ }
+
+ public Object newInstance() throws InvocationTargetException {
+ return fc.newInstance(index, null);
+ }
+
+ public Object newInstance(Object[] args) throws InvocationTargetException {
+ return fc.newInstance(index, args);
+ }
+
+ public Constructor getJavaConstructor() {
+ return (Constructor)member;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/FastMember.java b/blade-aop/src/main/java/net/sf/cglib/reflect/FastMember.java
new file mode 100644
index 000000000..08dc5cc7f
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/FastMember.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.reflect;
+
+import java.lang.reflect.Member;
+
+abstract public class FastMember
+{
+ protected FastClass fc;
+ protected Member member;
+ protected int index;
+
+ protected FastMember(FastClass fc, Member member, int index) {
+ this.fc = fc;
+ this.member = member;
+ this.index = index;
+ }
+
+ abstract public Class[] getParameterTypes();
+ abstract public Class[] getExceptionTypes();
+
+ public int getIndex() {
+ return index;
+ }
+
+ public String getName() {
+ return member.getName();
+ }
+
+ public Class getDeclaringClass() {
+ return fc.getJavaClass();
+ }
+
+ public int getModifiers() {
+ return member.getModifiers();
+ }
+
+ public String toString() {
+ return member.toString();
+ }
+
+ public int hashCode() {
+ return member.hashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof FastMember)) {
+ return false;
+ }
+ return member.equals(((FastMember)o).member);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/FastMethod.java b/blade-aop/src/main/java/net/sf/cglib/reflect/FastMethod.java
new file mode 100644
index 000000000..0c027be3a
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/FastMethod.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import net.sf.cglib.core.Signature;
+
+import org.objectweb.asm.Type;
+
+public class FastMethod extends FastMember
+{
+ FastMethod(FastClass fc, Method method) {
+ super(fc, method, helper(fc, method));
+ }
+
+ private static int helper(FastClass fc, Method method) {
+ int index = fc.getIndex(new Signature(method.getName(), Type.getMethodDescriptor(method)));
+ if (index < 0) {
+ Class[] types = method.getParameterTypes();
+ System.err.println("hash=" + method.getName().hashCode() + " size=" + types.length);
+ for (int i = 0; i < types.length; i++) {
+ System.err.println(" types[" + i + "]=" + types[i].getName());
+ }
+ throw new IllegalArgumentException("Cannot find method " + method);
+ }
+ return index;
+ }
+
+ public Class getReturnType() {
+ return ((Method)member).getReturnType();
+ }
+
+ public Class[] getParameterTypes() {
+ return ((Method)member).getParameterTypes();
+ }
+
+ public Class[] getExceptionTypes() {
+ return ((Method)member).getExceptionTypes();
+ }
+
+ public Object invoke(Object obj, Object[] args) throws InvocationTargetException {
+ return fc.invoke(index, obj, args);
+ }
+
+ public Method getJavaMethod() {
+ return (Method)member;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/MethodDelegate.java b/blade-aop/src/main/java/net/sf/cglib/reflect/MethodDelegate.java
new file mode 100644
index 000000000..54da1d355
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/MethodDelegate.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.reflect;
+
+import java.lang.reflect.*;
+import java.security.ProtectionDomain;
+import net.sf.cglib.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+
+// TODO: don't require exact match for return type
+
+/**
+ * DOCUMENTATION FROM APACHE AVALON DELEGATE CLASS
+ *
+ *
+ * Delegates are a typesafe pointer to another method. Since Java does not
+ * have language support for such a construct, this utility will construct
+ * a proxy that forwards method calls to any method with the same signature.
+ * This utility is inspired in part by the C# delegate mechanism. We
+ * implemented it in a Java-centric manner.
+ *
+ *
+ * Delegate
+ *
+ * Any interface with one method can become the interface for a delegate.
+ * Consider the example below:
+ *
+ *
+ *
+ * public interface MainDelegate {
+ * int main(String[] args);
+ * }
+ *
+ *
+ *
+ * The interface above is an example of an interface that can become a
+ * delegate. It has only one method, and the interface is public. In
+ * order to create a delegate for that method, all we have to do is
+ * call MethodDelegate.create(this, "alternateMain", MainDelegate.class).
+ * The following program will show how to use it:
+ *
+ *
+ *
+ * public class Main {
+ * public static int main( String[] args ) {
+ * Main newMain = new Main();
+ * MainDelegate start = (MainDelegate)
+ * MethodDelegate.create(newMain, "alternateMain", MainDelegate.class);
+ * return start.main( args );
+ * }
+ *
+ * public int alternateMain( String[] args ) {
+ * for (int i = 0; i < args.length; i++) {
+ * System.out.println( args[i] );
+ * }
+ * return args.length;
+ * }
+ * }
+ *
+ *
+ *
+ * By themselves, delegates don't do much. Their true power lies in the fact that
+ * they can be treated like objects, and passed to other methods. In fact that is
+ * one of the key building blocks of building Intelligent Agents which in tern are
+ * the foundation of artificial intelligence. In the above program, we could have
+ * easily created the delegate to match the static main method by
+ * substituting the delegate creation call with this:
+ * MethodDelegate.createStatic(getClass(), "main", MainDelegate.class).
+ *
+ *
+ * Another key use for Delegates is to register event listeners. It is much easier
+ * to have all the code for your events separated out into methods instead of individual
+ * classes. One of the ways Java gets around that is to create anonymous classes.
+ * They are particularly troublesome because many Debuggers do not know what to do
+ * with them. Anonymous classes tend to duplicate alot of code as well. We can
+ * use any interface with one declared method to forward events to any method that
+ * matches the signature (although the method name can be different).
+ *
+ *
+ * Equality
+ * The criteria that we use to test if two delegates are equal are:
+ *
+ *
+ * They both refer to the same instance. That is, the instance
+ * parameter passed to the newDelegate method was the same for both. The
+ * instances are compared with the identity equality operator, ==.
+ *
+ * They refer to the same method as resolved by Method.equals.
+ *
+ *
+ * @version $Id: MethodDelegate.java,v 1.25 2006/03/05 02:43:19 herbyderby Exp $
+ */
+abstract public class MethodDelegate {
+ private static final MethodDelegateKey KEY_FACTORY =
+ (MethodDelegateKey)KeyFactory.create(MethodDelegateKey.class, KeyFactory.CLASS_BY_NAME);
+
+ protected Object target;
+ protected String eqMethod;
+
+ interface MethodDelegateKey {
+ Object newInstance(Class delegateClass, String methodName, Class iface);
+ }
+
+ public static MethodDelegate createStatic(Class targetClass, String methodName, Class iface) {
+ Generator gen = new Generator();
+ gen.setTargetClass(targetClass);
+ gen.setMethodName(methodName);
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public static MethodDelegate create(Object target, String methodName, Class iface) {
+ Generator gen = new Generator();
+ gen.setTarget(target);
+ gen.setMethodName(methodName);
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public boolean equals(Object obj) {
+ MethodDelegate other = (MethodDelegate)obj;
+ return (other != null && target == other.target) && eqMethod.equals(other.eqMethod);
+ }
+
+ public int hashCode() {
+ return target.hashCode() ^ eqMethod.hashCode();
+ }
+
+ public Object getTarget() {
+ return target;
+ }
+
+ abstract public MethodDelegate newInstance(Object target);
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(MethodDelegate.class.getName());
+ private static final Type METHOD_DELEGATE =
+ TypeUtils.parseType("net.sf.cglib.reflect.MethodDelegate");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", METHOD_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
+
+ private Object target;
+ private Class targetClass;
+ private String methodName;
+ private Class iface;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ public void setTarget(Object target) {
+ this.target = target;
+ this.targetClass = target.getClass();
+ }
+
+ public void setTargetClass(Class targetClass) {
+ this.targetClass = targetClass;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public void setInterface(Class iface) {
+ this.iface = iface;
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return targetClass.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(targetClass);
+ }
+
+ public MethodDelegate create() {
+ setNamePrefix(targetClass.getName());
+ Object key = KEY_FACTORY.newInstance(targetClass, methodName, iface);
+ return (MethodDelegate)super.create(key);
+ }
+
+ protected Object firstInstance(Class type) {
+ return ((MethodDelegate)ReflectUtils.newInstance(type)).newInstance(target);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((MethodDelegate)instance).newInstance(target);
+ }
+
+ public void generateClass(ClassVisitor v) throws NoSuchMethodException {
+ Method proxy = ReflectUtils.findInterfaceMethod(iface);
+ final Method method = targetClass.getMethod(methodName, proxy.getParameterTypes());
+ if (!proxy.getReturnType().isAssignableFrom(method.getReturnType())) {
+ throw new IllegalArgumentException("incompatible return types");
+ }
+
+ MethodInfo methodInfo = ReflectUtils.getMethodInfo(method);
+
+ boolean isStatic = TypeUtils.isStatic(methodInfo.getModifiers());
+ if ((target == null) ^ isStatic) {
+ throw new IllegalArgumentException("Static method " + (isStatic ? "not " : "") + "expected");
+ }
+
+ ClassEmitter ce = new ClassEmitter(v);
+ CodeEmitter e;
+ ce.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ METHOD_DELEGATE,
+ new Type[]{ Type.getType(iface) },
+ Constants.SOURCE_FILE);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, "eqMethod", Constants.TYPE_STRING, null);
+ EmitUtils.null_constructor(ce);
+
+ // generate proxied method
+ MethodInfo proxied = ReflectUtils.getMethodInfo(iface.getDeclaredMethods()[0]);
+ int modifiers = Constants.ACC_PUBLIC;
+ if ((proxied.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
+ modifiers |= Constants.ACC_VARARGS;
+ }
+ e = EmitUtils.begin_method(ce, proxied, modifiers);
+ e.load_this();
+ e.super_getfield("target", Constants.TYPE_OBJECT);
+ e.checkcast(methodInfo.getClassInfo().getType());
+ e.load_args();
+ e.invoke(methodInfo);
+ e.return_value();
+ e.end_method();
+
+ // newInstance
+ e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
+ e.new_instance_this();
+ e.dup();
+ e.dup2();
+ e.invoke_constructor_this();
+ e.getfield("eqMethod");
+ e.super_putfield("eqMethod", Constants.TYPE_STRING);
+ e.load_arg(0);
+ e.super_putfield("target", Constants.TYPE_OBJECT);
+ e.return_value();
+ e.end_method();
+
+ // static initializer
+ e = ce.begin_static();
+ e.push(methodInfo.getSignature().toString());
+ e.putfield("eqMethod");
+ e.return_value();
+ e.end_method();
+
+ ce.end_class();
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/reflect/MulticastDelegate.java b/blade-aop/src/main/java/net/sf/cglib/reflect/MulticastDelegate.java
new file mode 100644
index 000000000..fe5e7b8d2
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/reflect/MulticastDelegate.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.reflect;
+
+import java.lang.reflect.*;
+import java.security.ProtectionDomain;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+
+abstract public class MulticastDelegate implements Cloneable {
+ protected Object[] targets = {};
+
+ protected MulticastDelegate() {
+ }
+
+ public List getTargets() {
+ return new ArrayList(Arrays.asList(targets));
+ }
+
+ abstract public MulticastDelegate add(Object target);
+
+ protected MulticastDelegate addHelper(Object target) {
+ MulticastDelegate copy = newInstance();
+ copy.targets = new Object[targets.length + 1];
+ System.arraycopy(targets, 0, copy.targets, 0, targets.length);
+ copy.targets[targets.length] = target;
+ return copy;
+ }
+
+ public MulticastDelegate remove(Object target) {
+ for (int i = targets.length - 1; i >= 0; i--) {
+ if (targets[i].equals(target)) {
+ MulticastDelegate copy = newInstance();
+ copy.targets = new Object[targets.length - 1];
+ System.arraycopy(targets, 0, copy.targets, 0, i);
+ System.arraycopy(targets, i + 1, copy.targets, i, targets.length - i - 1);
+ return copy;
+ }
+ }
+ return this;
+ }
+
+ abstract public MulticastDelegate newInstance();
+
+ public static MulticastDelegate create(Class iface) {
+ Generator gen = new Generator();
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(MulticastDelegate.class.getName());
+ private static final Type MULTICAST_DELEGATE =
+ TypeUtils.parseType("net.sf.cglib.reflect.MulticastDelegate");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", MULTICAST_DELEGATE, new Type[0]);
+ private static final Signature ADD_DELEGATE =
+ new Signature("add", MULTICAST_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
+ private static final Signature ADD_HELPER =
+ new Signature("addHelper", MULTICAST_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
+
+ private Class iface;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return iface.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(iface);
+ }
+
+ public void setInterface(Class iface) {
+ this.iface = iface;
+ }
+
+ public MulticastDelegate create() {
+ setNamePrefix(MulticastDelegate.class.getName());
+ return (MulticastDelegate)super.create(iface.getName());
+ }
+
+ public void generateClass(ClassVisitor cv) {
+ final MethodInfo method = ReflectUtils.getMethodInfo(ReflectUtils.findInterfaceMethod(iface));
+
+ ClassEmitter ce = new ClassEmitter(cv);
+ ce.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ MULTICAST_DELEGATE,
+ new Type[]{ Type.getType(iface) },
+ Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(ce);
+
+ // generate proxied method
+ emitProxy(ce, method);
+
+ // newInstance
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
+ e.new_instance_this();
+ e.dup();
+ e.invoke_constructor_this();
+ e.return_value();
+ e.end_method();
+
+ // add
+ e = ce.begin_method(Constants.ACC_PUBLIC, ADD_DELEGATE, null);
+ e.load_this();
+ e.load_arg(0);
+ e.checkcast(Type.getType(iface));
+ e.invoke_virtual_this(ADD_HELPER);
+ e.return_value();
+ e.end_method();
+
+ ce.end_class();
+ }
+
+ private void emitProxy(ClassEmitter ce, final MethodInfo method) {
+ int modifiers = Constants.ACC_PUBLIC;
+ if ((method.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
+ modifiers |= Constants.ACC_VARARGS;
+ }
+ final CodeEmitter e = EmitUtils.begin_method(ce, method, modifiers);
+ Type returnType = method.getSignature().getReturnType();
+ final boolean returns = returnType != Type.VOID_TYPE;
+ Local result = null;
+ if (returns) {
+ result = e.make_local(returnType);
+ e.zero_or_null(returnType);
+ e.store_local(result);
+ }
+ e.load_this();
+ e.super_getfield("targets", Constants.TYPE_OBJECT_ARRAY);
+ final Local result2 = result;
+ EmitUtils.process_array(e, Constants.TYPE_OBJECT_ARRAY, new ProcessArrayCallback() {
+ public void processElement(Type type) {
+ e.checkcast(Type.getType(iface));
+ e.load_args();
+ e.invoke(method);
+ if (returns) {
+ e.store_local(result2);
+ }
+ }
+ });
+ if (returns) {
+ e.load_local(result);
+ }
+ e.return_value();
+ e.end_method();
+ }
+
+ protected Object firstInstance(Class type) {
+ // make a new instance in case first object is used with a long list of targets
+ return ((MulticastDelegate)ReflectUtils.newInstance(type)).newInstance();
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((MulticastDelegate)instance).newInstance();
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassFilterTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassFilterTransformer.java
new file mode 100644
index 000000000..53742fb6f
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassFilterTransformer.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.*;
+
+abstract public class AbstractClassFilterTransformer extends AbstractClassTransformer {
+ private ClassTransformer pass;
+ private ClassVisitor target;
+
+ public void setTarget(ClassVisitor target) {
+ super.setTarget(target);
+ pass.setTarget(target);
+ }
+
+ protected AbstractClassFilterTransformer(ClassTransformer pass) {
+ this.pass = pass;
+ }
+
+ abstract protected boolean accept(int version, int access, String name, String signature, String superName, String[] interfaces);
+
+ public void visit(int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ target = accept(version, access, name, signature, superName, interfaces) ? pass : cv;
+ target.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ public void visitSource(String source, String debug) {
+ target.visitSource(source, debug);
+ }
+
+ public void visitOuterClass(String owner, String name, String desc) {
+ target.visitOuterClass(owner, name, desc);
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return target.visitAnnotation(desc, visible);
+ }
+
+ public void visitAttribute(Attribute attr) {
+ target.visitAttribute(attr);
+ }
+
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ target.visitInnerClass(name, outerName, innerName, access);
+ }
+
+ public FieldVisitor visitField(int access,
+ String name,
+ String desc,
+ String signature,
+ Object value) {
+ return target.visitField(access, name, desc, signature, value);
+ }
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ return target.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ public void visitEnd() {
+ target.visitEnd();
+ target = null; // just to be safe
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassLoader.java b/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassLoader.java
new file mode 100644
index 000000000..8f25e4fd6
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassLoader.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.transform;
+
+import net.sf.cglib.core.CodeGenerationException;
+import net.sf.cglib.core.ClassGenerator;
+import net.sf.cglib.core.DebuggingClassWriter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Attribute;
+
+import java.io.IOException;
+
+abstract public class AbstractClassLoader extends ClassLoader {
+ private ClassFilter filter;
+ private ClassLoader classPath;
+ private static java.security.ProtectionDomain DOMAIN ;
+
+ static{
+
+ DOMAIN = (java.security.ProtectionDomain)
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Object run() {
+ return AbstractClassLoader.class.getProtectionDomain();
+ }
+ });
+ }
+
+ protected AbstractClassLoader(ClassLoader parent, ClassLoader classPath, ClassFilter filter) {
+ super(parent);
+ this.filter = filter;
+ this.classPath = classPath;
+ }
+
+ public Class loadClass(String name) throws ClassNotFoundException {
+
+ Class loaded = findLoadedClass(name);
+
+ if( loaded != null ){
+ if( loaded.getClassLoader() == this ){
+ return loaded;
+ }//else reload with this class loader
+ }
+
+ if (!filter.accept(name)) {
+ return super.loadClass(name);
+ }
+ ClassReader r;
+ try {
+
+ java.io.InputStream is = classPath.getResourceAsStream(
+ name.replace('.','/') + ".class"
+ );
+
+ if (is == null) {
+
+ throw new ClassNotFoundException(name);
+
+ }
+ try {
+
+ r = new ClassReader(is);
+
+ } finally {
+
+ is.close();
+
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException(name + ":" + e.getMessage());
+ }
+
+ try {
+ DebuggingClassWriter w =
+ new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES);
+ getGenerator(r).generateClass(w);
+ byte[] b = w.toByteArray();
+ Class c = super.defineClass(name, b, 0, b.length, DOMAIN);
+ postProcess(c);
+ return c;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Error e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ protected ClassGenerator getGenerator(ClassReader r) {
+ return new ClassReaderGenerator(r, attributes(), getFlags());
+ }
+
+ protected int getFlags() {
+ return 0;
+ }
+
+ protected Attribute[] attributes() {
+ return null;
+ }
+
+ protected void postProcess(Class c) {
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassTransformer.java
new file mode 100644
index 000000000..67102054e
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/AbstractClassTransformer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+abstract public class AbstractClassTransformer extends ClassTransformer {
+ protected AbstractClassTransformer() {
+ super(Opcodes.ASM5);
+ }
+
+ public void setTarget(ClassVisitor target) {
+ cv = target;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/AnnotationVisitorTee.java b/blade-aop/src/main/java/net/sf/cglib/transform/AnnotationVisitorTee.java
new file mode 100644
index 000000000..5ca4a22a1
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/AnnotationVisitorTee.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class AnnotationVisitorTee extends AnnotationVisitor {
+ private AnnotationVisitor av1, av2;
+
+ public static AnnotationVisitor getInstance(AnnotationVisitor av1, AnnotationVisitor av2) {
+ if (av1 == null)
+ return av2;
+ if (av2 == null)
+ return av1;
+ return new AnnotationVisitorTee(av1, av2);
+ }
+
+ public AnnotationVisitorTee(AnnotationVisitor av1, AnnotationVisitor av2) {
+ super(Opcodes.ASM5);
+ this.av1 = av1;
+ this.av2 = av2;
+ }
+
+ public void visit(String name, Object value) {
+ av2.visit(name, value);
+ av2.visit(name, value);
+ }
+
+ public void visitEnum(String name, String desc, String value) {
+ av1.visitEnum(name, desc, value);
+ av2.visitEnum(name, desc, value);
+ }
+
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ return getInstance(av1.visitAnnotation(name, desc),
+ av2.visitAnnotation(name, desc));
+ }
+
+ public AnnotationVisitor visitArray(String name) {
+ return getInstance(av1.visitArray(name), av2.visitArray(name));
+ }
+
+ public void visitEnd() {
+ av1.visitEnd();
+ av2.visitEnd();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassEmitterTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassEmitterTransformer.java
new file mode 100644
index 000000000..8d0adb599
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassEmitterTransformer.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import net.sf.cglib.core.ClassEmitter;
+
+abstract public class ClassEmitterTransformer extends ClassEmitter {
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassFilter.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassFilter.java
new file mode 100644
index 000000000..10bc52285
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassFilter.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+/**
+ *
+ * @author baliuka
+ */
+public interface ClassFilter {
+
+ boolean accept(String className);
+
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassFilterTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassFilterTransformer.java
new file mode 100644
index 000000000..7f9e7bef3
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassFilterTransformer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.*;
+
+public class ClassFilterTransformer extends AbstractClassFilterTransformer {
+ private ClassFilter filter;
+
+ public ClassFilterTransformer(ClassFilter filter, ClassTransformer pass) {
+ super(pass);
+ this.filter = filter;
+ }
+
+ protected boolean accept(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ return filter.accept(name.replace('/', '.'));
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassReaderGenerator.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassReaderGenerator.java
new file mode 100644
index 000000000..9274f843d
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassReaderGenerator.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import net.sf.cglib.core.ClassGenerator;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+
+public class ClassReaderGenerator implements ClassGenerator {
+ private final ClassReader r;
+ private final Attribute[] attrs;
+ private final int flags;
+
+ public ClassReaderGenerator(ClassReader r, int flags) {
+ this(r, null, flags);
+ }
+
+ public ClassReaderGenerator(ClassReader r, Attribute[] attrs, int flags) {
+ this.r = r;
+ this.attrs = (attrs != null) ? attrs : new Attribute[0];
+ this.flags = flags;
+ }
+
+ public void generateClass(ClassVisitor v) {
+ r.accept(v, attrs, flags);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformer.java
new file mode 100644
index 000000000..853020c04
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+public abstract class ClassTransformer extends ClassVisitor {
+ public ClassTransformer() {
+ super(Opcodes.ASM5);
+ }
+ public ClassTransformer(int opcode) {
+ super(opcode);
+ }
+ public abstract void setTarget(ClassVisitor target);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerChain.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerChain.java
new file mode 100644
index 000000000..acce06ff6
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerChain.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.*;
+
+public class ClassTransformerChain extends AbstractClassTransformer {
+ private ClassTransformer[] chain;
+
+ public ClassTransformerChain(ClassTransformer[] chain) {
+ this.chain = (ClassTransformer[])chain.clone();
+ }
+
+ public void setTarget(ClassVisitor v) {
+ super.setTarget(chain[0]);
+ ClassVisitor next = v;
+ for (int i = chain.length - 1; i >= 0; i--) {
+ chain[i].setTarget(next);
+ next = chain[i];
+ }
+ }
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ return cv.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("ClassTransformerChain{");
+ for (int i = 0; i < chain.length; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(chain[i].toString());
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerFactory.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerFactory.java
new file mode 100644
index 000000000..cceac9261
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerFactory.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+public interface ClassTransformerFactory {
+ ClassTransformer newInstance();
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerTee.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerTee.java
new file mode 100644
index 000000000..367c3f7dc
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassTransformerTee.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class ClassTransformerTee extends ClassTransformer {
+ private ClassVisitor branch;
+
+ public ClassTransformerTee(ClassVisitor branch) {
+ super(Opcodes.ASM5);
+ this.branch = branch;
+ }
+
+ public void setTarget(ClassVisitor target) {
+ cv = new ClassVisitorTee(branch, target);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/ClassVisitorTee.java b/blade-aop/src/main/java/net/sf/cglib/transform/ClassVisitorTee.java
new file mode 100644
index 000000000..b4cb967fb
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/ClassVisitorTee.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.*;
+
+public class ClassVisitorTee extends ClassVisitor {
+ private ClassVisitor cv1, cv2;
+
+ public ClassVisitorTee(ClassVisitor cv1, ClassVisitor cv2) {
+ super(Opcodes.ASM5);
+ this.cv1 = cv1;
+ this.cv2 = cv2;
+ }
+
+ public void visit(int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ cv1.visit(version, access, name, signature, superName, interfaces);
+ cv2.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ public void visitEnd() {
+ cv1.visitEnd();
+ cv2.visitEnd();
+ cv1 = cv2 = null;
+ }
+
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ cv1.visitInnerClass(name, outerName, innerName, access);
+ cv2.visitInnerClass(name, outerName, innerName, access);
+ }
+
+ public FieldVisitor visitField(int access,
+ String name,
+ String desc,
+ String signature,
+ Object value) {
+ FieldVisitor fv1 = cv1.visitField(access, name, desc, signature, value);
+ FieldVisitor fv2 = cv2.visitField(access, name, desc, signature, value);
+ if (fv1 == null)
+ return fv2;
+ if (fv2 == null)
+ return fv1;
+ return new FieldVisitorTee(fv1, fv2);
+ }
+
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ MethodVisitor mv1 = cv1.visitMethod(access, name, desc, signature, exceptions);
+ MethodVisitor mv2 = cv2.visitMethod(access, name, desc, signature, exceptions);
+ if (mv1 == null)
+ return mv2;
+ if (mv2 == null)
+ return mv1;
+ return new MethodVisitorTee(mv1, mv2);
+ }
+
+ public void visitSource(String source, String debug) {
+ cv1.visitSource(source, debug);
+ cv2.visitSource(source, debug);
+ }
+
+ public void visitOuterClass(String owner, String name, String desc) {
+ cv1.visitOuterClass(owner, name, desc);
+ cv2.visitOuterClass(owner, name, desc);
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(cv1.visitAnnotation(desc, visible),
+ cv2.visitAnnotation(desc, visible));
+ }
+
+ public void visitAttribute(Attribute attrs) {
+ cv1.visitAttribute(attrs);
+ cv2.visitAttribute(attrs);
+ }
+
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(cv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
+ cv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/FieldVisitorTee.java b/blade-aop/src/main/java/net/sf/cglib/transform/FieldVisitorTee.java
new file mode 100644
index 000000000..1ade1dcd3
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/FieldVisitorTee.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.TypePath;
+
+public class FieldVisitorTee extends FieldVisitor {
+ private FieldVisitor fv1, fv2;
+
+ public FieldVisitorTee(FieldVisitor fv1, FieldVisitor fv2) {
+ super(Opcodes.ASM5);
+ this.fv1 = fv1;
+ this.fv2 = fv2;
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(fv1.visitAnnotation(desc, visible),
+ fv2.visitAnnotation(desc, visible));
+ }
+
+ public void visitAttribute(Attribute attr) {
+ fv1.visitAttribute(attr);
+ fv2.visitAttribute(attr);
+ }
+
+ public void visitEnd() {
+ fv1.visitEnd();
+ fv2.visitEnd();
+ }
+
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(fv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
+ fv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
+ }
+}
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/MethodFilter.java b/blade-aop/src/main/java/net/sf/cglib/transform/MethodFilter.java
new file mode 100644
index 000000000..2772f8165
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/MethodFilter.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.Attribute;
+
+public interface MethodFilter {
+ // TODO: pass class name too?
+ boolean accept(int access, String name, String desc, String signature, String[] exceptions);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/MethodFilterTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/MethodFilterTransformer.java
new file mode 100644
index 000000000..1220cb0a8
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/MethodFilterTransformer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.*;
+
+public class MethodFilterTransformer extends AbstractClassTransformer {
+ private MethodFilter filter;
+ private ClassTransformer pass;
+ private ClassVisitor direct;
+
+ public MethodFilterTransformer(MethodFilter filter, ClassTransformer pass) {
+ this.filter = filter;
+ this.pass = pass;
+ super.setTarget(pass);
+ }
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ return (filter.accept(access, name, desc, signature, exceptions) ? pass : direct).visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ public void setTarget(ClassVisitor target) {
+ pass.setTarget(target);
+ direct = target;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/MethodVisitorTee.java b/blade-aop/src/main/java/net/sf/cglib/transform/MethodVisitorTee.java
new file mode 100644
index 000000000..17eeca062
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/MethodVisitorTee.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import org.objectweb.asm.*;
+
+public class MethodVisitorTee extends MethodVisitor {
+ private final MethodVisitor mv1;
+ private final MethodVisitor mv2;
+
+ public MethodVisitorTee(MethodVisitor mv1, MethodVisitor mv2) {
+ super(Opcodes.ASM5);
+ this.mv1 = mv1;
+ this.mv2 = mv2;
+ }
+
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ mv1.visitFrame(type, nLocal, local, nStack, stack);
+ mv2.visitFrame(type, nLocal, local, nStack, stack);
+ }
+
+ public AnnotationVisitor visitAnnotationDefault() {
+ return AnnotationVisitorTee.getInstance(mv1.visitAnnotationDefault(),
+ mv2.visitAnnotationDefault());
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitAnnotation(desc, visible),
+ mv2.visitAnnotation(desc, visible));
+ }
+
+ public AnnotationVisitor visitParameterAnnotation(int parameter,
+ String desc,
+ boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitParameterAnnotation(parameter, desc, visible),
+ mv2.visitParameterAnnotation(parameter, desc, visible));
+ }
+
+ public void visitAttribute(Attribute attr) {
+ mv1.visitAttribute(attr);
+ mv2.visitAttribute(attr);
+ }
+
+ public void visitCode() {
+ mv1.visitCode();
+ mv2.visitCode();
+ }
+
+ public void visitInsn(int opcode) {
+ mv1.visitInsn(opcode);
+ mv2.visitInsn(opcode);
+ }
+
+ public void visitIntInsn(int opcode, int operand) {
+ mv1.visitIntInsn(opcode, operand);
+ mv2.visitIntInsn(opcode, operand);
+ }
+
+ public void visitVarInsn(int opcode, int var) {
+ mv1.visitVarInsn(opcode, var);
+ mv2.visitVarInsn(opcode, var);
+ }
+
+ public void visitTypeInsn(int opcode, String desc) {
+ mv1.visitTypeInsn(opcode, desc);
+ mv2.visitTypeInsn(opcode, desc);
+ }
+
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ mv1.visitFieldInsn(opcode, owner, name, desc);
+ mv2.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ mv1.visitMethodInsn(opcode, owner, name, desc);
+ mv2.visitMethodInsn(opcode, owner, name, desc);
+ }
+
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+ mv1.visitMethodInsn(opcode, owner, name, desc, itf);
+ mv2.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ public void visitJumpInsn(int opcode, Label label) {
+ mv1.visitJumpInsn(opcode, label);
+ mv2.visitJumpInsn(opcode, label);
+ }
+
+ public void visitLabel(Label label) {
+ mv1.visitLabel(label);
+ mv2.visitLabel(label);
+ }
+
+ public void visitLdcInsn(Object cst) {
+ mv1.visitLdcInsn(cst);
+ mv2.visitLdcInsn(cst);
+ }
+
+ public void visitIincInsn(int var, int increment) {
+ mv1.visitIincInsn(var, increment);
+ mv2.visitIincInsn(var, increment);
+ }
+
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label labels[]) {
+ mv1.visitTableSwitchInsn(min, max, dflt, labels);
+ mv2.visitTableSwitchInsn(min, max, dflt, labels);
+ }
+
+ public void visitLookupSwitchInsn(Label dflt, int keys[], Label labels[]) {
+ mv1.visitLookupSwitchInsn(dflt, keys, labels);
+ mv2.visitLookupSwitchInsn(dflt, keys, labels);
+ }
+
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+ mv1.visitMultiANewArrayInsn(desc, dims);
+ mv2.visitMultiANewArrayInsn(desc, dims);
+ }
+
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+ mv1.visitTryCatchBlock(start, end, handler, type);
+ mv2.visitTryCatchBlock(start, end, handler, type);
+ }
+
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ mv1.visitLocalVariable(name, desc, signature, start, end, index);
+ mv2.visitLocalVariable(name, desc, signature, start, end, index);
+ }
+
+ public void visitLineNumber(int line, Label start) {
+ mv1.visitLineNumber(line, start);
+ mv2.visitLineNumber(line, start);
+ }
+
+ public void visitMaxs(int maxStack, int maxLocals) {
+ mv1.visitMaxs(maxStack, maxLocals);
+ mv2.visitMaxs(maxStack, maxLocals);
+ }
+
+ public void visitEnd() {
+ mv1.visitEnd();
+ mv2.visitEnd();
+ }
+
+ public void visitParameter(String name, int access) {
+ mv1.visitParameter(name, access);
+ mv2.visitParameter(name, access);
+ }
+
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
+ mv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
+ }
+
+ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+ mv1.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ mv2.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ }
+
+ public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitInsnAnnotation(typeRef, typePath, desc, visible),
+ mv2.visitInsnAnnotation(typeRef, typePath, desc, visible));
+ }
+
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitTryCatchAnnotation(typeRef, typePath, desc, visible),
+ mv2.visitTryCatchAnnotation(typeRef, typePath, desc, visible));
+ }
+
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible),
+ mv2.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible));
+ }
+}
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/TransformingClassGenerator.java b/blade-aop/src/main/java/net/sf/cglib/transform/TransformingClassGenerator.java
new file mode 100644
index 000000000..386155fee
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/TransformingClassGenerator.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import net.sf.cglib.core.ClassGenerator;
+import net.sf.cglib.core.Transformer;
+import org.objectweb.asm.ClassVisitor;
+
+public class TransformingClassGenerator implements ClassGenerator {
+ private ClassGenerator gen;
+ private ClassTransformer t;
+
+ public TransformingClassGenerator(ClassGenerator gen, ClassTransformer t) {
+ this.gen = gen;
+ this.t = t;
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ t.setTarget(v);
+ gen.generateClass(t);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/TransformingClassLoader.java b/blade-aop/src/main/java/net/sf/cglib/transform/TransformingClassLoader.java
new file mode 100644
index 000000000..505f621e2
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/TransformingClassLoader.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform;
+
+import java.util.*;
+import net.sf.cglib.core.ClassGenerator;
+import org.objectweb.asm.*;
+
+public class TransformingClassLoader extends AbstractClassLoader {
+ private ClassTransformerFactory t;
+
+ public TransformingClassLoader(ClassLoader parent, ClassFilter filter, ClassTransformerFactory t) {
+ super(parent, parent, filter);
+ this.t = t;
+ }
+
+ protected ClassGenerator getGenerator(ClassReader r) {
+ ClassTransformer t2 = (ClassTransformer)t.newInstance();
+ return new TransformingClassGenerator(super.getGenerator(r), t2);
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/AbstractInterceptFieldCallback.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AbstractInterceptFieldCallback.java
new file mode 100644
index 000000000..302bd3567
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AbstractInterceptFieldCallback.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.transform.impl;
+
+/**
+ * @author Chris Nokleberg
+ */
+public class AbstractInterceptFieldCallback implements InterceptFieldCallback {
+
+ public int writeInt(Object obj, String name, int oldValue, int newValue) { return newValue; }
+ public char writeChar(Object obj, String name, char oldValue, char newValue) { return newValue; }
+ public byte writeByte(Object obj, String name, byte oldValue, byte newValue) { return newValue; }
+ public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) { return newValue; }
+ public short writeShort(Object obj, String name, short oldValue, short newValue) { return newValue; }
+ public float writeFloat(Object obj, String name, float oldValue, float newValue) { return newValue; }
+ public double writeDouble(Object obj, String name, double oldValue, double newValue) { return newValue; }
+ public long writeLong(Object obj, String name, long oldValue, long newValue) { return newValue; }
+ public Object writeObject(Object obj, String name, Object oldValue, Object newValue) { return newValue; }
+
+ public int readInt(Object obj, String name, int oldValue) { return oldValue; }
+ public char readChar(Object obj, String name, char oldValue) { return oldValue; }
+ public byte readByte(Object obj, String name, byte oldValue) { return oldValue; }
+ public boolean readBoolean(Object obj, String name, boolean oldValue) { return oldValue; }
+ public short readShort(Object obj, String name, short oldValue) { return oldValue; }
+ public float readFloat(Object obj, String name, float oldValue) { return oldValue; }
+ public double readDouble(Object obj, String name, double oldValue) { return oldValue; }
+ public long readLong(Object obj, String name, long oldValue) { return oldValue; }
+ public Object readObject(Object obj, String name, Object oldValue) { return oldValue; }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/AccessFieldTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AccessFieldTransformer.java
new file mode 100644
index 000000000..9de468eb4
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AccessFieldTransformer.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import net.sf.cglib.transform.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Type;
+
+public class AccessFieldTransformer extends ClassEmitterTransformer {
+ private Callback callback;
+
+ public AccessFieldTransformer(Callback callback) {
+ this.callback = callback;
+ }
+
+ public interface Callback {
+ String getPropertyName(Type owner, String fieldName);
+ }
+
+ public void declare_field(int access, final String name, Type type, Object value) {
+ super.declare_field(access, name, type, value);
+
+ String property = TypeUtils.upperFirst(callback.getPropertyName(getClassType(), name));
+ if (property != null) {
+ CodeEmitter e;
+ e = begin_method(Constants.ACC_PUBLIC,
+ new Signature("get" + property,
+ type,
+ Constants.TYPES_EMPTY),
+ null);
+ e.load_this();
+ e.getfield(name);
+ e.return_value();
+ e.end_method();
+
+ e = begin_method(Constants.ACC_PUBLIC,
+ new Signature("set" + property,
+ Type.VOID_TYPE,
+ new Type[]{ type }),
+ null);
+ e.load_this();
+ e.load_arg(0);
+ e.putfield(name);
+ e.return_value();
+ e.end_method();
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddDelegateTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddDelegateTransformer.java
new file mode 100644
index 000000000..a5423a7c4
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddDelegateTransformer.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import net.sf.cglib.transform.*;
+import java.lang.reflect.*;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Type;
+
+/**
+ * @author Juozas Baliuka
+ */
+public class AddDelegateTransformer extends ClassEmitterTransformer {
+ private static final String DELEGATE = "$CGLIB_DELEGATE";
+ private static final Signature CSTRUCT_OBJECT =
+ TypeUtils.parseSignature("void (Object)");
+
+ private Class[] delegateIf;
+ private Class delegateImpl;
+ private Type delegateType;
+
+ /** Creates a new instance of AddDelegateTransformer */
+ public AddDelegateTransformer(Class delegateIf[], Class delegateImpl) {
+ try {
+ delegateImpl.getConstructor(new Class[]{ Object.class });
+ this.delegateIf = delegateIf;
+ this.delegateImpl = delegateImpl;
+ delegateType = Type.getType(delegateImpl);
+ } catch (NoSuchMethodException e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ public void begin_class(int version, int access, String className, Type superType, Type[] interfaces, String sourceFile) {
+
+ if(!TypeUtils.isInterface(access)){
+
+ Type[] all = TypeUtils.add(interfaces, TypeUtils.getTypes(delegateIf));
+ super.begin_class(version, access, className, superType, all, sourceFile);
+
+ declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT,
+ DELEGATE,
+ delegateType,
+ null);
+ for (int i = 0; i < delegateIf.length; i++) {
+ Method[] methods = delegateIf[i].getMethods();
+ for (int j = 0; j < methods.length; j++) {
+ if (Modifier.isAbstract(methods[j].getModifiers())) {
+ addDelegate(methods[j]);
+ }
+ }
+ }
+ }else{
+ super.begin_class(version, access, className, superType, interfaces, sourceFile);
+ }
+ }
+
+ public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
+ final CodeEmitter e = super.begin_method(access, sig, exceptions);
+ if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) {
+ return new CodeEmitter(e) {
+ private boolean transformInit = true;
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ if (transformInit && opcode == Constants.INVOKESPECIAL) {
+ load_this();
+ new_instance(delegateType);
+ dup();
+ load_this();
+ invoke_constructor(delegateType, CSTRUCT_OBJECT);
+ putfield(DELEGATE);
+ transformInit = false;
+ }
+ }
+ };
+ }
+ return e;
+ }
+
+ private void addDelegate(Method m) {
+ Method delegate;
+ try {
+ delegate = delegateImpl.getMethod(m.getName(), m.getParameterTypes());
+ if (!delegate.getReturnType().getName().equals(m.getReturnType().getName())){
+ throw new IllegalArgumentException("Invalid delegate signature " + delegate);
+ }
+ } catch (NoSuchMethodException e) {
+ throw new CodeGenerationException(e);
+ }
+
+ final Signature sig = ReflectUtils.getSignature(m);
+ Type[] exceptions = TypeUtils.getTypes(m.getExceptionTypes());
+ CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, sig, exceptions);
+ e.load_this();
+ e.getfield(DELEGATE);
+ e.load_args();
+ e.invoke_virtual(delegateType, sig);
+ e.return_value();
+ e.end_method();
+ }
+}
+
+
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddInitTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddInitTransformer.java
new file mode 100644
index 000000000..a17a9f79f
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddInitTransformer.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2004 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 net.sf.cglib.transform.impl;
+
+import java.lang.reflect.Method;
+
+import net.sf.cglib.core.CodeEmitter;
+import net.sf.cglib.core.Constants;
+import net.sf.cglib.core.MethodInfo;
+import net.sf.cglib.core.ReflectUtils;
+import net.sf.cglib.core.Signature;
+import net.sf.cglib.transform.ClassEmitterTransformer;
+
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Type;
+
+/**
+ * @author Mark Hobson
+ */
+public class AddInitTransformer extends ClassEmitterTransformer {
+ private MethodInfo info;
+
+ public AddInitTransformer(Method method) {
+ info = ReflectUtils.getMethodInfo(method);
+
+ Type[] types = info.getSignature().getArgumentTypes();
+ if (types.length != 1 ||
+ !types[0].equals(Constants.TYPE_OBJECT) ||
+ !info.getSignature().getReturnType().equals(Type.VOID_TYPE)) {
+ throw new IllegalArgumentException(method + " illegal signature");
+ }
+ }
+
+ public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
+ final CodeEmitter emitter = super.begin_method(access, sig, exceptions);
+ if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) {
+ return new CodeEmitter(emitter) {
+ public void visitInsn(int opcode) {
+ if (opcode == Constants.RETURN) {
+ load_this();
+ invoke(info);
+ }
+ super.visitInsn(opcode);
+ }
+ };
+ }
+ return emitter;
+ }
+}
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddPropertyTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddPropertyTransformer.java
new file mode 100644
index 000000000..e13071acb
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddPropertyTransformer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import net.sf.cglib.transform.*;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Type;
+
+public class AddPropertyTransformer extends ClassEmitterTransformer {
+ private final String[] names;
+ private final Type[] types;
+
+ public AddPropertyTransformer(Map props) {
+ int size = props.size();
+ names = (String[])props.keySet().toArray(new String[size]);
+ types = new Type[size];
+ for (int i = 0; i < size; i++) {
+ types[i] = (Type)props.get(names[i]);
+ }
+ }
+
+ public AddPropertyTransformer(String[] names, Type[] types) {
+ this.names = names;
+ this.types = types;
+ }
+
+ public void end_class() {
+ if (!TypeUtils.isAbstract(getAccess())) {
+ EmitUtils.add_properties(this, names, types);
+ }
+ super.end_class();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddStaticInitTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddStaticInitTransformer.java
new file mode 100644
index 000000000..94a2eaebf
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/AddStaticInitTransformer.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2003,2004 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 net.sf.cglib.transform.impl;
+
+import java.lang.reflect.Method;
+import net.sf.cglib.core.*;
+import net.sf.cglib.transform.*;
+import org.objectweb.asm.Type;
+
+/**
+ * @author Juozas Baliuka, Chris Nokleberg
+ */
+public class AddStaticInitTransformer extends ClassEmitterTransformer {
+ private MethodInfo info;
+
+ public AddStaticInitTransformer(Method classInit) {
+ info = ReflectUtils.getMethodInfo(classInit);
+ if (!TypeUtils.isStatic(info.getModifiers())) {
+ throw new IllegalArgumentException(classInit + " is not static");
+ }
+ Type[] types = info.getSignature().getArgumentTypes();
+ if (types.length != 1 ||
+ !types[0].equals(Constants.TYPE_CLASS) ||
+ !info.getSignature().getReturnType().equals(Type.VOID_TYPE)) {
+ throw new IllegalArgumentException(classInit + " illegal signature");
+ }
+ }
+
+ protected void init() {
+ if (!TypeUtils.isInterface(getAccess())) {
+ CodeEmitter e = getStaticHook();
+ EmitUtils.load_class_this(e);
+ e.invoke(info);
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/FieldProvider.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/FieldProvider.java
new file mode 100644
index 000000000..d1eaace29
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/FieldProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+public interface FieldProvider {
+
+ String[] getFieldNames();
+
+ Class[] getFieldTypes();
+
+ void setField(int index, Object value);
+
+ Object getField(int index);
+
+
+ void setField(String name, Object value);
+
+ Object getField(String name);
+
+
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/FieldProviderTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/FieldProviderTransformer.java
new file mode 100644
index 000000000..90c9d1bd8
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/FieldProviderTransformer.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import net.sf.cglib.transform.*;
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+public class FieldProviderTransformer extends ClassEmitterTransformer {
+
+ private static final String FIELD_NAMES = "CGLIB$FIELD_NAMES";
+ private static final String FIELD_TYPES = "CGLIB$FIELD_TYPES";
+
+ private static final Type FIELD_PROVIDER =
+ TypeUtils.parseType("net.sf.cglib.transform.impl.FieldProvider");
+ private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
+ TypeUtils.parseType("IllegalArgumentException");
+ private static final Signature PROVIDER_GET =
+ TypeUtils.parseSignature("Object getField(String)");
+ private static final Signature PROVIDER_SET =
+ TypeUtils.parseSignature("void setField(String, Object)");
+ private static final Signature PROVIDER_SET_BY_INDEX =
+ TypeUtils.parseSignature("void setField(int, Object)");
+ private static final Signature PROVIDER_GET_BY_INDEX =
+ TypeUtils.parseSignature("Object getField(int)");
+ private static final Signature PROVIDER_GET_TYPES =
+ TypeUtils.parseSignature("Class[] getFieldTypes()");
+ private static final Signature PROVIDER_GET_NAMES =
+ TypeUtils.parseSignature("String[] getFieldNames()");
+
+ private int access;
+ private Map fields;
+
+ public void begin_class(int version, int access, String className, Type superType, Type[] interfaces, String sourceFile) {
+ if (!TypeUtils.isAbstract(access)) {
+ interfaces = TypeUtils.add(interfaces, FIELD_PROVIDER);
+ }
+ this.access = access;
+ fields = new HashMap();
+ super.begin_class(version, access, className, superType, interfaces, sourceFile);
+ }
+
+ public void declare_field(int access, String name, Type type, Object value) {
+ super.declare_field(access, name, type, value);
+
+ if (!TypeUtils.isStatic(access)) {
+ fields.put(name, type);
+ }
+ }
+
+ public void end_class() {
+ if (!TypeUtils.isInterface(access)) {
+ try {
+ generate();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+ super.end_class();
+ }
+
+ private void generate() throws Exception {
+ final String[] names = (String[])fields.keySet().toArray(new String[fields.size()]);
+
+ int indexes[] = new int[names.length];
+ for (int i = 0; i < indexes.length; i++) {
+ indexes[i] = i;
+ }
+
+ super.declare_field(Constants.PRIVATE_FINAL_STATIC, FIELD_NAMES, Constants.TYPE_STRING_ARRAY, null);
+ super.declare_field(Constants.PRIVATE_FINAL_STATIC, FIELD_TYPES, Constants.TYPE_CLASS_ARRAY, null);
+
+ // use separate methods here because each process switch inner class needs a final CodeEmitter
+ initFieldProvider(names);
+ getNames();
+ getTypes();
+ getField(names);
+ setField(names);
+ setByIndex(names, indexes);
+ getByIndex(names, indexes);
+ }
+
+ private void initFieldProvider(String[] names) {
+ CodeEmitter e = getStaticHook();
+ EmitUtils.push_object(e, names);
+ e.putstatic(getClassType(), FIELD_NAMES, Constants.TYPE_STRING_ARRAY);
+
+ e.push(names.length);
+ e.newarray(Constants.TYPE_CLASS);
+ e.dup();
+ for(int i = 0; i < names.length; i++ ){
+ e.dup();
+ e.push(i);
+ Type type = (Type)fields.get(names[i]);
+ EmitUtils.load_class(e, type);
+ e.aastore();
+ }
+ e.putstatic(getClassType(), FIELD_TYPES, Constants.TYPE_CLASS_ARRAY);
+ }
+
+ private void getNames() {
+ CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_NAMES, null);
+ e.getstatic(getClassType(), FIELD_NAMES, Constants.TYPE_STRING_ARRAY);
+ e.return_value();
+ e.end_method();
+ }
+
+ private void getTypes() {
+ CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_TYPES, null);
+ e.getstatic(getClassType(), FIELD_TYPES, Constants.TYPE_CLASS_ARRAY);
+ e.return_value();
+ e.end_method();
+ }
+
+ private void setByIndex(final String[] names, final int[] indexes) throws Exception {
+ final CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_SET_BY_INDEX, null);
+ e.load_this();
+ e.load_arg(1);
+ e.load_arg(0);
+ e.process_switch(indexes, new ProcessSwitchCallback() {
+ public void processCase(int key, Label end) throws Exception {
+ Type type = (Type)fields.get(names[key]);
+ e.unbox(type);
+ e.putfield(names[key]);
+ e.return_value();
+ }
+ public void processDefault() throws Exception {
+ e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field index");
+ }
+ });
+ e.end_method();
+ }
+
+ private void getByIndex(final String[] names, final int[] indexes) throws Exception {
+ final CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_BY_INDEX, null);
+ e.load_this();
+ e.load_arg(0);
+ e.process_switch(indexes, new ProcessSwitchCallback() {
+ public void processCase(int key, Label end) throws Exception {
+ Type type = (Type)fields.get(names[key]);
+ e.getfield(names[key]);
+ e.box(type);
+ e.return_value();
+ }
+ public void processDefault() throws Exception {
+ e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field index");
+ }
+ });
+ e.end_method();
+ }
+
+ // TODO: if this is used to enhance class files SWITCH_STYLE_TRIE should be used
+ // to avoid JVM hashcode implementation incompatibilities
+ private void getField(String[] names) throws Exception {
+ final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, PROVIDER_GET, null);
+ e.load_this();
+ e.load_arg(0);
+ EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ Type type = (Type)fields.get(key);
+ e.getfield((String)key);
+ e.box(type);
+ e.return_value();
+ }
+ public void processDefault() {
+ e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field name");
+ }
+ });
+ e.end_method();
+ }
+
+ private void setField(String[] names) throws Exception {
+ final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, PROVIDER_SET, null);
+ e.load_this();
+ e.load_arg(1);
+ e.load_arg(0);
+ EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ Type type = (Type)fields.get(key);
+ e.unbox(type);
+ e.putfield((String)key);
+ e.return_value();
+ }
+ public void processDefault() {
+ e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field name");
+ }
+ });
+ e.end_method();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldCallback.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldCallback.java
new file mode 100644
index 000000000..b53461b54
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldCallback.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+/**
+ * @author Juozas Baliuka
+ */
+public interface InterceptFieldCallback {
+
+ int writeInt(Object obj, String name, int oldValue, int newValue);
+ char writeChar(Object obj, String name, char oldValue, char newValue);
+ byte writeByte(Object obj, String name, byte oldValue, byte newValue);
+ boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue);
+ short writeShort(Object obj, String name, short oldValue, short newValue);
+ float writeFloat(Object obj, String name, float oldValue, float newValue);
+ double writeDouble(Object obj, String name, double oldValue, double newValue);
+ long writeLong(Object obj, String name, long oldValue, long newValue);
+ Object writeObject(Object obj, String name, Object oldValue, Object newValue);
+
+ int readInt(Object obj, String name, int oldValue);
+ char readChar(Object obj, String name, char oldValue);
+ byte readByte(Object obj, String name, byte oldValue);
+ boolean readBoolean(Object obj, String name, boolean oldValue);
+ short readShort(Object obj, String name, short oldValue);
+ float readFloat(Object obj, String name, float oldValue);
+ double readDouble(Object obj, String name, double oldValue);
+ long readLong(Object obj, String name, long oldValue);
+ Object readObject(Object obj, String name, Object oldValue);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldEnabled.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldEnabled.java
new file mode 100644
index 000000000..a4119e278
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldEnabled.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+public interface InterceptFieldEnabled {
+ void setInterceptFieldCallback(InterceptFieldCallback callback);
+ InterceptFieldCallback getInterceptFieldCallback();
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldFilter.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldFilter.java
new file mode 100644
index 000000000..0259dba39
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldFilter.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import org.objectweb.asm.Type;
+
+public interface InterceptFieldFilter {
+ boolean acceptRead(Type owner, String name);
+ boolean acceptWrite(Type owner, String name);
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldTransformer.java
new file mode 100644
index 000000000..c61521010
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/InterceptFieldTransformer.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import net.sf.cglib.transform.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+/**
+ * @author Juozas Baliuka, Chris Nokleberg
+ */
+public class InterceptFieldTransformer extends ClassEmitterTransformer {
+ private static final String CALLBACK_FIELD = "$CGLIB_READ_WRITE_CALLBACK";
+ private static final Type CALLBACK =
+ TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldCallback");
+ private static final Type ENABLED =
+ TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldEnabled");
+ private static final Signature ENABLED_SET =
+ new Signature("setInterceptFieldCallback", Type.VOID_TYPE, new Type[]{ CALLBACK });
+ private static final Signature ENABLED_GET =
+ new Signature("getInterceptFieldCallback", CALLBACK, new Type[0]);
+
+ private InterceptFieldFilter filter;
+
+ public InterceptFieldTransformer(InterceptFieldFilter filter) {
+ this.filter = filter;
+ }
+
+ public void begin_class(int version, int access, String className, Type superType, Type[] interfaces, String sourceFile) {
+ if (!TypeUtils.isInterface(access)) {
+ super.begin_class(version, access, className, superType, TypeUtils.add(interfaces, ENABLED), sourceFile);
+
+ super.declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT,
+ CALLBACK_FIELD,
+ CALLBACK,
+ null);
+
+ CodeEmitter e;
+ e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_GET, null);
+ e.load_this();
+ e.getfield(CALLBACK_FIELD);
+ e.return_value();
+ e.end_method();
+
+ e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_SET, null);
+ e.load_this();
+ e.load_arg(0);
+ e.putfield(CALLBACK_FIELD);
+ e.return_value();
+ e.end_method();
+ } else {
+ super.begin_class(version, access, className, superType, interfaces, sourceFile);
+ }
+ }
+
+ public void declare_field(int access, String name, Type type, Object value) {
+ super.declare_field(access, name, type, value);
+ if (!TypeUtils.isStatic(access)) {
+ if (filter.acceptRead(getClassType(), name)) {
+ addReadMethod(name, type);
+ }
+ if (filter.acceptWrite(getClassType(), name)) {
+ addWriteMethod(name, type);
+ }
+ }
+ }
+
+ private void addReadMethod(String name, Type type) {
+ CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
+ readMethodSig(name, type.getDescriptor()),
+ null);
+ e.load_this();
+ e.getfield(name);
+ e.load_this();
+ e.invoke_interface(ENABLED,ENABLED_GET);
+ Label intercept = e.make_label();
+ e.ifnonnull(intercept);
+ e.return_value();
+
+ e.mark(intercept);
+ Local result = e.make_local(type);
+ e.store_local(result);
+ e.load_this();
+ e.invoke_interface(ENABLED,ENABLED_GET);
+ e.load_this();
+ e.push(name);
+ e.load_local(result);
+ e.invoke_interface(CALLBACK, readCallbackSig(type));
+ if (!TypeUtils.isPrimitive(type)) {
+ e.checkcast(type);
+ }
+ e.return_value();
+ e.end_method();
+ }
+
+ private void addWriteMethod(String name, Type type) {
+ CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
+ writeMethodSig(name, type.getDescriptor()),
+ null);
+ e.load_this();
+ e.dup();
+ e.invoke_interface(ENABLED,ENABLED_GET);
+ Label skip = e.make_label();
+ e.ifnull(skip);
+
+ e.load_this();
+ e.invoke_interface(ENABLED,ENABLED_GET);
+ e.load_this();
+ e.push(name);
+ e.load_this();
+ e.getfield(name);
+ e.load_arg(0);
+ e.invoke_interface(CALLBACK, writeCallbackSig(type));
+ if (!TypeUtils.isPrimitive(type)) {
+ e.checkcast(type);
+ }
+ Label go = e.make_label();
+ e.goTo(go);
+ e.mark(skip);
+ e.load_arg(0);
+ e.mark(go);
+ e.putfield(name);
+ e.return_value();
+ e.end_method();
+ }
+
+ public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
+ return new CodeEmitter(super.begin_method(access, sig, exceptions)) {
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ Type towner = TypeUtils.fromInternalName(owner);
+ switch (opcode) {
+ case Constants.GETFIELD:
+ if (filter.acceptRead(towner, name)) {
+ helper(towner, readMethodSig(name, desc));
+ return;
+ }
+ break;
+ case Constants.PUTFIELD:
+ if (filter.acceptWrite(towner, name)) {
+ helper(towner, writeMethodSig(name, desc));
+ return;
+ }
+ break;
+ }
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ private void helper(Type owner, Signature sig) {
+ invoke_virtual(owner, sig);
+ }
+ };
+ }
+
+ private static Signature readMethodSig(String name, String desc) {
+ return new Signature("$cglib_read_" + name, "()" + desc);
+ }
+
+ private static Signature writeMethodSig(String name, String desc) {
+ return new Signature("$cglib_write_" + name, "(" + desc + ")V");
+ }
+
+ private static Signature readCallbackSig(Type type) {
+ Type remap = remap(type);
+ return new Signature("read" + callbackName(remap),
+ remap,
+ new Type[]{ Constants.TYPE_OBJECT,
+ Constants.TYPE_STRING,
+ remap });
+ }
+
+ private static Signature writeCallbackSig(Type type) {
+ Type remap = remap(type);
+ return new Signature("write" + callbackName(remap),
+ remap,
+ new Type[]{ Constants.TYPE_OBJECT,
+ Constants.TYPE_STRING,
+ remap,
+ remap });
+ }
+
+ private static Type remap(Type type) {
+ switch (type.getSort()) {
+ case Type.OBJECT:
+ case Type.ARRAY:
+ return Constants.TYPE_OBJECT;
+ default:
+ return type;
+ }
+ }
+
+ private static String callbackName(Type type) {
+ return (type == Constants.TYPE_OBJECT) ?
+ "Object" :
+ TypeUtils.upperFirst(TypeUtils.getClassName(type));
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/UndeclaredThrowableStrategy.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/UndeclaredThrowableStrategy.java
new file mode 100644
index 000000000..aaf3789dd
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/UndeclaredThrowableStrategy.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import net.sf.cglib.core.ClassGenerator;
+import net.sf.cglib.core.DefaultGeneratorStrategy;
+import net.sf.cglib.core.GeneratorStrategy;
+import net.sf.cglib.core.TypeUtils;
+import net.sf.cglib.transform.ClassTransformer;
+import net.sf.cglib.transform.MethodFilter;
+import net.sf.cglib.transform.MethodFilterTransformer;
+import net.sf.cglib.transform.TransformingClassGenerator;
+
+/**
+ * A {@link GeneratorStrategy} suitable for use with {@link net.sf.cglib.Enhancer} which
+ * causes all undeclared exceptions thrown from within a proxied method to be wrapped
+ * in an alternative exception of your choice.
+ */
+public class UndeclaredThrowableStrategy extends DefaultGeneratorStrategy {
+
+
+ private Class wrapper;
+
+ /**
+ * Create a new instance of this strategy.
+ * @param wrapper a class which extends either directly or
+ * indirectly from Throwable and which has at least one
+ * constructor that takes a single argument of type
+ * Throwable, for example
+ * java.lang.reflect.UndeclaredThrowableException.class
+ */
+ public UndeclaredThrowableStrategy(Class wrapper) {
+ this.wrapper = wrapper;
+ }
+
+ private static final MethodFilter TRANSFORM_FILTER = new MethodFilter() {
+ public boolean accept(int access, String name, String desc, String signature, String[] exceptions) {
+ return !TypeUtils.isPrivate(access) && name.indexOf('$') < 0;
+ }
+ };
+
+ protected ClassGenerator transform(ClassGenerator cg) throws Exception {
+ ClassTransformer tr = new UndeclaredThrowableTransformer(wrapper);
+ tr = new MethodFilterTransformer(TRANSFORM_FILTER, tr);
+ return new TransformingClassGenerator(cg, tr);
+ }
+}
+
diff --git a/blade-aop/src/main/java/net/sf/cglib/transform/impl/UndeclaredThrowableTransformer.java b/blade-aop/src/main/java/net/sf/cglib/transform/impl/UndeclaredThrowableTransformer.java
new file mode 100644
index 000000000..6369abae4
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/transform/impl/UndeclaredThrowableTransformer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.transform.impl;
+
+import java.lang.reflect.Constructor;
+import net.sf.cglib.core.*;
+import net.sf.cglib.transform.*;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.ClassVisitor;
+
+public class UndeclaredThrowableTransformer extends ClassEmitterTransformer {
+ private Type wrapper;
+
+ public UndeclaredThrowableTransformer(Class wrapper) {
+ this.wrapper = Type.getType(wrapper);
+ boolean found = false;
+ Constructor[] cstructs = wrapper.getConstructors();
+ for (int i = 0; i < cstructs.length; i++) {
+ Class[] types = cstructs[i].getParameterTypes();
+ if (types.length == 1 && types[0].equals(Throwable.class)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ throw new IllegalArgumentException(wrapper + " does not have a single-arg constructor that takes a Throwable");
+ }
+
+ public CodeEmitter begin_method(int access, final Signature sig, final Type[] exceptions) {
+ CodeEmitter e = super.begin_method(access, sig, exceptions);
+ if (TypeUtils.isAbstract(access) || sig.equals(Constants.SIG_STATIC)) {
+ return e;
+ }
+ return new CodeEmitter(e) {
+ private Block handler;
+ /* init */ {
+ handler = begin_block();
+ }
+ public void visitMaxs(int maxStack, int maxLocals) {
+ handler.end();
+ EmitUtils.wrap_undeclared_throwable(this, handler, exceptions, wrapper);
+ super.visitMaxs(maxStack, maxLocals);
+ }
+ };
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/util/ParallelSorter.java b/blade-aop/src/main/java/net/sf/cglib/util/ParallelSorter.java
new file mode 100644
index 000000000..04574a315
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/util/ParallelSorter.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.util;
+
+import java.lang.reflect.*;
+import java.util.Comparator;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+
+/**
+ * For the efficient sorting of multiple arrays in parallel.
+ *
+ * Given two arrays of equal length and varying types, the standard
+ * technique for sorting them in parallel is to create a new temporary
+ * object for each row, store the objects in a temporary array, sort the
+ * array using a custom comparator, and the extract the original values
+ * back into their respective arrays. This is wasteful in both time and
+ * memory.
+ *
+ * This class generates bytecode customized to the particular set of
+ * arrays you need to sort, in such a way that both arrays are sorted
+ * in-place, simultaneously.
+ *
+ * Two sorting algorithms are provided.
+ * Quicksort is best when you only need to sort by a single column, as
+ * it requires very few comparisons and swaps. Mergesort is best used
+ * when sorting multiple columns, as it is a "stable" sort--that is, it
+ * does not affect the relative order of equal objects from previous sorts.
+ *
+ * The mergesort algorithm here is an "in-place" variant, which while
+ * slower, does not require a temporary array.
+ *
+ * @author Chris Nokleberg
+ */
+abstract public class ParallelSorter extends SorterTemplate {
+ protected Object[] a;
+ private Comparer comparer;
+
+ protected ParallelSorter() {
+ }
+
+ abstract public ParallelSorter newInstance(Object[] arrays);
+
+ /**
+ * Create a new ParallelSorter object for a set of arrays. You may
+ * sort the arrays multiple times via the same ParallelSorter object.
+ * @param arrays An array of arrays to sort. The arrays may be a mix
+ * of primitive and non-primitive types, but should all be the same
+ * length.
+ * @param loader ClassLoader for generated class, uses "current" if null
+ */
+ public static ParallelSorter create(Object[] arrays) {
+ Generator gen = new Generator();
+ gen.setArrays(arrays);
+ return gen.create();
+ }
+
+ private int len() {
+ return ((Object[])a[0]).length;
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ */
+ public void quickSort(int index) {
+ quickSort(index, 0, len(), null);
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ */
+ public void quickSort(int index, int lo, int hi) {
+ quickSort(index, lo, hi, null);
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ * @param cmp Comparator to use if the specified column is non-primitive
+ */
+ public void quickSort(int index, Comparator cmp) {
+ quickSort(index, 0, len(), cmp);
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ * @param cmp Comparator to use if the specified column is non-primitive
+ */
+ public void quickSort(int index, int lo, int hi, Comparator cmp) {
+ chooseComparer(index, cmp);
+ super.quickSort(lo, hi - 1);
+ }
+
+ /**
+ * @param index array (column) to sort by
+ */
+ public void mergeSort(int index) {
+ mergeSort(index, 0, len(), null);
+ }
+
+ /**
+ * Sort the arrays using an in-place merge sort.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ */
+ public void mergeSort(int index, int lo, int hi) {
+ mergeSort(index, lo, hi, null);
+ }
+
+ /**
+ * Sort the arrays using an in-place merge sort.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ */
+ public void mergeSort(int index, Comparator cmp) {
+ mergeSort(index, 0, len(), cmp);
+ }
+
+ /**
+ * Sort the arrays using an in-place merge sort.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ * @param cmp Comparator to use if the specified column is non-primitive
+ */
+ public void mergeSort(int index, int lo, int hi, Comparator cmp) {
+ chooseComparer(index, cmp);
+ super.mergeSort(lo, hi - 1);
+ }
+
+ private void chooseComparer(int index, Comparator cmp) {
+ Object array = a[index];
+ Class type = array.getClass().getComponentType();
+ if (type.equals(Integer.TYPE)) {
+ comparer = new IntComparer((int[])array);
+ } else if (type.equals(Long.TYPE)) {
+ comparer = new LongComparer((long[])array);
+ } else if (type.equals(Double.TYPE)) {
+ comparer = new DoubleComparer((double[])array);
+ } else if (type.equals(Float.TYPE)) {
+ comparer = new FloatComparer((float[])array);
+ } else if (type.equals(Short.TYPE)) {
+ comparer = new ShortComparer((short[])array);
+ } else if (type.equals(Byte.TYPE)) {
+ comparer = new ByteComparer((byte[])array);
+ } else if (cmp != null) {
+ comparer = new ComparatorComparer((Object[])array, cmp);
+ } else {
+ comparer = new ObjectComparer((Object[])array);
+ }
+ }
+
+ protected int compare(int i, int j) {
+ return comparer.compare(i, j);
+ }
+
+ interface Comparer {
+ int compare(int i, int j);
+ }
+
+ static class ComparatorComparer implements Comparer {
+ private Object[] a;
+ private Comparator cmp;
+
+ public ComparatorComparer(Object[] a, Comparator cmp) {
+ this.a = a;
+ this.cmp = cmp;
+ }
+
+ public int compare(int i, int j) {
+ return cmp.compare(a[i], a[j]);
+ }
+ }
+
+ static class ObjectComparer implements Comparer {
+ private Object[] a;
+ public ObjectComparer(Object[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ return ((Comparable)a[i]).compareTo(a[j]);
+ }
+ }
+
+ static class IntComparer implements Comparer {
+ private int[] a;
+ public IntComparer(int[] a) { this.a = a; }
+ public int compare(int i, int j) { return a[i] - a[j]; }
+ }
+
+ static class LongComparer implements Comparer {
+ private long[] a;
+ public LongComparer(long[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ long vi = a[i];
+ long vj = a[j];
+ return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
+ }
+ }
+
+ static class FloatComparer implements Comparer {
+ private float[] a;
+ public FloatComparer(float[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ float vi = a[i];
+ float vj = a[j];
+ return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
+ }
+ }
+
+ static class DoubleComparer implements Comparer {
+ private double[] a;
+ public DoubleComparer(double[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ double vi = a[i];
+ double vj = a[j];
+ return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
+ }
+ }
+
+ static class ShortComparer implements Comparer {
+ private short[] a;
+ public ShortComparer(short[] a) { this.a = a; }
+ public int compare(int i, int j) { return a[i] - a[j]; }
+ }
+
+ static class ByteComparer implements Comparer {
+ private byte[] a;
+ public ByteComparer(byte[] a) { this.a = a; }
+ public int compare(int i, int j) { return a[i] - a[j]; }
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(ParallelSorter.class.getName());
+
+ private Object[] arrays;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return null; // TODO
+ }
+
+ public void setArrays(Object[] arrays) {
+ this.arrays = arrays;
+ }
+
+ public ParallelSorter create() {
+ return (ParallelSorter)super.create(ClassesKey.create(arrays));
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ if (arrays.length == 0) {
+ throw new IllegalArgumentException("No arrays specified to sort");
+ }
+ for (int i = 0; i < arrays.length; i++) {
+ if (!arrays[i].getClass().isArray()) {
+ throw new IllegalArgumentException(arrays[i].getClass() + " is not an array");
+ }
+ }
+ new ParallelSorterEmitter(v, getClassName(), arrays);
+ }
+
+ protected Object firstInstance(Class type) {
+ return ((ParallelSorter)ReflectUtils.newInstance(type)).newInstance(arrays);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((ParallelSorter)instance).newInstance(arrays);
+ }
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/util/ParallelSorterEmitter.java b/blade-aop/src/main/java/net/sf/cglib/util/ParallelSorterEmitter.java
new file mode 100644
index 000000000..06351a9cf
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/util/ParallelSorterEmitter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+
+class ParallelSorterEmitter extends ClassEmitter {
+ private static final Type PARALLEL_SORTER =
+ TypeUtils.parseType("net.sf.cglib.util.ParallelSorter");
+ private static final Signature CSTRUCT_OBJECT_ARRAY =
+ TypeUtils.parseConstructor("Object[]");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", PARALLEL_SORTER, new Type[]{ Constants.TYPE_OBJECT_ARRAY });
+ private static final Signature SWAP =
+ TypeUtils.parseSignature("void swap(int, int)");
+
+ public ParallelSorterEmitter(ClassVisitor v, String className, Object[] arrays) {
+ super(v);
+ begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, PARALLEL_SORTER, null, Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(this);
+ EmitUtils.factory_method(this, NEW_INSTANCE);
+ generateConstructor(arrays);
+ generateSwap(arrays);
+ end_class();
+ }
+
+ private String getFieldName(int index) {
+ return "FIELD_" + index;
+ }
+
+ private void generateConstructor(Object[] arrays) {
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT_ARRAY, null);
+ e.load_this();
+ e.super_invoke_constructor();
+ e.load_this();
+ e.load_arg(0);
+ e.super_putfield("a", Constants.TYPE_OBJECT_ARRAY);
+ for (int i = 0; i < arrays.length; i++) {
+ Type type = Type.getType(arrays[i].getClass());
+ declare_field(Constants.ACC_PRIVATE, getFieldName(i), type, null);
+ e.load_this();
+ e.load_arg(0);
+ e.push(i);
+ e.aaload();
+ e.checkcast(type);
+ e.putfield(getFieldName(i));
+ }
+ e.return_value();
+ e.end_method();
+ }
+
+ private void generateSwap(final Object[] arrays) {
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SWAP, null);
+ for (int i = 0; i < arrays.length; i++) {
+ Type type = Type.getType(arrays[i].getClass());
+ Type component = TypeUtils.getComponentType(type);
+ Local T = e.make_local(type);
+
+ e.load_this();
+ e.getfield(getFieldName(i));
+ e.store_local(T);
+
+ e.load_local(T);
+ e.load_arg(0);
+
+ e.load_local(T);
+ e.load_arg(1);
+ e.array_load(component);
+
+ e.load_local(T);
+ e.load_arg(1);
+
+ e.load_local(T);
+ e.load_arg(0);
+ e.array_load(component);
+
+ e.array_store(component);
+ e.array_store(component);
+ }
+ e.return_value();
+ e.end_method();
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/util/SorterTemplate.java b/blade-aop/src/main/java/net/sf/cglib/util/SorterTemplate.java
new file mode 100644
index 000000000..b5c95f53c
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/util/SorterTemplate.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.util;
+
+import java.util.*;
+
+abstract class SorterTemplate {
+ private static final int MERGESORT_THRESHOLD = 12;
+ private static final int QUICKSORT_THRESHOLD = 7;
+
+ abstract protected void swap(int i, int j);
+ abstract protected int compare(int i, int j);
+
+ protected void quickSort(int lo, int hi) {
+ quickSortHelper(lo, hi);
+ insertionSort(lo, hi);
+ }
+
+ private void quickSortHelper(int lo, int hi) {
+ for (;;) {
+ int diff = hi - lo;
+ if (diff <= QUICKSORT_THRESHOLD) {
+ break;
+ }
+ int i = (hi + lo) / 2;
+ if (compare(lo, i) > 0) {
+ swap(lo, i);
+ }
+ if (compare(lo, hi) > 0) {
+ swap(lo, hi);
+ }
+ if (compare(i, hi) > 0) {
+ swap(i, hi);
+ }
+ int j = hi - 1;
+ swap(i, j);
+ i = lo;
+ int v = j;
+ for (;;) {
+ while (compare(++i, v) < 0) {
+ /* nothing */;
+ }
+ while (compare(--j, v) > 0) {
+ /* nothing */;
+ }
+ if (j < i) {
+ break;
+ }
+ swap(i, j);
+ }
+ swap(i, hi - 1);
+ if (j - lo <= hi - i + 1) {
+ quickSortHelper(lo, j);
+ lo = i + 1;
+ } else {
+ quickSortHelper(i + 1, hi);
+ hi = j;
+ }
+ }
+ }
+
+ private void insertionSort(int lo, int hi) {
+ for (int i = lo + 1 ; i <= hi; i++) {
+ for (int j = i; j > lo; j--) {
+ if (compare(j - 1, j) > 0) {
+ swap(j - 1, j);
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ protected void mergeSort(int lo, int hi) {
+ int diff = hi - lo;
+ if (diff <= MERGESORT_THRESHOLD) {
+ insertionSort(lo, hi);
+ return;
+ }
+ int mid = lo + diff / 2;
+ mergeSort(lo, mid);
+ mergeSort(mid, hi);
+ merge(lo, mid, hi, mid - lo, hi - mid);
+ }
+
+ private void merge(int lo, int pivot, int hi, int len1, int len2) {
+ if (len1 == 0 || len2 == 0) {
+ return;
+ }
+ if (len1 + len2 == 2) {
+ if (compare(pivot, lo) < 0) {
+ swap(pivot, lo);
+ }
+ return;
+ }
+ int first_cut, second_cut;
+ int len11, len22;
+ if (len1 > len2) {
+ len11 = len1 / 2;
+ first_cut = lo + len11;
+ second_cut = lower(pivot, hi, first_cut);
+ len22 = second_cut - pivot;
+ } else {
+ len22 = len2 / 2;
+ second_cut = pivot + len22;
+ first_cut = upper(lo, pivot, second_cut);
+ len11 = first_cut - lo;
+ }
+ rotate(first_cut, pivot, second_cut);
+ int new_mid = first_cut + len22;
+ merge(lo, first_cut, new_mid, len11, len22);
+ merge(new_mid, second_cut, hi, len1 - len11, len2 - len22);
+ }
+
+ private void rotate(int lo, int mid, int hi) {
+ int lot = lo;
+ int hit = mid - 1;
+ while (lot < hit) {
+ swap(lot++, hit--);
+ }
+ lot = mid; hit = hi - 1;
+ while (lot < hit) {
+ swap(lot++, hit--);
+ }
+ lot = lo; hit = hi - 1;
+ while (lot < hit) {
+ swap(lot++, hit--);
+ }
+ }
+
+ private int lower(int lo, int hi, int val) {
+ int len = hi - lo;
+ while (len > 0) {
+ int half = len / 2;
+ int mid= lo + half;
+ if (compare(mid, val) < 0) {
+ lo = mid + 1;
+ len = len - half -1;
+ } else {
+ len = half;
+ }
+ }
+ return lo;
+ }
+
+ private int upper(int lo, int hi, int val) {
+ int len = hi - lo;
+ while (len > 0) {
+ int half = len / 2;
+ int mid = lo + half;
+ if (compare(val, mid) < 0) {
+ len = half;
+ } else {
+ lo = mid + 1;
+ len = len - half -1;
+ }
+ }
+ return lo;
+ }
+}
diff --git a/blade-aop/src/main/java/net/sf/cglib/util/StringSwitcher.java b/blade-aop/src/main/java/net/sf/cglib/util/StringSwitcher.java
new file mode 100644
index 000000000..df6248822
--- /dev/null
+++ b/blade-aop/src/main/java/net/sf/cglib/util/StringSwitcher.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2003 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 net.sf.cglib.util;
+
+import java.util.*;
+import net.sf.cglib.core.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+/**
+ * This class implements a simple String->int mapping for a fixed set of keys.
+ */
+abstract public class StringSwitcher {
+ private static final Type STRING_SWITCHER =
+ TypeUtils.parseType("net.sf.cglib.util.StringSwitcher");
+ private static final Signature INT_VALUE =
+ TypeUtils.parseSignature("int intValue(String)");
+ private static final StringSwitcherKey KEY_FACTORY =
+ (StringSwitcherKey)KeyFactory.create(StringSwitcherKey.class);
+
+ interface StringSwitcherKey {
+ public Object newInstance(String[] strings, int[] ints, boolean fixedInput);
+ }
+
+ /**
+ * Helper method to create a StringSwitcher.
+ * For finer control over the generated instance, use a new instance of StringSwitcher.Generator
+ * instead of this static method.
+ * @param strings the array of String keys; must be the same length as the value array
+ * @param ints the array of integer results; must be the same length as the key array
+ * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as -1; if true,
+ * the result will be undefined, and the resulting code will be faster
+ */
+ public static StringSwitcher create(String[] strings, int[] ints, boolean fixedInput) {
+ Generator gen = new Generator();
+ gen.setStrings(strings);
+ gen.setInts(ints);
+ gen.setFixedInput(fixedInput);
+ return gen.create();
+ }
+
+ protected StringSwitcher() {
+ }
+
+ /**
+ * Return the integer associated with the given key.
+ * @param s the key
+ * @return the associated integer value, or -1 if the key is unknown (unless
+ * fixedInput was specified when this StringSwitcher was created,
+ * in which case the return value for an unknown key is undefined)
+ */
+ abstract public int intValue(String s);
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(StringSwitcher.class.getName());
+
+ private String[] strings;
+ private int[] ints;
+ private boolean fixedInput;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ /**
+ * Set the array of recognized Strings.
+ * @param strings the array of String keys; must be the same length as the value array
+ * @see #setInts
+ */
+ public void setStrings(String[] strings) {
+ this.strings = strings;
+ }
+
+ /**
+ * Set the array of integer results.
+ * @param ints the array of integer results; must be the same length as the key array
+ * @see #setStrings
+ */
+ public void setInts(int[] ints) {
+ this.ints = ints;
+ }
+
+ /**
+ * Configure how unknown String keys will be handled.
+ * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as -1; if true,
+ * the result will be undefined, and the resulting code will be faster
+ */
+ public void setFixedInput(boolean fixedInput) {
+ this.fixedInput = fixedInput;
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return getClass().getClassLoader();
+ }
+
+ /**
+ * Generate the StringSwitcher.
+ */
+ public StringSwitcher create() {
+ setNamePrefix(StringSwitcher.class.getName());
+ Object key = KEY_FACTORY.newInstance(strings, ints, fixedInput);
+ return (StringSwitcher)super.create(key);
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ ClassEmitter ce = new ClassEmitter(v);
+ ce.begin_class(Constants.V1_2,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ STRING_SWITCHER,
+ null,
+ Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(ce);
+ final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, INT_VALUE, null);
+ e.load_arg(0);
+ final List stringList = Arrays.asList(strings);
+ int style = fixedInput ? Constants.SWITCH_STYLE_HASHONLY : Constants.SWITCH_STYLE_HASH;
+ EmitUtils.string_switch(e, strings, style, new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ e.push(ints[stringList.indexOf(key)]);
+ e.return_value();
+ }
+ public void processDefault() {
+ e.push(-1);
+ e.return_value();
+ }
+ });
+ e.end_method();
+ ce.end_class();
+ }
+
+ protected Object firstInstance(Class type) {
+ return (StringSwitcher)ReflectUtils.newInstance(type);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return instance;
+ }
+ }
+}
diff --git a/blade-sql2o/pom.xml b/blade-auth/pom.xml
similarity index 53%
rename from blade-sql2o/pom.xml
rename to blade-auth/pom.xml
index 06a2c5b4f..fcf6e9319 100644
--- a/blade-sql2o/pom.xml
+++ b/blade-auth/pom.xml
@@ -5,33 +5,36 @@
4.0.0
com.bladejava
- blade-root
+ blade
1.0
-
- blade-sql2o
- jar
- ${blade.version}
- blade-sql2o
- https://github.com/biezhi/blade/blade-sql2o
-
+
+ blade-auth
+ 0.0.1
+ blade-auth
+ http://maven.apache.org
+
+
+ org.slf4j
+ slf4j-api
+
com.bladejava
blade-core
- ${blade.version}
- provided
+ ${blade-core.version}
+
- com.bladejava
- blade-cache
- ${blade.version}
+ javax.servlet
+ javax.servlet-api
+ ${servlet.version}
provided
- org.sql2o
- sql2o
- 1.5.4
+ junit
+ junit
+ test
diff --git a/blade-auth/src/main/java/com/blade/auth/CSRFConfig.java b/blade-auth/src/main/java/com/blade/auth/CSRFConfig.java
new file mode 100644
index 000000000..142383c68
--- /dev/null
+++ b/blade-auth/src/main/java/com/blade/auth/CSRFConfig.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
+ *
+ * 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 com.blade.auth;
+
+/**
+ * CSRF Config
+ *
+ * @author biezhi
+ * @since 1.0
+ */
+public class CSRFConfig {
+
+ // For the global key generation token, default random string
+ String secret = "blade";
+
+ // ID to save the session name of the user, default is "csrf_token"
+ String session = "csrf_token";
+
+ // HTTP request header information field for passing the token, default is "X-CSRFToken""
+ String header = "X-CSRFToken";
+
+ // Form field name for passing a token, defaukt is "_csrf"
+ String form = "_csrf";
+
+ // Cookie name for passing a token, default is "_csrf"
+ String cookie = "_csrf";
+
+ // Cookie path, default is "/"
+ String cookiePath = "/";
+
+ // Generate the token's length, the default 32
+ int length = 32;
+
+ // Cookie long, the default 60 seconds
+ int expire = 3600;
+
+ // Is used to specify whether the Cookie is set to HTTPS, default is false
+ boolean secured = false;
+
+ // Is used to specify whether the token is set to the header information in the response, default is false
+ boolean setHeader = false;
+
+ // Is used to specify whether the token is set to the Cookie of the response, default is false
+ boolean setCookie = false;
+
+ public CSRFConfig() {
+ }
+
+ public void setSecret(String secret) {
+ this.secret = secret;
+ }
+
+ public void setSession(String session) {
+ this.session = session;
+ }
+
+ public void setHeader(String header) {
+ this.header = header;
+ }
+
+ public void setForm(String form) {
+ this.form = form;
+ }
+
+ public void setCookie(String cookie) {
+ this.cookie = cookie;
+ }
+
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ public void setExpire(int expire) {
+ this.expire = expire;
+ }
+
+ public void setSetHeader(boolean setHeader) {
+ this.setHeader = setHeader;
+ }
+
+ public void setSetCookie(boolean setCookie) {
+ this.setCookie = setCookie;
+ }
+
+ public void setCookiePath(String cookiePath) {
+ this.cookiePath = cookiePath;
+ }
+
+ public void setSecured(boolean secured) {
+ this.secured = secured;
+ }
+
+}
diff --git a/blade-auth/src/main/java/com/blade/auth/CSRFTokenManager.java b/blade-auth/src/main/java/com/blade/auth/CSRFTokenManager.java
new file mode 100644
index 000000000..a16a41c68
--- /dev/null
+++ b/blade-auth/src/main/java/com/blade/auth/CSRFTokenManager.java
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
+ *
+ * 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 com.blade.auth;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.blade.kit.HashidKit;
+import com.blade.kit.StringKit;
+import com.blade.mvc.http.Request;
+import com.blade.mvc.http.Response;
+import com.blade.mvc.http.wrapper.Session;
+
+/**
+ * CSRF token Manager
+ *
+ * @author biezhi
+ * @since 1.0
+ */
+public class CSRFTokenManager {
+
+ private static Logger LOGGER = LoggerFactory.getLogger(CSRFTokenManager.class);
+
+ private static CSRFConfig config = new CSRFConfig();
+
+ private static HashidKit HASHID = new HashidKit(config.secret, config.length);
+
+ private CSRFTokenManager() {
+ }
+
+ public static void config(CSRFConfig config){
+ CSRFTokenManager.config = config;
+ HASHID = new HashidKit(config.secret, config.length);
+ }
+
+ /**
+ * Create a token
+ *
+ * @param request request object
+ * @param response response object
+ * @return return token
+ */
+ public static String createToken(Request request, Response response) {
+ String token = null;
+ synchronized (request) {
+ Session session = request.session();
+ String objToken = session.attribute(config.session);
+
+ if(StringKit.isBlank(objToken)){
+ token = createNewToken(request, response);
+ LOGGER.debug("create csrf_token:{}", token);
+ } else {
+ token = objToken;
+ session.attribute(config.session, token);
+ }
+ }
+ return token;
+ }
+
+ /**
+ * Create a token
+ *
+ * @param request request object
+ * @param response response object
+ * @return return token
+ */
+ public static String createNewToken(Request request, Response response) {
+ String token = null;
+ synchronized (request) {
+ Session session = request.session();
+ session.removeAttribute(config.session);
+ token = HASHID.encode( System.currentTimeMillis() );
+ session.attribute(config.session, token);
+ if(config.setHeader){
+ response.header(config.header, token);
+ }
+ if(config.setCookie){
+ response.cookie(config.cookiePath, config.cookie, token, config.expire, config.secured);
+ }
+ LOGGER.debug("create csrf_token:{}", token);
+ }
+ return token;
+ }
+
+ public static boolean verify(Request request, Response response) {
+ // csrftoken attribute from session
+ String sToken = request.session().attribute(config.session);
+ if (sToken == null) {
+ // Generate new token into session
+ sToken = CSRFTokenManager.createToken(request, response);
+ return true;
+ } else {
+ String pToken = request.query(config.form);
+ if(config.setHeader){
+ pToken = request.header(config.form);
+ }
+ if(config.setCookie){
+ pToken = request.cookie(config.form);
+ }
+ if (StringKit.isNotBlank(pToken) && sToken.equals(pToken)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * According to form parameter verification
+ *
+ * @param request request object
+ * @param response response object
+ * @return return verify is success
+ */
+ public static boolean verifyAsForm(Request request, Response response) {
+ // csrftoken attribute from session
+ String sToken = request.session().attribute(config.session);
+ if (sToken == null) {
+ // Generate new token into session
+ sToken = CSRFTokenManager.createToken(request, response);
+ return true;
+ } else {
+ String pToken = request.query(config.form);
+ if(config.setHeader){
+ pToken = request.header(config.form);
+ }
+ if(config.setCookie){
+ pToken = request.cookie(config.form);
+ }
+ if (StringKit.isNotBlank(pToken) && sToken.equals(pToken)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * According to header information verification
+ *
+ * @param request request object
+ * @param response response object
+ * @return return verify is success
+ */
+ public static boolean verifyAsHeader(Request request, Response response) {
+ // csrftoken attribute from session
+ String sToken = request.session().attribute(config.session);
+ if (sToken == null) {
+ // Generate new token into session
+ sToken = CSRFTokenManager.createToken(request, response);
+ return true;
+ } else {
+ String pToken = request.header(config.header);
+ if (StringKit.isNotBlank(pToken) && sToken.equals(pToken)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * According to cookie verification
+ *
+ * @param request request object
+ * @param response response object
+ * @return return verify is success
+ */
+ public static boolean verifyAsCookie(Request request, Response response) {
+ // csrftoken attribute from session
+ String sToken = request.session().attribute(config.session);
+ if (sToken == null) {
+ // Generate new token into session
+ sToken = CSRFTokenManager.createToken(request, response);
+ return true;
+ } else {
+ String pToken = request.cookie(config.cookie);
+ if (StringKit.isNotBlank(pToken) && sToken.equals(pToken)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/blade-auth/src/main/java/com/blade/auth/Xss.java b/blade-auth/src/main/java/com/blade/auth/Xss.java
new file mode 100644
index 000000000..1b79074d4
--- /dev/null
+++ b/blade-auth/src/main/java/com/blade/auth/Xss.java
@@ -0,0 +1,11 @@
+package com.blade.auth;
+
+import com.blade.kit.text.HTMLFilter;
+
+public class Xss {
+
+ public String filter(String str){
+ return HTMLFilter.htmlSpecialChars(str);
+ }
+
+}
diff --git a/blade-auth/src/main/java/com/blade/auth/package-info.java b/blade-auth/src/main/java/com/blade/auth/package-info.java
new file mode 100644
index 000000000..8cc06e0e8
--- /dev/null
+++ b/blade-auth/src/main/java/com/blade/auth/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Authentication And Security
+ */
+package com.blade.auth;
\ No newline at end of file
diff --git a/blade-auth/src/test/java/com/blade/auth/AppTest.java b/blade-auth/src/test/java/com/blade/auth/AppTest.java
new file mode 100644
index 000000000..45f271d54
--- /dev/null
+++ b/blade-auth/src/test/java/com/blade/auth/AppTest.java
@@ -0,0 +1,38 @@
+package com.blade.auth;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest
+ extends TestCase
+{
+ /**
+ * Create the test case
+ *
+ * @param testName name of the test case
+ */
+ public AppTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * @return the suite of tests being tested
+ */
+ public static Test suite()
+ {
+ return new TestSuite( AppTest.class );
+ }
+
+ /**
+ * Rigourous Test :-)
+ */
+ public void testApp()
+ {
+ assertTrue( true );
+ }
+}
diff --git a/blade-beetl/pom.xml b/blade-beetl/pom.xml
deleted file mode 100644
index 318680756..000000000
--- a/blade-beetl/pom.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
- 4.0.0
-
- com.bladejava
- blade-root
- 1.0
-
-
- blade-beetl
- jar
- ${blade.version}
- blade-beetl
- https://github.com/biezhi/blade/blade-beetl
-
-
-
- com.bladejava
- blade-core
- ${blade.version}
-
-
- org.beetl
- beetl-core
- 2.2.3
-
-
-
diff --git a/blade-beetl/src/main/java/blade/render/BeetlRender.java b/blade-beetl/src/main/java/blade/render/BeetlRender.java
deleted file mode 100644
index d2ee6d82a..000000000
--- a/blade-beetl/src/main/java/blade/render/BeetlRender.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package blade.render;
-
-import java.io.IOException;
-import java.util.Enumeration;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.beetl.core.Configuration;
-import org.beetl.core.GroupTemplate;
-import org.beetl.core.Template;
-import org.beetl.core.exception.BeetlException;
-import org.beetl.core.resource.FileResourceLoader;
-
-import blade.Blade;
-import blade.BladeWebContext;
-import blade.exception.BladeException;
-
-/**
- * Velocity渲染引擎
- * @author biezhi
- *
- */
-public class BeetlRender extends Render {
-
- private GroupTemplate groupTemplate = null;
-
- /**
- * 默认构造函数
- */
- public BeetlRender() {
- String root = Blade.webRoot();
- FileResourceLoader resourceLoader = new FileResourceLoader(root,"utf-8");
- try {
- Configuration cfg = Configuration.defaultConfiguration();
- groupTemplate = new GroupTemplate(resourceLoader, cfg);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 渲染视图
- */
- @Override
- public Object render(String view) {
-
- try {
- HttpServletRequest servletRequest = BladeWebContext.servletRequest();
- HttpServletResponse servletResponse = BladeWebContext.servletResponse();
-
- view = disposeView(view);
-
- Template template = groupTemplate.getTemplate(view);
-
- Enumeration attrs = servletRequest.getAttributeNames();
-
- if(null != attrs && attrs.hasMoreElements()){
- while(attrs.hasMoreElements()){
- String attr = attrs.nextElement();
- template.binding(attr, servletRequest.getAttribute(attr));
- }
- }
-
- template.renderTo(servletResponse.getOutputStream());
- } catch (BeetlException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
-
- /**
- * 渲染视图
- */
- @Override
- public Object render(ModelAndView modelAndView) {
- HttpServletRequest servletRequest = BladeWebContext.servletRequest();
- HttpServletResponse servletResponse = BladeWebContext.servletResponse();
-
- if(null == modelAndView){
- throw new BladeException("modelAndView is null");
- }
-
- try {
-
- String view = disposeView(modelAndView.getView());
-
- Template template = groupTemplate.getTemplate(view);
-
- Enumeration attrs = servletRequest.getAttributeNames();
-
- if(null != attrs && attrs.hasMoreElements()){
- while(attrs.hasMoreElements()){
- String attr = attrs.nextElement();
- template.binding(attr, servletRequest.getAttribute(attr));
- }
- }
-
- template.renderTo(servletResponse.getOutputStream());
- } catch (BeetlException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return null;
- }
-
-}
diff --git a/blade-cache/pom.xml b/blade-cache/pom.xml
deleted file mode 100644
index 36ba051b1..000000000
--- a/blade-cache/pom.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
- 4.0.0
-
- com.bladejava
- blade-root
- 1.0
-
-
- blade-cache
- jar
- ${blade.version}
- blade-cache
- https://github.com/biezhi/blade/blade-cache
-
-
diff --git a/blade-cache/src/main/java/blade/cache/AbstractCache.java b/blade-cache/src/main/java/blade/cache/AbstractCache.java
deleted file mode 100644
index 3b292ed6e..000000000
--- a/blade-cache/src/main/java/blade/cache/AbstractCache.java
+++ /dev/null
@@ -1,306 +0,0 @@
-package blade.cache;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * 抽象缓存基础实现
- *
- * @author biezhi
- * @since 1.0
- * @param
- * @param
- */
-@SuppressWarnings("unchecked")
-public abstract class AbstractCache implements Cache {
-
- /**
- * 同步缓存容器
- */
- protected Map> _mCache;
-
- /**
- * 同步缓存容器
- */
- protected Map>> _hCache;
-
- /**
- * 缓存锁
- */
- protected final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
-
- /**
- * 读取锁
- */
- protected final Lock readLock = cacheLock.readLock();
-
- /**
- * 写入锁
- */
- protected final Lock writeLock = cacheLock.writeLock();
-
- /**
- * 最大缓存数
- */
- protected int cacheSize;
-
- /**
- * 默认过期时间, 0 -> 永不过期
- */
- protected long defaultExpire;
-
- /**
- * 是否设置默认过期时间
- */
- protected boolean existCustomExpire;
-
- /**
- * 淘汰对象具体实现
- * @return
- */
- protected abstract int eliminateCache();
-
- /**
- * 设置一个缓存大小并初始化
- * @param cacheSize
- */
- public AbstractCache(int cacheSize) {
- this.cacheSize = cacheSize;
- this._mCache = Collections.synchronizedMap(new HashMap>());
- this._hCache = Collections.synchronizedMap(new HashMap>>());
- }
-
- /**
- * 放一个缓存
- */
- public void set(K key, V obj) {
- set(key, obj, defaultExpire);
- }
-
- /**
- * 放一个缓存并设置缓存时间
- */
- public void set(K key, V value, long expire) {
- writeLock.lock();
- try {
- CacheObject co = new CacheObject(key, value, expire);
- if (expire != 0) {
- existCustomExpire = true;
- }
- if (isFull()) {
- eliminate() ;
- }
- _mCache.put(key, co);
- }
- finally {
- writeLock.unlock();
- }
- }
-
- /**
- * 放一个缓存
- */
- public void hset(K key, F field, V obj) {
- hset(key, field, obj, defaultExpire);
- }
-
- /**
- * 放一个hash类型缓存并设置缓存时间
- */
- public void hset(K key, F field, V value, long expire) {
- writeLock.lock();
- try {
- CacheObject co = new CacheObject(key, value, expire);
-
- if(expire != 0){
- existCustomExpire = true;
- }
-
- if(isFull()){
- eliminate() ;
- }
-
- Map> coMap = (Map>) _hCache.get(key);
- if(null == coMap){
- coMap = new HashMap>();
- }
- coMap.put(field, co);
-
- _hCache.put(key, coMap);
- }
- finally {
- writeLock.unlock();
- }
- }
-
-
- /**
- * 取一个缓存
- */
- public V get(K key) {
- readLock.lock();
- try {
- CacheObject co = _mCache.get(key);
- if (co == null) {
- return null;
- }
- if (co.isExpired() == true) {
- _mCache.remove(key);
- return null;
- }
- return co.getValue();
- } finally {
- readLock.unlock();
- }
- }
-
- /**
- * 取一个缓存
- */
- public V hget(K key, F field) {
- readLock.lock();
- try {
- Map, CacheObject> coMap = _hCache.get(key);
-
- if(null == coMap){
- return null;
- }
-
- CacheObject co = coMap.get(field);
-
- if(null == co){
- return null;
- }
-
- if (co.isExpired() == true) {
- coMap.remove(field);
- return null;
- }
-
- return co.getValue();
- } finally {
- readLock.unlock();
- }
- }
-
- /**
- * 移除一个缓存
- */
- public void del(K key) {
- writeLock.lock();
- try {
- _mCache.remove(key);
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * 移除一个缓存
- */
- public void hdel(K key) {
- writeLock.lock();
- try {
- _hCache.remove(key);
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * 移除一个缓存
- */
- public void del(K key, F feild) {
- writeLock.lock();
- try {
- Map, CacheObject> coMap = _hCache.get(key);
- if(null != coMap){
- coMap.remove(feild);
- }
- } finally {
- writeLock.unlock();
- }
- }
-
- @Override
- public Set keys() {
- return _mCache.keySet();
- }
-
- @Override
- public Set flieds(K key) {
- Map, CacheObject> coMap = _hCache.get(key);
- if(null == coMap){
- return null;
- }
- return (Set) coMap.keySet();
- }
-
- public int elementsInCache() {
- return ( _mCache.size() + _hCache.size() );
- }
-
- @Override
- public int size() {
- return ( _mCache.size() + _hCache.size() );
- }
-
- protected boolean isNeedClearExpiredObject(){
- return defaultExpire > 0 || existCustomExpire ;
- }
-
- public final int eliminate() {
- writeLock.lock();
- try {
- return eliminateCache();
- }
- finally {
- writeLock.unlock();
- }
- }
-
- @Override
- public boolean isFull() {
- if (cacheSize == 0) {// o -> 无限制
- return false;
- }
- return ( _mCache.size() + _hCache.size() ) >= cacheSize;
- }
-
- @Override
- public void clear() {
- writeLock.lock();
- try {
- _mCache.clear();
- } finally {
- writeLock.unlock();
- }
- }
-
- @Override
- public int getCacheSize() {
- return cacheSize;
- }
-
- @Override
- public boolean isEmpty() {
- return size() == 0;
- }
-
- @Override
- public Cache cacheSize(int cacheSize) {
- this.cacheSize = cacheSize;
- return this;
- }
-
- @Override
- public Cache expire(long expire) {
- this.defaultExpire = expire;
- return this;
- }
-
-}
\ No newline at end of file
diff --git a/blade-cache/src/main/java/blade/cache/Cache.java b/blade-cache/src/main/java/blade/cache/Cache.java
deleted file mode 100644
index 557f86ef3..000000000
--- a/blade-cache/src/main/java/blade/cache/Cache.java
+++ /dev/null
@@ -1,153 +0,0 @@
-
-package blade.cache;
-
-import java.util.Set;
-
-
-/**
- * 缓存顶级接口
- *
- * @author biezhi
- * @since 1.0
- * @param
- * @param
- */
-public interface Cache {
-
- /**
- * 向缓存添加value对象,其在缓存中生存时间为默认值
- *
- * @param key
- * @param value
- * @throws CacheException
- */
- void set(K key, V value);
-
- /**
- * 向缓存添加value对象,并指定存活时间
- *
- * @param key
- * @param value 过期时间
- * @param expire
- * @throws CacheException
- */
- void set(K key, V value, long expire);
-
- /**
- * 向缓存添加一个hash类型的数据
- *
- * @param key
- * @param field
- * @param value
- */
- void hset(K key, F field, V value);
-
- /**
- * 向缓存添加一个hash类型的数据并设置有效期
- *
- * @param key
- * @param field
- * @param value
- * @param expire
- */
- void hset(K key, F field, V value, long expire);
-
- /**
- * 查找缓存对象
- *
- * @param key
- * @return
- * @throws CacheException
- */
- V get(K key);
-
- /**
- * 查找缓存对象
- *
- * @param key
- * @param field
- * @return
- */
- V hget(K key, F field);
-
- /**
- * 删除缓存对象
- *
- * @param key
- */
- void del(K key);
-
- /**
- * 删除缓存对象
- *
- * @param key
- */
- void hdel(K key);
-
- /**
- * 删除缓存对象
- *
- * @param key
- * @param field
- */
- void del(K key, F field);
-
- /**
- * @return 返回所有key
- */
- Set keys();
-
- /**
- * @return 返回一个key所有flied
- */
- Set flieds(K key);
-
- /**
- * @return 返回当前缓存的大小
- */
- int size();
-
- /**
- * 淘汰对象
- *
- * @return 被删除对象大小
- */
- int eliminate();
-
- /**
- * 缓存是否已经满
- * @return
- */
- boolean isFull();
-
- /**
- * 清除所有缓存对象
- */
- void clear();
-
- /**
- * 返回缓存大小
- *
- * @return
- */
- int getCacheSize();
-
- /**
- * 缓存中是否为空
- */
- boolean isEmpty();
-
- /**
- * 设置缓存大小
- * @param cacheSize
- * @return
- */
- Cache cacheSize(int cacheSize);
-
- /**
- * 设置缓存有效期
- * @param expire
- * @return
- */
- Cache expire(long expire);
- }
diff --git a/blade-cache/src/main/java/blade/cache/CacheCleaner.java b/blade-cache/src/main/java/blade/cache/CacheCleaner.java
deleted file mode 100644
index 2f68766f1..000000000
--- a/blade-cache/src/main/java/blade/cache/CacheCleaner.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package blade.cache;
-
-import java.util.Set;
-
-/**
- * 定时清理缓存线程
- *
- * @author biezhi
- * @since 1.0
- */
-public class CacheCleaner extends Thread {
-
- /**
- * 清理间隔
- */
- private long _cleanInterval;
-
- /**
- * 是不是在睡眠中
- */
- private boolean _sleep = false;
-
- /**
- * 设置清理间隔并初始化
- *
- * @param cleanInterval
- */
- public CacheCleaner(long cleanInterval) {
- _cleanInterval = cleanInterval;
- setName(this.getClass().getName());
- setDaemon(true);
- }
-
- /**
- * 设置清理间隔
- *
- * @param cleanInterval
- */
- public void setCleanInterval(long cleanInterval) {
- _cleanInterval = cleanInterval;
- synchronized (this) {
- if (_sleep) {
- interrupt();
- }
- }
- }
-
- /**
- * 执行缓存清理工作
- */
- @Override
- public void run() {
- while (true) {
- try {
- try {
- sleep(_cleanInterval);
- } catch (Throwable t) {
- } finally {
- _sleep = false;
- }
- CacheManager cacheFactory = CacheManager.getInstance();
- Set cacheIds = cacheFactory.getCacheIds();
- if (null != cacheIds) {
- for (String cacheId : cacheIds) {
- Cache cache = cacheFactory.getCache(cacheId);
- if (cache != null) {
- cache.clear();
- }
- yield();
- }
- }
- } catch (Throwable t) {
- t.printStackTrace();
- }
- _sleep = true;
-// try {
-// sleep(_cleanInterval);
-// } catch (Throwable t) {
-// } finally {
-// _sleep = false;
-// }
- }
- }
-
-}
\ No newline at end of file
diff --git a/blade-cache/src/main/java/blade/cache/CacheException.java b/blade-cache/src/main/java/blade/cache/CacheException.java
deleted file mode 100644
index 16e8a3c97..000000000
--- a/blade-cache/src/main/java/blade/cache/CacheException.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package blade.cache;
-
-/**
- * 缓存异常封装
- *
- * @author biezhi
- * @since 1.0
- */
-public class CacheException extends Exception {
-
- private static final long serialVersionUID = 2794445171318574075L;
-
- public CacheException() {
- }
-
- public CacheException(String msg) {
- super(msg);
- }
-}
\ No newline at end of file
diff --git a/blade-cache/src/main/java/blade/cache/CacheManager.java b/blade-cache/src/main/java/blade/cache/CacheManager.java
deleted file mode 100644
index 81479ff10..000000000
--- a/blade-cache/src/main/java/blade/cache/CacheManager.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package blade.cache;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import blade.cache.impl.FIFOCache;
-import blade.cache.impl.LFUCache;
-import blade.cache.impl.LRUCache;
-
-/**
- * 缓存管理对象
- *
- * @author biezhi
- * @since 1.0
- */
-@SuppressWarnings({"rawtypes", "unchecked"})
-public class CacheManager {
-
- private static final CacheManager _instance = new CacheManager();
-
- private static final String CACHE_SUFFIX = "blade_cache_ID_";
-
- private Map _cacheMap;
-
- private CacheCleaner _cleaner;
-
- private int _cacheSize = 100;
-
- // 一小时
- private static final int DEFAULT_CLEAN_TIME = 3600000;
-
- private static Object _mlock = new Object();
-
- public CacheManager() {
- _cacheMap = new HashMap();
- _cleaner = new CacheCleaner(DEFAULT_CLEAN_TIME); //默认30秒自动清空缓存
- _cleaner.start();
- }
-
- public static CacheManager getInstance(){
- return _instance;
- }
-
- public void setCleanInterval(long time) {
- _cleaner.setCleanInterval(time);
- }
-
- public Cache getCache(String cacheId){
- if (cacheId == null) {
- throw new NullPointerException("cacheId is null");
- }
- synchronized (_mlock) {
- return _cacheMap.get(cacheId);
- }
- }
-
- /***************************** LRUCache:START **************************************/
- public Cache newLRUCache(){
- synchronized (_mlock) {
- String cacheId = CACHE_SUFFIX + System.currentTimeMillis();
- return newLRUCache(cacheId, _cacheSize);
- }
- }
-
- public Cache newLRUCache(String cacheId){
- if (cacheId == null) {
- throw new NullPointerException("cacheId is null");
- }
- return newLRUCache(cacheId, _cacheSize);
- }
-
- public Cache newLRUCache(int cacheSize){
- synchronized (_mlock) {
- String cacheId = CACHE_SUFFIX + System.currentTimeMillis();
- return newLRUCache(cacheId, cacheSize);
- }
- }
-
- public Cache newLRUCache(String cacheId, int cacheSize){
- synchronized (_mlock) {
- Cache cache = new LRUCache(cacheSize);
- _cacheMap.put(cacheId, cache);
- return cache;
- }
- }
- /***************************** LRUCache:END **************************************/
-
-
- /***************************** LFUCache:START **************************************/
- public Cache newLFUCache(){
- synchronized (_mlock) {
- String cacheId = CACHE_SUFFIX + System.currentTimeMillis();
- return newLFUCache(cacheId, _cacheSize);
- }
- }
-
- public Cache newLFUCache(String cacheId){
- if (cacheId == null) {
- throw new NullPointerException("cacheId is null");
- }
- return newLFUCache(cacheId, _cacheSize);
- }
-
- public Cache newLFUCache(int cacheSize){
- synchronized (_mlock) {
- String cacheId = CACHE_SUFFIX + System.currentTimeMillis();
- return newLFUCache(cacheId, cacheSize);
- }
- }
-
- public Cache newLFUCache(String cacheId, int cacheSize){
- synchronized (_mlock) {
- Cache cache = new LFUCache(cacheSize);
- _cacheMap.put(cacheId, cache);
- return cache;
- }
- }
- /***************************** LFUCache:END **************************************/
-
-
- /***************************** LFUCache:START **************************************/
- public Cache newFIFOCache(){
- synchronized (_mlock) {
- String cacheId = CACHE_SUFFIX + System.currentTimeMillis();
- return newFIFOCache(cacheId, _cacheSize);
- }
- }
-
- public Cache newFIFOCache(String cacheId){
- if (cacheId == null) {
- throw new NullPointerException("cacheId is null");
- }
- return newLFUCache(cacheId, _cacheSize);
- }
-
- public Cache newFIFOCache(int cacheSize){
- synchronized (_mlock) {
- String cacheId = CACHE_SUFFIX + System.currentTimeMillis();
- return newFIFOCache(cacheId, cacheSize);
- }
- }
-
- public Cache newFIFOCache(String cacheId, int cacheSize){
- synchronized (_mlock) {
- Cache cache = new FIFOCache(cacheSize);
- _cacheMap.put(cacheId, cache);
- return cache;
- }
- }
- /***************************** LFUCache:END **************************************/
-
- /**
- * @return 返回所有缓存id
- */
- public Set getCacheIds(){
- synchronized (_mlock) {
- if(null != _cacheMap && _cacheMap.size() > 0){
- return _cacheMap.keySet();
- }
- }
- return null;
- }
-
- /**
- * 移除一个缓存
- * @param cacheId
- * @throws CacheException
- */
- public void removeCache(String cacheId) throws CacheException {
- if(cacheId == null) {
- throw new NullPointerException("cacheId is null");
- }
- synchronized(_mlock){
- _cacheMap.remove(cacheId);
- }
- }
-
- /**
- * 移除所有缓存
- * @param cacheId
- * @throws CacheException
- */
- public void removeAll() {
- synchronized(_mlock){
- if(null != _cacheMap && _cacheMap.size() > 0){
-
- Set keys = _cacheMap.keySet();
- for(String key : keys){
- Cache cache = _cacheMap.get(key);
- if(null != cache){
- cache.clear();
- }
- }
- _cacheMap.clear();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/blade-cache/src/main/java/blade/cache/CacheObject.java b/blade-cache/src/main/java/blade/cache/CacheObject.java
deleted file mode 100644
index fa3010967..000000000
--- a/blade-cache/src/main/java/blade/cache/CacheObject.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package blade.cache;
-
-/**
- * 缓存实体对象
- *
- * @author biezhi
- * @since 1.0
- * @param
- * @param
- */
-public class CacheObject {
-
- private K key;
- private V value;
- private long expires; // 对象存活时间(time-to-live)
- private long lastAccess; // 最后访问时间
- private long accessCount; // 访问次数
- private CacheObject previous;
- private CacheObject next;
-
- public CacheObject(K k, V v, long expires) {
- this.key = k;
- this.value = v;
- this.expires = expires;
- }
-
- public CacheObject() {
- }
-
- /**
- * @return 返回是否已经过期
- */
- public boolean isExpired() {
- if (expires == 0) {
- return false;
- }
- return lastAccess + expires < System.currentTimeMillis();
- }
-
- public V getValue() {
- lastAccess = System.currentTimeMillis();
- accessCount++;
- return value;
- }
-
- public K getKey() {
- return key;
- }
-
- public long getExpires() {
- return expires;
- }
-
- public void setExpires(long expires) {
- this.expires = expires;
- }
-
- public long getLastAccess() {
- return lastAccess;
- }
-
- public void setLastAccess(long lastAccess) {
- this.lastAccess = lastAccess;
- }
-
- public long getAccessCount() {
- return accessCount;
- }
-
- public void setAccessCount(long accessCount) {
- this.accessCount = accessCount;
- }
-
- public CacheObject getPrevious() {
- return previous;
- }
-
- public void setPrevious(CacheObject previous) {
- this.previous = previous;
- }
-
- public CacheObject getNext() {
- return next;
- }
-
- public void setNext(CacheObject next) {
- this.next = next;
- }
-
- public void setKey(K key) {
- this.key = key;
- }
-
- public void setValue(V value) {
- this.value = value;
- }
-
-}
\ No newline at end of file
diff --git a/blade-cache/src/main/java/blade/cache/impl/FIFOCache.java b/blade-cache/src/main/java/blade/cache/impl/FIFOCache.java
deleted file mode 100644
index 20399c474..000000000
--- a/blade-cache/src/main/java/blade/cache/impl/FIFOCache.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package blade.cache.impl;
-
-import java.util.Iterator;
-
-import blade.cache.AbstractCache;
-import blade.cache.CacheObject;
-
-
-/**
- * FIFO实现
- *
- * @author biezhi
- * @since 1.0
- * @param
- * @param
- */
-public class FIFOCache extends AbstractCache {
-
- public FIFOCache(int cacheSize) {
- super(cacheSize);
- }
-
- @Override
- protected int eliminateCache() {
-
- int count = 0;
- K firstKey = null;
-
- Iterator> iterator = _mCache.values().iterator();
- while (iterator.hasNext()) {
- CacheObject cacheObject = iterator.next();
-
- if (cacheObject.isExpired()) {
- iterator.remove();
- count++;
- } else {
- if (firstKey == null)
- firstKey = cacheObject.getKey();
- }
- }
-
- if (firstKey != null && isFull()) {// 删除过期对象还是满,继续删除链表第一个
- _mCache.remove(firstKey);
- }
-
- return count;
- }
-
-}
\ No newline at end of file
diff --git a/blade-cache/src/main/java/blade/cache/impl/LFUCache.java b/blade-cache/src/main/java/blade/cache/impl/LFUCache.java
deleted file mode 100644
index 9a82ccaeb..000000000
--- a/blade-cache/src/main/java/blade/cache/impl/LFUCache.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package blade.cache.impl;
-
-import java.util.Iterator;
-
-import blade.cache.AbstractCache;
-import blade.cache.CacheObject;
-
-/**
- * LFU实现
- *
- * @author biezhi
- * @since 1.0
- * @param
- * @param
- */
-public class LFUCache extends AbstractCache {
-
- public LFUCache(int cacheSize) {
- super(cacheSize);
- }
-
- /**
- * 实现删除过期对象 和 删除访问次数最少的对象
- *
- */
- @Override
- protected int eliminateCache() {
- Iterator> iterator = _mCache.values().iterator();
- int count = 0;
- long minAccessCount = Long.MAX_VALUE;
-
- while (iterator.hasNext()) {
- CacheObject cacheObject = iterator.next();
-
- if (cacheObject.isExpired()) {
- iterator.remove();
- count++;
- continue;
- } else {
- minAccessCount = Math.min(cacheObject.getAccessCount(),
- minAccessCount);
- }
- }
-
- if (count > 0)
- return count;
-
- if (minAccessCount != Long.MAX_VALUE) {
-
- iterator = _mCache.values().iterator();
-
- while (iterator.hasNext()) {
- CacheObject cacheObject = iterator.next();
-
- cacheObject.setAccessCount(cacheObject.getAccessCount() - minAccessCount);
-
- if (cacheObject.getAccessCount() <= 0) {
- iterator.remove();
- count++;
- }
-
- }
-
- }
-
- return count;
- }
-
-}
\ No newline at end of file
diff --git a/blade-cache/src/main/java/blade/cache/impl/LRUCache.java b/blade-cache/src/main/java/blade/cache/impl/LRUCache.java
deleted file mode 100644
index 939c82f7a..000000000
--- a/blade-cache/src/main/java/blade/cache/impl/LRUCache.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package blade.cache.impl;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import blade.cache.AbstractCache;
-import blade.cache.CacheObject;
-
-/**
- * LRU 实现
- *
- * @author biezhi
- * @since 1.0
- * @param
- * @param
- */
-public class LRUCache extends AbstractCache {
-
- public LRUCache(int cacheSize) {
-
- super(cacheSize) ;
-
- //linkedHash已经实现LRU算法 是通过双向链表来实现,当某个位置被命中,通过调整链表的指向将该位置调整到头位置,新加入的内容直接放在链表头,如此一来,最近被命中的内容就向链表头移动,需要替换时,链表最后的位置就是最近最少使用的位置
- this._mCache = new LinkedHashMap>( cacheSize +1 , 1f,true ) {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- protected boolean removeEldestEntry(Map.Entry> eldest) {
- return LRUCache.this.removeEldestEntry(eldest);
- }
-
- };
- }
-
- private boolean removeEldestEntry(Map.Entry> eldest) {
- if (cacheSize == 0)
- return false;
- return size() > cacheSize;
- }
-
- /**
- * 只需要实现清除过期对象就可以了,linkedHashMap已经实现LRU
- */
- @Override
- protected int eliminateCache() {
-
- if(!isNeedClearExpiredObject()){ return 0 ;}
-
- Iterator> iterator = _mCache.values().iterator();
- int count = 0 ;
- while(iterator.hasNext()){
- CacheObject cacheObject = iterator.next();
-
- if(cacheObject.isExpired() ){
- iterator.remove();
- count++ ;
- }
- }
-
- return count;
- }
-
-}
\ No newline at end of file
diff --git a/blade-cache/src/test/java/blade/test/CacheTest.java b/blade-cache/src/test/java/blade/test/CacheTest.java
deleted file mode 100644
index c414640fa..000000000
--- a/blade-cache/src/test/java/blade/test/CacheTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package blade.test;
-
-import org.junit.Test;
-
-import blade.cache.Cache;
-import blade.cache.CacheManager;
-
-public class CacheTest {
-
- @Test
- public void testLRU2(){
- CacheManager cm = CacheManager.getInstance();
-
- Cache cache = cm.newLRUCache();
- cache.set("name:1", "jack");
- cache.set("name:2", "jack2");
-
- System.out.println(cache.get("name:2"));
-
- }
-
- @Test
- public void testAutoClean(){
- CacheManager cm = CacheManager.getInstance();
- cm.setCleanInterval(1000);
-
- Cache cache = cm.newLRUCache();
- cache.set("name:1", "jack");
- cache.set("name:2", "jack2");
-
- System.out.println(cache.get("name:2"));
-
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(cache.get("name:2"));
- }
-
- @Test
- public void testHashCache(){
- CacheManager cm = CacheManager.getInstance();
-
- Cache cache = cm.newLRUCache();
- cache.hset("user:list", "a1", "123");
- cache.hset("user:list", "a2", "456");
- cache.hset("user:list", "a3", "789");
-
- System.out.println(cache.hget("user:list", "a1"));
- System.out.println(cache.hget("user:list", "a2"));
- System.out.println(cache.hget("user:list", "a3"));
-
- }
-
-}
diff --git a/blade-core/pom.xml b/blade-core/pom.xml
index c9a8a1f25..c80b313e9 100644
--- a/blade-core/pom.xml
+++ b/blade-core/pom.xml
@@ -1,43 +1,70 @@
-
-
- 4.0.0
-
- com.bladejava
- blade-root
- 1.0
-
-
- blade-core
- jar
- ${blade.version}
- blade-core
- https://github.com/biezhi/blade/blade-core
-
-
- 9.0.2.v20130417
-
-
-
-
-
- com.bladejava
- blade-kit
- ${blade.version}
-
-
-
- org.eclipse.jetty
- jetty-server
- ${jetty.version}
- provided
-
-
- org.eclipse.jetty
- jetty-webapp
- ${jetty.version}
- provided
-
-
-
+
+
+ 4.0.0
+
+
+ com.bladejava
+ blade
+ 1.0
+
+
+ blade-core
+ jar
+ ${blade-core.version}
+ blade-core
+ https://github.com/biezhi/blade/blade-core
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+
+ com.bladejava
+ blade-kit
+ ${blade-kit.version}
+
+
+
+ javax.servlet
+ javax.servlet-api
+ ${servlet.version}
+ provided
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-all
+ test
+
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${jetty.version}
+ test
+
+
+ org.eclipse.jetty
+ jetty-webapp
+ ${jetty.version}
+ test
+
+
+
+
+
diff --git a/blade-core/src/main/java/blade/BladeBase.java b/blade-core/src/main/java/blade/BladeBase.java
deleted file mode 100644
index d9bebb8ac..000000000
--- a/blade-core/src/main/java/blade/BladeBase.java
+++ /dev/null
@@ -1,471 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade;
-
-import java.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.Map;
-
-import blade.ioc.Container;
-import blade.ioc.DefaultContainer;
-import blade.render.Render;
-import blade.render.RenderFactory;
-import blade.route.DefaultRouteMatcher;
-import blade.server.BladeServer;
-
-/**
- * Blade的基础类
- *
- * @author biezhi
- * @since 1.0
- */
-abstract class BladeBase {
-
- /**
- * 默认路由后缀包,用户扫描路由所在位置,默认为route,用户可自定义
- */
- public static String PACKAGE_ROUTE = "route";
-
- protected static final String DEFAULT_ACCEPT_TYPE = "*/*";
-
- /**
- * 默认拦截器后缀包,用户扫描拦截器所在位置,默认为interceptor,用户可自定义
- */
- public static String PACKAGE_INTERCEPTOR = "interceptor";
-
- public static final Charset UTF_8 = Charset.forName("UTF-8");
-
- /**
- * 是否以jetty方式运行
- */
- public static boolean runJetty = false;
-
- /**
- * web应用根目录,应用启动时载入
- */
- private static String WEB_ROOT = "";
-
- /**
- * Blade默认编码,可修改
- */
- protected static String ENCODING = UTF_8.toString();
-
- /**
- * 默认视图的路径,默认渲染引擎为JSP,设置WEB-INF目录更安全,可配置
- */
- protected static String VIEW_PATH = "/WEB-INF/";
-
- /**
- * 静态资源所在文件夹
- */
- protected static String[] STATIC_FOLDER = null;
-
- /**
- * 框架是否已经初始化
- */
- protected static boolean IS_INIT = false;
-
- /**
- * 默认视图文件后缀名
- */
- protected static String VIEW_EXT = ".jsp";
-
- /**
- * blade全局初始化对象,在web.xml中配置,必须
- */
- protected static BladeApplication bladeApplication;
-
- /**
- * 路由匹配器,用于添加,删除,查找路由
- */
- protected static DefaultRouteMatcher routeMatcher;
-
- /**
- * 存放要扫描的包map
- */
- protected static final Map packageMap = new HashMap();
-
- /**
- * 默认的404视图
- */
- protected static String VIEW_404 = null;
-
- /**
- * 默认的500视图
- */
- protected static String VIEW_500 = null;
-
- /**
- * jetty启动的默认端口
- */
- protected static int PORT = 9000;
-
- protected static boolean DEBUG = true;
-
- /**
- * IOC容器,存储路由到ioc中
- */
- private final static Container container = DefaultContainer.single();
-
- /**
- * 包类型枚举
- *
- * basepackge 基础包,默认的路由,拦截器包
- * route 路由包,所有路由所在包,可递归
- * interceptor 拦截器包,所有拦截器所在包,不可递归
- * ioc IOC对象所在包,可递归
- * @author biezhi
- *
- */
- public enum PackageNames {
- basepackge, route, interceptor, ioc
- }
-
- protected BladeBase() {
- }
-
- /*--------------------SET CONST:START-------------------------*/
-
- /**
- * 设置路由包,如:com.baldejava.route
- * 可传入多个包,所有的路由类都在该包下
- *
- * @param pckages 路由包路径
- */
- public static synchronized void routes(String...pckages){
- if(null != pckages && pckages.length >0){
- packageMap.put(PackageNames.route, pckages);
- }
- }
-
- /**
- * 设置顶层包,框架自动寻找路由包和拦截器包,如:com.bladejava
- * 如上规则,会超找com.bladejava.route、com.bladejava.interceptor下的路由和拦截器
- *
- * @param basePackage 默认包路径
- */
- public static synchronized void defaultRoute(String basePackage){
- if(null != basePackage){
- packageMap.put(PackageNames.basepackge, new String[]{basePackage});
- }
- }
-
- /**
- * 设置拦截器所在的包路径,如:com.bladejava.interceptor
- *
- * @param packageName 拦截器所在的包
- */
- public static synchronized void interceptor(String packageName) {
- if(null != packageName && packageName.length() >0){
- packageMap.put(PackageNames.interceptor, new String[]{packageName});
- }
- }
-
- /**
- * 设置依赖注入包,如:com.bladejava.service
- *
- * @param pckages 所有需要做注入的包,可传入多个
- */
- public static synchronized void ioc(String...pckages){
- if(null != pckages && pckages.length >0){
- packageMap.put(PackageNames.ioc, pckages);
- }
- }
-
- /**
- * 设置渲染引擎,默认是JSP引擎
- *
- * @param render 渲染引擎对象
- */
- public static synchronized void viewEngin(Render render) {
- RenderFactory.init(render);
- }
-
- /**
- * 设置默认视图路径,默认为WEB_ROOT/WEB-INF目录
- *
- * @param viewPath 视图路径,如:/WEB-INF/views
- */
- public static synchronized void viewPath(final String viewPath) {
- if(null != viewPath && viewPath.startsWith("/")){
- VIEW_PATH = viewPath;
- }
- }
-
- /**
- * 设置视图默认后缀名,默认为.jsp
- *
- * @param viewExt 视图后缀,如:.html .vm
- */
- public static synchronized void viewExt(final String viewExt) {
- if(null != viewExt && viewExt.startsWith(".")){
- VIEW_EXT = viewExt;
- }
- }
-
- /**
- * 同事设置视图所在目录和视图后缀名
- *
- * @param viewPath 视图路径,如:/WEB-INF/views
- * @param viewExt 视图后缀,如:.html .vm
- */
- public static synchronized void view(final String viewPath, final String viewExt) {
- viewPath(viewPath);
- viewExt(viewExt);
- }
-
- /**
- * 设置框架静态文件所在文件夹
- *
- * @param folder
- */
- public static synchronized void staticFolder(final String ... folder) {
- STATIC_FOLDER = folder;
- }
-
- /**
- * 动态设置全局初始化类
- *
- * @param clazz 全局初始化Class
- */
- public static synchronized void app(Class extends BladeApplication> clazz){
- try {
- BladeBase.bladeApplication = clazz.newInstance();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- /**
- * 动态设置全局初始化类
- *
- * @param bladeApplication 全局初始化bladeApplication
- */
- public static synchronized void app(BladeApplication bladeApplication){
- BladeBase.bladeApplication = bladeApplication;
- }
-
- /**
- * 设置404视图页面
- *
- * @param view404 404视图页面
- */
- public static synchronized void view404(final String view404){
- BladeBase.VIEW_404 = view404;
- }
-
- /**
- * 设置500视图页面
- *
- * @param view500 500视图页面
- */
- public static synchronized void view500(final String view500){
- BladeBase.VIEW_500 = view500;
- }
-
- /**
- * 设置web根目录
- *
- * @param webRoot web根目录物理路径
- */
- public static synchronized void webRoot(final String webRoot){
- BladeBase.WEB_ROOT = webRoot;
- }
-
- /**
- * 设置系统是否以debug方式运行
- * @param isdebug true:是,默认true;false:否
- */
- public static synchronized void debug(boolean isdebug){
- BladeBase.DEBUG = isdebug;
- }
-
- /**--------------------SET CONST:END-------------------------*/
-
-
-
- /**--------------------GET CONST:START-------------------------*/
-
- /**
- * @return 返回Blade要扫描的基础包
- */
- public static String[] defaultRoutes(){
- return packageMap.get(PackageNames.basepackge);
- }
-
- /**
- * @return 返回路由包数组
- */
- public static String[] routes(){
- return packageMap.get(PackageNames.route);
- }
-
- /**
- * @return 返回拦截器包数组,只有一个元素 这里统一用String[]
- */
- public static String[] interceptor(){
- return packageMap.get(PackageNames.interceptor);
- }
-
- /**
- * @return 返回视图存放路径
- */
- public static String viewPath(){
- return VIEW_PATH;
- }
-
- /**
- * @return 返回系统默认字符编码
- */
- public static String encoding(){
- return ENCODING;
- }
-
- /**
- * @return 返回balde启动端口
- */
- public static String viewExt(){
- return VIEW_EXT;
- }
-
- /**
- * @return 返回404视图
- */
- public static String view404(){
- return BladeBase.VIEW_404;
- }
-
- /**
- * @return 返回500视图
- */
- public static String view500(){
- return BladeBase.VIEW_500;
- }
-
- /**
- * @return 返回webroot路径
- */
- public static String webRoot(){
- return BladeBase.WEB_ROOT;
- }
-
- /**
- * @return 返回系统是否以debug方式运行
- */
- public static boolean debug(){
- return BladeBase.DEBUG;
- }
-
- /**
- * @return 返回静态资源目录
- */
- public static String[] staticFolder(){
- return BladeBase.STATIC_FOLDER;
- }
-
- /**
- * @return 返回BladeApplication对象
- */
- public static BladeApplication application(){
- return bladeApplication;
- }
-
- /**--------------------GET CONST:END-------------------------*/
-
-
- /**----------------------jetty:START-------------------------*/
-
- /**
- * 设置jetty启动端口
- *
- * @param port 端口号,范围在0~65535之间,默认为9000
- */
- public static synchronized void port(int port){
- if(port > 0 && port < 65535){
- PORT = port;
- }
- }
-
- /**
- * 运行jetty服务
- *
- * @param port 端口号,范围在0~65535之间,默认为9000
- * @param host host,默认为本机;127.0.0.1/localhost
- * @param context context,应用上下文,默认为"/"
- */
- public static void run(Integer port, String host, String context) {
- PORT = port;
- BladeServer.run(port, host, context);
- }
-
- /**
- * 运行jetty服务
- */
- public static void run() {
- run(PORT, null, null);
- }
-
- /**
- * 运行jetty服务并设置主机
- *
- * @param host host,默认为本机;127.0.0.1/localhost
- */
- public static void run(String host) {
- run(PORT, host, null);
- }
-
- /**
- * 运行jetty服务并设置端口
- *
- * @param port 端口号,范围在0~65535之间,默认为9000
- */
- public static void run(Integer port) {
- run(port, null, null);
- }
-
- public static void run(Class extends BladeApplication> clazz, Integer port) {
- if(null != clazz){
- app(clazz);
- }
- run(port, null, null);
- }
-
- /**
- * 运行jetty服务并设置端口和主机
- *
- * @param host host,默认为本机;127.0.0.1/localhost
- * @param port 端口号,范围在0~65535之间,默认为9000
- */
- public static void run(String host, Integer port) {
- run(port, host, null);
- }
- /**----------------------jetty:END-------------------------*/
-
- /**
- * 手动注册一个对象到ioc容器中
- *
- * @param object 要注册的object
- */
- public static synchronized void register(Object object){
- container.registBean(object);
- }
-
- static synchronized void init() {
- BladeBase.IS_INIT = true;
- }
-
-}
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/BladeFilter.java b/blade-core/src/main/java/blade/BladeFilter.java
deleted file mode 100644
index 690d38e2e..000000000
--- a/blade-core/src/main/java/blade/BladeFilter.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade;
-
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import blade.kit.log.Logger;
-import blade.route.RouteMatcherBuilder;
-
-/**
- * blade核心过滤器,mvc总线
- * 匹配所有请求过滤
- *
- * @author biezhi
- * @since 1.0
- */
-public class BladeFilter implements Filter {
-
- private static final Logger LOGGER = Logger.getLogger(BladeFilter.class);
-
- /**
- * blade全局初始化类
- */
- private static final String APPLCATION_CLASS = "applicationClass";
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
-
- // 防止重复初始化
- if(!Blade.IS_INIT){
-
- BladeBase.webRoot(filterConfig.getServletContext().getRealPath("/"));
-
- BladeWebContext.servletContext(filterConfig.getServletContext());
-
- final BladeApplication application = getApplication(filterConfig);
- application.init();
- Blade.app(application);
-
- // 构建所有路由
- RequestHandler.routeMatcher = RouteMatcherBuilder.building();
-
- // 全局初始化
- IocApplication.init();
-
- application.contextInitialized(BladeWebContext.servletContext());
-
- LOGGER.info("blade init complete!");
- BladeBase.init();
- }
-
- }
-
- /**
- * 获取全局初始化对象,初始化应用
- *
- * @param filterConfig 过滤器配置对象
- * @return 一个全局初始化对象
- * @throws ServletException
- */
- private BladeApplication getApplication(FilterConfig filterConfig) throws ServletException {
- try {
- String applicationClassName = filterConfig.getInitParameter(APPLCATION_CLASS);
- if(!BladeBase.runJetty && null != applicationClassName){
- Class> applicationClass = Class.forName(applicationClassName);
- return (BladeApplication) applicationClass.newInstance();
- }
- return BladeBase.bladeApplication;
- } catch (Exception e) {
- throw new ServletException(e);
- }
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
-
- HttpServletRequest httpRequest = (HttpServletRequest) request;
- HttpServletResponse httpResponse = (HttpServletResponse) response;
-
- httpRequest.setCharacterEncoding(BladeBase.encoding());
- httpResponse.setCharacterEncoding(BladeBase.encoding());
-
- /**
- * 是否被RequestHandler执行
- */
- boolean isHandler = RequestHandler.single().handler(httpRequest, httpResponse);
- if(!isHandler && !httpResponse.isCommitted()){
- chain.doFilter(httpRequest, httpResponse);
- }
- }
-
- @Override
- public void destroy() {
- IocApplication.destroy();
- LOGGER.info("blade destroy!");
- }
-
-}
diff --git a/blade-core/src/main/java/blade/BladeWebContext.java b/blade-core/src/main/java/blade/BladeWebContext.java
deleted file mode 100644
index 0b9b9300a..000000000
--- a/blade-core/src/main/java/blade/BladeWebContext.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import blade.servlet.Request;
-import blade.servlet.Response;
-import blade.servlet.Session;
-
-/**
- * 全局的WeContext
- *
- * @author biezhi
- * @since 1.0
- */
-public final class BladeWebContext {
-
- /**
- * 当前线程的Request对象
- */
- private static ThreadLocal currentRequest = new ThreadLocal();
-
- /**
- * 当前线程的Response对象
- */
- private static ThreadLocal currentResponse = new ThreadLocal();
-
- /**
- * ServletContext对象,在应用初始化时创建
- */
- private static ServletContext servletContext;
-
- private BladeWebContext(){}
-
- /**
- * @return 返回当前线程的Request对象
- */
- public static Request request() {
- return currentRequest.get();
- }
-
- /**
- * @return 返回当前线程的HttpServletRequest对象
- */
- public static HttpServletRequest servletRequest() {
- return request().servletRequest();
- }
-
- /**
- * @return 返回当前线程的Response对象
- */
- public static Response response() {
- return currentResponse.get();
- }
-
- /**
- * @return 返回当前线程的HttpServletResponse对象
- */
- public static HttpServletResponse servletResponse() {
- return response().servletResponse();
- }
-
- /**
- * @return 返回当前线程的Session对象
- */
- public static Session session() {
- return request().session();
- }
-
- /**
- * 设置ServletContext
- *
- * @param servletContext ServletContext对象
- */
- public static void servletContext(ServletContext servletContext) {
- BladeWebContext.servletContext = servletContext;
- }
-
- /**
- * @return 返回当前线程的ServletContext对象
- */
- public static ServletContext servletContext() {
- return servletContext;
- }
-
- /**
- * 设置context对象到ActionContext中
- *
- * @param request HttpServletRequest对象
- * @param response HttpServletResponse对象
- */
- public static void put(Request request, Response response) {
- currentRequest.set(request);
- currentResponse.set(response);
- }
-
- /**
- * 移除当前线程的Request、Response对象
- */
- public static void remove(){
- currentRequest.remove();
- currentResponse.remove();
- }
-
-}
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/IocApplication.java b/blade-core/src/main/java/blade/IocApplication.java
deleted file mode 100644
index bafdfa520..000000000
--- a/blade-core/src/main/java/blade/IocApplication.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade;
-
-import java.util.Set;
-
-import blade.BladeBase.PackageNames;
-import blade.ioc.Container;
-import blade.ioc.DefaultContainer;
-import blade.kit.log.Logger;
-import blade.kit.resource.ClassPathClassReader;
-import blade.kit.resource.ClassReader;
-
-/**
- * IOC容器初始化类
- *
- * 用于初始化ioc对象
- *
- *
- * @author biezhi
- * @since 1.0
- */
-public final class IocApplication {
-
- private static final Logger LOGGER = Logger.getLogger(IocApplication.class);
-
- /**
- * IOC容器,单例获取默认的容器实现
- */
- static final Container container = DefaultContainer.single();
-
- /**
- * 类读取对象,加载class
- */
- static final ClassReader classReader = new ClassPathClassReader();
-
- public static void init(){
-
- // 初始化全局配置类
- initApp();
-
- // 初始化ioc容器
- initIOC();
-
- // 初始化注入
- container.initWired();
- }
-
- private static void initApp(){
- container.registBean(Blade.application());
- }
-
- /**
- * 初始化IOC容器,加载ioc包的对象
- * 要配置符合ioc的注解的类才会被加载
- *
- */
- private static void initIOC() {
- String[] iocPackages = BladeBase.packageMap.get(PackageNames.ioc);
- if(null != iocPackages && iocPackages.length > 0){
- for(String packageName : iocPackages){
- registerBean(packageName);
- }
- }
- }
-
- /**
- * 注册一个包下的所有对象
- *
- * @param packageName 包名称
- */
- private static void registerBean(String packageName) {
-
- // 是否递归扫描
- boolean recursive = false;
- if (packageName.endsWith(".*")) {
- packageName = packageName.substring(0, packageName.length() - 2);
- recursive = true;
- }
-
- // 扫描包下所有class
- Set> classes = classReader.getClass(packageName, recursive);
- for (Class> clazz : classes) {
- // 注册带有Component和Service注解的类
- if (container.isRegister(clazz.getAnnotations())) {
- container.registBean(clazz);
- }
- }
-
- if(Blade.debug()){
- Set beanNames = container.getBeanNames();
- for(String beanName : beanNames){
- LOGGER.debug("Load The Class:" + beanName);
- }
- }
- }
-
- /**
- * 销毁
- */
- public static void destroy() {
- // 清空ioc容器
- container.removeAll();
- }
-
-}
diff --git a/blade-core/src/main/java/blade/RequestHandler.java b/blade-core/src/main/java/blade/RequestHandler.java
deleted file mode 100644
index 36e99c370..000000000
--- a/blade-core/src/main/java/blade/RequestHandler.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import blade.exception.BladeException;
-import blade.ioc.Container;
-import blade.ioc.DefaultContainer;
-import blade.ioc.Scope;
-import blade.kit.PathKit;
-import blade.kit.ReflectKit;
-import blade.kit.log.Logger;
-import blade.render.ModelAndView;
-import blade.route.DefaultRouteMatcher;
-import blade.route.HttpMethod;
-import blade.route.RouteMatcher;
-import blade.servlet.Request;
-import blade.servlet.Response;
-import blade.wrapper.RequestResponseBuilder;
-import blade.wrapper.RequestWrapper;
-import blade.wrapper.ResponseWrapper;
-
-/**
- * 请求执行的Handler
- *
- * 拦截器所有blade的请求,处理route and interceptor
- *
- *
- * @author biezhi
- * @since 1.0
- */
-public class RequestHandler {
-
- private static final Logger LOGGER = Logger.getLogger(RequestHandler.class);
-
- private static final String ACCEPT_TYPE_REQUEST_MIME_HEADER = "Accept";
-
- /**
- * 服务器500错误时返回的HTML
- */
- private static final String INTERNAL_ERROR = "500 Internal Error ";
-
- private final static Container container = DefaultContainer.single();
-
- /**
- * 路由处理器,查找请求过来的URL
- */
- static DefaultRouteMatcher routeMatcher;
-
- private RequestHandler(){}
-
- public static RequestHandler single() {
- return RequestHandlerHolder.single;
- }
-
- /**
- * 单例的RequestHandler
- *
- * @author biezhi
- * @since 1.0
- *
- */
- private static class RequestHandlerHolder {
- private static final RequestHandler single = new RequestHandler();
- }
-
- /**
- * handler执行方法
- *
- * @param httpRequest HttpServletRequest请求对象
- * @param httpResponse HttpServletResponse响应对象
- * @return 是否拦截到请求
- */
- boolean handler(HttpServletRequest httpRequest, HttpServletResponse httpResponse){
-
- // http方法, GET/POST ...
- String method = httpRequest.getMethod();
-
- // 请求的uri
- String uri = PathKit.getRelativePath(httpRequest);
-
- // 如果是静态资源则交给filter处理
- if(null != Blade.staticFolder() && Blade.staticFolder().length > 0){
- if(!filterStaticFolder(uri)){
- return false;
- }
- }
-
- String acceptType = httpRequest.getHeader(ACCEPT_TYPE_REQUEST_MIME_HEADER);
-
- // 响应体
- String bodyContent = null;
- Request request = null;
-
- // 构建一个包装后的response
- Response response = RequestResponseBuilder.build(httpResponse);
-
- // 创建RequestWrapper And RequestWrapper
- RequestWrapper requestWrapper = new RequestWrapper();
- ResponseWrapper responseWrapper = new ResponseWrapper(response);
-
- if(Blade.debug()){
- LOGGER.debug("Request : " + method + "\t" + uri);
- }
-
- HttpMethod httpMethod = HttpMethod.valueOf(method);
-
- try {
-
- // 执行before拦截
- before(requestWrapper, responseWrapper, httpRequest, uri, acceptType);
-
- // 查找用户请求的uri
- RouteMatcher match = routeMatcher.findRouteMatcher(httpMethod, uri, acceptType);
-
- // 如果找到
- if (match != null) {
-
- Class> target = match.getTarget();
-
- Object targetObject = container.getBean(target, Scope.SINGLE);
-
- // 要执行的路由方法
- Method execMethod = match.getExecMethod();
-
- if(null != requestWrapper.getDelegate()){
- request = requestWrapper.getDelegate();
- request.initRequest(match);
- } else {
- request = RequestResponseBuilder.build(match, httpRequest);
- }
- requestWrapper.setDelegate(request);
-
- BladeWebContext.put(requestWrapper, responseWrapper);
-
- // 执行route方法
- Object result = executeMethod(targetObject, execMethod, requestWrapper, responseWrapper);
-
- // 执行after拦截
- after(requestWrapper, responseWrapper, httpRequest, uri, acceptType);
-
- if(null != result){
- render(responseWrapper, result);
- }
- return true;
- } else {
- // 没有找到
- response.render404(uri);
- }
- } catch (BladeException bex) {
- LOGGER.error(bex.getMessage());
- httpResponse.setStatus(500);
- if (bex.getMessage() != null) {
- bodyContent = bex.getMessage();
- } else {
- bodyContent = INTERNAL_ERROR;
- }
- }
- boolean consumed = bodyContent != null;
- if (consumed) {
- // 写入内容到浏览器
- if (!httpResponse.isCommitted()) {
- response.render500(bodyContent);
- return true;
- }
- }
- return false;
-
- }
-
- /**
- * 前置事件,在route执行前执行
- * 这里如果执行则Request和Response都会被创建好
- *
- * @param requestWrapper RequestWrapper对象,包装了Request对象
- * @param responseWrapper ResponseWrapper对象,包装了Response对象
- * @param httpRequest HttpServletRequest请求对象,用于构建Request
- * @param uri 请求的URI
- * @param acceptType 请求头过滤
- */
- private void before(RequestWrapper requestWrapper, ResponseWrapper responseWrapper, HttpServletRequest httpRequest, final String uri, final String acceptType){
-
- List matchSet = routeMatcher.findInterceptor(HttpMethod.BEFORE, uri, acceptType);
-
- for (RouteMatcher filterMatch : matchSet) {
-
- Class> target = filterMatch.getTarget();
-
- Object targetObject = container.getBean(target, Scope.SINGLE);
-
- Method execMethod = filterMatch.getExecMethod();
-
- Request request = RequestResponseBuilder.build(filterMatch, httpRequest);
- requestWrapper.setDelegate(request);
-
- executeMethod(targetObject, execMethod, requestWrapper, responseWrapper);
-
- }
- }
-
- /**
- * 后置事件,在route执行后执行
- *
- * @param requestWrapper RequestWrapper对象,包装了Request对象
- * @param responseWrapper ResponseWrapper对象,包装了Response对象
- * @param httpRequest HttpServletRequest请求对象,用于构建Request
- * @param uri 请求的URI
- * @param acceptType 请求头过滤
- */
- private String after(RequestWrapper requestWrapper, ResponseWrapper responseWrapper, HttpServletRequest httpRequest, final String uri, final String acceptType){
- List matchSet = routeMatcher.findInterceptor(HttpMethod.AFTER, uri, acceptType);
-
- String bodyContent = null;
- for (RouteMatcher filterMatch : matchSet) {
- Class> target = filterMatch.getTarget();
-
- Object targetObject = container.getBean(target, Scope.SINGLE);
-
- Method execMethod = filterMatch.getExecMethod();
-
- if (requestWrapper.getDelegate() == null) {
- Request request = RequestResponseBuilder.build(filterMatch, httpRequest);
- requestWrapper.setDelegate(request);
- } else {
- requestWrapper.initRequest(filterMatch);
- }
-
- executeMethod(targetObject, execMethod, requestWrapper, responseWrapper);
-
- String bodyAfterFilter = responseWrapper.getDelegate().body();
- if (bodyAfterFilter != null) {
- bodyContent = bodyAfterFilter;
- }
- }
-
- return bodyContent;
- }
-
- /**
- * 获取方法内的参数
- *
- * @param request Request对象,用于注入到method参数列表中
- * @param response Response对象,用于注入到method参数列表中
- * @param params params参数列表
- * @return 返回生成后的参数数组
- */
- private Object[] getArgs(Request request, Response response, Class>[] params){
-
- int len = params.length;
- Object[] args = new Object[len];
-
- for(int i=0; i paramTypeClazz = params[i];
- if(paramTypeClazz.getName().equals(Request.class.getName())){
- args[i] = request;
- }
- if(paramTypeClazz.getName().equals(Response.class.getName())){
- args[i] = response;
- }
- }
-
- return args;
- }
-
- /**
- * 执行路由方法
- * @param object 方法的实例,即该方法所在类的对象
- * @param method 要执行的method
- * @param request Request对象,作为参数注入
- * @param response Response对象,作为参数注入
- * @return 返回方法执行后的返回值
- */
- private Object executeMethod(Object object, Method method, Request request, Response response){
- int len = method.getParameterTypes().length;
- if(len > 0){
- Object[] args = getArgs(request, response, method.getParameterTypes());
- return ReflectKit.invokeMehod(object, method, args);
- } else {
- return ReflectKit.invokeMehod(object, method);
- }
- }
-
- /**
- * 渲染视图
- *
- * @param response
- * @param result
- * @return
- */
- private Object render(Response response, Object result){
- if(result instanceof String){
- response.render(result.toString());
- } else if(result instanceof ModelAndView){
- response.render( (ModelAndView) result );
- }
- return null;
- }
-
- private boolean filterStaticFolder(String uri){
- int len = Blade.staticFolder().length;
- for(int i=0; ibiezhi
- * @since 1.0
- */
-public abstract class AbstractBeanFactory {
-
- protected Container container = DefaultContainer.single();
-
- public abstract Object getBean(String className);
-
- public abstract Object getBean(Class> clazz);
-
- public boolean resetBean(Class> clazz, Object object){
- System.out.println("resetBean object=" + object);
- if(null != clazz.getInterfaces() && null != object){
- container.removeBean(clazz);
- container.getBeanMap().put(clazz.getName(), object);
- }
- return true;
- }
-
- public Set getBeanNames(){
- return container.getBeanNames();
- }
-
- public Collection getBeans(){
- return container.getBeans();
- }
-
- public List getBeansByAnnotation(Class extends Annotation> annotation){
- return container.getBeansByAnnotation(annotation);
- }
-
- public List> getClassesByAnnotation(Class extends Annotation> annotation){
- return container.getClassesByAnnotation(annotation);
- }
-
-}
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/ioc/Container.java b/blade-core/src/main/java/blade/ioc/Container.java
deleted file mode 100644
index 3517f98a4..000000000
--- a/blade-core/src/main/java/blade/ioc/Container.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade.ioc;
-
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * IOC容器顶层接口
- *
- * @author biezhi
- * @since 1.0
- */
-public interface Container {
-
- /**
- * 根据bean名称和对象作用于获取一个bean对象
- *
- * @param name bean名称,可以是类名
- * @param scope 对象作用域,单例或者每次都创建
- * @return 一个bean对象
- */
- Object getBean(String name, Scope scope);
-
- /**
- * 根据class和对象作用于获取一个bean对象
- *
- * @param type class类型
- * @param scope 对象作用域,单例或者每次都创建
- * @return 一个bean对象
- */
- Object getBean(Class> type, Scope scope);
-
- /**
- * @return 返回所有bean的名称集合
- */
- Set getBeanNames();
-
- /**
- * @return 返回所有bean的集合
- */
- Collection getBeans();
-
- /**
- * 根据注解获取ioc容器中匹配的bean class集合
- *
- * @param annotation annotation class类型
- * @return 返回符合annotation class类型的所有class
- */
- List> getClassesByAnnotation(Class extends Annotation> annotation);
-
- /**
- * 根据注解获取ioc容器中匹配的bean对象集合
- *
- * @param annotation annotation class类型
- * @return 返回符合annotation class类型的所有bean
- */
- List getBeansByAnnotation(Class extends Annotation> annotation);
-
- /**
- * 判断是否存在一个bean,根据class类型
- *
- * @param clazz 类的class类型
- * @return true:存在,false:不存在
- */
- boolean hasBean(Class> clazz);
-
- /**
- * 判断是否存在一个bean,根据bena name
- *
- * @param name bean的名称,一般是class名称
- * @return true:存在,false:不存在
- */
- boolean hasBean(String name);
-
- /**
- * 根据名称从ioc容器中移除一个bean对象
- *
- * @param name 要移除的bean对象名称
- * @return true:成功,false:失败
- */
- boolean removeBean(String name);
-
- /**
- * 根据名称从ioc容器中移除一个bean对象
- *
- * @param clazz 要移除的bean class类型
- * @return true:成功,false:失败
- */
- boolean removeBean(Class> clazz);
-
- /**
- * @return 清空容器
- */
- boolean removeAll();
-
- /**
- * 获取annotations中的注解是否可以注册进入ioc容器
- *
- * @param annotations annotations要检测的annotation数组
- * @return true:可以注册,false:不可以注册
- */
- boolean isRegister(Annotation[] annotations);
-
- /**
- * 注册一个class类型的bean到容器中
- *
- * @param clazz 要注册的class类型
- * @return 返回注册后的bean对象
- */
- Object registBean(Class> clazz);
-
- /**
- * 注册一个对象到bean容器中
- *
- * @param object 要注册的object
- * @return 返回注册后的Bean实例
- */
- Object registBean(Object object);
-
- /**
- * 注册一个class集合进入ioc容器
- *
- * @param classes 要注册的class集合
- */
- void registBean(Set> classes);
-
- /**
- * 初始化IOC
- */
- void initWired();
-
- /**
- * @return 返回ioc容器中的所有bean对象的K,V
- */
- Map getBeanMap();
-
-}
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/ioc/DefaultContainer.java b/blade-core/src/main/java/blade/ioc/DefaultContainer.java
deleted file mode 100644
index 466d18809..000000000
--- a/blade-core/src/main/java/blade/ioc/DefaultContainer.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade.ioc;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import blade.annotation.Component;
-import blade.annotation.Inject;
-import blade.annotation.Path;
-import blade.kit.CloneKit;
-import blade.kit.CollectionKit;
-import blade.kit.ReflectKit;
-import blade.kit.log.Logger;
-
-/**
- * 默认的IOC容器实现
- *
- * @author biezhi
- * @since 1.0
- */
-public class DefaultContainer implements Container {
-
- private static final Logger LOGGER = Logger.getLogger(DefaultContainer.class);
-
- /**
- * 保存所有bean对象
- */
- private static final Map beansMap = CollectionKit.newConcurrentHashMap();
-
- /**
- * 保存所有注解的class
- */
- private static final Map, List> annotationMap = CollectionKit.newConcurrentHashMap();
-
- private DefaultContainer() {
- }
-
- public static DefaultContainer single() {
- return DefaultContainerHoder.single;
- }
-
- private static class DefaultContainerHoder {
- private static final DefaultContainer single = new DefaultContainer();
- }
-
- public Map getBeanMap() {
- return beansMap;
- }
-
- @Override
- public Object getBean(String name, Scope scope) {
- Object obj = beansMap.get(name);
- if(null != scope && scope == Scope.PROTOTYPE){
- try {
- return CloneKit.deepClone(obj);
- } catch (Exception e) {
- LOGGER.error("克隆对象失败," + e.getMessage());
- }
- }
- return obj;
- }
-
- @Override
- public Object getBean(Class> type, Scope scope) {
- Iterator it = beansMap.values().iterator();
- while (it.hasNext()) {
- Object obj = it.next();
- if (type.isAssignableFrom(obj.getClass())) {
- if(null != scope && scope == Scope.PROTOTYPE){
- try {
- return CloneKit.deepClone(obj);
- } catch (Exception e) {
- LOGGER.error("克隆对象失败," + e.getMessage());
- }
- } else {
- return obj;
- }
- }
- }
- return null;
- }
-
- @Override
- public Set getBeanNames() {
- return beansMap.keySet();
- }
-
- @Override
- public Collection getBeans() {
- return beansMap.values();
- }
-
- @Override
- public boolean hasBean(Class> clz) {
- if (null != this.getBean(clz, Scope.SINGLE)) {
- return true;
- }
- return false;
- }
-
- @Override
- public boolean hasBean(String name) {
- if (null != this.getBean(name, Scope.SINGLE)) {
- return true;
- }
- return false;
- }
-
- @Override
- public boolean removeBean(String name) {
- Object object = beansMap.remove(name);
- return (null != object);
- }
-
- @Override
- public boolean removeBean(Class> clazz) {
- Object object = beansMap.remove(clazz.getName());
- return (null != object);
- }
-
- /**
- * 注册一个bean对象到容器里
- *
- * @param clazz 要注册的class
- * @return 返回注册后的bean对象
- */
- @Override
- public Object registBean(Class> clazz) {
-
- String name = clazz.getCanonicalName();
-
- Object object = null;
-
- //非抽象类、接口
- if (!Modifier.isAbstract(clazz.getModifiers()) && !clazz.isInterface()) {
-
- object = ReflectKit.newInstance(clazz);
-
- put(name, object);
- //实现的接口对应存储
- if(clazz.getInterfaces().length > 0){
- put(clazz.getInterfaces()[0].getCanonicalName(), object);
- }
-
- //带有annotation
- if(null != clazz.getDeclaredAnnotations()){
- putAnnotationMap(clazz, object);
- }
- }
- return object;
- }
-
- /**
- * bean容器存储
- *
- * @param name 要进入IOC容器的bean名称
- * @param object 要进入IOC容器的bean对象
- */
- private void put(String name, Object object){
- if(null == beansMap.get(name)){
- beansMap.put(name, object);
- }
- }
-
- /**
- * 给annotationMap添加元素
- *
- * @param clazz 要注入的class类型
- * @param object 注册的bean对象
- */
- private void putAnnotationMap(Class> clazz, Object object){
- Annotation[] annotations = clazz.getAnnotations();
- for(Annotation annotation : annotations){
- if(null != annotation){
- List listObject = annotationMap.get(annotation.annotationType());
- if(CollectionKit.isEmpty(listObject)){
- listObject = CollectionKit.newArrayList();
- }
- listObject.add(object);
- put(annotation.annotationType(), listObject);
- }
- }
- }
-
- /**
- * annotationBean容器存储
- *
- * @param clazz 允许注册的Annotation类型
- * @param listObject 要注入的对象列表
- */
- private void put(Class extends Annotation> clazz, List listObject){
- if(null == annotationMap.get(clazz)){
- annotationMap.put(clazz, listObject);
- }
- }
-
- /**
- * 初始化注入
- */
- @Override
- public void initWired() {
- Iterator it = beansMap.values().iterator();
- try {
- while (it.hasNext()) {
-
- Object obj = it.next();
-
- // 所有字段
- Field[] fields = obj.getClass().getDeclaredFields();
- for (Field field : fields) {
-
- // 需要注入的字段
- Inject inject = field.getAnnotation(Inject.class);
- if (null != inject) {
-
- // 要注入的字段
- Object injectField = this.getBean(field.getType(), Scope.SINGLE);
-
- // 指定装配的类
- if (inject.value() != Class.class) {
- injectField = this.getBean(inject.value(), Scope.SINGLE);
- // 容器有该类
- if (null == injectField) {
- injectField = this.registBean(inject.value());
- }
- } else{
- // 没有指定装配class, 容器没有该类,则创建一个对象放入容器
- if (null == injectField) {
- injectField = this.registBean(field.getType());
- }
- }
- if (null == injectField) {
- throw new RuntimeException("Unable to load " + field.getType().getCanonicalName() + "!");
- }
- boolean accessible = field.isAccessible();
- field.setAccessible(true);
- field.set(obj, injectField);
- field.setAccessible(accessible);
- }
- }
- }
- } catch (SecurityException e) {
- LOGGER.error(e.getMessage());
- } catch (IllegalArgumentException e) {
- LOGGER.error(e.getMessage());
- } catch (IllegalAccessException e) {
- LOGGER.error(e.getMessage());
- }
- }
-
- /**
- * 判断是否是可以注册的bean
- *
- * @param annotations 注解类型
- * @return true:可以注册 false:不可以注册
- */
- @Override
- public boolean isRegister(Annotation[] annotations) {
- if (null == annotations || annotations.length == 0) {
- return false;
- }
- for (Annotation annotation : annotations) {
- if (annotation instanceof Component || annotation instanceof Path) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public List> getClassesByAnnotation(Class extends Annotation> annotation) {
- List objectList = getBeansByAnnotation(annotation);
- if(!CollectionKit.isEmpty(objectList)){
- List> classList = CollectionKit.newArrayList(objectList.size());
- for(Object object : objectList){
- classList.add(object.getClass());
- }
- return classList;
- }
- return null;
- }
-
- @Override
- public List getBeansByAnnotation(Class extends Annotation> annotation) {
- return annotationMap.get(annotation);
- }
-
- @Override
- public void registBean(Set> classes) {
- if(!CollectionKit.isEmpty(classes)){
- for(Class> clazz : classes){
- this.registBean(clazz);
- }
- }
- }
-
- @Override
- public Object registBean(Object object) {
- String name = object.getClass().getName();
- put(name, object);
- return object;
- }
-
- @Override
- public boolean removeAll() {
- beansMap.clear();
- annotationMap.clear();
- return true;
- }
-
-}
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/ioc/package-info.java b/blade-core/src/main/java/blade/ioc/package-info.java
deleted file mode 100644
index 3b4f02639..000000000
--- a/blade-core/src/main/java/blade/ioc/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * blade依赖注入包
- */
-package blade.ioc;
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/kit/package-info.java b/blade-core/src/main/java/blade/kit/package-info.java
deleted file mode 100644
index 66554ccaf..000000000
--- a/blade-core/src/main/java/blade/kit/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * blade工具包
- */
-package blade.kit;
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/package-info.java b/blade-core/src/main/java/blade/package-info.java
deleted file mode 100644
index bd5612aa1..000000000
--- a/blade-core/src/main/java/blade/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * blade
- */
-package blade;
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/plugin/package-info.java b/blade-core/src/main/java/blade/plugin/package-info.java
deleted file mode 100644
index 60d209844..000000000
--- a/blade-core/src/main/java/blade/plugin/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * blade插件包
- */
-package blade.plugin;
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/render/JspRender.java b/blade-core/src/main/java/blade/render/JspRender.java
deleted file mode 100644
index bfb439a41..000000000
--- a/blade-core/src/main/java/blade/render/JspRender.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade.render;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import blade.Blade;
-import blade.BladeWebContext;
-
-/**
- * JSP渲染引擎,默认的渲染器
- *
- * @author biezhi
- * @since 1.0
- */
-public final class JspRender extends Render {
-
- private JspRender() {
- }
-
- /**
- * 视图渲染
- */
- public Object render(final String view){
- try {
- HttpServletRequest servletRequest = BladeWebContext.servletRequest();
- HttpServletResponse servletResponse = BladeWebContext.servletResponse();
-
- // 设置编码
- servletRequest.setCharacterEncoding(Blade.encoding());
- servletResponse.setCharacterEncoding(Blade.encoding());
-
- // 构造jsp地址
- String realPath = disposeView(view);
-
- // 跳转到页面
- servletRequest.getRequestDispatcher(realPath).forward(servletRequest, servletResponse);
-
- } catch (ServletException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * ModelAndView渲染
- */
- public Object render(ModelAndView modelAndView){
- try {
- HttpServletRequest servletRequest = BladeWebContext.servletRequest();
- HttpServletResponse servletResponse = BladeWebContext.servletResponse();
-
- String realPath = disposeView(modelAndView.getView());
-
- Map model = modelAndView.getModel();
-
- if (null != model && !model.isEmpty()) {
- Set keys = model.keySet();
- for (String key : keys) {
- servletRequest.setAttribute(key, model.get(key));
- }
- }
- servletRequest.getRequestDispatcher(realPath).forward(servletRequest, servletResponse);
- } catch (ServletException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
-
- public static JspRender single() {
- return JspRenderHolder.single;
- }
-
- private static class JspRenderHolder {
- private static final JspRender single = new JspRender();
- }
-
-}
diff --git a/blade-core/src/main/java/blade/render/Render.java b/blade-core/src/main/java/blade/render/Render.java
deleted file mode 100644
index 04145010c..000000000
--- a/blade-core/src/main/java/blade/render/Render.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade.render;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import blade.Blade;
-import blade.BladeWebContext;
-/**
- * 渲染器抽象类
- *
- * @author biezhi
- * @since 1.0
- */
-public abstract class Render {
-
- static final String VIEW_NOTFOUND = "404 %s ";
-
- public void render404(String viewName){
- render404(null, viewName);
- }
-
- /**
- * 404视图
- *
- * @param httpResponse HttpServletResponse对象
- * @param viewName 视图名称
- */
- public void render404(HttpServletResponse httpResponse, String viewName){
- try {
- String view404 = Blade.view404();
- if(null != view404){
- ModelAndView modelAndView = new ModelAndView(view404);
- modelAndView.add("viewName", viewName);
- render(modelAndView);
- } else {
- if(null == httpResponse){
- httpResponse = BladeWebContext.servletResponse();
- }
-
- httpResponse.setContentType("text/html; charset=utf-8");
- httpResponse.setStatus(404);
- ServletOutputStream outputStream = httpResponse.getOutputStream();
- outputStream.print(String.format(VIEW_NOTFOUND, viewName + " Not Found"));
- outputStream.flush();
- outputStream.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 渲染500视图
- *
- * @param bodyContent 错误消息
- */
- public void render500(String bodyContent){
- try {
-
- String view500 = Blade.view500();
- if(null != view500){
- ModelAndView modelAndView = new ModelAndView(view500);
- modelAndView.add("body", bodyContent);
- render(modelAndView);
- } else {
- HttpServletResponse httpResponse = BladeWebContext.servletResponse();
-
- httpResponse.setContentType("text/html; charset=utf-8");
- ServletOutputStream outputStream = httpResponse.getOutputStream();
-
- outputStream.print(bodyContent.toString());
- outputStream.flush();
- outputStream.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 输出json
- *
- * @param json json内容
- */
- public void json(String json){
- if(null != json){
- HttpServletResponse response = BladeWebContext.servletResponse();
- HttpServletRequest request = BladeWebContext.servletRequest();
-
- response.setHeader("Cache-Control", "no-cache");
- String userAgent = request.getHeader("User-Agent");
- if (userAgent.contains("MSIE")) {
- response.setContentType("text/html;charset=utf-8");
- } else {
- response.setContentType("application/json;charset=utf-8");
- }
- try {
- request.setCharacterEncoding("utf-8");
- PrintWriter out = response.getWriter();
- out.print(json.toString());
- out.flush();
- out.close();
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- * 输出text
- * @param text text内容
- */
- public void text(String text){
- if(null != text){
- HttpServletResponse response = BladeWebContext.servletResponse();
- HttpServletRequest request = BladeWebContext.servletRequest();
- response.setHeader("Cache-Control", "no-cache");
- response.setContentType("text/plain;charset=utf-8");
- try {
- request.setCharacterEncoding("utf-8");
- PrintWriter out = response.getWriter();
- out.print(text);
- out.flush();
- out.close();
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- * 输出xml
- * @param xml xml内容
- */
- public void xml(String xml){
- if(null != xml){
- HttpServletResponse response = BladeWebContext.servletResponse();
- HttpServletRequest request = BladeWebContext.servletRequest();
- response.setHeader("Cache-Control", "no-cache");
- response.setContentType("text/xml;charset=utf-8");
- try {
- request.setCharacterEncoding("utf-8");
- PrintWriter out = response.getWriter();
- out.print(xml);
- out.flush();
- out.close();
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- * 输出HTML
- * @param html html内容
- */
- public void html(String html){
- if(null != html){
- HttpServletResponse response = BladeWebContext.servletResponse();
- HttpServletRequest request = BladeWebContext.servletRequest();
- response.setHeader("Cache-Control", "no-cache");
- response.setContentType("text/html;charset=utf-8");
- try {
- request.setCharacterEncoding("utf-8");
- PrintWriter out = response.getWriter();
- out.print(html);
- out.flush();
- out.close();
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- * 输出javascript
- * @param javascript js内容
- */
- public void javascript(String javascript){
- if(null != javascript){
- HttpServletResponse response = BladeWebContext.servletResponse();
- HttpServletRequest request = BladeWebContext.servletRequest();
- response.setHeader("Cache-Control", "no-cache");
- response.setContentType("text/javascript;charset=utf-8");
- try {
- request.setCharacterEncoding("utf-8");
- PrintWriter out = response.getWriter();
- out.print(javascript);
- out.flush();
- out.close();
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- * 处理视图
- * @param view 视图名称
- * @return 返回取出多余"/"的全路径
- */
- String disposeView(String view){
- if(null != view){
- view = Blade.viewPath() + view;
- view = view.replaceAll("[/]+", "/");
- if(!view.endsWith(Blade.viewExt())){
- view = view + Blade.viewExt();
- }
- }
- return view;
- }
-
- /**
- * 渲染方法
- * @param view 视图名称
- * @return null
- */
- public abstract Object render(final String view);
-
- /**
- * 渲染方法
- * @param modelAndView modelAndView对象
- * @return null
- */
- public abstract Object render(ModelAndView modelAndView);
-
-}
diff --git a/blade-core/src/main/java/blade/render/package-info.java b/blade-core/src/main/java/blade/render/package-info.java
deleted file mode 100644
index a8e93cae8..000000000
--- a/blade-core/src/main/java/blade/render/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * blade视图渲染
- */
-package blade.render;
\ No newline at end of file
diff --git a/blade-core/src/main/java/blade/route/DefaultRouteMatcher.java b/blade-core/src/main/java/blade/route/DefaultRouteMatcher.java
deleted file mode 100644
index cb2a988b7..000000000
--- a/blade-core/src/main/java/blade/route/DefaultRouteMatcher.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/**
- * Copyright (c) 2015, biezhi 王爵 (biezhi.me@gmail.com)
- *
- * 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 blade.route;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import blade.Blade;
-import blade.kit.MimeParse;
-import blade.kit.StringKit;
-import blade.kit.log.Logger;
-
-/**
- * 默认的路由匹配器
- *
- * @author biezhi
- * @since 1.0
- */
-public class DefaultRouteMatcher {
-
- private static final Logger LOGGER = Logger.getLogger(DefaultRouteMatcher.class);
-
- // 存储所有路由
- private List routes;
- // 存储所有拦截器
- private List interceptors;
-
- public DefaultRouteMatcher() {
- routes = new ArrayList();
- interceptors = new ArrayList();
- }
-
- /**
- * 查询是否有路由
- *
- * @param httpMethod http请求方法,GET/POST
- * @param uri 请求路径
- * @param acceptType 请求的acceptType
- * @return 返回一个路由匹配对象
- */
- public RouteMatcher findRouteMatcher(HttpMethod httpMethod, String uri, String acceptType) {
-
- uri = uri.length() > 1 && uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
-
- List routeEntries = this.findRouteMatcher(httpMethod, uri);
-
- RouteMatcher entry = findTargetWithGivenAcceptType(routeEntries, acceptType);
-
- return entry != null ? new RouteMatcher(entry.target, entry.execMethod, entry.httpMethod, entry.path, uri, acceptType) : null;
- }
-
- /**
- * 查询一个路由集合
- *
- * @param httpMethod http请求方法,GET/POST
- * @param path 请求路径
- * @param acceptType 请求的acceptType
- * @return 返回一个路由匹配对象集合
- */
- public List findInterceptor(HttpMethod httpMethod, String uri, String acceptType) {
- if(uri.length() > 1){
- uri = uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
- }
- List matchSet = new ArrayList();
- List routeEntries = this.findInterceptor(httpMethod, uri);
-
- for (RouteMatcher routeEntry : routeEntries) {
- if (acceptType != null) {
-
- String bestMatch = MimeParse.bestMatch(Arrays.asList(routeEntry.acceptType), acceptType);
-
- if (routeWithGivenAcceptType(bestMatch)) {
- matchSet.add(routeEntry);
- }
- } else {
- matchSet.add(routeEntry);
- }
- }
-
- return matchSet;
- }
-
- /**
- * 清空路由集合
- */
- public void clearRoutes() {
- routes.clear();
- }
-
- /**
- * 移除一个路由
- *
- * @param path 移除路由的路径
- * @param httpMethod 移除路由的方法
- * @return true:移除成功,false:移除失败
- */
- public boolean removeRoute(String path, String httpMethod) {
- if (StringKit.isEmpty(path)) {
- throw new IllegalArgumentException("path cannot be null or blank");
- }
-
- if (StringKit.isEmpty(httpMethod)) {
- throw new IllegalArgumentException("httpMethod cannot be null or blank");
- }
-
- HttpMethod method = HttpMethod.valueOf(httpMethod);
-
- return removeRoute(method, path);
- }
-
- public boolean removeRoute(String path) {
- if (StringKit.isEmpty(path)) {
- throw new IllegalArgumentException("path cannot be null or blank");
- }
-
- return removeRoute((HttpMethod)null, path);
- }
-
- /**
- * 添加一个路由对象
- *
- * @param target 路由目标执行的class
- * @param execMethod 路由执行方法
- * @param url 路由url
- * @param method 路由http方法
- * @param acceptType 路由acceptType
- */
- public void addRoute(Class> target, Method execMethod, String url, HttpMethod method, String acceptType) {
- RouteMatcher entry = new RouteMatcher();
- entry.target = target;
- entry.execMethod = execMethod;
- entry.httpMethod = method;
- entry.path = url;
- entry.requestURI = url;
- entry.acceptType = acceptType;
-
- if(Blade.debug()){
- LOGGER.debug("Add Route:" + entry);
- }
-
- // 添加到路由集合
- routes.add(entry);
- }
-
- /**
- * 添加一个拦截器对象
- *
- * @param target 路由目标执行的class
- * @param execMethod 路由执行方法
- * @param url 路由url
- * @param method 路由http方法
- * @param acceptType 路由acceptType
- */
- public void addInterceptor(Class> target, Method execMethod, String url, HttpMethod method, String acceptType) {
- RouteMatcher entry = new RouteMatcher();
- entry.target = target;
- entry.execMethod = execMethod;
- entry.httpMethod = method;
- entry.path = url;
- entry.requestURI = url;
- entry.acceptType = acceptType;
-
- if(Blade.debug()){
- LOGGER.debug("Add Interceptor:" + entry);
- }
-
- // 添加到路由集合
- interceptors.add(entry);
- }
-
- private Map getAcceptedMimeTypes(List routes) {
- Map acceptedTypes = new HashMap();
-
- for (RouteMatcher routeEntry : routes) {
- if (!acceptedTypes.containsKey(routeEntry.acceptType)) {
- acceptedTypes.put(routeEntry.acceptType, routeEntry);
- }
- }
-
- return acceptedTypes;
- }
-
- private boolean routeWithGivenAcceptType(String bestMatch) {
- return !MimeParse.NO_MIME_TYPE.equals(bestMatch);
- }
-
- /**
- * 查找所有匹配HttpMethod和path的路由
- *
- * @param httpMethod http方法
- * @param path 路由路径
- * @return 返回匹配的所有路由集合
- */
- private List findRouteMatcher(HttpMethod httpMethod, String path) {
- path = path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
-
- List matchSet = new ArrayList();
- for (RouteMatcher entry : routes) {
- if (entry.matches(httpMethod, path)) {
- matchSet.add(entry);
- }
- }
- return matchSet;
- }
-
- /**
- * 查找所有匹配HttpMethod和path的路由
- *
- * @param httpMethod http方法
- * @param path 路由路径
- * @return 返回匹配的所有路由集合
- */
- private List