001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.util.proxy;
017:
018: import java.lang.reflect.Method;
019: import java.io.BufferedOutputStream;
020: import java.io.ByteArrayOutputStream;
021: import java.io.DataOutputStream;
022: import java.io.File;
023: import java.io.FileOutputStream;
024: import java.io.IOException;
025: import java.security.ProtectionDomain;
026:
027: import javassist.CannotCompileException;
028: import javassist.bytecode.ClassFile;
029:
030: /**
031: * A helper class for implementing <code>ProxyFactory</code>.
032: * The users of <code>ProxyFactory</code> do not have to see this class.
033: *
034: * @see ProxyFactory
035: */
036: public class FactoryHelper {
037: private static java.lang.reflect.Method defineClass1, defineClass2;
038:
039: static {
040: try {
041: Class cl = Class.forName("java.lang.ClassLoader");
042: defineClass1 = cl.getDeclaredMethod("defineClass",
043: new Class[] { String.class, byte[].class,
044: int.class, int.class });
045:
046: defineClass2 = cl.getDeclaredMethod("defineClass",
047: new Class[] { String.class, byte[].class,
048: int.class, int.class,
049: ProtectionDomain.class });
050: } catch (Exception e) {
051: throw new RuntimeException("cannot initialize");
052: }
053: }
054:
055: /**
056: * Returns an index for accessing arrays in this class.
057: *
058: * @throws RuntimeException if a given type is not a primitive type.
059: */
060: public static final int typeIndex(Class type) {
061: Class[] list = primitiveTypes;
062: int n = list.length;
063: for (int i = 0; i < n; i++)
064: if (list[i] == type)
065: return i;
066:
067: throw new RuntimeException("bad type:" + type.getName());
068: }
069:
070: /**
071: * <code>Class</code> objects representing primitive types.
072: */
073: public static final Class[] primitiveTypes = { Boolean.TYPE,
074: Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE,
075: Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE };
076:
077: /**
078: * The fully-qualified names of wrapper classes for primitive types.
079: */
080: public static final String[] wrapperTypes = { "java.lang.Boolean",
081: "java.lang.Byte", "java.lang.Character", "java.lang.Short",
082: "java.lang.Integer", "java.lang.Long", "java.lang.Float",
083: "java.lang.Double", "java.lang.Void" };
084:
085: /**
086: * The descriptors of the constructors of wrapper classes.
087: */
088: public static final String[] wrapperDesc = { "(Z)V", "(B)V",
089: "(C)V", "(S)V", "(I)V", "(J)V", "(F)V", "(D)V" };
090:
091: /**
092: * The names of methods for obtaining a primitive value
093: * from a wrapper object. For example, <code>intValue()</code>
094: * is such a method for obtaining an integer value from a
095: * <code>java.lang.Integer</code> object.
096: */
097: public static final String[] unwarpMethods = { "booleanValue",
098: "byteValue", "charValue", "shortValue", "intValue",
099: "longValue", "floatValue", "doubleValue" };
100:
101: /**
102: * The descriptors of the unwrapping methods contained
103: * in <code>unwrapMethods</code>.
104: */
105: public static final String[] unwrapDesc = { "()Z", "()B", "()C",
106: "()S", "()I", "()J", "()F", "()D" };
107:
108: /**
109: * The data size of primitive types. <code>long</code>
110: * and <code>double</code> are 2; the others are 1.
111: */
112: public static final int[] dataSize = { 1, 1, 1, 1, 1, 2, 1, 2 };
113:
114: /**
115: * Loads a class file by a given class loader.
116: * This method uses a default protection domain for the class
117: * but it may not work with a security manager or a sigend jar file.
118: *
119: * @see #toClass(ClassFile,ClassLoader,ProtectionDomain)
120: */
121: public static Class toClass(ClassFile cf, ClassLoader loader)
122: throws CannotCompileException {
123: return toClass(cf, loader, null);
124: }
125:
126: /**
127: * Loads a class file by a given class loader.
128: *
129: * @param domain if it is null, a default domain is used.
130: * @since 3.3
131: */
132: public static Class toClass(ClassFile cf, ClassLoader loader,
133: ProtectionDomain domain) throws CannotCompileException {
134: try {
135: byte[] b = toBytecode(cf);
136: Method method;
137: Object[] args;
138: if (domain == null) {
139: method = defineClass1;
140: args = new Object[] { cf.getName(), b, new Integer(0),
141: new Integer(b.length) };
142: } else {
143: method = defineClass2;
144: args = new Object[] { cf.getName(), b, new Integer(0),
145: new Integer(b.length), domain };
146: }
147:
148: return toClass2(method, loader, args);
149: } catch (RuntimeException e) {
150: throw e;
151: } catch (java.lang.reflect.InvocationTargetException e) {
152: throw new CannotCompileException(e.getTargetException());
153: } catch (Exception e) {
154: throw new CannotCompileException(e);
155: }
156: }
157:
158: private static synchronized Class toClass2(Method method,
159: ClassLoader loader, Object[] args) throws Exception {
160: method.setAccessible(true);
161: Class clazz = (Class) method.invoke(loader, args);
162: method.setAccessible(false);
163: return clazz;
164: }
165:
166: private static byte[] toBytecode(ClassFile cf) throws IOException {
167: ByteArrayOutputStream barray = new ByteArrayOutputStream();
168: DataOutputStream out = new DataOutputStream(barray);
169: try {
170: cf.write(out);
171: } finally {
172: out.close();
173: }
174:
175: return barray.toByteArray();
176: }
177:
178: /**
179: * Writes a class file.
180: */
181: public static void writeFile(ClassFile cf, String directoryName)
182: throws CannotCompileException {
183: try {
184: writeFile0(cf, directoryName);
185: } catch (IOException e) {
186: throw new CannotCompileException(e);
187: }
188: }
189:
190: private static void writeFile0(ClassFile cf, String directoryName)
191: throws CannotCompileException, IOException {
192: String classname = cf.getName();
193: String filename = directoryName + File.separatorChar
194: + classname.replace('.', File.separatorChar) + ".class";
195: int pos = filename.lastIndexOf(File.separatorChar);
196: if (pos > 0) {
197: String dir = filename.substring(0, pos);
198: if (!dir.equals("."))
199: new File(dir).mkdirs();
200: }
201:
202: DataOutputStream out = new DataOutputStream(
203: new BufferedOutputStream(new FileOutputStream(filename)));
204: try {
205: cf.write(out);
206: } catch (IOException e) {
207: throw e;
208: } finally {
209: out.close();
210: }
211: }
212: }
|