KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > Compile


1 /*
2 Copyright (c) 2003-2005, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29
30 package org.jibx.binding;
31
32 import java.io.ByteArrayOutputStream JavaDoc;
33 import java.io.File JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.net.URL JavaDoc;
36 import java.net.URLClassLoader JavaDoc;
37
38 import org.apache.bcel.classfile.Method;
39 import org.apache.bcel.verifier.VerificationResult;
40 import org.apache.bcel.verifier.Verifier;
41 import org.apache.bcel.verifier.VerifierFactory;
42 import org.jibx.binding.classes.BoundClass;
43 import org.jibx.binding.classes.BranchWrapper;
44 import org.jibx.binding.classes.ClassCache;
45 import org.jibx.binding.classes.ClassFile;
46 import org.jibx.binding.classes.MungedClass;
47 import org.jibx.binding.def.BindingDefinition;
48 import org.jibx.runtime.JiBXException;
49
50 /**
51  * Binding compiler. This version checks the modified and generated classes
52  * by loading them and listing method information.
53  *
54  * @author Dennis M. Sosnoski
55  * @version 1.0
56  */

57  
58 public class Compile
59 {
60     private boolean m_verbose;
61     private boolean m_load;
62     private boolean m_verify;
63     private boolean m_trackBranches;
64     private boolean m_errorOverride;
65     private boolean m_skipValidate;
66     
67     /**
68      * Default constructor. This just initializes all options disabled.
69      */

70
71     public Compile() {}
72     
73     /**
74      * Constructor with settings specified.
75      *
76      * @param verbose report binding details and results
77      * @param load test load modified classes to validate
78      * @param verify use BCEL validation of modified classes
79      * @param track keep tracking information for source of branch generation
80      * @param over override code generation error handling
81      */

82     public Compile(boolean verbose, boolean load, boolean verify,
83         boolean track, boolean over) {
84         m_verbose = verbose;
85         m_load = load;
86         m_verify = verify;
87         m_trackBranches = track;
88         m_errorOverride = over;
89     }
90     
91     /**
92      * Verify generated and modified files using BCEL verifier. This provides a
93      * more comprehensive listing of errors than just loading a class in the
94      * JVM.
95      *
96      * @param file information for class to be verified
97      * @return <code>true</code> if successfully verified, <code>false</code> if
98      * problem found (automatically reported)
99      */

100     private boolean verifyBCEL(ClassFile file) {
101         try {
102             
103             // construct verifier for class file
104
Verifier verifier = VerifierFactory.getVerifier(file.getName());
105             
106             // run validation in stages with error handling for each stage
107
boolean verified = false;
108             VerificationResult vr = verifier.doPass1();
109             if (vr.getStatus() == VerificationResult.VERIFIED_OK) {
110                 vr = verifier.doPass2();
111                 if (vr.getStatus() == VerificationResult.VERIFIED_OK) {
112                     Method[] methods = file.getRawClass().getMethods();
113                     for (int j = 0; j < methods.length; j++) {
114                         vr = verifier.doPass3a(j);
115                         if (vr.getStatus() == VerificationResult.VERIFIED_OK) {
116                             vr = verifier.doPass3b(j);
117                         }
118                         if (vr.getStatus() == VerificationResult.VERIFIED_OK) {
119                             verified = true;
120                         } else {
121                             System.out.println
122                                 ("Verification failure on method " +
123                                 methods[j].getName() + " of class " +
124                                 file.getName() + ":");
125                             System.out.println(" " + vr.toString());
126                         }
127                     }
128                 } else {
129                     System.out.println("Verification failure on class " +
130                         file.getName() + ":");
131                     System.out.println(" " + vr.toString());
132                 }
133             } else {
134                 System.out.println("Verification failure on class " +
135                     file.getName() + ":");
136                 System.out.println(" " + vr.toString());
137             }
138             return verified;
139             
140         } catch (Exception JavaDoc ex) { // catch BCEL errors
141
System.out.println("BCEL failure:");
142             ex.printStackTrace();
143             return false;
144         }
145     }
146     
147     /**
148      * Output all generated and modified class files. Writes the actual files,
149      * and optionally verifies and/or reports the changes.
150      *
151      * @param list of paths used for loading files
152      * @exception JiBXException if error in processing the binding definition
153      * @exception IOException if path cannot be accessed
154      */

155     private void handleOutput(String JavaDoc[] paths)
156         throws JiBXException, IOException JavaDoc {
157         
158         // output the modified class files
159
ClassFile[][] lists = MungedClass.fixChanges(true);
160         
161         // report modified file results to user
162
ClassFile[] files = lists[0];
163         if (m_verbose) {
164             System.out.println("\nWrote " + files.length + " files");
165         }
166         if (m_verbose || m_load) {
167             
168             // generate class paths as URLs if needed for test loading
169
URL JavaDoc[] urls = null;
170             if (m_load) {
171                 urls = new URL JavaDoc[paths.length];
172                 for (int i = 0; i < urls.length; i++) {
173                     urls[i] = new File JavaDoc(paths[i]).toURL();
174                 }
175             }
176             for (int i = 0; i < files.length; i++) {
177                 
178                 // write class file to bytes
179
ClassFile file = files[i];
180                 ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
181                 file.writeFile(bos);
182                 byte[] bytes = bos.toByteArray();
183                 if(m_verbose){
184                     System.out.println("\n " + file.getName() +
185                         " output file size is " + bytes.length + " bytes");
186                 }
187                 
188                 // verify using BCEL verifier
189
if (m_verify) {
190                     verifyBCEL(file);
191                 }
192                 
193                 // load to JVM and list method information from class
194
if (m_load) {
195                     DirectLoader cloader = new DirectLoader(urls);
196                     Class JavaDoc clas = cloader.load(file.getName(), bytes);
197                     if (m_verbose) {
198                         java.lang.reflect.Method JavaDoc[] methods =
199                             clas.getDeclaredMethods();
200                         System.out.println(" Found " + methods.length +
201                             " methods:");
202                         for (int j = 0; j < methods.length; j++) {
203                             java.lang.reflect.Method JavaDoc method = methods[j];
204                             System.out.println(" " +
205                                 method.getReturnType().getName() + " " +
206                                 method.getName());
207                         }
208                     }
209                 }
210             }
211         }
212         
213         // report summary information for files unchanged or deleted
214
if (m_verbose) {
215             files = lists[1];
216             System.out.println("\nKept " + files.length + " files unchanged:");
217             for (int i = 0; i < files.length; i++) {
218                 System.out.println(" " + files[i].getName());
219             }
220             files = lists[2];
221             System.out.println("\nDeleted " + files.length + " files:");
222             for (int i = 0; i < files.length; i++) {
223                 System.out.println(" " + files[i].getName());
224             }
225         }
226     }
227
228     /**
229      * Set control flag for test loading generated/modified classes.
230      *
231      * @param load test load generated/modified classes flag
232      */

233     public void setLoad(boolean load) {
234         m_load = load;
235     }
236
237     /**
238      * Set control flag for verbose processing reports.
239      *
240      * @param verbose report verbose information in processing bindings flag
241      */

242     public void setVerbose(boolean verbose) {
243         m_verbose = verbose;
244     }
245
246     /**
247      * Set control flag for verifying generated/modified classes with BCEL.
248      *
249      * @param verify use BCEL verification for generated/modified classes flag
250      */

251     public void setVerify(boolean verify) {
252         m_verify = verify;
253     }
254
255     /**
256      * Set control flag for test loading generated/modified classes.
257      *
258      * @param load test load generated/modified classes flag
259      */

260     public void setSkipValidate(boolean skip) {
261         m_skipValidate = skip;
262     }
263     
264     /**
265      * Compile a set of bindings using supplied classpaths.
266      *
267      * @param paths list of paths for loading classes
268      * @param files list of binding definition files
269      * @exception JiBXException if error in processing the binding definition
270      */

271     public void compile(String JavaDoc[] paths, String JavaDoc[] files) throws JiBXException {
272         try {
273             
274             // include current version information in verbose output
275
if (m_verbose) {
276                 System.out.println("Running binding compiler version " +
277                     BindingDefinition.CURRENT_VERSION_NAME);
278             }
279             
280             // set paths to be used for loading referenced classes
281
ClassCache.setPaths(paths);
282             ClassFile.setPaths(paths);
283             
284             // reset static information accumulation for binding
285
BoundClass.reset();
286             MungedClass.reset();
287             BindingDefinition.reset();
288             BranchWrapper.setTracking(m_trackBranches);
289             BranchWrapper.setErrorOverride(m_errorOverride);
290             
291             // load all supplied bindings
292
BindingDefinition[] defs = new BindingDefinition[files.length];
293             for (int i = 0; i < files.length; i++) {
294                 defs[i] = Utility.loadFileBinding(files[i], !m_skipValidate);
295                 if (m_verbose) {
296                     defs[i].print();
297                 }
298             }
299             
300             // modify the class files with JiBX hooks
301
for (int i = 0; i < defs.length; i++) {
302                 try {
303                     defs[i].generateCode(m_verbose);
304                 } catch (RuntimeException JavaDoc e) {
305                     throw new JiBXException
306                         ("\n*** Error during code generation - please report " +
307                         "this error on the JiBX users list so that the " +
308                         "condition can be caught during validation ***\n", e);
309                 }
310             }
311             
312             // handle file and reporting output
313
handleOutput(paths);
314             
315         } catch (IOException JavaDoc ex) {
316             throw new JiBXException("IOException in compile", ex);
317         } catch (ExceptionInInitializerError JavaDoc ex) {
318             throw new JiBXException("Error during initialization;" +
319                 " is jibx-run.jar in load classpath?", ex.getException());
320         } catch (Throwable JavaDoc ex) {
321             throw new JiBXException("Error running binding compiler", ex);
322         }
323     }
324     
325     /**
326      * Main method for running compiler as application.
327      *
328      * @param args command line arguments
329      */

330     public static void main(String JavaDoc[] args) {
331         if (args.length > 0) {
332             try {
333                 
334                 // check for various flags set
335
boolean verbose = false;
336                 boolean load = false;
337                 boolean verify = false;
338                 boolean track = false;
339                 boolean over = false;
340                 boolean skip = false;
341                 int offset = 0;
342                 for (; offset < 5 && offset < args.length; offset++) {
343                     String JavaDoc arg = args[offset];
344                     if ("-v".equalsIgnoreCase(arg)) {
345                         verbose = true;
346                     } else if ("-l".equalsIgnoreCase(arg)) {
347                         load = true;
348                     } else if ("-b".equalsIgnoreCase(arg)) {
349                         verify = true;
350                     } else if ("-o".equalsIgnoreCase(arg)) {
351                         over = true;
352                     } else if ("-s".equalsIgnoreCase(arg)) {
353                         skip = true;
354                     } else if ("-t".equalsIgnoreCase(arg)) {
355                         track = true;
356                     } else {
357                         break;
358                     }
359                 }
360                 
361                 // set up path and binding lists
362
String JavaDoc[] clsspths = Utility.getClassPaths();
363                 String JavaDoc[] bindings = new String JavaDoc[args.length - offset];
364                 System.arraycopy(args, offset, bindings, 0, bindings.length);
365                 
366                 // report on the configuration
367
if (verbose) {
368                     System.out.println("Using paths:");
369                     for (int i = 0; i < clsspths.length; i++) {
370                         System.out.println(" " + clsspths[i]);
371                     }
372                     System.out.println("Using bindings:");
373                     for (int i = 0; i < bindings.length; i++) {
374                         System.out.println(" " + bindings[i]);
375                     }
376                 }
377                 
378                 // compile the bindings
379
Compile compiler =
380                     new Compile(verbose, load, verify, track, over);
381                 compiler.setSkipValidate(skip);
382                 compiler.compile(clsspths, bindings);
383                 
384             } catch (JiBXException ex) {
385                 ex.printStackTrace(System.out);
386                 System.exit(1);
387             }
388             
389         } else {
390             System.out.println
391                 ("\nUsage: java org.jibx.binding.Compile [-b] [-l] [-v] " +
392                 "binding1 binding2 ...\nwhere:\n -b turns on BCEL " +
393                 "verification (debug option),\n -l turns on test loading of " +
394                 "modified or generated classes for validation, and\n" +
395                 " -v turns on verbose output\nThe bindingn files are " +
396                 "different bindings to be compiled.\n");
397             System.exit(1);
398         }
399     }
400     
401     /**
402      * Direct class loader. This is optionally used for test loading the
403      * modified class files to make sure they're still valid.
404      */

405     private static class DirectLoader extends URLClassLoader JavaDoc
406     {
407         protected DirectLoader(URL JavaDoc[] urls) {
408             super(urls, DirectLoader.class.getClassLoader());
409         }
410         
411         protected Class JavaDoc load(String JavaDoc name, byte[] data) {
412             return defineClass(name, data, 0, data.length);
413         }
414     }
415 }
Popular Tags