OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [classpath/] [ServiceFactory.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* 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
 * &#x2f;**
95
 * * Provices a super-quick, but not very deep implementation of ThinkService.
96
 * *&#x2f;
97
 * public class QuickThinker
98
 *   implements org.foo.ThinkService
99
 * {
100
 *   &#x2f;**
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
 *   * &lt;p&gt;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
 *   *&#x2f;
111
 *   public QuickThinker()
112
 *   {
113
 *   }
114
 *
115
 *   &#x2f;**
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
 *   *&#x2f;
120
 *   public double getSpeed()
121
 *   {
122
 *     return 314159.2654;
123
 *   }
124
 *
125
 *   &#x2f;**
126
 *   * Produces a thought. While the returned thoughts are not very
127
 *   * deep, they are generated in very short time.
128
 *   *&#x2f;
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&#x2019;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/&lt;org.foo.SomeService&gt;</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/&lt;org.foo.SomeService&gt;</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>&#x201c;Could not
614
   * load {0}.&#x201d;</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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.