KickJava   Java API By Example, From Geeks To Geeks.

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


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.ByteArrayInputStream JavaDoc;
33 import java.io.ByteArrayOutputStream JavaDoc;
34 import java.io.File JavaDoc;
35 import java.io.FileInputStream JavaDoc;
36 import java.io.FileNotFoundException JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.io.InputStream JavaDoc;
39 import java.net.URL JavaDoc;
40 import java.util.ArrayList JavaDoc;
41 import java.util.jar.Attributes JavaDoc;
42 import java.util.jar.JarFile JavaDoc;
43 import java.util.jar.Manifest JavaDoc;
44
45 import org.jibx.binding.classes.BoundClass;
46 import org.jibx.binding.classes.ClassFile;
47 import org.jibx.binding.def.BindingBuilder;
48 import org.jibx.binding.def.BindingDefinition;
49 import org.jibx.binding.def.MappingBase;
50 import org.jibx.binding.model.BindingElement;
51 import org.jibx.binding.model.MappingElement;
52 import org.jibx.binding.model.ValidationContext;
53 import org.jibx.runtime.JiBXException;
54 import org.jibx.runtime.impl.UnmarshallingContext;
55
56 /**
57  * Binding compiler support class. Supplies common methods for use in compiling
58  * binding definitions.
59  *
60  * @author Dennis M. Sosnoski
61  * @version 1.0
62  */

