| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.jclouds; |
| |
| import static com.google.common.base.MoreObjects.toStringHelper; |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static com.google.common.base.Predicates.containsPattern; |
| import static com.google.common.base.Predicates.instanceOf; |
| import static com.google.common.base.Predicates.not; |
| import static com.google.common.base.Predicates.notNull; |
| import static com.google.common.base.Throwables.propagate; |
| import static com.google.common.collect.Iterables.addAll; |
| import static com.google.common.collect.Iterables.any; |
| import static com.google.common.collect.Iterables.filter; |
| import static com.google.common.collect.Iterables.find; |
| import static com.google.common.collect.Iterables.transform; |
| import static com.google.common.collect.Lists.newArrayList; |
| import static com.google.common.collect.Lists.newArrayListWithCapacity; |
| import static com.google.common.collect.Maps.filterKeys; |
| import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService; |
| import static org.jclouds.Constants.PROPERTY_API; |
| import static org.jclouds.Constants.PROPERTY_API_VERSION; |
| import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; |
| import static org.jclouds.Constants.PROPERTY_CREDENTIAL; |
| import static org.jclouds.Constants.PROPERTY_ENDPOINT; |
| import static org.jclouds.Constants.PROPERTY_IDENTITY; |
| import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; |
| import static org.jclouds.Constants.PROPERTY_PROVIDER; |
| import static org.jclouds.reflect.Reflection2.typeToken; |
| import static org.jclouds.rest.config.BinderUtils.bindHttpApi; |
| import static org.jclouds.util.Throwables2.propagateAuthorizationOrOriginalException; |
| |
| import java.io.Closeable; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.NoSuchElementException; |
| import java.util.Properties; |
| import java.util.Set; |
| |
| import org.jclouds.apis.ApiMetadata; |
| import org.jclouds.apis.Apis; |
| import org.jclouds.concurrent.SingleThreaded; |
| import org.jclouds.concurrent.config.ConfiguresExecutorService; |
| import org.jclouds.concurrent.config.ExecutorServiceModule; |
| import org.jclouds.config.BindApiContextWithWildcardExtendsExplicitAndRawType; |
| import org.jclouds.config.BindNameToContext; |
| import org.jclouds.domain.Credentials; |
| import org.jclouds.events.config.ConfiguresEventBus; |
| import org.jclouds.events.config.EventBusModule; |
| import org.jclouds.functions.ExpandProperties; |
| import org.jclouds.http.config.ConfiguresHttpCommandExecutorService; |
| import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; |
| import org.jclouds.javax.annotation.Nullable; |
| import org.jclouds.lifecycle.config.LifeCycleModule; |
| import org.jclouds.logging.config.LoggingModule; |
| import org.jclouds.logging.jdk.config.JDKLoggingModule; |
| import org.jclouds.providers.ProviderMetadata; |
| import org.jclouds.providers.Providers; |
| import org.jclouds.providers.config.BindProviderMetadataContextAndCredentials; |
| import org.jclouds.providers.internal.UpdateProviderMetadataFromProperties; |
| import org.jclouds.reflect.Invocation; |
| import org.jclouds.rest.ConfiguresCredentialStore; |
| import org.jclouds.rest.ConfiguresHttpApi; |
| import org.jclouds.rest.HttpApiMetadata; |
| import org.jclouds.rest.HttpClient; |
| import org.jclouds.rest.config.CredentialStoreModule; |
| import org.jclouds.rest.config.HttpApiModule; |
| import org.jclouds.rest.config.RestModule; |
| import org.jclouds.rest.internal.InvokeHttpMethod; |
| import org.jclouds.util.TypeTokenUtils; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Function; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Objects; |
| import com.google.common.base.Optional; |
| import com.google.common.base.Predicate; |
| import com.google.common.base.Splitter; |
| import com.google.common.base.Supplier; |
| import com.google.common.base.Suppliers; |
| import com.google.common.collect.ImmutableMultimap; |
| import com.google.common.collect.ImmutableMultimap.Builder; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| import com.google.common.reflect.TypeToken; |
| import com.google.common.util.concurrent.ExecutionList; |
| import com.google.inject.AbstractModule; |
| import com.google.inject.Guice; |
| import com.google.inject.Injector; |
| import com.google.inject.Key; |
| import com.google.inject.Module; |
| import com.google.inject.Stage; |
| import com.google.inject.TypeLiteral; |
| |
| /** |
| * Creates {@link Context} or {@link Injector} configured to an api and |
| * endpoint. Alternatively, this can be used to make a portable {@link View} of |
| * that api. |
| * |
| * <br/> |
| * ex. to build a {@code Api} on a particular endpoint using the typed |
| * interface |
| * |
| * <pre> |
| * api = ContextBuilder.newBuilder(new NovaApiMetadata()) |
| * .endpoint("http://10.10.10.10:5000/v2.0") |
| * .credentials(user, pass) |
| * .buildApi(NovaApi.class); |
| * </pre> |
| * |
| * <br/> |
| * ex. to build a {@link View} of a particular backend context, looked up by |
| * key. |
| * |
| * <pre> |
| * context = ContextBuilder.newBuilder("aws-s3") |
| * .credentials(apikey, secret) |
| * .buildView(BlobStoreContext.class); |
| * </pre> |
| * |
| * <h4>Assumptions</h4> |
| * |
| * Threadsafe objects will be bound as singletons to the Injector or Context |
| * provided. |
| * <p/> |
| * If no <code>Module</code>s are specified, the default |
| * {@link JDKLoggingModule logging} and |
| * {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be |
| * installed. |
| * |
| * @see Context |
| * @see View |
| * @see ApiMetadata |
| * @see ProviderMetadata |
| */ |
| public class ContextBuilder { |
| |
| private static final Stage GUICE_STAGE = Stage.PRODUCTION; |
| |
| /** |
| * looks up a provider or api with the given id |
| * |
| * @param providerOrApi |
| * id of the provider or api |
| * @return means to build a context to that provider |
| * @throws NoSuchElementException |
| * if the id was not configured. |
| */ |
| public static ContextBuilder newBuilder(String providerOrApi) throws NoSuchElementException { |
| try { |
| try { |
| return ContextBuilder.newBuilder(Providers.withId(providerOrApi)); |
| } catch (NoSuchElementException e) { |
| return ContextBuilder.newBuilder(Apis.withId(providerOrApi)); |
| } |
| } catch (NoSuchElementException e) { |
| Builder<String, String> builder = ImmutableMultimap.<String, String> builder(); |
| builder.putAll("providers", transform(Providers.all(), Providers.idFunction())); |
| builder.putAll("apis", transform(Apis.all(), Apis.idFunction())); |
| throw new NoSuchElementException(String.format("key [%s] not in the list of providers or apis: %s", |
| providerOrApi, builder.build())); |
| } |
| } |
| |
| public static ContextBuilder newBuilder(ApiMetadata apiMetadata) { |
| try { |
| return new ContextBuilder(apiMetadata); |
| } catch (Exception e) { |
| return propagateAuthorizationOrOriginalException(e); |
| } |
| } |
| |
| public static ContextBuilder newBuilder(ProviderMetadata providerMetadata) { |
| try { |
| return new ContextBuilder(providerMetadata); |
| } catch (Exception e) { |
| return propagateAuthorizationOrOriginalException(e); |
| } |
| } |
| |
| protected Optional<String> name = Optional.absent(); |
| protected Optional<ProviderMetadata> providerMetadata = Optional.absent(); |
| protected final String providerId; |
| protected Optional<String> endpoint = Optional.absent(); |
| protected Optional<String> identity = Optional.absent(); |
| protected Optional<Supplier<Credentials>> credentialsSupplierOption = Optional.absent(); |
| @Nullable |
| protected String credential; |
| protected ApiMetadata apiMetadata; |
| protected String apiVersion; |
| protected String buildVersion; |
| protected Optional<Properties> overrides = Optional.absent(); |
| protected List<Module> modules = newArrayListWithCapacity(3); |
| |
| @Override |
| public String toString() { |
| return toStringHelper("").add("providerMetadata", providerMetadata).add("apiMetadata", apiMetadata).toString(); |
| } |
| |
| protected ContextBuilder(ProviderMetadata providerMetadata) { |
| this(providerMetadata, checkNotNull(providerMetadata, "providerMetadata").getApiMetadata()); |
| } |
| |
| protected ContextBuilder(@Nullable ProviderMetadata providerMetadata, ApiMetadata apiMetadata) { |
| this.apiMetadata = checkNotNull(apiMetadata, "apiMetadata"); |
| if (providerMetadata != null) { |
| this.providerMetadata = Optional.of(providerMetadata); |
| this.endpoint = Optional.of(providerMetadata.getEndpoint()); |
| this.providerId = providerMetadata.getId(); |
| } else { |
| this.endpoint = apiMetadata.getDefaultEndpoint(); |
| this.providerId = apiMetadata.getId(); |
| } |
| this.identity = apiMetadata.getDefaultIdentity(); |
| this.credential = apiMetadata.getDefaultCredential().orNull(); |
| this.apiVersion = apiMetadata.getVersion(); |
| this.buildVersion = apiMetadata.getBuildVersion().or(""); |
| } |
| |
| public ContextBuilder(ApiMetadata apiMetadata) { |
| this(null, apiMetadata); |
| } |
| |
| public ContextBuilder name(String name) { |
| this.name = Optional.of(checkNotNull(name, "name")); |
| return this; |
| } |
| |
| /** |
| * returns the current login credentials. jclouds will not cache this value. Use this when you need to change |
| * credentials at runtime. |
| */ |
| public ContextBuilder credentialsSupplier(Supplier<Credentials> credentialsSupplier) { |
| this.credentialsSupplierOption = Optional.of(checkNotNull(credentialsSupplier, "credentialsSupplier")); |
| return this; |
| } |
| |
| /** |
| * constant value of the cloud identity and credential. |
| * |
| * @param credential (optional depending on {@link ApiMetadata#getCredentialName()} |
| */ |
| public ContextBuilder credentials(String identity, @Nullable String credential) { |
| this.identity = Optional.of(checkNotNull(identity, "identity")); |
| this.credential = credential; |
| return this; |
| } |
| |
| public ContextBuilder endpoint(String endpoint) { |
| this.endpoint = Optional.of(checkNotNull(endpoint, "endpoint")); |
| return this; |
| } |
| |
| public ContextBuilder apiVersion(String apiVersion) { |
| this.apiVersion = checkNotNull(apiVersion, "apiVersion"); |
| return this; |
| } |
| |
| public ContextBuilder buildVersion(String buildVersion) { |
| this.buildVersion = checkNotNull(buildVersion, "buildVersion"); |
| return this; |
| } |
| |
| public ContextBuilder modules(Iterable<? extends Module> modules) { |
| addAll(this.modules, checkNotNull(modules, "modules")); |
| return this; |
| } |
| |
| public ContextBuilder overrides(Properties overrides) { |
| this.overrides = Optional.of(checkNotNull(overrides, "overrides")); |
| return this; |
| } |
| |
| public static String searchPropertiesForProviderScopedProperty(Properties mutable, String prov, String key) throws NoSuchElementException { |
| try { |
| return find(newArrayList(mutable.getProperty(prov + "." + key), mutable.getProperty("jclouds." + key)), |
| notNull()); |
| } catch (NoSuchElementException e) { |
| throw new NoSuchElementException(String.format("property %s.%s not present in properties: %s", prov, key, mutable.keySet())); |
| } finally { |
| mutable.remove(prov + "." + key); |
| mutable.remove("jclouds." + key); |
| } |
| } |
| |
| public Injector buildInjector() { |
| |
| Properties unexpanded = currentStateToUnexpandedProperties(); |
| |
| Set<String> keysToResolve = ImmutableSet.of(PROPERTY_IDENTITY, PROPERTY_CREDENTIAL, PROPERTY_ENDPOINT, |
| PROPERTY_API, PROPERTY_API_VERSION, PROPERTY_BUILD_VERSION); |
| |
| Set<String> optionalKeys; |
| if (credentialsSupplierOption.isPresent()) { |
| optionalKeys = ImmutableSet.of(PROPERTY_IDENTITY, PROPERTY_CREDENTIAL); |
| } else if (!apiMetadata.getCredentialName().isPresent()) { |
| optionalKeys = ImmutableSet.of(PROPERTY_CREDENTIAL); |
| } else { |
| optionalKeys = ImmutableSet.of(); |
| } |
| |
| Properties resolved = resolveProperties(unexpanded, providerId, keysToResolve, optionalKeys); |
| |
| Properties expanded = new ExpandProperties().apply(resolved); |
| |
| Supplier<Credentials> credentialsSupplier = buildCredentialsSupplier(expanded); |
| |
| ProviderMetadata providerMetadata = new UpdateProviderMetadataFromProperties(apiMetadata, this.providerMetadata) |
| .apply(expanded); |
| |
| // We use either the specified name (optional) or a hash of provider/api, endpoint, api version & identity. Hash |
| // is used to be something readable. |
| return buildInjector(name.or(String.valueOf(Objects.hashCode(providerMetadata.getId(), |
| providerMetadata.getEndpoint(), providerMetadata.getApiMetadata().getVersion(), credentialsSupplier))), |
| providerMetadata, credentialsSupplier, modules); |
| } |
| |
| protected Supplier<Credentials> buildCredentialsSupplier(Properties expanded) { |
| Credentials creds = new Credentials(getAndRemove(expanded, PROPERTY_IDENTITY), getAndRemove(expanded, |
| PROPERTY_CREDENTIAL)); |
| |
| Supplier<Credentials> credentialsSupplier; |
| if (credentialsSupplierOption.isPresent()) { |
| credentialsSupplier = credentialsSupplierOption.get(); |
| } else { |
| credentialsSupplier = Suppliers.ofInstance(creds); |
| } |
| return credentialsSupplier; |
| } |
| |
| private static String getAndRemove(Properties expanded, String key) { |
| try { |
| return expanded.getProperty(key); |
| } finally { |
| expanded.remove(key); |
| } |
| } |
| |
| private Properties currentStateToUnexpandedProperties() { |
| Properties defaults = new Properties(); |
| putAllAsString(apiMetadata.getDefaultProperties(), defaults); |
| defaults.setProperty(PROPERTY_PROVIDER, providerId); |
| if (providerMetadata.isPresent()) { |
| putAllAsString(providerMetadata.get().getDefaultProperties(), defaults); |
| defaults.setProperty(PROPERTY_ISO3166_CODES, Joiner.on(',').join(providerMetadata.get().getIso3166Codes())); |
| } |
| if (endpoint.isPresent()) |
| defaults.setProperty(PROPERTY_ENDPOINT, endpoint.get()); |
| defaults.setProperty(PROPERTY_API, apiMetadata.getName()); |
| defaults.setProperty(PROPERTY_API_VERSION, apiVersion); |
| defaults.setProperty(PROPERTY_BUILD_VERSION, buildVersion); |
| if (identity.isPresent()) |
| defaults.setProperty(PROPERTY_IDENTITY, identity.get()); |
| if (credential != null) |
| defaults.setProperty(PROPERTY_CREDENTIAL, credential); |
| if (overrides.isPresent()) |
| putAllAsString(overrides.get(), defaults); |
| putAllAsString(propertiesPrefixedWithJcloudsApiOrProviderId(getSystemProperties(), apiMetadata.getId(), providerId), defaults); |
| return defaults; |
| } |
| |
| private static void putAllAsString(Map<?, ?> source, Properties target) { |
| for (Map.Entry<?, ?> entry : source.entrySet()) { |
| target.setProperty(entry.getKey().toString(), entry.getValue().toString()); |
| } |
| } |
| |
| @VisibleForTesting |
| protected Properties getSystemProperties() { |
| return System.getProperties(); |
| } |
| |
| public static Injector buildInjector(String name, ProviderMetadata providerMetadata, Supplier<Credentials> creds, List<Module> inputModules) { |
| List<Module> modules = newArrayList(); |
| modules.addAll(inputModules); |
| boolean apiModuleSpecifiedByUser = apiModulePresent(inputModules); |
| Iterable<Module> defaultModules = ifSpecifiedByUserDontIncludeDefaultApiModule( |
| providerMetadata.getApiMetadata(), apiModuleSpecifiedByUser); |
| addAll(modules, defaultModules); |
| addClientModuleIfNotPresent(providerMetadata.getApiMetadata(), modules); |
| addRestContextBinding(providerMetadata.getApiMetadata(), modules); |
| addLoggingModuleIfNotPresent(modules); |
| addHttpModuleIfNeededAndNotPresent(modules); |
| addExecutorServiceIfNotPresent(modules); |
| addEventBusIfNotPresent(modules); |
| addCredentialStoreIfNotPresent(modules); |
| modules.add(new LifeCycleModule()); |
| modules.add(new BindProviderMetadataContextAndCredentials(providerMetadata, creds)); |
| modules.add(new BindNameToContext(name)); |
| Injector returnVal = Guice.createInjector(GUICE_STAGE, modules); |
| returnVal.getInstance(ExecutionList.class).execute(); |
| return returnVal; |
| } |
| |
| static Properties resolveProperties(Properties mutable, String providerId, Set<String> keys, Set<String> optionalKeys) throws NoSuchElementException { |
| for (String key : keys) { |
| String scopedProperty = Iterables.get(Splitter.on('.').split(key), 1); |
| try { |
| mutable.setProperty(key, searchPropertiesForProviderScopedProperty(mutable, providerId, scopedProperty)); |
| } catch (NoSuchElementException e) { |
| if (!optionalKeys.contains(key)) |
| throw e; |
| } |
| } |
| return mutable; |
| } |
| |
| static void addRestContextBinding(ApiMetadata apiMetadata, List<Module> modules) { |
| if (apiMetadata instanceof HttpApiMetadata) { |
| try { |
| modules |
| .add(new BindApiContextWithWildcardExtendsExplicitAndRawType(HttpApiMetadata.class.cast(apiMetadata))); |
| } catch (IllegalArgumentException ignored) { |
| |
| } |
| } |
| } |
| |
| static Iterable<Module> ifSpecifiedByUserDontIncludeDefaultApiModule(ApiMetadata apiMetadata, |
| boolean restModuleSpecifiedByUser) { |
| Iterable<Module> defaultModules = transform(apiMetadata.getDefaultModules(), |
| new Function<Class<? extends Module>, Module>() { |
| |
| @Override |
| public Module apply(Class<? extends Module> arg0) { |
| try { |
| return arg0.getConstructor().newInstance(); |
| } catch (InstantiationException e) { |
| throw propagate(e); |
| } catch (IllegalAccessException e) { |
| throw propagate(e); |
| } catch (InvocationTargetException e) { |
| throw propagate(e); |
| } catch (NoSuchMethodException e) { |
| throw propagate(e); |
| } |
| } |
| |
| }); |
| if (restModuleSpecifiedByUser) |
| defaultModules = filter(defaultModules, not(configuresApi)); |
| return defaultModules; |
| } |
| |
| @SuppressWarnings( { "unchecked" }) |
| static Map<String, Object> propertiesPrefixedWithJcloudsApiOrProviderId(Properties properties, String apiId, |
| String providerId) { |
| return filterKeys(Map.class.cast(properties), containsPattern("^(jclouds|" + providerId + "|" + apiId + ").*")); |
| } |
| |
| @VisibleForTesting |
| static void addLoggingModuleIfNotPresent(List<Module> modules) { |
| if (!any(modules, instanceOf(LoggingModule.class))) |
| modules.add(new JDKLoggingModule()); |
| } |
| |
| @VisibleForTesting |
| static void addHttpModuleIfNeededAndNotPresent(List<Module> modules) { |
| if (nothingConfiguresAnHttpService(modules)) |
| modules.add(new JavaUrlHttpCommandExecutorServiceModule()); |
| } |
| |
| static boolean nothingConfiguresAnHttpService(List<Module> modules) { |
| return !any(modules, new Predicate<Module>() { |
| public boolean apply(Module input) { |
| return input.getClass().isAnnotationPresent(ConfiguresHttpCommandExecutorService.class); |
| } |
| |
| }); |
| } |
| |
| @VisibleForTesting |
| static void addClientModuleIfNotPresent(ApiMetadata apiMetadata, List<Module> modules) { |
| if (!apiModulePresent(modules)) { |
| addClientModule(apiMetadata, modules); |
| } |
| } |
| private static boolean apiModulePresent(List<Module> modules) { |
| return any(modules, configuresApi); |
| } |
| |
| private static Predicate<Module> configuresApi = new Predicate<Module>() { |
| public boolean apply(Module input) { |
| return input.getClass().isAnnotationPresent(ConfiguresHttpApi.class); |
| } |
| |
| }; |
| |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| static void addClientModule(ApiMetadata apiMetadata, List<Module> modules) { |
| // TODO: move this up |
| if (apiMetadata instanceof HttpApiMetadata) { |
| HttpApiMetadata api = HttpApiMetadata.class.cast(apiMetadata); |
| modules.add(new HttpApiModule(api.getApi())); |
| } else { |
| modules.add(new RestModule()); |
| // Minimally bind HttpClient so that Utils works. |
| modules.add(new AbstractModule() { |
| @Override public void configure() { |
| bind(new TypeLiteral<Function<Invocation, Object>>() { |
| }).to(InvokeHttpMethod.class); |
| bindHttpApi(binder(), HttpClient.class); |
| } |
| }); |
| } |
| } |
| |
| @VisibleForTesting |
| static void addEventBusIfNotPresent(List<Module> modules) { |
| if (!any(modules, new Predicate<Module>() { |
| public boolean apply(Module input) { |
| return input.getClass().isAnnotationPresent(ConfiguresEventBus.class); |
| } |
| } |
| |
| )) { |
| modules.add(new EventBusModule()); |
| } |
| } |
| |
| @VisibleForTesting |
| static void addExecutorServiceIfNotPresent(List<Module> modules) { |
| if (!any(modules, new Predicate<Module>() { |
| public boolean apply(Module input) { |
| return input.getClass().isAnnotationPresent(ConfiguresExecutorService.class); |
| } |
| } |
| |
| )) { |
| if (any(modules, new Predicate<Module>() { |
| public boolean apply(Module input) { |
| return input.getClass().isAnnotationPresent(SingleThreaded.class); |
| } |
| })) { |
| modules.add(new ExecutorServiceModule(newDirectExecutorService())); |
| } else { |
| modules.add(new ExecutorServiceModule()); |
| } |
| } |
| } |
| |
| @VisibleForTesting |
| static void addCredentialStoreIfNotPresent(List<Module> modules) { |
| if (!any(modules, new Predicate<Module>() { |
| public boolean apply(Module input) { |
| return input.getClass().isAnnotationPresent(ConfiguresCredentialStore.class); |
| } |
| } |
| |
| )) { |
| modules.add(new CredentialStoreModule()); |
| } |
| |
| } |
| |
| /** |
| * Builds the base context for this api. Note that this may be of type {@link Closer}, if nothing |
| * else was configured via {@link ApiMetadata#getContext()}. Typically, the type returned is |
| * {@link ApiContext} |
| * |
| * @see ApiMetadata#getContext() |
| * @see #build(TypeToken) |
| */ |
| @SuppressWarnings("unchecked") |
| public <C extends Context> C build() { |
| return (C) build(apiMetadata.getContext()); |
| } |
| |
| /** |
| * @see #buildView(Class) |
| */ |
| public <V extends View> V build(Class<V> viewType) { |
| return buildView(checkNotNull(viewType, "viewType")); |
| } |
| |
| /** |
| * @see #buildView(TypeToken) |
| */ |
| public <V extends View> V buildView(Class<V> viewType) { |
| return buildView(typeToken(viewType)); |
| } |
| |
| /** |
| * this will build any {@link ApiMetadata#getViews() view} supported by the ApiMetadata. |
| * |
| * ex. {@code builder.build(BlobStoreContext.class) } will work, if {@code TypeToken<BlobStore>} |
| * is a configured {@link ApiMetadata#getViews() view} of this api. |
| * |
| */ |
| @SuppressWarnings("unchecked") |
| public <V extends View> V buildView(TypeToken<V> viewType) { |
| TypeToken<V> returnType; |
| try { |
| returnType = (TypeToken<V>) Apis.findView(apiMetadata, checkNotNull(viewType, "viewType")); |
| } catch (NoSuchElementException e) { |
| throw new IllegalArgumentException(String.format( |
| "api %s not wrappable as %s; context: %s, views: %s", apiMetadata, |
| viewType, apiMetadata.getContext(), apiMetadata.getViews())); |
| } |
| return (V) buildInjector().getInstance(Key.get(TypeLiteral.get(returnType.getType()))); |
| } |
| |
| /** |
| * this will build the {@link ApiMetadata#getContext() context} supported by the current ApiMetadata. |
| */ |
| @SuppressWarnings("unchecked") |
| public <C extends Context> C build(TypeToken<C> contextType) { |
| TypeToken<C> returnType = null; |
| if (TypeTokenUtils.isSupertypeOf(contextType, apiMetadata.getContext())) |
| returnType = (TypeToken<C>) apiMetadata.getContext(); |
| else |
| throw new IllegalArgumentException(String.format("api %s not assignable from %s; context: %s", apiMetadata, |
| contextType, apiMetadata.getContext())); |
| return (C) buildInjector().getInstance(Key.get(TypeLiteral.get(returnType.getType()))); |
| } |
| |
| /** |
| * This will return the top-level interface for the api or provider. |
| * |
| * Ex. |
| * <pre> |
| * api = ContextBuilder.newBuilder("openstack-nova") |
| * ... |
| * .buildApi(NovaApi.class); |
| *</pre> |
| */ |
| public <A extends Closeable> A buildApi(Class<A> api) { |
| return buildApi(typeToken(api)); |
| } |
| |
| /** |
| * like {@link #buildApi(Class)} but permits a type-token for convenience. |
| */ |
| @SuppressWarnings("unchecked") |
| public <A extends Closeable> A buildApi(TypeToken<A> apiType) { |
| return (A) buildInjector().getInstance(Key.get(TypeLiteral.get(apiType.getType()))); |
| } |
| |
| public ApiMetadata getApiMetadata() { |
| return apiMetadata; |
| } |
| } |