View Javadoc

1   // CodeFragment.java, created Jan 25, 2005 5:41:21 PM 2005 by jwhaley
2   // Copyright (C) 2005 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package net.sf.bddbddb;
5   
6   import java.util.Iterator;
7   import java.util.StringTokenizer;
8   import java.io.BufferedWriter;
9   import java.io.File;
10  import java.io.FileWriter;
11  import java.io.FilenameFilter;
12  import java.io.IOException;
13  import java.io.OutputStream;
14  import java.lang.reflect.InvocationTargetException;
15  import java.lang.reflect.Method;
16  import jwutil.io.InputStreamGobbler;
17  import jwutil.io.SystemProperties;
18  import net.sf.javabdd.BDD;
19  
20  /***
21   * CodeFragment
22   * 
23   * @author jwhaley
24   * @version $Id: CodeFragment.java 605 2005-07-12 01:40:35Z cunkel $
25   */
26  public class CodeFragment {
27  
28      static boolean TRACE = false;
29      
30      String fragment;
31      Method method;
32      
33      /***
34       */
35      public CodeFragment(String string, InferenceRule ir) {
36          this.fragment = string;
37          this.method = genMethod(ir);
38          if (this.method == null) throw new IllegalArgumentException();
39      }
40  
41      /***
42       */
43      public CodeFragment(String string, Relation r) {
44          this.fragment = string;
45          this.method = genMethod(r);
46          if (this.method == null) throw new IllegalArgumentException();
47      }
48      
49      /***
50       * Find a place for a temp file in classpath.
51       * 
52       * @return path in classpath that is writable, or null.
53       */
54      public static File findWritablePath() {
55          // Find a place for a temp file in classpath.
56          String cp = SystemProperties.getProperty("java.class.path");
57          StringTokenizer st = new StringTokenizer(cp, SystemProperties.getProperty("path.separator"));
58          while (st.hasMoreTokens()) {
59              String p = st.nextToken();
60              File f = new File(p);
61              if (!f.isDirectory()) continue;
62              if (!f.canWrite()) continue;
63              if (TRACE) System.out.println("Path for code fragment: "+f);
64              return f;
65          }
66          return null;
67      }
68      
69      /***
70       * Search for javac executable.
71       * 
72       * @return path to javac executable, or null
73       */
74      static String searchForJavac(String path, String[] dirs) {
75          String sep = SystemProperties.getProperty("file.separator");
76          for (int i = 0; i < dirs.length; ++i) {
77              File f2 = new File(path+sep+dirs[i]+sep+"bin"+sep+"javac");
78              if (f2.exists()) return f2.getAbsolutePath();
79              f2 = new File(path+sep+dirs[i]+sep+"bin"+sep+"javac.exe");
80              if (f2.exists()) return f2.getAbsolutePath();
81          }
82          return null;
83      }
84      
85      /***
86       * Try to find where javac executable is installed.
87       * 
88       * @return path to javac, or null.
89       */
90      public static String findJavac() {
91          // First, check to see if it is in the normal path.
92          try {
93              Process p = Runtime.getRuntime().exec("javac");
94              new InputStreamGobbler(p.getInputStream(), (OutputStream)null).start();
95              new InputStreamGobbler(p.getErrorStream(), (OutputStream)null).start();
96              int c = p.waitFor();
97              return "javac";
98          } catch (IOException e) {
99          } catch (InterruptedException e) {
100         }
101         try {
102             Process p = Runtime.getRuntime().exec("jikes");
103             new InputStreamGobbler(p.getInputStream(), (OutputStream)null).start();
104             new InputStreamGobbler(p.getErrorStream(), (OutputStream)null).start();
105             int c = p.waitFor();
106             return "jikes";
107         } catch (IOException e) {
108         } catch (InterruptedException e) {
109         }
110         
111         // Try harder.
112         String path = SystemProperties.getProperty("java.home");
113         String sep = SystemProperties.getProperty("file.separator");
114         FilenameFilter filter = new FilenameFilter() {
115             public boolean accept(File dir, String name) {
116                 if (name.startsWith("jdk")) return true;
117                 if (name.startsWith("j2sdk")) return true;
118                 return false;
119             }
120         };
121         // Look relative to "java.home".
122         File f = new File(path+sep+"..");
123         String[] s = f.list(filter);
124         String s2 = searchForJavac(path+sep+"..", s);
125         if (s2 != null) return s2;
126         
127         // Look in the root directory.
128         f = new File(sep);
129         s = f.list(filter);
130         s2 = searchForJavac(sep, s);
131         if (s2 != null) return s2;
132         
133         // Look in some other common places.
134         f = new File("/usr/java/bin/javac");
135         if (f.exists()) return f.getAbsolutePath();
136         f = new File("/usr/java");
137         s = f.list(filter);
138         if (s != null) s2 = searchForJavac("/usr/java", s);
139         if (s2 != null) return s2;
140         
141         // Give up!
142         return null;
143     }
144     
145     Method genMethod(Object o) {
146         File path = findWritablePath();
147         if (path == null) {
148             System.err.println("Cannot find writable directory in class path, skipping code fragment generation.");
149             return null;
150         }
151         String javacName = findJavac();
152         if (javacName == null) {
153             System.err.println("Cannot find java compiler, skipping code fragment generation.");
154             return null;
155         }
156         if (TRACE) System.out.println("Using Java compiler "+javacName);
157         
158         String className;
159         try {
160             // Create temp file.
161             File temp = File.createTempFile("frag", ".java", path);
162             
163             // Delete temp file when program exits.
164             temp.deleteOnExit();
165             
166             // Get class name from file name.
167             className = temp.getName();
168             className = className.substring(0, className.length()-5);
169             if (TRACE) System.out.println("Writing temporary file for code fragment to: "+temp);
170             
171             // Write to temp file
172             BufferedWriter out = new BufferedWriter(new FileWriter(temp));
173             out.write("import net.sf.bddbddb.*;\nimport net.sf.javabdd.*;\n");
174             out.write("import net.sf.bddbddb.dataflow.*;\nimport net.sf.bddbddb.ir.*;\nimport net.sf.bddbddb.order.*;\n\n");
175             out.write("public class ");
176             out.write(className);
177             out.write(" {\n    public static void go(");
178             if (o instanceof BDDInferenceRule) {
179                 BDDInferenceRule ir = (BDDInferenceRule) o;
180                 out.write("BDDInferenceRule rule, BDD val) throws Exception {\n");
181                 out.write("    java.util.List subgoals = rule.getSubgoals();\n");
182                 int k = 0;
183                 for (Iterator i = ir.top.iterator(); i.hasNext(); ) {
184                     RuleTerm rt = (RuleTerm) i.next();
185                     out.write("    RuleTerm subgoal"+k+" = (RuleTerm) subgoals.get("+k+");\n");
186                     out.write("    Relation "+rt.relation.name+" = subgoal"+k+".getRelation();\n");
187                     ++k;
188                 }
189                 out.write("    RuleTerm head = rule.getHead();\n");
190                 out.write("    Relation "+ir.bottom.relation.name+" = head.getRelation();\n");
191             } else {
192                 BDDRelation r = (BDDRelation) o;
193                 out.write("BDDRelation "+r.name+", BDD val) throws Exception {\n");
194             }
195             out.write(fragment);
196             out.write("\n    }\n}\n");
197             out.close();
198             
199             String cp = SystemProperties.getProperty("java.class.path");
200             Process javac = Runtime.getRuntime().exec(
201                 new String[] { javacName, "-source", "1.3", "-target", "1.3",
202                     "-classpath", cp, className+".java" }, null, path);
203             new InputStreamGobbler(javac.getInputStream(), System.out).start();
204             new InputStreamGobbler(javac.getErrorStream(), System.err).start();
205             javac.waitFor();
206             int rc = javac.exitValue();
207             if (rc != 0) {
208                 System.err.println("Error occurred while compiling code fragment: "+rc);
209                 return null;
210             }
211             File classFile = new File(path, className+".class");
212             classFile.deleteOnExit();
213             
214             Class c = Class.forName(className);
215             try {
216                 Class type = (o instanceof BDDInferenceRule) ? BDDInferenceRule.class : BDDRelation.class;
217                 Method method = c.getDeclaredMethod("go", new Class[] { type, BDD.class });
218                 return method;
219             } catch (SecurityException e) {
220                 System.err.println("Security exception occurred while accessing method for code fragment.");
221             } catch (NoSuchMethodException e) {
222                 System.err.println("Cannot find method for code fragment.");
223             }
224         } catch (IOException e) {
225             System.err.println("Error occurred while writing class file for code fragment: "+e);
226         } catch (InterruptedException e) {
227             System.err.println("Error: compilation of code fragment was interrupted.");
228         } catch (ClassNotFoundException e) {
229             System.err.println("Error: cannot find compiled code fragment.");
230         }
231         return null;
232     }
233     
234     /***
235      * @param rule
236      * @param oldValue
237      */
238     public void invoke(InferenceRule rule, BDD oldValue) {
239         if (method == null) return;
240         try {
241             method.invoke(null, new Object[] { rule, oldValue });
242         } catch (IllegalArgumentException e) {
243             // TODO Auto-generated catch block
244             e.printStackTrace();
245         } catch (IllegalAccessException e) {
246             // TODO Auto-generated catch block
247             e.printStackTrace();
248         } catch (InvocationTargetException e) {
249             // TODO Auto-generated catch block
250             if (e.getCause() instanceof RuntimeException) {
251                 throw (RuntimeException) e.getCause();
252             }
253             e.printStackTrace();
254         }
255     }
256     
257     /***
258      * @param r
259      * @param oldValue
260      */
261     public void invoke(Relation r, BDD oldValue) {
262         if (method == null) return;
263         try {
264             method.invoke(null, new Object[] { r, oldValue });
265         } catch (IllegalArgumentException e) {
266             // TODO Auto-generated catch block
267             e.printStackTrace();
268         } catch (IllegalAccessException e) {
269             // TODO Auto-generated catch block
270             e.printStackTrace();
271         } catch (InvocationTargetException e) {
272             // TODO Auto-generated catch block
273             if (e.getCause() instanceof RuntimeException) {
274                 throw (RuntimeException) e.getCause();
275             }
276             e.printStackTrace();
277         }
278     }
279 }