blob: a3091b087803fcfaa51e2ed75c309c59c5756615 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/**
2 * Copyright (c) 2001, Thai Open Source Software Center Ltd
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * Neither the name of the Thai Open Source Software Center Ltd nor
18 * the names of its contributors may be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34package org.relaxng.datatype.helpers;
35
36import org.relaxng.datatype.DatatypeLibraryFactory;
37import org.relaxng.datatype.DatatypeLibrary;
38import java.util.Enumeration;
39import java.util.NoSuchElementException;
40import java.util.Vector;
41import java.io.Reader;
42import java.io.InputStream;
43import java.io.InputStreamReader;
44import java.io.BufferedReader;
45import java.io.IOException;
46import java.io.UnsupportedEncodingException;
47import java.net.URL;
48
49/**
50 * Discovers the datatype library implementation from the classpath.
51 *
52 * <p>
53 * The call of the createDatatypeLibrary method finds an implementation
54 * from a given datatype library URI at run-time.
55 */
56public class DatatypeLibraryLoader implements DatatypeLibraryFactory {
57 private final Service service = new Service(DatatypeLibraryFactory.class);
58
59 public DatatypeLibrary createDatatypeLibrary(String uri) {
60 for (Enumeration e = service.getProviders();
61 e.hasMoreElements();) {
62 DatatypeLibraryFactory factory
63 = (DatatypeLibraryFactory)e.nextElement();
64 DatatypeLibrary library = factory.createDatatypeLibrary(uri);
65 if (library != null)
66 return library;
67 }
68 return null;
69 }
70
71 private static class Service {
72 private final Class serviceClass;
73 private final Enumeration configFiles;
74 private Enumeration classNames = null;
75 private final Vector providers = new Vector();
76 private Loader loader;
77
78 private class ProviderEnumeration implements Enumeration {
79 private int nextIndex = 0;
80
81 public boolean hasMoreElements() {
82 return nextIndex < providers.size() || moreProviders();
83 }
84
85 public Object nextElement() {
86 try {
87 return providers.elementAt(nextIndex++);
88 }
89 catch (ArrayIndexOutOfBoundsException e) {
90 throw new NoSuchElementException();
91 }
92 }
93 }
94
95 private static class Singleton implements Enumeration {
96 private Object obj;
97 private Singleton(Object obj) {
98 this.obj = obj;
99 }
100
101 public boolean hasMoreElements() {
102 return obj != null;
103 }
104
105 public Object nextElement() {
106 if (obj == null)
107 throw new NoSuchElementException();
108 Object tem = obj;
109 obj = null;
110 return tem;
111 }
112 }
113
114 // JDK 1.1
115 private static class Loader {
116 Enumeration getResources(String resName) {
117 ClassLoader cl = Loader.class.getClassLoader();
118 URL url;
119 if (cl == null)
120 url = ClassLoader.getSystemResource(resName);
121 else
122 url = cl.getResource(resName);
123 return new Singleton(url);
124 }
125
126 Class loadClass(String name) throws ClassNotFoundException {
127 return Class.forName(name);
128 }
129 }
130
131 // JDK 1.2+
132 private static class Loader2 extends Loader {
133 private ClassLoader cl;
134
135 Loader2() {
136 cl = Loader2.class.getClassLoader();
137 // If the thread context class loader has the class loader
138 // of this class as an ancestor, use the thread context class
139 // loader. Otherwise, the thread context class loader
140 // probably hasn't been set up properly, so don't use it.
141 ClassLoader clt = Thread.currentThread().getContextClassLoader();
142 for (ClassLoader tem = clt; tem != null; tem = tem.getParent())
143 if (tem == cl) {
144 cl = clt;
145 break;
146 }
147 }
148
149 Enumeration getResources(String resName) {
150 try {
151 return cl.getResources(resName);
152
153 }
154 catch (IOException e) {
155 return new Singleton(null);
156 }
157 }
158
159 Class loadClass(String name) throws ClassNotFoundException {
160 return Class.forName(name, true, cl);
161 }
162 }
163
164 public Service(Class cls) {
165 try {
166 loader = new Loader2();
167 }
168 catch (NoSuchMethodError e) {
169 loader = new Loader();
170 }
171 serviceClass = cls;
172 String resName = "META-INF/services/" + serviceClass.getName();
173 configFiles = loader.getResources(resName);
174 }
175
176 public Enumeration getProviders() {
177 return new ProviderEnumeration();
178 }
179
180 synchronized private boolean moreProviders() {
181 for (;;) {
182 while (classNames == null) {
183 if (!configFiles.hasMoreElements())
184 return false;
185 classNames = parseConfigFile((URL)configFiles.nextElement());
186 }
187 while (classNames.hasMoreElements()) {
188 String className = (String)classNames.nextElement();
189 try {
190 Class cls = loader.loadClass(className);
191 Object obj = cls.newInstance();
192 if (serviceClass.isInstance(obj)) {
193 providers.addElement(obj);
194 return true;
195 }
196 }
197 catch (ClassNotFoundException e) { }
198 catch (InstantiationException e) { }
199 catch (IllegalAccessException e) { }
200 catch (LinkageError e) { }
201 }
202 classNames = null;
203 }
204 }
205
206 private static final int START = 0;
207 private static final int IN_NAME = 1;
208 private static final int IN_COMMENT = 2;
209
210 private static Enumeration parseConfigFile(URL url) {
211 try {
212 InputStream in = url.openStream();
213 Reader r;
214 try {
215 r = new InputStreamReader(in, "UTF-8");
216 }
217 catch (UnsupportedEncodingException e) {
218 r = new InputStreamReader(in, "UTF8");
219 }
220 r = new BufferedReader(r);
221 Vector tokens = new Vector();
222 StringBuffer tokenBuf = new StringBuffer();
223 int state = START;
224 for (;;) {
225 int n = r.read();
226 if (n < 0)
227 break;
228 char c = (char)n;
229 switch (c) {
230 case '\r':
231 case '\n':
232 state = START;
233 break;
234 case ' ':
235 case '\t':
236 break;
237 case '#':
238 state = IN_COMMENT;
239 break;
240 default:
241 if (state != IN_COMMENT) {
242 state = IN_NAME;
243 tokenBuf.append(c);
244 }
245 break;
246 }
247 if (tokenBuf.length() != 0 && state != IN_NAME) {
248 tokens.addElement(tokenBuf.toString());
249 tokenBuf.setLength(0);
250 }
251 }
252 if (tokenBuf.length() != 0)
253 tokens.addElement(tokenBuf.toString());
254 return tokens.elements();
255 }
256 catch (IOException e) {
257 return null;
258 }
259 }
260 }
261
262}