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