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 */ ServiceFactory()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 */ lookupProviders(Class<P> spi, ClassLoader loader)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 */ lookupProviders(Class<P> spi, ClassLoader loader, boolean error)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 */ lookupProviders(Class<P> spi)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 */ ServiceIterator(Class<P> spi, Enumeration<URL> urls, ClassLoader loader, boolean error, AccessControlContext securityContext)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 */ next()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 hasNext()456 public boolean hasNext() 457 { 458 return nextProvider != null; 459 } 460 461 remove()462 public void remove() 463 { 464 throw new UnsupportedOperationException(); 465 } 466 467 loadNextServiceProvider()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 advanceReader()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 */ log(Level level, String msg, Object param, Throwable t)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 } 654