001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.xml.tax.parser;
042:
043: import org.openide.util.Lookup;
044:
045: import java.io.*;
046: import java.net.*;
047: import java.util.*;
048: import org.openide.modules.InstalledFileLocator;
049:
050: /**
051: * A filtering classloader (isolator) ensuring that a particuler version of
052: * Xerces2 parser is used. The filtering rule is inlined to perform well.
053: * <p>
054: * If the rule match it loads data from isolated resource otherwise delegates
055: * to a parent (TopManager.getSystemClassLoader()).
056: * <p>
057: * Use getInstance() followed by loadClass() method for obtaining the parser.
058: *
059: * @author Petr Kuzel
060: * @version
061: */
062: public final class ParserLoader extends URLClassLoader {
063:
064: // filtering "rules"
065: private static final String PARSER_PACKAGE = "org.apache.xerces"; // NOI18N
066: private static final String USER_PREFIXES[] = new String[] {
067: "org.netbeans.tax.io.XNIBuilder", // NOI18N
068: "org.netbeans.modules.xml.tools.action.XMLCompiler" //!!! outdated // NOI18N
069: };
070:
071: private static final String CODENAME_BASE = "org.netbeans.modules.xml.tax"; // NOI18N
072:
073: // parser library relative to installed or users directoty
074: private static final String XERCES_ARCHIVE = "modules/autoload/ext/xerces2.jar"; // NOI18N
075:
076: // module.jar relative to installed or users directoty
077: private static final String MODULE_ARCHIVE = "modules/autoload/xml-tax.jar"; // NOI18N
078:
079: // delegating classloader
080: private ClassLoader parentLoader;
081:
082: // the only instance of this classloader
083: private static ParserLoader instance = null;
084:
085: /** Creates new ParserLoader */
086: private ParserLoader(URL[] locations) {
087: super (locations);
088: parentLoader = (ClassLoader) Lookup.getDefault().lookup(
089: ClassLoader.class);
090: }
091:
092: /**
093: * Bootstrapping method.
094: * @return ParserLoader or null if library can not be located
095: */
096: public static synchronized ParserLoader getInstance() {
097:
098: if (instance != null)
099: return instance;
100:
101: try {
102: InstalledFileLocator installedFileLocator = InstalledFileLocator
103: .getDefault();
104:
105: URL xer2url = installedFileLocator.locate(XERCES_ARCHIVE,
106: CODENAME_BASE, false).toURL(); // NOI18N
107: if (Util.THIS.isLoggable())
108: Util.THIS.debug("Isolated library URL=" + xer2url); // NOI18N
109:
110: // The isolating classloader itself (not parent) must also see&load interface
111: // implementation class because all subsequent classes must be loaded by the
112: // isolating classloader (not its parent that does not see isolated jar)
113: URL module = installedFileLocator.locate(MODULE_ARCHIVE,
114: CODENAME_BASE, false).toURL(); // NOI18N
115: if (Util.THIS.isLoggable())
116: Util.THIS.debug("Isolated module URL=" + module); // NOI18N
117:
118: instance = new ParserLoader(new URL[] { xer2url, module });
119:
120: } catch (MalformedURLException ex) {
121: if (Util.THIS.isLoggable())
122: Util.THIS.debug(ex);
123: }
124:
125: return instance;
126: }
127:
128: /**
129: * Use simple filtering rule for distingvishing
130: * of classes that must be loaded from particular
131: * library version.
132: * ASSUMPTION parentLoader see bootstrap resources
133: */
134: public Class loadClass(String name) throws ClassNotFoundException {
135: Class clazz = null;
136:
137: if (name.startsWith(PARSER_PACKAGE)) {
138:
139: clazz = super .findLoadedClass(name); //no class duplication allowed
140: if (clazz == null) {
141: clazz = super .findClass(name); //define new class
142: }
143:
144: } else {
145:
146: // all potential users of this class loader (using isolated classes) must
147: // be known in compile time to eliminate multiple loaded classes by
148: // multiple instance of this classloader
149:
150: for (int i = 0; i < USER_PREFIXES.length; i++) {
151: if (name.startsWith(USER_PREFIXES[i])) {
152:
153: synchronized (this ) {
154: clazz = super .findLoadedClass(name); //no class duplication allowed
155: if (clazz == null) {
156: clazz = super .findClass(name); //define new class
157: }
158: }
159: }
160: }
161:
162: // delegate to parent
163:
164: if (clazz == null) {
165: clazz = parentLoader.loadClass(name);
166: }
167: }
168:
169: return clazz;
170: }
171:
172: /*
173: * Prefer isolated library when looking for resource.
174: * ASSUMPTION parentLoader see bootstrap resources
175: */
176: public URL getResource(String name) {
177: URL in = super .getResource(name);
178: if (in == null) {
179: in = parentLoader.getResource(name);
180: }
181:
182: if (Util.THIS.isLoggable()) /* then */
183: Util.THIS.debug("Resource: " + name + " =>" + in); // NOI18N
184:
185: return in;
186: }
187:
188: /*
189: * Prefer isolated library when looking for resource stream.
190: * ASSUMPTION parentLoader see bootstrap resources
191: */
192: public InputStream getResourceAsStream(String name) {
193: try {
194: URL url = this .getResource(name);
195: if (url == null) {
196: return null;
197: } else {
198: return url.openStream();
199: }
200: } catch (IOException ex) {
201: return null;
202: }
203: }
204:
205: /*
206: * Prefer isolated library when looking for resources.
207: * It is defacto implementation of getResources() that is final.
208: * //!!! this inplemetation does not isolate bootstrap resources
209: */
210: public Enumeration findResources(String name) throws IOException {
211: Enumeration en1 = super .findResources(name);
212: Enumeration en2 = parentLoader.getResources(name);
213:
214: return org.openide.util.Enumerations.concat(en1, en2);
215: }
216:
217: /**
218: * Perform basic self test.
219: */
220: public static void main(String args[]) throws Exception {
221:
222: ParserLoader me = ParserLoader.getInstance();
223:
224: Class apache = me.loadClass("org.apache.xerces.util.QName"); // NOI18N
225: Class java = me.loadClass("java.lang.String"); // NOI18N
226: Class netbeans = me.loadClass("org.openide.util.Mutex"); // NOI18N
227:
228: System.err.println("apache " + apache.getClassLoader()); // NOI18N
229: System.err.println("netbeans " + netbeans.getClassLoader()); // NOI18N
230: System.err.println("java " + java.getClassLoader()); // NOI18N
231:
232: }
233:
234: }
|