1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  */
18 
19 import java.awt.event.ActionEvent;
20 import java.awt.event.ActionListener;
21 
22 import org.apache.bcel.Constants;
23 import org.apache.bcel.classfile.Utility;
24 import org.apache.bcel.generic.ALOAD;
25 import org.apache.bcel.generic.ClassGen;
26 import org.apache.bcel.generic.ConstantPoolGen;
27 import org.apache.bcel.generic.GETSTATIC;
28 import org.apache.bcel.generic.INVOKEVIRTUAL;
29 import org.apache.bcel.generic.InstructionConstants;
30 import org.apache.bcel.generic.InstructionFactory;
31 import org.apache.bcel.generic.InstructionList;
32 import org.apache.bcel.generic.MethodGen;
33 import org.apache.bcel.generic.ObjectType;
34 import org.apache.bcel.generic.PUSH;
35 import org.apache.bcel.generic.Type;
36 
37 /**
38  * Dynamically creates and uses a proxy for {@code java.awt.event.ActionListener}
39  * via the classloader mechanism if called with
40  * <pre>java org.apache.bcel.util.JavaWrapper ProxyCreator</pre>
41  *
42  * The trick is to encode the byte code we need into the class name
43  * using the Utility.encode() method. This will result however in big
44  * ugly class name, so for many cases it will be more sufficient to
45  * put some clever creation code into the class loader.<br> This is
46  * comparable to the mechanism provided via
47  * {@code java.lang.reflect.Proxy}, but much more flexible.
48  *
49  * @version $Id$
50  * @see org.apache.bcel.util.JavaWrapper
51  * @see Utility
52  */
53 public class ProxyCreator {
54 
55     /**
56      * Load class and create instance
57      */
createProxy(String pack, String class_name)58     public static Object createProxy(String pack, String class_name) {
59         try {
60             Class<?> cl = Class.forName(pack + "$$BCEL$$" + class_name);
61             return cl.newInstance();
62         } catch (Exception e) {
63             e.printStackTrace();
64         }
65 
66         return null;
67     }
68 
69     /**
70      * Create JavaClass object for a simple proxy for an java.awt.event.ActionListener
71      * that just prints the passed arguments, load and use it via the class loader
72      * mechanism.
73      */
main(String[] argv)74     public static void main(String[] argv) throws Exception {
75         ClassLoader loader = ProxyCreator.class.getClassLoader();
76 
77         // instanceof won't work here ...
78         // TODO this is broken; cannot ever be true now that ClassLoader has been dropped
79         if (loader.getClass().toString().equals("class org.apache.bcel.util.ClassLoader")) {
80             // Real class name will be set by the class loader
81             ClassGen cg = new ClassGen("foo", "java.lang.Object", "", Constants.ACC_PUBLIC,
82                     new String[]{"java.awt.event.ActionListener"});
83 
84             // That's important, otherwise newInstance() won't work
85             cg.addEmptyConstructor(Constants.ACC_PUBLIC);
86 
87             InstructionList il = new InstructionList();
88             ConstantPoolGen cp = cg.getConstantPool();
89             InstructionFactory factory = new InstructionFactory(cg);
90 
91             int out = cp.addFieldref("java.lang.System", "out",
92                     "Ljava/io/PrintStream;");
93             int println = cp.addMethodref("java.io.PrintStream", "println",
94                     "(Ljava/lang/Object;)V");
95             MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
96                     new Type[]{
97                             new ObjectType("java.awt.event.ActionEvent")
98                     }, null, "actionPerformed", "foo", il, cp);
99 
100             // System.out.println("actionPerformed:" + event);
101             il.append(new GETSTATIC(out));
102             il.append(factory.createNew("java.lang.StringBuffer"));
103             il.append(InstructionConstants.DUP);
104             il.append(new PUSH(cp, "actionPerformed:"));
105             il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID,
106                     new Type[]{Type.STRING}, Constants.INVOKESPECIAL));
107 
108             il.append(new ALOAD(1));
109             il.append(factory.createAppend(Type.OBJECT));
110             il.append(new INVOKEVIRTUAL(println));
111             il.append(InstructionConstants.RETURN);
112 
113             mg.stripAttributes(true);
114             mg.setMaxStack();
115             mg.setMaxLocals();
116             cg.addMethod(mg.getMethod());
117 
118             byte[] bytes = cg.getJavaClass().getBytes();
119 
120             System.out.println("Uncompressed class: " + bytes.length);
121 
122             String s = Utility.encode(bytes, true);
123             System.out.println("Encoded class: " + s.length());
124 
125             System.out.print("Creating proxy ... ");
126             ActionListener a = (ActionListener) createProxy("foo.bar.", s);
127             System.out.println("Done. Now calling actionPerformed()");
128 
129             a.actionPerformed(new ActionEvent(a, ActionEvent.ACTION_PERFORMED, "hello"));
130         } else {
131             System.err.println("Call me with java org.apache.bcel.util.JavaWrapper ProxyCreator");
132         }
133     }
134 
135 }
136