1 // Copyright 2012 Google Inc. All rights reserved.
3 package com
.google
.appengine
.spi
;
5 import com
.google
.common
.base
.Preconditions
;
7 import java
.security
.AccessController
;
8 import java
.security
.PrivilegedAction
;
9 import java
.util
.Collections
;
10 import java
.util
.LinkedList
;
11 import java
.util
.List
;
12 import java
.util
.ServiceConfigurationError
;
13 import java
.util
.ServiceLoader
;
14 import java
.util
.concurrent
.atomic
.AtomicReference
;
17 * <b>This class is not intended for end users.</b>
19 * <p>Provide factory instances for AppEngine APIs. Each API will have an associated
20 * {@link FactoryProvider} registered with this class. N.B. <i>Once {@link #getFactory(Class)} has
21 * been called, no further mappings may be registered with this class.</i>
23 * <p>To construct the runtime mapping, this class first uses {@code java.util.ServiceLoader} to
24 * find all registered {@link FactoryProvider} entities using the {@code ClassLoader} of
25 * {@code ServiceFactoryFactory}. Finally, the explicitly registered providers
26 * {@link #register(FactoryProvider)} are merged in.
28 * <p>If {@code ServiceLoader} locates multiple providers for a given factory interface, the
29 * ambiguity can be resolved by using the {@link ServiceProvider#precedence} annotation property
30 * (higher precedence wins; <i>the google implementations all have precedence
31 * Integer.MIN_VALUE</i>). An exception is raised if the ambiguity cannot be resolved. Note that
32 * explicit registration ({@link #register(FactoryProvider)}) always takes precedence (it does not
33 * honor the {@link ServiceProvider#precedence} annotation property).
35 * <p>Authors of {@link FactoryProvider}s are encouraged to leverage {@link ServiceProvider} and
36 * {@link ServiceProviderProcessor}.
39 public final class ServiceFactoryFactory
{
42 * Providers should be registered with this entity prior to the first call to getFactory().
44 private static AtomicReference
<FactoryProviderRegistry
> explicitRegistry
=
45 new AtomicReference
<FactoryProviderRegistry
>(new FactoryProviderRegistry());
48 * Used by AppEngine service factories. Returns an instance of the factory implementing the
49 * interface provide by {@code base}. Since there must always be a provider registered for a given
50 * base, an error will be raised if no appropriate registration is found.
52 * @param base The returned factory must extend this class.
53 * @param <T> The type of the factory
55 * @throws IllegalArgumentException raised if the client requests a factory that does not have a
56 * provider registered for it.
57 * @throws ServiceConfigurationError raised if there is a problem creating the factory instance
59 public static <T
> T
getFactory(Class
<T
> base
) {
61 FactoryProvider
<T
> p
= RuntimeRegistry
.runtimeRegistry
.getFactoryProvider(base
);
64 throw new IllegalArgumentException(
65 "No provider was registered for " + base
.getCanonicalName());
69 return p
.getFactoryInstance();
70 } catch (Exception e
) {
71 throw new ServiceConfigurationError(
72 "Exception while getting factory instance for " + base
.getCanonicalName(), e
);
78 * Explicitly register a provider. This does not take the precedence (see
79 * {@link FactoryProvider#getPrecedence()}) of the provider into consideration; subsequent
80 * registrations will always override previous ones.
82 * @param p The provider to register
84 * @throws IllegalStateException raised if calls to getFactoryProvider have already been made.
86 public static synchronized <I
> void register(FactoryProvider
<I
> p
) {
88 FactoryProviderRegistry temp
= explicitRegistry
.get();
90 Preconditions
.checkState(
91 temp
!= null, "No modifications allowed after calls to getFactoryProvider");
96 private static final class RuntimeRegistry
{
97 static final FactoryProviderRegistry runtimeRegistry
= new FactoryProviderRegistry();
101 FactoryProviderRegistry explicitRegistrations
= explicitRegistry
.getAndSet(null);
103 List
<FactoryProvider
<?
>> providers
= getProvidersUsingServiceLoader();
105 Collections
.sort(providers
);
107 for (FactoryProvider
<?
> provider
: providers
) {
108 FactoryProvider
<?
> previous
= runtimeRegistry
.register(provider
);
109 Preconditions
.checkState(!provider
.equals(previous
),
110 "Ambiguous providers: " + provider
+ " versus " + previous
);
113 for (FactoryProvider
<?
> provider
: explicitRegistrations
.getAllProviders())
115 runtimeRegistry
.register(provider
);
121 * Retrieves the list of factory providers from the classpath
123 private static List
<FactoryProvider
<?
>> getProvidersUsingServiceLoader() {
124 return AccessController
.doPrivileged(new PrivilegedAction
<List
<FactoryProvider
<?
>>>() {
126 public List
<FactoryProvider
<?
>> run() {
127 List
<FactoryProvider
<?
>> result
= new LinkedList
<FactoryProvider
<?
>>();
129 ClassLoader classLoader
= ServiceFactoryFactory
.class.getClassLoader();
131 @SuppressWarnings("rawtypes")
132 ServiceLoader
<FactoryProvider
> providers
=
133 ServiceLoader
.load(FactoryProvider
.class, classLoader
);
135 if (providers
!= null) {
136 for (FactoryProvider
<?
> provider
: providers
) {
137 result
.add(provider
);