/Users/lyon/j4p/src/classUtils/pack/util/pool2/StubGenerator.java
|
1 package classUtils.pack.util.pool2;
2
3 import java.io.BufferedInputStream;
4 import java.io.BufferedWriter;
5 import java.io.ByteArrayOutputStream;
6 import java.io.File;
7 import java.io.FileInputStream;
8 import java.io.FileWriter;
9 import java.io.IOException;
10 import java.io.PrintStream;
11 import java.io.StringReader;
12 import java.io.StringWriter;
13 import java.lang.reflect.Method;
14 import java.lang.reflect.Modifier;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.Set;
18 import java.util.StringTokenizer;
19
20 import classUtils.pack.util.IndentedPrintWriter;
21 import classUtils.pack.util.codegen.VariableNameGenerator;
22
23 import classUtils.pack.util.util.SignatureAnalyzer;
24
25 /**
26 * This class generates a stub for a class C in the same package as C, extending the given
27 * base class. The base class must implement the PooledObject interface.
28 *
29 * @author Cristiano Sadun
30 */
31 class StubGenerator {
32
33 private static String lineSep = System.getProperty("line.separator");
34 private File codeDir;
35 private PrintStream logStream;
36 private String classPath;
37 private Class clsToExtend;
38
39 public StubGenerator(Class clsToExtend) throws IOException {
40 this(clsToExtend, new File(File.separator + "temp"));
41 }
42
43 public StubGenerator(Class clsToExtend, File codeDir) throws IOException {
44 this(clsToExtend, codeDir, System.getProperty("java.class.path"));
45 }
46
47 public StubGenerator(Class clsToExtend, File codeDir, String classPath)
48 throws IOException {
49 this.codeDir = codeDir;
50 this.classPath = classPath;
51 this.clsToExtend = clsToExtend;
52 if (!PooledObject.class.isAssignableFrom(clsToExtend))
53 throw new IllegalArgumentException(
54 "The given base class "
55 + clsToExtend.getName()
56 + " does not implement the PooledObject interface");
57 if (!codeDir.exists())
58 if (!codeDir.mkdirs())
59 throw new IOException("Cannot create directory " + codeDir);
60 }
61
62 public String generateCode(Class cls, StringWriter unqualifiedClsName) {
63
64 if (logStream != null) {
65 logStream.println("Generating code..");
66 }
67
68 /*
69 * Compute implemented interfaces
70 */
71 Set implementedInterfaces = new HashSet();
72 Class[] declaredClasses = cls.getInterfaces();
73 for (int i = 0; i < declaredClasses.length; i++) {
74 //if (declaredClasses[i].isInterface())
75 implementedInterfaces.add(declaredClasses[i]);
76 }
77
78 StringWriter sw = new StringWriter();
79 IndentedPrintWriter pw = new IndentedPrintWriter(sw);
80
81 /*
82 * Package declaration
83 */
84 pw.print("package ");
85 pw.print(cls.getPackage().getName());
86 pw.println(";");
87 pw.println();
88
89 /*
90 * Imports
91 */
92
93 pw.println("import org.sadun.util.pool2.ActivationException;");
94 pw.println();
95
96 /*
97 * Class name
98 */
99
100 pw.print("public class ");
101
102 unqualifiedClsName.write("Pooled");
103 unqualifiedClsName.write(getUnqualifedName(cls));
104 pw.print(unqualifiedClsName.toString());
105 pw.print(" extends " + BasePooledObject.class.getName());
106
107 /*
108 * Implemented interfaces
109 */
110 if (implementedInterfaces.size() != 0) {
111 pw.print(" implements ");
112 for (Iterator i = implementedInterfaces.iterator(); i.hasNext();) {
113 Class interfaceCls=(Class)i.next();
114 pw.print(interfaceCls.getName());
115 if (i.hasNext())
116 pw.print(", ");
117 }
118 }
119
120 pw.println(" {");
121 pw.println();
122
123 /*
124 * Constructor
125 */
126
127 pw.incIndentation(3);
128
129 pw.print("public ");
130 pw.print(unqualifiedClsName.toString());
131 pw.print("(org.sadun.util.pool2.ObjectPool objectPool, ");
132 pw.print(cls.getName());
133 pw.println(" obj) {");
134 pw.println(" super(objectPool, obj);");
135 pw.println("}");
136 pw.println();
137
138 /*
139 * Methods
140 */
141
142 Method[] methods = cls.getMethods();
143 for (int i = 0; i < methods.length; i++) {
144 Method method = methods[i];
145
146 // Skip "Object" methods
147 if (method.getDeclaringClass() == Object.class)
148 continue;
149
150 int modifiers = method.getModifiers();
151
152 if (Modifier.isPublic(modifiers))
153 pw.print("public ");
154 else if (Modifier.isPrivate(modifiers))
155 pw.print("private ");
156 else if (Modifier.isProtected(modifiers))
157 pw.print("protected ");
158
159 // Synchronized and native are ignored on purpose
160 if (Modifier.isStatic(modifiers))
161 pw.print("static ");
162 if (Modifier.isFinal(modifiers))
163 pw.print("final ");
164 if (Modifier.isStrict(modifiers))
165 pw.print("strictfp ");
166
167 pw.print(SignatureAnalyzer.getJavaTypeName(method.getReturnType()));
168 pw.print(" ");
169
170 pw.print(method.getName());
171 pw.print("(");
172 Class[] paramTypes = method.getParameterTypes();
173
174 VariableNameGenerator vng = new VariableNameGenerator();
175 String[][] pList = new String[paramTypes.length][2];
176
177 for (int j = 0; j < paramTypes.length; j++) {
178 pw.print(
179 pList[j][0] =
180 SignatureAnalyzer.getJavaTypeName(paramTypes[j]));
181 pw.print(" ");
182 pw.print(
183 pList[j][1] =
184 vng.generateNext(method.getName(), paramTypes[j]));
185 if (j < paramTypes.length - 1)
186 pw.print(", ");
187 }
188
189 pw.print(") ");
190
191 /*
192 * Exceptions
193 */
194 Class[] excTypes = method.getExceptionTypes();
195 if (excTypes.length > 0) {
196 pw.print("throws ");
197 for (int j = 0; j < excTypes.length; j++) {
198 pw.print(excTypes[j].getName());
199 if (j < excTypes.length - 1)
200 pw.print(", ");
201 }
202 pw.print(" ");
203 }
204
205 pw.println("{");
206
207 /*
208 * Method body
209 */
210
211 addMethodBody(pw, pList, cls, method);
212
213 pw.println("}");
214 pw.println();
215 }
216
217 pw.decIndentation(3);
218
219 pw.print("}");
220
221 return sw.toString();
222 }
223
224 public byte[] generateStub(Class cls) throws IOException {
225
226 // Create the file
227 StringWriter clsName = new StringWriter();
228 StringReader code = new StringReader(generateCode(cls, clsName));
229
230 File sourceCodeFile =
231 getFileForClassSource(cls.getPackage(), clsName.toString());
232 if (logStream != null) {
233 logStream.println(
234 "Writing " + sourceCodeFile.getAbsolutePath() + "..");
235 }
236
237 BufferedWriter bw = new BufferedWriter(new FileWriter(sourceCodeFile));
238 int c;
239 while ((c = code.read()) != -1)
240 bw.write(c);
241 bw.close();
242
243 // Delete existing class file if any
244 File compiledFile =
245 getFileForCompiledClass(cls.getPackage(), clsName.toString());
246 if (compiledFile.exists()) {
247 if (logStream != null) {
248 logStream.println(
249 "Deleting existing "
250 + compiledFile.getAbsolutePath()
251 + "..");
252 }
253 if (!compiledFile.delete())
254 throw new IOException(
255 "Cannot delete existing class file " + compiledFile);
256 }
257
258 // Create command line options
259 String[] args = new String[5];
260
261 args[0] = "-classpath";
262 args[1] = codeDir.getCanonicalPath();
263 if (classPath != null)
264 args[1] += ";" + classPath;
265 args[2] = "-d";
266 args[3] = codeDir.getCanonicalPath();
267 args[4] = sourceCodeFile.getAbsolutePath();
268
269 if (logStream != null) {
270 synchronized (logStream) {
271 logStream.print("Invoking javac ");
272 for (int i = 0; i < args.length; i++) {
273 logStream.print(args[i]);
274 if (i < args.length - 1)
275 logStream.print(" ");
276 }
277 logStream.println();
278 }
279 }
280
281 // Compile it
282
283 com.sun.tools.javac.Main compiler = new com.sun.tools.javac.Main();
284
285 compiler.compile(args);
286
287 if (logStream != null) {
288 logStream.println("Reading " + compiledFile.getAbsolutePath());
289 }
290
291 ByteArrayOutputStream bis = new ByteArrayOutputStream();
292 BufferedInputStream is =
293 new BufferedInputStream(new FileInputStream(compiledFile));
294 while ((c = is.read()) != -1)
295 bis.write(c);
296 is.close();
297
298 if (logStream != null) {
299 logStream.println(
300 "Class bytecode for " + clsName.toString() + " generated");
301 }
302
303 return bis.toByteArray();
304
305 }
306
307 private File getFileForClassSource(Package pkg, String unqualifiedClsName)
308 throws IOException {
309 return getFileForClass0(pkg, unqualifiedClsName, "java");
310 }
311
312 private File getFileForCompiledClass(
313 Package pkg,
314 String unqualifiedClsName)
315 throws IOException {
316 return getFileForClass0(pkg, unqualifiedClsName, "class");
317 }
318
319 /**
320 * Method getFileForClass0.
321 * @param string
322 */
323 private File getFileForClass0(
324 Package pkg,
325 String unqualifiedClsName,
326 String ext)
327 throws IOException {
328 StringWriter sw = new StringWriter();
329 StringTokenizer st = new StringTokenizer(pkg.getName(), ".");
330 while (st.hasMoreTokens()) {
331 sw.write(st.nextToken());
332 sw.write(File.separator);
333 }
334
335 File dir = new File(codeDir, sw.toString());
336 if (!dir.exists())
337 if (!dir.mkdirs())
338 throw new IOException(
339 "Cannot create directory " + dir.getAbsolutePath());
340
341 sw.write(unqualifiedClsName);
342 File f = new File(codeDir, sw.toString() + "." + ext);
343 return f;
344 }
345
346 /**
347 * Method addMethodBody.
348 * @param method
349 */
350 private void addMethodBody(
351 IndentedPrintWriter pw,
352 String[][] pList,
353 Class originalClass,
354 Method method) {
355 pw.incIndentation(3);
356
357 if (!Modifier.isStatic(method.getModifiers())) {
358 pw.println("_getOriginal();");
359
360 if (method.getReturnType() != Void.TYPE)
361 printResultVariable(method.getReturnType(), pw);
362
363 pw.print("((");
364 pw.print(originalClass.getName());
365 pw.print(")");
366 pw.print("getOriginal()).");
367 } else {
368
369 if (method.getReturnType() != Void.TYPE)
370 printResultVariable(method.getReturnType(), pw);
371
372 pw.print(originalClass.getName());
373 pw.print(".");
374 }
375 pw.print(method.getName());
376 pw.print("(");
377 for (int i = 0; i < pList.length; i++) {
378 pw.print(pList[i][1]);
379 if (i < pList.length - 1)
380 pw.print(",");
381 }
382 pw.println(");");
383 if (!Modifier.isStatic(method.getModifiers()))
384 pw.println("_releaseOriginal();");
385
386 if (method.getReturnType() != Void.TYPE)
387 pw.println("return res;");
388
389 pw.decIndentation(3);
390
391 }
392
393 private void printResultVariable(
394 Class returnType,
395 IndentedPrintWriter pw) {
396 pw.print(SignatureAnalyzer.getJavaTypeName(returnType));
397 pw.print(" res = ");
398 }
399
400 /**
401 * Method getUnqualifedName.
402 * @param class
403 * @return String
404 */
405 private String getUnqualifedName(Class cls) {
406 int i = cls.getName().lastIndexOf(".");
407 if (i == -1)
408 return cls.getName();
409 return cls.getName().substring(i + 1);
410 }
411
412 /*public static void main(String[] args) throws Exception {
413 //String code = new StubGenerator().generateCode(StubGenerator.class, new StringWriter());
414 byte[] classBytes =
415 new StubGenerator(BasePooledObject.class).generateStub(
416 StubGenerator.class);
417 }
418 */
419
420 /**
421 * Returns the logStream.
422 * @return PrintStream
423 */
424 public PrintStream getLogStream() {
425 return logStream;
426 }
427
428 /**
429 * Sets the logStream.
430 * @param logStream The logStream to set
431 */
432 public void setLogStream(PrintStream logStream) {
433 this.logStream = logStream;
434 }
435
436 }
437