63  
64 public class Utility
65 {
66     // buffer size for copying stream input
67
private static final int COPY_BUFFER_SIZE = 1024;
68     
69     // private constructor to prevent any instance creation
70
private Utility() {}
71
72     /**
73      * Read contents of stream into byte array.
74      *
75      * @param is input stream to be read
76      * @return array of bytes containing all data from stream
77      * @throws IOException on stream access error
78      */

79     private static byte[] getStreamData(InputStream JavaDoc is) throws IOException JavaDoc {
80         byte[] buff = new byte[COPY_BUFFER_SIZE];
81         ByteArrayOutputStream JavaDoc os = new ByteArrayOutputStream JavaDoc();
82         int count;
83         while ((count = is.read(buff)) >= 0) {
84             os.write(buff, 0, count);
85         }
86         return os.toByteArray();
87     }
88     
89     /**
90      * Recurse through jar file path component, adding all jars referenced from
91      * the original jar to the path collection. Silently ignores problems
92      * loading jar files.
93      *
94      * @param path jar path component
95      * @param paths set of paths processed (added to by call)
96      */

97     private static void recursePathJars(String JavaDoc path, ArrayList JavaDoc paths) {
98         try {
99             
100             // check class path information in jar file
101
JarFile JavaDoc jfile = new JarFile JavaDoc(path, false);
102             Manifest JavaDoc mfst = jfile.getManifest();
103             if (mfst != null) {
104                 
105                 // look for class path information from manifest
106
Attributes JavaDoc attrs = mfst.getMainAttributes();
107                 String JavaDoc cpath = (String JavaDoc)attrs.get(Attributes.Name.CLASS_PATH);
108                 if (cpath != null) {
109                 
110                     // set base path for all relative references
111
int split = path.lastIndexOf(File.separatorChar);
112                     String JavaDoc base = (split >= 0) ?
113                         path.substring(0, split+1) : "";
114                 
115                     // process all references in jar class path
116
while (cpath != null) {
117                         split = cpath.indexOf(' ');
118                         String JavaDoc item;
119                         if (split >= 0) {
120                             item = cpath.substring(0, split);
121                             cpath = cpath.substring(split+1).trim();
122                         } else {
123                             item = cpath;
124                             cpath = null;
125                         }
126                         String JavaDoc ipath = base + item;
127                         if (!paths.contains(ipath)) {
128                             paths.add(ipath);
129                             split = ipath.lastIndexOf('.');
130                             if (split >= 0 && "jar".equalsIgnoreCase
131                                 (ipath.substring(split+1))) {
132                                 recursePathJars(ipath, paths);
133                             }
134                         }
135                     }
136                 }
137             }
138         } catch (IOException JavaDoc ex) { /* silently ignore problems in loading */ }
139     }
140     
141     /**
142      * Method builds a string array of items in the class path.
143      *
144      * @return array of classpath components
145      */

146     public static String JavaDoc[] getClassPaths() {
147         
148         // get all class path components
149
String JavaDoc path = System.getProperty("java.class.path");
150         ArrayList JavaDoc paths = new ArrayList JavaDoc();
151         int start = 0;
152         int mark;
153         while (path != null) {
154             mark = path.indexOf(File.pathSeparatorChar, start);
155             String JavaDoc item;
156             if (mark >= 0) {
157                 item = path.substring(start, mark);
158             } else {
159                 item = path.substring(start);
160                 path = null;
161             }
162             if (!paths.contains(item)) {
163                 paths.add(item);
164                 int split = item.lastIndexOf('.');
165                 if (split >= 0 &&
166                     "jar".equalsIgnoreCase(item.substring(split+1))) {
167                     recursePathJars(item, paths);
168                 }
169             }
170             start = mark + 1;
171         }
172         paths.add(".");
173         String JavaDoc[] clsspths = new String JavaDoc[paths.size()];
174         paths.toArray(clsspths);
175         return clsspths;
176     }
177     
178     /**
179      * Generate binding name. This takes a base name (such as a file name with
180      * extension stripped off) and converts it to legal form by substituting '_'
181      * characters for illegal characters in the base name.
182      *
183      * @param name base binding name
184      * @return converted binding name
185      */

186     public static String JavaDoc convertName(String JavaDoc name) {
187         
188         // convert name to use only legal characters
189
StringBuffer JavaDoc buff = new StringBuffer JavaDoc(name);
190         if (!Character.isJavaIdentifierStart(buff.charAt(0))) {
191             buff.insert(0, 'X');
192         }
193         for (int i = 1; i < buff.length(); i++) {
194             if (!Character.isJavaIdentifierPart(buff.charAt(i))) {
195                 buff.setCharAt(i, '_');
196             }
197         }
198         return buff.toString();
199     }
200     
201     /**
202      * Extract base file name from a full path.
203      *
204      * @param path full file path
205      * @return file name component from path
206      */

207     public static String JavaDoc fileName(String JavaDoc path) {
208         int split = path.lastIndexOf(File.separatorChar);
209         return path.substring(split+1);
210     }
211     
212     /**
213      * Validate binding definition. If issues are found in the binding the
214      * issues are printed directly to the console.
215      *
216      * @param name identifier for binding definition
217      * @param url URL for binding definition (<code>null</code> if not
218      * available)
219      * @param is input stream for reading binding definition
220      * @return root element of binding model if binding is valid,
221      * <code>null</code> if one or more errors in binding
222      */

223     public static BindingElement validateBinding(String JavaDoc name, URL JavaDoc url,
224         InputStream JavaDoc is) {
225         try {
226             ValidationContext vctx = BindingElement.newValidationContext();
227             BindingElement root =
228                 BindingElement.validateBinding(name, url, is, vctx);
229             if (vctx.getErrorCount() == 0 && vctx.getFatalCount() == 0) {
230                 return root;
231             }
232         } catch (JiBXException ex) {
233             System.err.println("Unable to process binding " + name);
234             ex.printStackTrace();
235         }
236         return null;
237     }
238     
239     /**
240      * Load validated binding definition. This first reads the input stream into
241      * a memory buffer, then parses the data once for validation and a second
242      * time for the actual binding definition construction. If any errors are
243      * found in the binding definition validation the construction is skipped
244      * and an exception is thrown.
245      *
246      * @param fname binding definition full name
247      * @param sname short form of name to use as the default name of the binding
248      * @param istrm input stream for binding definition document
249      * @param url URL for binding definition (<code>null</code> if not
250      * available)
251      * @param test validate binding flag
252      * @return constructed binding definition
253      * @exception FileNotFoundException if path cannot be accessed
254      * @exception JiBXException if error in processing the binding definition
255      */

256     public static BindingDefinition loadBinding(String JavaDoc fname, String JavaDoc sname,
257         InputStream JavaDoc istrm, URL JavaDoc url, boolean test)
258         throws JiBXException, IOException JavaDoc {
259         
260         // read stream into memory buffer
261
byte[] data = getStreamData(istrm);
262         
263         // validate using binding object model
264
boolean valid = true;
265         ClassFile cf = null;
266         String JavaDoc tpack = null;
267         if (test) {
268             BindingElement root = validateBinding(fname, url,
269                 new ByteArrayInputStream JavaDoc(data));
270             if (root == null) {
271                 valid = false;
272             } else {
273                 
274                 // find package of first mapping to use for added classes
275
ArrayList JavaDoc childs = root.topChildren();
276                 if (childs != null) {
277                     
278                     // set up package information from mapped class
279
for (int i = 0; i < childs.size(); i++) {
280                         Object JavaDoc child = childs.get(i);
281                         if (child instanceof MappingElement) {
282                             
283                             // end scan if a real mapping is found
284
MappingElement map = (MappingElement)child;
285                             cf = map.getHandledClass().getClassFile();
286                             if (!cf.isInterface() && cf.isModifiable()) {
287                                 break;
288                             }
289                         }
290                     }
291                 }
292                 tpack = root.getTargetPackage();
293                 if (tpack == null && cf != null) {
294                     tpack = cf.getPackage();
295                 }
296             }
297         }
298         if (valid) {
299             try {
300                 // construct the binding definition code generator
301
UnmarshallingContext uctx = new UnmarshallingContext(0,
302                     new String JavaDoc[0], new String JavaDoc[0], new String JavaDoc[0], new String JavaDoc[0]);
303                 uctx.setDocument(new ByteArrayInputStream JavaDoc(data), fname, null);
304                 if (cf != null) {
305                     
306                     // set target root and package for created classes
307
BoundClass.setModify(cf.getRoot(), tpack);
308                 }
309                 BindingDefinition bdef =
310                     BindingBuilder.unmarshalBindingDefinition(uctx, sname, url);
311                 
312                 // set package and class if not validated
313
if (!test) {
314                     
315                     // a kludge, but needed to support skipping validation
316
ArrayList JavaDoc maps = bdef.getDefinitionContext().getMappings();
317                     if (maps != null) {
318                         
319                         // set up package information from mapped class
320
for (int i = 0; i < maps.size(); i++) {
321                             Object JavaDoc child = maps.get(i);
322                             if (child instanceof MappingBase) {
323                                 
324                                 // end scan if a real mapping is found
325
MappingBase mapbase = (MappingBase)child;
326                                 cf = mapbase.getBoundClass().getMungedFile();
327                                 if (mapbase.getBoundClass().isDirectAccess()) {
328                                     break;
329                                 }
330                                 
331                             }
332                         }
333                     }
334                 }
335                 
336                 // set up binding root based on first mapping
337
if (cf == null) {
338                     throw new JiBXException("One or more <mapping> elements " +
339                         "must be defined in <binding>");
340                 } else {
341                     
342                     // get package to be used for binding classes
343
if (tpack == null) {
344                         tpack = bdef.getDefaultPackage();
345                         if (tpack == null) {
346                             tpack = cf.getPackage();
347                         }
348                     }
349                     bdef.setFactoryLocation(tpack, cf.getRoot());
350                     return bdef;
351                 }
352                 
353             } catch (JiBXException e) {
354                 throw new JiBXException
355                     ("\n*** Error during code generation - please report " +
356                     "this error on the JiBX users list so that the condition " +
357                     "can be caught during validation ***\n", e);
358             }
359             
360         } else {
361             throw new JiBXException("Binding " + fname +
362                 " is unusable because of validation errors");
363         }
364     }
365     
366     /**
367      * Load binding definition from file.
368      *
369      * @param path file path for binding definition
370      * @param valid validate binding flag
371      * @return constructed binding definition
372      * @exception IOException if error accessing file
373      * @exception JiBXException if error in processing the binding definition
374      */

375     public static BindingDefinition loadFileBinding(String JavaDoc path, boolean valid)
376         throws JiBXException, IOException JavaDoc {
377         
378         // extract basic name of binding file from path
379
String JavaDoc fname = fileName(path);
380         String JavaDoc sname = fname;
381         int split = sname.indexOf('.');
382         if (split > 0) {
383             sname = sname.substring(0, split);
384         }
385         sname = convertName(sname);
386         
387         // construct and return the binding definition
388
File JavaDoc file = new File JavaDoc(path);
389         return loadBinding(fname, sname, new FileInputStream JavaDoc(file),
390             new URL JavaDoc("file://" + file.getAbsolutePath()), valid);
391     }
392 }
Popular Tags