KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.InputStream JavaDoc;
36 import java.net.MalformedURLException JavaDoc;
37 import java.net.URL JavaDoc;
38 import java.net.URLClassLoader JavaDoc;
39 import java.util.ArrayList JavaDoc;
40 import java.util.HashMap JavaDoc;
41
42 import org.jibx.binding.classes.BoundClass;
43 import org.jibx.binding.classes.ClassCache;
44 import org.jibx.binding.classes.ClassFile;
45 import org.jibx.binding.classes.MungedClass;
46 import org.jibx.binding.def.BindingDefinition;
47 import org.jibx.runtime.JiBXException;
48
49 /**
50  * Binding classloader. This is intended to substitute for the System
51  * classloader (i.e., the one used for loading user classes). It first processes
52  * one or more binding definitions, caching the binary classes modified by the
53  * bindings. It then uses these modified forms of the classes when they're
54  * requested for loading.
55  *
56  * @author Dennis M. Sosnoski
57  * @version 1.0
58  */

59  
60 public class Loader extends URLClassLoader JavaDoc
61 {
62     /** Binding definitions used by loader. */
63     private ArrayList JavaDoc m_bindings;
64     
65     /** Flag for bindings compiled into class code. */
66     private boolean m_isBound;
67     
68     /** Map of classes modified by binding. */
69     private HashMap JavaDoc m_classMap;
70     
71     /**
72      * Constructor with classpath URLs and parent classloader supplied. Sets up
73      * the paths for both actual classloading and finding classes to be bound.
74      *
75      * @param paths array of classpath URLs
76      * @param parent classloader used for delegation loading
77      */

78     public Loader(URL JavaDoc[] paths, ClassLoader JavaDoc parent) {
79         
80         // configure the base class
81
super(paths, parent);
82         m_bindings = new ArrayList JavaDoc();
83         m_classMap = new HashMap JavaDoc();
84         
85         // find all the file URLs in path
86
ArrayList JavaDoc fpaths = new ArrayList JavaDoc(paths.length);
87         for (int i = 0; i < paths.length; i++) {
88             URL JavaDoc path = paths[i];
89             if ("file".equals(path.getProtocol())) {
90                 fpaths.add(path.getPath());
91             }
92         }
93         
94         // set paths to be used for loading referenced classes
95
String JavaDoc[] dirs = (String JavaDoc[])fpaths.toArray(new String JavaDoc[0]);
96         ClassCache.setPaths(dirs);
97         ClassFile.setPaths(dirs);
98             
99         // reset static information accumulation for binding
100
BoundClass.reset();
101         MungedClass.reset();
102         BindingDefinition.reset();
103     }
104     
105     /**
106      * Constructor with classpath URLs supplied. This uses the supplied
107      * classpaths, delegating directly to the parent classloader of the normal
108      * System classloader.
109      *
110      * @param paths array of classpath URLs
111      */

112     public Loader(URL JavaDoc[] paths) {
113         this(paths, ClassLoader.getSystemClassLoader().getParent());
114     }
115     
116     /**
117      * Default constructor. This reads the standard class path and uses it for
118      * locating classes used by the binding, delegating directly to the parent
119      * classloader of the normal System classloader.
120      *
121      * @exception MalformedURLException on error in classpath URLs
122      */

123     public Loader() throws MalformedURLException JavaDoc {
124         this(getClassPaths());
125     }
126     
127     /**
128      * Reset loader information. This discards all prior bindings and clears the
129      * internal state in preparation for loading a different set of bindings. It
130      * is not possible to clear the loaded classes, though, so any new bindings
131      * must refer to different classes from those previously loaded.
132      */

133     public void reset() {
134         m_bindings.clear();
135         m_classMap.clear();
136         m_isBound = false;
137         BoundClass.reset();
138         MungedClass.reset();
139         BindingDefinition.reset();
140     }
141     
142     /**
143      * Method builds an array of URL for items in the class path.
144      *
145      * @return array of classpath URLs
146      */

147     public static URL JavaDoc[] getClassPaths() throws MalformedURLException JavaDoc {
148         String JavaDoc[] paths = Utility.getClassPaths();
149         URL JavaDoc[] urls = new URL JavaDoc[paths.length];
150         for (int i = 0; i < urls.length; i++) {
151             urls[i] = new File JavaDoc(paths[i]).toURL();
152         }
153         return urls;
154     }
155     
156     /**
157      * Load binding definition. This may be called multiple times to load
158      * multiple bindings, but only prior to the bindings being compiled. The
159      * reader form of the call is generally preferred, since the document
160      * encoding may not be properly interpreted from a stream.
161      *
162      * @param fname binding definition full name
163      * @param sname short form of name to use as the default name of the binding
164      * @param is input stream for binding definition document
165      * @param url URL for binding definition (<code>null</code> if not
166      * available)
167      * @exception IllegalStateException if called after bindings have been
168      * compiled
169      * @exception IOException if error reading the binding
170      * @exception JiBXException if error in processing the binding definition
171      */

172     public void loadBinding(String JavaDoc fname, String JavaDoc sname, InputStream JavaDoc is, URL JavaDoc url)
173         throws JiBXException, IOException JavaDoc {
174         
175         // error if called after bindings have been compiled
176
if (m_isBound) {
177             throw new IllegalStateException JavaDoc
178                 ("Call not allowed after bindings compiled");
179         } else {
180             m_bindings.add(Utility.loadBinding(fname, sname, is, url, true));
181         }
182     }
183     
184     /**
185      * Load binding definition from file path. This may be called multiple times
186      * to load multiple bindings, but only prior to the bindings being compiled.
187      *
188      * @param path binding definition file path
189      * @exception IllegalStateException if called after bindings have been
190      * compiled
191      * @exception IOException if error reading the file
192      * @exception JiBXException if error in processing the binding definition
193      */

194     public void loadFileBinding(String JavaDoc path) throws JiBXException, IOException JavaDoc {
195     
196         // error if called after bindings have been compiled
197
if (m_isBound) {
198             throw new IllegalStateException JavaDoc
199                 ("Call not allowed after bindings compiled");
200         } else {
201             m_bindings.add(Utility.loadFileBinding(path, true));
202         }
203     }
204     
205     /**
206      * Load binding definition from file path. This may be called multiple times
207      * to load multiple bindings, but only prior to the bindings being compiled.
208      *
209      * @param path binding definition file path
210      * @exception IllegalStateException if called after bindings have been
211      * compiled
212      * @exception IOException if error reading the file
213      * @exception JiBXException if error in processing the binding definition
214      */

215     public void loadResourceBinding(String JavaDoc path)
216         throws JiBXException, IOException JavaDoc {
217     
218         // error if called after bindings have been compiled
219
if (m_isBound) {
220             throw new IllegalStateException JavaDoc
221                 ("Call not allowed after bindings compiled");
222         } else {
223             String JavaDoc fname = path;
224             int split = fname.lastIndexOf('/');
225             if (split >= 0) {
226                 fname = fname.substring(split+1);
227             }
228             String JavaDoc sname = fname;
229             split = sname.lastIndexOf('.');
230             if (split >= 0) {
231                 sname = sname.substring(0, split);
232             }
233             sname = Utility.convertName(sname);
234             InputStream JavaDoc is = getResourceAsStream(path);
235             if (is == null) {
236                 throw new IOException JavaDoc("Resource " + path + " not found");
237             } else {
238                 loadBinding(fname, sname, is, null);
239             }
240         }
241     }
242     
243     /**
244      * Process the binding definitions. This compiles the bindings into the
245      * classes, saving the modified classes for loading when needed.
246      *
247      * @exception JiBXException if error in processing the binding definition
248      */

249     public void processBindings() throws JiBXException {
250         if (!m_isBound) {
251             
252             // handle code generation from bindings
253
int count = m_bindings.size();
254             for (int i = 0; i < count; i++) {
255                 BindingDefinition binding =
256                     (BindingDefinition)m_bindings.get(i);
257                 binding.generateCode(false);
258             }
259             
260             // build hashmap of modified classes
261
ClassFile[][] lists = MungedClass.fixChanges(false);
262             count = lists[0].length;
263             for (int i = 0; i < count; i++) {
264                 ClassFile clas = lists[0][i];
265                 m_classMap.put(clas.getName(), clas);
266             }
267             
268             // finish by setting flag for binding done
269
m_isBound = true;
270         }
271     }
272     
273     /**
274      * Find and load class by name. If the named class has been modified by a
275      * binding this loads the modified binary class; otherwise, it just uses the
276      * base class implementation to do the loading. If bindings haven't been
277      * compiled prior to this call they will be compiled automatically when this
278      * method is called.
279      * @see java.lang.ClassLoader#findClass(java.lang.String)
280      *
281      * @param name fully qualified package and class name to be found
282      * @return the loaded class
283      * @throws ClassNotFoundException if the class cannot be found
284      */

285     protected Class JavaDoc findClass(String JavaDoc name) throws ClassNotFoundException JavaDoc {
286         
287         // first complete binding processing if not already done
288
if (!m_isBound) {
289             try {
290                 processBindings();
291             } catch (JiBXException e) {
292                 e.printStackTrace();
293             }
294         }
295         
296         // check if class has been modified by binding
297
ClassFile clas = (ClassFile)m_classMap.get(name);
298         if (clas != null) {
299             try {
300                 
301                 // convert class information to byte array
302
ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
303                 clas.writeFile(bos);
304                 byte[] bytes = bos.toByteArray();
305                 return defineClass(name, bytes, 0, bytes.length);
306                 
307             } catch (IOException JavaDoc e) {
308                 throw new ClassNotFoundException JavaDoc
309                     ("Unable to load modified class " + name);
310             }
311         } else {
312             
313             // just use base class handling
314
return super.findClass(name);
315             
316         }
317     }
318 }
Popular Tags