]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/loader/RefJxtaLoader.java
4683499835e226e6b99dbced17d68302909989eb
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / impl / src / net / jxta / impl / loader / RefJxtaLoader.java
1 /*
2  * Copyright (c) 2001-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56 package net.jxta.impl.loader;
57
58 import net.jxta.document.MimeMediaType;
59 import net.jxta.document.StructuredDocument;
60 import net.jxta.document.StructuredDocumentFactory;
61 import net.jxta.impl.peergroup.CompatibilityEquater;
62 import net.jxta.platform.JxtaLoader;
63 import net.jxta.platform.ModuleSpecID;
64 import net.jxta.protocol.ModuleImplAdvertisement;
65
66 import java.io.IOException;
67 import java.io.StringReader;
68 import java.net.MalformedURLException;
69 import java.net.URL;
70 import java.util.HashMap;
71 import java.util.Map;
72 import java.util.WeakHashMap;
73 import java.util.logging.Level;
74 import java.util.logging.Logger;
75 import net.jxta.logging.Logging;
76 import net.jxta.platform.Module;
77
78
79 /**
80  * This class is the reference implementation of the JxtaLoader.
81  */
82 public class RefJxtaLoader extends JxtaLoader {
83
84     /**
85      * Logger
86      */
87     private final static transient Logger LOG = Logger.getLogger(RefJxtaLoader.class.getName());
88
89     /**
90      * The equator we will use to determine if compatibility statements are
91      * compatible with this JXTA implementation.
92      */
93     private final CompatibilityEquater equator;
94
95     /**
96      * <ul>
97      *     <li>Keys are {@link net.jxta.platform.ModuleSpecID}.</li>
98      *     <li>Values are {@link java.util.Map}.
99      *         <ul>
100      *             <li>Keys are {@link java.lang.String} Compatibility Statements serialized as XML UTF-8</li>
101      *             <li>Values are {@link java.lang.Class}<? extends Module>.</li>
102      *         </ul>
103      *     </li>
104      * </ul>
105      */
106     private final Map<ModuleSpecID, Map<String, Class<? extends Module>>> classes = new HashMap<ModuleSpecID, Map<String, Class<? extends Module>>>();
107
108     /**
109      * Classes and ImplAdvs we have known. Weak Map so that classes can be GCed.
110      */
111     private final Map<Class<? extends Module>, ModuleImplAdvertisement> implAdvs = new WeakHashMap<Class<? extends Module>, ModuleImplAdvertisement>();
112
113     /**
114      * Construct a new loader for the specified URLS with the default parent
115      * loader and specified compatibility equator.
116      *
117      * @param urls    The URLs from which to load classes and resources.
118      * @param equator The equator to use in comparing compatibility statements.
119      */
120     public RefJxtaLoader(URL[] urls, CompatibilityEquater equator) {
121         this(urls, RefJxtaLoader.class.getClassLoader(), equator);
122     }
123
124     /**
125      * Construct a new loader for the specified URLS with the specified parent
126      * loader and specified compatibility equator.
127      *
128      * @param urls    The URLs from which to load classes and resources.
129      * @param parent  The parent class loader for delegation.
130      * @param equator The equator to use in comparing compatibility statements.
131      */
132     public RefJxtaLoader(URL[] urls, ClassLoader parent, CompatibilityEquater equator) {
133         super(urls, parent);
134         this.equator = equator;
135     }
136
137     /**
138      * Make a stub for a version that uses URL, so that code that load
139      * services can be written properly, even if it works only for classes
140      * that do not need download.
141      *
142      * @param name    The class name.
143      * @param url     The location of the class.
144      * @param resolve If {@code true} then resolve the class.
145      * @return the class
146      * @throws ClassNotFoundException if class not found
147      */
148     protected Class<? extends Module> loadClass(String name, URL url, boolean resolve) throws ClassNotFoundException {
149         try {
150             return loadClass(name, resolve);
151         } catch (ClassNotFoundException e) {
152             if (url != null) {
153                 addURL(url);
154                 return loadClass(name, resolve);
155             } else {
156                 throw e;
157             }
158         }
159     }
160
161     /**
162      * {@inheritDoc}
163      */
164     @Override
165     public Class<? extends Module> loadClass(String name, boolean resolve) throws ClassNotFoundException {
166
167         Class<? extends Module> newClass = (Class<? extends Module>) findLoadedClass(name);
168
169         if (newClass == null) { // I'd rather say parent.loadClass() but it is private
170             try {
171                 newClass = (Class<? extends Module>) super.loadClass(name, false);
172             } catch (ClassNotFoundException ignored) {
173             // that's ok
174             }
175         }
176
177         if (newClass == null) {
178             try {
179                 newClass = (Class<? extends Module>) findSystemClass(name);
180                 if (newClass != null) {
181                     return newClass;
182                 }
183             } catch (ClassNotFoundException ignored) {
184             // that's ok
185             }
186
187             // We need to also check if the Context ClassLoader associated to the
188             // the current thread can load the class.
189             if (newClass == null) {
190                 try {
191                     newClass = (Class<? extends Module>) Thread.currentThread().getContextClassLoader().loadClass(name);
192                     if (newClass != null) {
193                         return newClass;
194                     }
195                 } catch (ClassNotFoundException ignored) {
196                 // that's ok
197                 }
198             }
199
200         // try {
201             // byte[] buf = bytesForClass(name);
202             // newClass = defineClass(name, buf, 0, buf.length);
203             // } catch (IOException e) {
204             // throw new ClassNotFoundException(e.toString());
205             // }
206         }
207
208         if (resolve) {
209             resolveClass(newClass);
210         }
211
212         return newClass;
213     }
214
215     // /**
216     // *  {@inheritDoc}
217     // **/
218     // protected byte[] bytesForClass(String name)
219     // throws IOException, ClassNotFoundException {
220     //
221     // File file = new File( dir, name.replace('.', File.separatorChar) + ".java");
222     // FileInputStream in = new FileInputStream(file);
223     // int length = (int) file.length();
224     // if (length == 0)
225     // throw new ClassNotFoundException(name);
226     // byte[] buf = new byte[length];
227     // in.read(buf);
228     // return buf;
229     // }
230
231     /**
232      * {@inheritDoc}
233      */
234     @Override
235     public synchronized Class<? extends Module> findClass(ModuleSpecID spec) throws ClassNotFoundException {
236
237         Map<String, Class<? extends Module>> compats = classes.get(spec);
238
239         if (null == compats) {
240             throw new ClassNotFoundException("No matching class for : " + spec);
241         }
242
243         for (Map.Entry<String, Class<? extends Module>> anEntry : compats.entrySet()) {
244             String aCompat = anEntry.getKey();
245
246             StructuredDocument asDoc;
247
248             try {
249                 asDoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(aCompat));
250             } catch (IOException ignored) {
251                 continue;
252             }
253
254             if (equator.compatible(asDoc)) {
255                 return anEntry.getValue();
256             } 
257         }
258
259         throw new ClassNotFoundException(spec.toString());
260     }
261
262     /**
263      * {@inheritDoc}
264      */
265     @Override
266     public Class<? extends Module> loadClass(ModuleSpecID spec) throws ClassNotFoundException {
267
268         Class found = findClass(spec);
269
270         resolveClass(found);
271
272         return found;
273     }
274
275     /**
276      * Loads a class
277      *
278      * @param name class name
279      * @param url  url to class
280      * @return the Class
281      * @throws ClassNotFoundException if class not found
282      */
283     public Class<? extends Module> loadClass(String name, URL url) throws ClassNotFoundException {
284         return loadClass(name, url, true);
285     }
286
287     /**
288      * {@inheritDoc}
289      */
290     @Override
291     public synchronized Class<? extends Module> defineClass(ModuleImplAdvertisement impl) throws ClassFormatError {
292         String asString = impl.getCompat().toString();
293
294         // See if we have any classes defined for this ModuleSpecID.
295         // Note that there may be multiple definitions with different compatibility statements.
296         Map<String, Class<? extends Module>> compats = classes.get(impl.getModuleSpecID());
297
298         if (null == compats) {
299             compats = new HashMap<String, Class<? extends Module>>();
300             classes.put(impl.getModuleSpecID(), compats);
301         }
302
303         // See if there is a class defined which matches the compatibility statement of the implAdv.
304         Class<? extends Module> loaded = compats.get(asString);
305
306         if (null == loaded) {
307             try {
308                 loaded = loadClass(impl.getCode(), new URL(impl.getUri()), false);
309             } catch (ClassNotFoundException failed) {
310                 throw new ClassFormatError("Class '" + impl.getCode() + "' could not be loaded from : " + impl.getUri());
311             } catch (MalformedURLException failed) {
312                 throw new ClassFormatError("Cannot load class '" + impl.getCode() + "' from : " + impl.getUri());
313             }
314
315             // Remember the class along with the matching compatibility statement.
316             compats.put(asString, loaded);
317         }
318
319         // Force update of impl advertisement. This is done because the class will frequently redefine itself.
320         implAdvs.put(loaded, impl);
321
322         return loaded;
323     }
324
325     /**
326      * {@inheritDoc}
327      */
328     @Override
329     public ModuleImplAdvertisement findModuleImplAdvertisement(Class clazz) {
330         ModuleImplAdvertisement result = implAdvs.get(clazz);
331
332         if (null == result) {
333             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
334                 LOG.log(Level.WARNING, "No module imp adv for " + clazz);
335             }
336             return null;
337         } else {
338             return result.clone();
339         }
340     }
341
342     /**
343      * {@inheritDoc}
344      */
345     @Override
346     public ModuleImplAdvertisement findModuleImplAdvertisement(ModuleSpecID msid) {
347         Class<? extends Module> moduleClass;
348
349         try {
350             moduleClass = findClass(msid);
351         } catch (ClassNotFoundException failed) {
352             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
353                 LOG.log(Level.WARNING, "Failed to find class for " + msid, failed);
354             }
355             return null;
356         }
357
358         if (null == moduleClass) {
359             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
360                 LOG.log(Level.WARNING, "No class for " + msid);
361             }
362             return null;
363         } else {
364             return findModuleImplAdvertisement(moduleClass);
365         }
366     }
367
368     /**
369      * {@inheritDoc}
370      */
371     @Override
372     public String toString() {
373         StringBuilder result = new StringBuilder();
374
375         result.append("Classes : ");
376         for (Map.Entry<ModuleSpecID, Map<String, Class<? extends Module>>> eachMCID : classes.entrySet()) {
377             ModuleSpecID mcid = eachMCID.getKey();
378             result.append("\n\t" + mcid + " :");
379             for (Map.Entry<String, Class<? extends Module>> eachClass : eachMCID.getValue().entrySet()) {
380                 result.append("\n\t\t" + eachClass.getValue().toString());
381             }
382         }
383
384         return result.toString();
385     }
386 }