/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