Source for org.relaxng.datatype.helpers.DatatypeLibraryLoader

   1: /**
   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:  */
  34: package org.relaxng.datatype.helpers;
  35: 
  36: import org.relaxng.datatype.DatatypeLibraryFactory;
  37: import org.relaxng.datatype.DatatypeLibrary;
  38: import java.util.Enumeration;
  39: import java.util.NoSuchElementException;
  40: import java.util.Vector;
  41: import java.io.Reader;
  42: import java.io.InputStream;
  43: import java.io.InputStreamReader;
  44: import java.io.BufferedReader;
  45: import java.io.IOException;
  46: import java.io.UnsupportedEncodingException;
  47: import 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:  */
  56: public 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:               catch (IOException e) {
 154:                 return new Singleton(null);
 155:               }
 156:             }
 157: 
 158:             Class loadClass(String name) throws ClassNotFoundException {
 159:               return Class.forName(name, true, cl);
 160:             }
 161:           }
 162: 
 163:           public Service(Class cls) {
 164:             try {
 165:               loader = new Loader2();
 166:             }
 167:             catch (NoSuchMethodError e) {
 168:               loader = new Loader();
 169:             }
 170:             serviceClass = cls;
 171:             String resName = "META-INF/services/" + serviceClass.getName();
 172:             configFiles = loader.getResources(resName);
 173:           }
 174: 
 175:           public Enumeration getProviders() {
 176:             return new ProviderEnumeration();
 177:           }
 178: 
 179:           synchronized private boolean moreProviders() {
 180:             for (;;) {
 181:               while (classNames == null) {
 182:                 if (!configFiles.hasMoreElements())
 183:                   return false;
 184:                 classNames = parseConfigFile((URL)configFiles.nextElement());
 185:               }
 186:               while (classNames.hasMoreElements()) {
 187:                 String className = (String)classNames.nextElement();
 188:                 try {
 189:                   Class cls = loader.loadClass(className);
 190:                   Object obj = cls.newInstance();
 191:                   if (serviceClass.isInstance(obj)) {
 192:                     providers.addElement(obj);
 193:                     return true;
 194:                   }
 195:                 }
 196:                 catch (ClassNotFoundException e) { }
 197:                 catch (InstantiationException e) { }
 198:                 catch (IllegalAccessException e) { }
 199:                 catch (LinkageError e) { }
 200:               }
 201:               classNames = null;
 202:             }
 203:           }
 204: 
 205:           private static final int START = 0;
 206:           private static final int IN_NAME = 1;
 207:           private static final int IN_COMMENT = 2;
 208: 
 209:           private static Enumeration parseConfigFile(URL url) {
 210:             try {
 211:               InputStream in = url.openStream();
 212:               Reader r;
 213:               try {
 214:                 r = new InputStreamReader(in, "UTF-8");
 215:               }
 216:               catch (UnsupportedEncodingException e) {
 217:                 r = new InputStreamReader(in, "UTF8");
 218:               }
 219:               r = new BufferedReader(r);
 220:               Vector tokens = new Vector();
 221:               StringBuffer tokenBuf = new StringBuffer();
 222:               int state = START;
 223:               for (;;) {
 224:                 int n = r.read();
 225:                 if (n < 0)
 226:                   break;
 227:                 char c = (char)n;
 228:                 switch (c) {
 229:                 case '\r':
 230:                 case '\n':
 231:                   state = START;
 232:                   break;
 233:                 case ' ':
 234:                 case '\t':
 235:                   break;
 236:                 case '#':
 237:                   state = IN_COMMENT;
 238:                   break;
 239:                 default:
 240:                   if (state != IN_COMMENT) {
 241:                     state = IN_NAME;
 242:                     tokenBuf.append(c);
 243:                   }
 244:                   break;
 245:                 }
 246:                 if (tokenBuf.length() != 0 && state != IN_NAME) {
 247:                   tokens.addElement(tokenBuf.toString());
 248:                   tokenBuf.setLength(0);
 249:                 }
 250:               }
 251:               if (tokenBuf.length() != 0)
 252:                 tokens.addElement(tokenBuf.toString());
 253:               return tokens.elements();
 254:             }
 255:             catch (IOException e) {
 256:               return null;
 257:             }
 258:           }
 259:         }
 260: 
 261: }