Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / spi / ServiceFactoryFactory.java
blobbd147030336bda8c03d4f548b9f00add18079d2a
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;
16 /**
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 {
41 /**
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());
47 /**
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);
63 if (p == null) {
64 throw new IllegalArgumentException(
65 "No provider was registered for " + base.getCanonicalName());
68 try {
69 return p.getFactoryInstance();
70 } catch (Exception e) {
71 throw new ServiceConfigurationError(
72 "Exception while getting factory instance for " + base.getCanonicalName(), e);
77 /**
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");
93 temp.register(p);
96 private static final class RuntimeRegistry {
97 static final FactoryProviderRegistry runtimeRegistry = new FactoryProviderRegistry();
99 static {
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<?>>>() {
125 @Override
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);
141 return result;