Frames | No Frames |
1: /* ServiceFactory.java -- Factory for plug-in services. 2: Copyright (C) 2004 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package gnu.classpath; 40: 41: import java.io.BufferedReader; 42: import java.io.IOException; 43: import java.io.InputStreamReader; 44: import java.net.URL; 45: import java.security.AccessControlContext; 46: import java.security.AccessController; 47: import java.security.PrivilegedActionException; 48: import java.util.Collections; 49: import java.util.Enumeration; 50: import java.util.Iterator; 51: import java.util.NoSuchElementException; 52: import java.util.ServiceConfigurationError; 53: import java.util.logging.Level; 54: import java.util.logging.LogRecord; 55: import java.util.logging.Logger; 56: 57: 58: /** 59: * A factory for plug-ins that conform to a service provider 60: * interface. This is a general mechanism that gets used by a number 61: * of packages in the Java API. For instance, {@link 62: * java.nio.charset.spi.CharsetProvider} allows to write custom 63: * encoders and decoders for character sets, {@link 64: * javax.imageio.spi.ImageReaderSpi} allows to support custom image 65: * formats, and {@link javax.print.PrintService} makes it possible to 66: * write custom printer drivers. 67: * 68: * <p>The plug-ins are concrete implementations of the service 69: * provider interface, which is defined as an interface or an abstract 70: * class. The implementation classes must be public and have a public 71: * constructor that takes no arguments. 72: * 73: * <p>Plug-ins are usually deployed in JAR files. A JAR that provides 74: * an implementation of a service must declare this in a resource file 75: * whose name is the fully qualified service name and whose location 76: * is the directory <code>META-INF/services</code>. This UTF-8 encoded 77: * text file lists, on separate lines, the fully qualified names of 78: * the concrete implementations. Thus, one JAR file can provide an 79: * arbitrary number of implementations for an arbitrary count of 80: * service provider interfaces. 81: * 82: * <p><b>Example</b> 83: * 84: * <p>For example, a JAR might provide two implementations of the 85: * service provider interface <code>org.foo.ThinkService</code>, 86: * namely <code>com.acme.QuickThinker</code> and 87: * <code>com.acme.DeepThinker</code>. The code for <code>QuickThinker</code> 88: * woud look as follows: 89: * 90: * <pre> 91: * package com.acme; 92: * 93: * /** 94: * * Provices a super-quick, but not very deep implementation of ThinkService. 95: * */ 96: * public class QuickThinker 97: * implements org.foo.ThinkService 98: * { 99: * /** 100: * * Constructs a new QuickThinker. The service factory (which is 101: * * part of the Java environment) calls this no-argument constructor 102: * * when it looks up the available implementations of ThinkService. 103: * * 104: * * <p>Note that an application might query all available 105: * * ThinkService providers, but use just one of them. Therefore, 106: * * constructing an instance should be very inexpensive. For example, 107: * * large data structures should only be allocated when the service 108: * * actually gets used. 109: * */ 110: * public QuickThinker() 111: * { 112: * } 113: * 114: * /** 115: * * Returns the speed of this ThinkService in thoughts per second. 116: * * Applications can choose among the available service providers 117: * * based on this value. 118: * */ 119: * public double getSpeed() 120: * { 121: * return 314159.2654; 122: * } 123: * 124: * /** 125: * * Produces a thought. While the returned thoughts are not very 126: * * deep, they are generated in very short time. 127: * */ 128: * public Thought think() 129: * { 130: * return null; 131: * } 132: * } 133: * </pre> 134: * 135: * <p>The code for <code>com.acme.DeepThinker</code> is left as an 136: * exercise to the reader. 137: * 138: * <p>Acme’s <code>ThinkService</code> plug-in gets deployed as 139: * a JAR file. Besides the bytecode and resources for 140: * <code>QuickThinker</code> and <code>DeepThinker</code>, it also 141: * contains the text file 142: * <code>META-INF/services/org.foo.ThinkService</code>: 143: * 144: * <pre> 145: * # Available implementations of org.foo.ThinkService 146: * com.acme.QuickThinker 147: * com.acme.DeepThinker 148: * </pre> 149: * 150: * <p><b>Thread Safety</b> 151: * 152: * <p>It is safe to use <code>ServiceFactory</code> from multiple 153: * concurrent threads without external synchronization. 154: * 155: * <p><b>Note for User Applications</b> 156: * 157: * <p>User applications that want to load plug-ins should not directly 158: * use <code>gnu.classpath.ServiceFactory</code>, because this class 159: * is only available in Java environments that are based on GNU 160: * Classpath. Instead, it is recommended that user applications call 161: * {@link 162: * javax.imageio.spi.ServiceRegistry#lookupProviders(Class)}. This API 163: * is actually independent of image I/O, and it is available on every 164: * environment. 165: * 166: * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> 167: */ 168: public final class ServiceFactory 169: { 170: /** 171: * A logger that gets informed when a service gets loaded, or 172: * when there is a problem with loading a service. 173: * 174: * <p>Because {@link java.util.logging.Logger#getLogger(String)} 175: * is thread-safe, we do not need to worry about synchronization 176: * here. 177: */ 178: private static final Logger LOGGER = Logger.getLogger("gnu.classpath"); 179: 180: /** 181: * Declared private in order to prevent constructing instances of 182: * this utility class. 183: */ 184: private ServiceFactory() 185: { 186: } 187: 188: 189: /** 190: * Finds service providers that are implementing the specified 191: * Service Provider Interface. 192: * 193: * <p><b>On-demand loading:</b> Loading and initializing service 194: * providers is delayed as much as possible. The rationale is that 195: * typical clients will iterate through the set of installed service 196: * providers until one is found that matches some criteria (like 197: * supported formats, or quality of service). In such scenarios, it 198: * might make sense to install only the frequently needed service 199: * providers on the local machine. More exotic providers can be put 200: * onto a server; the server will only be contacted when no suitable 201: * service could be found locally. 202: * 203: * <p><b>Security considerations:</b> Any loaded service providers 204: * are loaded through the specified ClassLoader, or the system 205: * ClassLoader if <code>classLoader</code> is 206: * <code>null</code>. When <code>lookupProviders</code> is called, 207: * the current {@link AccessControlContext} gets recorded. This 208: * captured security context will determine the permissions when 209: * services get loaded via the <code>next()</code> method of the 210: * returned <code>Iterator</code>. 211: * 212: * @param spi the service provider interface which must be 213: * implemented by any loaded service providers. 214: * 215: * @param loader the class loader that will be used to load the 216: * service providers, or <code>null</code> for the system class 217: * loader. For using the context class loader, see {@link 218: * #lookupProviders(Class)}. 219: * 220: * @return an iterator over instances of <code>spi</code>. 221: * 222: * @throws IllegalArgumentException if <code>spi</code> is 223: * <code>null</code>. 224: */ 225: public static Iterator lookupProviders(Class spi, 226: ClassLoader loader) 227: { 228: return lookupProviders(spi, loader, false); 229: } 230: 231: /** 232: * Finds service providers that are implementing the specified 233: * Service Provider Interface. 234: * 235: * <p><b>On-demand loading:</b> Loading and initializing service 236: * providers is delayed as much as possible. The rationale is that 237: * typical clients will iterate through the set of installed service 238: * providers until one is found that matches some criteria (like 239: * supported formats, or quality of service). In such scenarios, it 240: * might make sense to install only the frequently needed service 241: * providers on the local machine. More exotic providers can be put 242: * onto a server; the server will only be contacted when no suitable 243: * service could be found locally. 244: * 245: * <p><b>Security considerations:</b> Any loaded service providers 246: * are loaded through the specified ClassLoader, or the system 247: * ClassLoader if <code>classLoader</code> is 248: * <code>null</code>. When <code>lookupProviders</code> is called, 249: * the current {@link AccessControlContext} gets recorded. This 250: * captured security context will determine the permissions when 251: * services get loaded via the <code>next()</code> method of the 252: * returned <code>Iterator</code>. 253: * 254: * @param spi the service provider interface which must be 255: * implemented by any loaded service providers. 256: * 257: * @param loader the class loader that will be used to load the 258: * service providers, or <code>null</code> for the system class 259: * loader. For using the context class loader, see {@link 260: * #lookupProviders(Class)}. 261: * @param error true if a {@link ServiceConfigurationError} 262: * should be thrown when an error occurs, rather 263: * than it merely being logged. 264: * @return an iterator over instances of <code>spi</code>. 265: * 266: * @throws IllegalArgumentException if <code>spi</code> is 267: * <code>null</code>. 268: */ 269: public static Iterator lookupProviders(Class spi, 270: ClassLoader loader, 271: boolean error) 272: { 273: String resourceName; 274: Enumeration urls; 275: 276: if (spi == null) 277: throw new IllegalArgumentException(); 278: 279: if (loader == null) 280: loader = ClassLoader.getSystemClassLoader(); 281: 282: resourceName = "META-INF/services/" + spi.getName(); 283: try 284: { 285: urls = loader.getResources(resourceName); 286: } 287: catch (IOException ioex) 288: { 289: /* If an I/O error occurs here, we cannot provide any service 290: * providers. In this case, we simply return an iterator that 291: * does not return anything (no providers installed). 292: */ 293: log(Level.WARNING, "cannot access {0}", resourceName, ioex); 294: if (error) 295: throw new ServiceConfigurationError("Failed to access + " + 296: resourceName, ioex); 297: else 298: return Collections.EMPTY_LIST.iterator(); 299: } 300: 301: return new ServiceIterator(spi, urls, loader, error, 302: AccessController.getContext()); 303: } 304: 305: 306: /** 307: * Finds service providers that are implementing the specified 308: * Service Provider Interface, using the context class loader 309: * for loading providers. 310: * 311: * @param spi the service provider interface which must be 312: * implemented by any loaded service providers. 313: * 314: * @return an iterator over instances of <code>spi</code>. 315: * 316: * @throws IllegalArgumentException if <code>spi</code> is 317: * <code>null</code>. 318: * 319: * @see #lookupProviders(Class, ClassLoader) 320: */ 321: public static Iterator lookupProviders(Class spi) 322: { 323: ClassLoader ctxLoader; 324: 325: ctxLoader = Thread.currentThread().getContextClassLoader(); 326: return lookupProviders(spi, ctxLoader); 327: } 328: 329: 330: /** 331: * An iterator over service providers that are listed in service 332: * provider configuration files, which get passed as an Enumeration 333: * of URLs. This is a helper class for {@link 334: * ServiceFactory#lookupProviders(Class, ClassLoader)}. 335: * 336: * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> 337: */ 338: private static final class ServiceIterator 339: implements Iterator 340: { 341: /** 342: * The service provider interface (usually an interface, sometimes 343: * an abstract class) which the services must implement. 344: */ 345: private final Class spi; 346: 347: 348: /** 349: * An Enumeration<URL> over the URLs that contain a resource 350: * <code>META-INF/services/<org.foo.SomeService></code>, 351: * as returned by {@link ClassLoader#getResources(String)}. 352: */ 353: private final Enumeration urls; 354: 355: 356: /** 357: * The class loader used for loading service providers. 358: */ 359: private final ClassLoader loader; 360: 361: 362: /** 363: * The security context used when loading and initializing service 364: * providers. We want to load and initialize all plug-in service 365: * providers under the same security context, namely the one that 366: * was active when {@link #lookupProviders(Class, ClassLoader)} has 367: * been called. 368: */ 369: private final AccessControlContext securityContext; 370: 371: 372: /** 373: * A reader for the current file listing class names of service 374: * implementors, or <code>null</code> when the last reader has 375: * been fetched. 376: */ 377: private BufferedReader reader; 378: 379: 380: /** 381: * The URL currently being processed. This is only used for 382: * emitting error messages. 383: */ 384: private URL currentURL; 385: 386: 387: /** 388: * The service provider that will be returned by the next call to 389: * {@link #next()}, or <code>null</code> if the iterator has 390: * already returned all service providers. 391: */ 392: private Object nextProvider; 393: 394: /** 395: * True if a {@link ServiceConfigurationError} should be thrown 396: * when an error occurs, instead of it merely being logged. 397: */ 398: private boolean error; 399: 400: /** 401: * Constructs an Iterator that loads and initializes services on 402: * demand. 403: * 404: * @param spi the service provider interface which the services 405: * must implement. Usually, this is a Java interface type, but it 406: * might also be an abstract class or even a concrete superclass. 407: * 408: * @param urls an Enumeration<URL> over the URLs that contain a 409: * resource 410: * <code>META-INF/services/<org.foo.SomeService></code>, as 411: * determined by {@link ClassLoader#getResources(String)}. 412: * 413: * @param loader the ClassLoader that gets used for loading 414: * service providers. 415: * 416: * @param error true if a {@link ServiceConfigurationError} 417: * should be thrown when an error occurs, rather 418: * than it merely being logged. 419: * 420: * @param securityContext the security context to use when loading 421: * and initializing service providers. 422: */ 423: ServiceIterator(Class spi, Enumeration urls, ClassLoader loader, 424: boolean error, AccessControlContext securityContext) 425: { 426: this.spi = spi; 427: this.urls = urls; 428: this.loader = loader; 429: this.securityContext = securityContext; 430: this.error = error; 431: this.nextProvider = loadNextServiceProvider(); 432: } 433: 434: 435: /** 436: * @throws NoSuchElementException if {@link #hasNext} returns 437: * <code>false</code>. 438: */ 439: public Object next() 440: { 441: Object result; 442: 443: if (!hasNext()) 444: throw new NoSuchElementException(); 445: 446: result = nextProvider; 447: nextProvider = loadNextServiceProvider(); 448: return result; 449: } 450: 451: 452: public boolean hasNext() 453: { 454: return nextProvider != null; 455: } 456: 457: 458: public void remove() 459: { 460: throw new UnsupportedOperationException(); 461: } 462: 463: 464: private Object loadNextServiceProvider() 465: { 466: String line; 467: 468: if (reader == null) 469: advanceReader(); 470: 471: for (;;) 472: { 473: /* If we have reached the last provider list, we cannot 474: * retrieve any further lines. 475: */ 476: if (reader == null) 477: return null; 478: 479: try 480: { 481: line = reader.readLine(); 482: } 483: catch (IOException readProblem) 484: { 485: log(Level.WARNING, "IOException upon reading {0}", currentURL, 486: readProblem); 487: line = null; 488: if (error) 489: throw new ServiceConfigurationError("Error reading " + 490: currentURL, readProblem); 491: } 492: 493: /* When we are at the end of one list of services, 494: * switch over to the next one. 495: */ 496: if (line == null) 497: { 498: advanceReader(); 499: continue; 500: } 501: 502: 503: // Skip whitespace at the beginning and end of each line. 504: line = line.trim(); 505: 506: // Skip empty lines. 507: if (line.length() == 0) 508: continue; 509: 510: // Skip comment lines. 511: if (line.charAt(0) == '#') 512: continue; 513: 514: try 515: { 516: log(Level.FINE, 517: "Loading service provider \"{0}\", specified" 518: + " by \"META-INF/services/{1}\" in {2}.", 519: new Object[] { line, spi.getName(), currentURL }, 520: null); 521: 522: /* Load the class in the security context that was 523: * active when calling lookupProviders. 524: */ 525: return AccessController.doPrivileged( 526: new ServiceProviderLoadingAction(spi, line, loader), 527: securityContext); 528: } 529: catch (Exception ex) 530: { 531: String msg = "Cannot load service provider class \"{0}\"," 532: + " specified by \"META-INF/services/{1}\" in {2}"; 533: if (ex instanceof PrivilegedActionException 534: && ex.getCause() instanceof ClassCastException) 535: msg = "Service provider class \"{0}\" is not an instance" 536: + " of \"{1}\". Specified" 537: + " by \"META-INF/services/{1}\" in {2}."; 538: 539: log(Level.WARNING, msg, 540: new Object[] { line, spi.getName(), currentURL }, 541: ex); 542: if (error) 543: throw new ServiceConfigurationError("Cannot load service "+ 544: "provider class " + 545: line + " specified by "+ 546: "\"META-INF/services/"+ 547: spi.getName() + "\" in "+ 548: currentURL, ex); 549: continue; 550: } 551: } 552: } 553: 554: 555: private void advanceReader() 556: { 557: do 558: { 559: if (reader != null) 560: { 561: try 562: { 563: reader.close(); 564: log(Level.FINE, "closed {0}", currentURL, null); 565: } 566: catch (Exception ex) 567: { 568: log(Level.WARNING, "cannot close {0}", currentURL, ex); 569: if (error) 570: throw new ServiceConfigurationError("Cannot close " + 571: currentURL, ex); 572: } 573: reader = null; 574: currentURL = null; 575: } 576: 577: if (!urls.hasMoreElements()) 578: return; 579: 580: currentURL = (URL) urls.nextElement(); 581: try 582: { 583: reader = new BufferedReader(new InputStreamReader( 584: currentURL.openStream(), "UTF-8")); 585: log(Level.FINE, "opened {0}", currentURL, null); 586: } 587: catch (Exception ex) 588: { 589: log(Level.WARNING, "cannot open {0}", currentURL, ex); 590: if (error) 591: throw new ServiceConfigurationError("Cannot open " + 592: currentURL, ex); 593: } 594: } 595: while (reader == null); 596: } 597: } 598: 599: 600: // Package-private to avoid a trampoline. 601: /** 602: * Passes a log message to the <code>java.util.logging</code> 603: * framework. This call returns very quickly if no log message will 604: * be produced, so there is not much overhead in the standard case. 605: * 606: * @param level the severity of the message, for instance {@link 607: * Level#WARNING}. 608: * 609: * @param msg the log message, for instance <code>“Could not 610: * load {0}.”</code> 611: * 612: * @param param the parameter(s) for the log message, or 613: * <code>null</code> if <code>msg</code> does not specify any 614: * parameters. If <code>param</code> is not an array, an array with 615: * <code>param</code> as its single element gets passed to the 616: * logging framework. 617: * 618: * @param t a Throwable that is associated with the log record, or 619: * <code>null</code> if the log message is not associated with a 620: * Throwable. 621: */ 622: static void log(Level level, String msg, Object param, Throwable t) 623: { 624: LogRecord rec; 625: 626: // Return quickly if no log message will be produced. 627: if (!LOGGER.isLoggable(level)) 628: return; 629: 630: rec = new LogRecord(level, msg); 631: if (param != null && param.getClass().isArray()) 632: rec.setParameters((Object[]) param); 633: else 634: rec.setParameters(new Object[] { param }); 635: 636: rec.setThrown(t); 637: 638: // While java.util.logging can sometimes infer the class and 639: // method of the caller, this automatic inference is not reliable 640: // on highly optimizing VMs. Also, log messages make more sense to 641: // developers when they display a public method in a public class; 642: // otherwise, they might feel tempted to figure out the internals 643: // of ServiceFactory in order to understand the problem. 644: rec.setSourceClassName(ServiceFactory.class.getName()); 645: rec.setSourceMethodName("lookupProviders"); 646: 647: LOGGER.log(rec); 648: } 649: }