1 package org.openrdf.elmo.dynacode;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.File;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.net.MalformedURLException;
9 import java.net.URL;
10 import java.util.concurrent.ConcurrentHashMap;
11 import java.util.concurrent.ConcurrentMap;
12
13 import javassist.CannotCompileException;
14 import javassist.ClassPool;
15 import javassist.CtClass;
16 import javassist.LoaderClassPath;
17 import javassist.NotFoundException;
18 import javassist.bytecode.Descriptor;
19
20 import org.openrdf.elmo.exceptions.ElmoCompositionException;
21
22 public class ClassFactory extends ClassLoader {
23 private static final URL exists;
24
25 static {
26 try {
27 exists = new URL("http://java/"
28 + ClassFactory.class.getName().replace('.', '/')
29 + "#exists");
30 } catch (MalformedURLException e) {
31 throw new AssertionError(e);
32 }
33 }
34
35 private static CtClass getPrimitive(Class<?> type, ClassFactory cp) {
36 if (type.equals(Boolean.TYPE))
37 return CtClass.booleanType;
38 if (type.equals(Byte.TYPE))
39 return CtClass.byteType;
40 if (type.equals(Character.TYPE))
41 return CtClass.charType;
42 if (type.equals(Double.TYPE))
43 return CtClass.doubleType;
44 if (type.equals(Float.TYPE))
45 return CtClass.floatType;
46 if (type.equals(Integer.TYPE))
47 return CtClass.intType;
48 if (type.equals(Long.TYPE))
49 return CtClass.longType;
50 if (type.equals(Short.TYPE))
51 return CtClass.shortType;
52 if (type.equals(Void.TYPE))
53 return CtClass.voidType;
54 throw new ElmoCompositionException("Unknown primative type: "
55 + type.getName());
56 }
57
58 private ConcurrentMap<String, byte[]> bytecodes;
59
60 private ClassPool cp;
61
62 private File target;
63
64
65
66
67 public ClassFactory() {
68 this(Thread.currentThread().getContextClassLoader());
69 }
70
71
72
73
74
75
76 public ClassFactory(ClassLoader parent) {
77 super(parent);
78 cp = new ClassPool();
79 cp.appendClassPath(new LoaderClassPath(this));
80 bytecodes = new ConcurrentHashMap<String, byte[]>();
81 String property = System.getProperty("elmobeans.target");
82 if (property != null) {
83 target = new File(property);
84 }
85 }
86
87
88
89
90
91
92
93
94 public Class<?> createClass(ClassTemplate template)
95 throws ElmoCompositionException {
96 CtClass cc = template.getCtClass();
97 String name = cc.getName();
98 try {
99 byte[] bytecode = cc.toBytecode();
100 cc.detach();
101 return defineClass(name, bytecode);
102 } catch (IOException e) {
103 throw new ElmoCompositionException(e);
104 } catch (CannotCompileException e) {
105 throw new ElmoCompositionException(e);
106 }
107 }
108
109
110
111
112
113
114
115
116 public ClassTemplate createClassTemplate(String className) {
117 return new ClassTemplate(cp.makeClass(className), this);
118 }
119
120
121
122
123
124
125
126
127
128 public ClassTemplate createClassTemplate(String name, Class<?> class1) {
129 try {
130 CtClass cc = cp.makeClass(name, cp.get(class1.getName()));
131 return new ClassTemplate(cc, this);
132 } catch (NotFoundException e) {
133 throw new ElmoCompositionException(e);
134 }
135 }
136
137 @Override
138 public URL getResource(String name) {
139 if (bytecodes.containsKey(name))
140 return exists;
141 return super.getResource(name);
142 }
143
144 @Override
145 public InputStream getResourceAsStream(String name) {
146 if (bytecodes.containsKey(name)) {
147 byte[] b = bytecodes.get(name);
148 return new ByteArrayInputStream(b);
149 }
150 return super.getResourceAsStream(name);
151 }
152
153
154
155
156
157 public void setTraget(File folder) {
158 target = folder;
159 }
160
161 CtClass get(Class<?> type) throws ElmoCompositionException {
162 if (type.isPrimitive()) {
163 return getPrimitive(type, this);
164 }
165 try {
166 if (type.isArray())
167 return Descriptor.toCtClass(type.getName(), cp);
168 return cp.get(type.getName());
169 } catch (NotFoundException e) {
170 throw new ElmoCompositionException(e);
171 }
172 }
173
174 private Class defineClass(String name, byte[] bytecode) {
175 String resource = name.replace('.', '/') + ".class";
176 if (target != null) {
177 saveResource(resource, bytecode);
178 }
179 bytecodes.putIfAbsent(resource, bytecode);
180 return defineClass(name, bytecode, 0, bytecode.length);
181 }
182
183 private void saveResource(String fileName, byte[] bytecode) {
184 try {
185 File file = new File(target, fileName);
186 file.getParentFile().mkdirs();
187 FileOutputStream out = new FileOutputStream(file);
188 try {
189 out.write(bytecode);
190 } finally {
191 out.close();
192 }
193 } catch (Exception e) {
194 }
195 }
196
197 Class<?> getJavaClass(CtClass cc) throws ClassNotFoundException {
198 if (cc.isPrimitive()) {
199 if (cc.equals(CtClass.booleanType))
200 return Boolean.TYPE;
201 if (cc.equals(CtClass.byteType))
202 return Byte.TYPE;
203 if (cc.equals(CtClass.charType))
204 return Character.TYPE;
205 if (cc.equals(CtClass.doubleType))
206 return Double.TYPE;
207 if (cc.equals(CtClass.floatType))
208 return Float.TYPE;
209 if (cc.equals(CtClass.intType))
210 return Integer.TYPE;
211 if (cc.equals(CtClass.longType))
212 return Long.TYPE;
213 if (cc.equals(CtClass.shortType))
214 return Short.TYPE;
215 throw new AssertionError();
216 }
217 String name = Descriptor.toJavaName(Descriptor.toJvmName(cc));
218 return Class.forName(name, true, this);
219 }
220 }