2 * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved.
4 * The Sun Project JXTA(TM) Software License
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
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.
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.
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.
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.
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.
41 * JXTA is a registered trademark of Sun Microsystems, Inc. in the United
42 * States and other countries.
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.
48 * ====================================================================
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.
54 * This license is based on the BSD license adopted by the Apache Foundation.
56 package net.jxta.impl.loader;
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;
66 import java.io.IOException;
67 import java.io.StringReader;
68 import java.net.MalformedURLException;
70 import java.util.HashMap;
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;
80 * This class is the reference implementation of the JxtaLoader.
82 public class RefJxtaLoader extends JxtaLoader {
87 private final static transient Logger LOG = Logger.getLogger(RefJxtaLoader.class.getName());
90 * The equator we will use to determine if compatibility statements are
91 * compatible with this JXTA implementation.
93 private final CompatibilityEquater equator;
97 * <li>Keys are {@link net.jxta.platform.ModuleSpecID}.</li>
98 * <li>Values are {@link java.util.Map}.
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>
106 private final Map<ModuleSpecID, Map<String, Class<? extends Module>>> classes = new HashMap<ModuleSpecID, Map<String, Class<? extends Module>>>();
109 * Classes and ImplAdvs we have known. Weak Map so that classes can be GCed.
111 private final Map<Class<? extends Module>, ModuleImplAdvertisement> implAdvs = new WeakHashMap<Class<? extends Module>, ModuleImplAdvertisement>();
114 * Construct a new loader for the specified URLS with the default parent
115 * loader and specified compatibility equator.
117 * @param urls The URLs from which to load classes and resources.
118 * @param equator The equator to use in comparing compatibility statements.
120 public RefJxtaLoader(URL[] urls, CompatibilityEquater equator) {
121 this(urls, RefJxtaLoader.class.getClassLoader(), equator);
125 * Construct a new loader for the specified URLS with the specified parent
126 * loader and specified compatibility equator.
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.
132 public RefJxtaLoader(URL[] urls, ClassLoader parent, CompatibilityEquater equator) {
134 this.equator = equator;
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.
142 * @param name The class name.
143 * @param url The location of the class.
144 * @param resolve If {@code true} then resolve the class.
146 * @throws ClassNotFoundException if class not found
148 protected Class<? extends Module> loadClass(String name, URL url, boolean resolve) throws ClassNotFoundException {
150 return loadClass(name, resolve);
151 } catch (ClassNotFoundException e) {
154 return loadClass(name, resolve);
165 public Class<? extends Module> loadClass(String name, boolean resolve) throws ClassNotFoundException {
167 Class<? extends Module> newClass = (Class<? extends Module>) findLoadedClass(name);
169 if (newClass == null) { // I'd rather say parent.loadClass() but it is private
171 newClass = (Class<? extends Module>) super.loadClass(name, false);
172 } catch (ClassNotFoundException ignored) {
177 if (newClass == null) {
179 newClass = (Class<? extends Module>) findSystemClass(name);
180 if (newClass != null) {
183 } catch (ClassNotFoundException ignored) {
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) {
191 newClass = (Class<? extends Module>) Thread.currentThread().getContextClassLoader().loadClass(name);
192 if (newClass != null) {
195 } catch (ClassNotFoundException ignored) {
201 // byte[] buf = bytesForClass(name);
202 // newClass = defineClass(name, buf, 0, buf.length);
203 // } catch (IOException e) {
204 // throw new ClassNotFoundException(e.toString());
209 resolveClass(newClass);
218 // protected byte[] bytesForClass(String name)
219 // throws IOException, ClassNotFoundException {
221 // File file = new File( dir, name.replace('.', File.separatorChar) + ".java");
222 // FileInputStream in = new FileInputStream(file);
223 // int length = (int) file.length();
225 // throw new ClassNotFoundException(name);
226 // byte[] buf = new byte[length];
235 public synchronized Class<? extends Module> findClass(ModuleSpecID spec) throws ClassNotFoundException {
237 Map<String, Class<? extends Module>> compats = classes.get(spec);
239 if (null == compats) {
240 throw new ClassNotFoundException("No matching class for : " + spec);
243 for (Map.Entry<String, Class<? extends Module>> anEntry : compats.entrySet()) {
244 String aCompat = anEntry.getKey();
246 StructuredDocument asDoc;
249 asDoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(aCompat));
250 } catch (IOException ignored) {
254 if (equator.compatible(asDoc)) {
255 return anEntry.getValue();
259 throw new ClassNotFoundException(spec.toString());
266 public Class<? extends Module> loadClass(ModuleSpecID spec) throws ClassNotFoundException {
268 Class found = findClass(spec);
278 * @param name class name
279 * @param url url to class
281 * @throws ClassNotFoundException if class not found
283 public Class<? extends Module> loadClass(String name, URL url) throws ClassNotFoundException {
284 return loadClass(name, url, true);
291 public synchronized Class<? extends Module> defineClass(ModuleImplAdvertisement impl) throws ClassFormatError {
292 String asString = impl.getCompat().toString();
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());
298 if (null == compats) {
299 compats = new HashMap<String, Class<? extends Module>>();
300 classes.put(impl.getModuleSpecID(), compats);
303 // See if there is a class defined which matches the compatibility statement of the implAdv.
304 Class<? extends Module> loaded = compats.get(asString);
306 if (null == loaded) {
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());
315 // Remember the class along with the matching compatibility statement.
316 compats.put(asString, loaded);
319 // Force update of impl advertisement. This is done because the class will frequently redefine itself.
320 implAdvs.put(loaded, impl);
329 public ModuleImplAdvertisement findModuleImplAdvertisement(Class clazz) {
330 ModuleImplAdvertisement result = implAdvs.get(clazz);
332 if (null == result) {
333 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
334 LOG.log(Level.WARNING, "No module imp adv for " + clazz);
338 return result.clone();
346 public ModuleImplAdvertisement findModuleImplAdvertisement(ModuleSpecID msid) {
347 Class<? extends Module> moduleClass;
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);
358 if (null == moduleClass) {
359 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
360 LOG.log(Level.WARNING, "No class for " + msid);
364 return findModuleImplAdvertisement(moduleClass);
372 public String toString() {
373 StringBuilder result = new StringBuilder();
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());
384 return result.toString();