001: /**
002: * Copyright (c) 2001, Thai Open Source Software Center Ltd
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are
007: * met:
008: *
009: * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * Neither the name of the Thai Open Source Software Center Ltd nor
018: * the names of its contributors may be used to endorse or promote
019: * products derived from this software without specific prior written
020: * permission.
021: *
022: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
023: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
024: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
025: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
026: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
027: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
028: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
029: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
030: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
031: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
032: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033: */package org.relaxng.datatype.helpers;
034:
035: import org.relaxng.datatype.DatatypeLibraryFactory;
036: import org.relaxng.datatype.DatatypeLibrary;
037: import java.util.Enumeration;
038: import java.util.NoSuchElementException;
039: import java.util.Vector;
040: import java.io.Reader;
041: import java.io.InputStream;
042: import java.io.InputStreamReader;
043: import java.io.BufferedReader;
044: import java.io.IOException;
045: import java.io.UnsupportedEncodingException;
046: import java.net.URL;
047:
048: /**
049: * Discovers the datatype library implementation from the classpath.
050: *
051: * <p>
052: * The call of the createDatatypeLibrary method finds an implementation
053: * from a given datatype library URI at run-time.
054: */
055: public class DatatypeLibraryLoader implements DatatypeLibraryFactory {
056: private final Service service = new Service(
057: DatatypeLibraryFactory.class);
058:
059: public DatatypeLibrary createDatatypeLibrary(String uri) {
060: for (Enumeration e = service.getProviders(); e
061: .hasMoreElements();) {
062: DatatypeLibraryFactory factory = (DatatypeLibraryFactory) e
063: .nextElement();
064: DatatypeLibrary library = factory
065: .createDatatypeLibrary(uri);
066: if (library != null)
067: return library;
068: }
069: return null;
070: }
071:
072: private static class Service {
073: private final Class serviceClass;
074: private final Enumeration configFiles;
075: private Enumeration classNames = null;
076: private final Vector providers = new Vector();
077: private Loader loader;
078:
079: private class ProviderEnumeration implements Enumeration {
080: private int nextIndex = 0;
081:
082: public boolean hasMoreElements() {
083: return nextIndex < providers.size() || moreProviders();
084: }
085:
086: public Object nextElement() {
087: try {
088: return providers.elementAt(nextIndex++);
089: } catch (ArrayIndexOutOfBoundsException e) {
090: throw new NoSuchElementException();
091: }
092: }
093: }
094:
095: private static class Singleton implements Enumeration {
096: private Object obj;
097:
098: private Singleton(Object obj) {
099: this .obj = obj;
100: }
101:
102: public boolean hasMoreElements() {
103: return obj != null;
104: }
105:
106: public Object nextElement() {
107: if (obj == null)
108: throw new NoSuchElementException();
109: Object tem = obj;
110: obj = null;
111: return tem;
112: }
113: }
114:
115: // JDK 1.1
116: private static class Loader {
117: Enumeration getResources(String resName) {
118: ClassLoader cl = Loader.class.getClassLoader();
119: URL url;
120: if (cl == null)
121: url = ClassLoader.getSystemResource(resName);
122: else
123: url = cl.getResource(resName);
124: return new Singleton(url);
125: }
126:
127: Class loadClass(String name) throws ClassNotFoundException {
128: return Class.forName(name);
129: }
130: }
131:
132: // JDK 1.2+
133: private static class Loader2 extends Loader {
134: private ClassLoader cl;
135:
136: Loader2() {
137: cl = Loader2.class.getClassLoader();
138: // If the thread context class loader has the class loader
139: // of this class as an ancestor, use the thread context class
140: // loader. Otherwise, the thread context class loader
141: // probably hasn't been set up properly, so don't use it.
142: ClassLoader clt = Thread.currentThread()
143: .getContextClassLoader();
144: for (ClassLoader tem = clt; tem != null; tem = tem
145: .getParent())
146: if (tem == cl) {
147: cl = clt;
148: break;
149: }
150: }
151:
152: Enumeration getResources(String resName) {
153: try {
154: return cl.getResources(resName);
155: } catch (IOException e) {
156: return new Singleton(null);
157: }
158: }
159:
160: Class loadClass(String name) throws ClassNotFoundException {
161: return Class.forName(name, true, cl);
162: }
163: }
164:
165: public Service(Class cls) {
166: try {
167: loader = new Loader2();
168: } catch (NoSuchMethodError e) {
169: loader = new Loader();
170: }
171: serviceClass = cls;
172: String resName = "META-INF/services/"
173: + serviceClass.getName();
174: configFiles = loader.getResources(resName);
175: }
176:
177: public Enumeration getProviders() {
178: return new ProviderEnumeration();
179: }
180:
181: synchronized private boolean moreProviders() {
182: for (;;) {
183: while (classNames == null) {
184: if (!configFiles.hasMoreElements())
185: return false;
186: classNames = parseConfigFile((URL) configFiles
187: .nextElement());
188: }
189: while (classNames.hasMoreElements()) {
190: String className = (String) classNames
191: .nextElement();
192: try {
193: Class cls = loader.loadClass(className);
194: Object obj = cls.newInstance();
195: if (serviceClass.isInstance(obj)) {
196: providers.addElement(obj);
197: return true;
198: }
199: } catch (ClassNotFoundException e) {
200: } catch (InstantiationException e) {
201: } catch (IllegalAccessException e) {
202: } catch (LinkageError e) {
203: }
204: }
205: classNames = null;
206: }
207: }
208:
209: private static final int START = 0;
210: private static final int IN_NAME = 1;
211: private static final int IN_COMMENT = 2;
212:
213: private static Enumeration parseConfigFile(URL url) {
214: try {
215: InputStream in = url.openStream();
216: Reader r;
217: try {
218: r = new InputStreamReader(in, "UTF-8");
219: } catch (UnsupportedEncodingException e) {
220: r = new InputStreamReader(in, "UTF8");
221: }
222: r = new BufferedReader(r);
223: Vector tokens = new Vector();
224: StringBuffer tokenBuf = new StringBuffer();
225: int state = START;
226: for (;;) {
227: int n = r.read();
228: if (n < 0)
229: break;
230: char c = (char) n;
231: switch (c) {
232: case '\r':
233: case '\n':
234: state = START;
235: break;
236: case ' ':
237: case '\t':
238: break;
239: case '#':
240: state = IN_COMMENT;
241: break;
242: default:
243: if (state != IN_COMMENT) {
244: state = IN_NAME;
245: tokenBuf.append(c);
246: }
247: break;
248: }
249: if (tokenBuf.length() != 0 && state != IN_NAME) {
250: tokens.addElement(tokenBuf.toString());
251: tokenBuf.setLength(0);
252: }
253: }
254: if (tokenBuf.length() != 0)
255: tokens.addElement(tokenBuf.toString());
256: return tokens.elements();
257: } catch (IOException e) {
258: return null;
259: }
260: }
261: }
262:
263: }
|