All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jclouds.rest.RestContextBuilder Maven / Gradle / Ivy

/**
 * Licensed to jclouds, Inc. (jclouds) under one or more
 * contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  jclouds 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.rest;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.base.Predicates.not;
import static com.google.common.base.Splitter.on;
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.inject.Scopes.SINGLETON;
import static com.google.inject.name.Names.bindProperties;
import static com.google.inject.util.Types.newParameterizedType;
import static org.jclouds.Constants.PROPERTY_API;
import static org.jclouds.Constants.PROPERTY_API_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.Constants.PROPERTY_TIMEOUTS_PREFIX;

import java.net.URI;
import java.util.*;
import java.util.Map.Entry;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import com.google.common.collect.*;
import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.SingleThreaded;
import org.jclouds.concurrent.config.ConfiguresExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.location.Iso3166;
import org.jclouds.location.Provider;
import org.jclouds.location.config.ProvideIso3166CodesByLocationIdViaProperties;
import org.jclouds.logging.config.LoggingModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rest.annotations.Api;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.annotations.Credential;
import org.jclouds.rest.annotations.Identity;
import org.jclouds.rest.config.CredentialStoreModule;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestContextImpl;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
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.Provides;
import com.google.inject.TypeLiteral;

/**
 * Creates {@link RestContext} or {@link Injector} instances based on the most commonly requested
 * arguments.
 * 

* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided. *

*

* If no Modules are specified, the default {@link JDKLoggingModule logging} and * {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed. * * @author Adrian Cole, Andrew Newdigate * @see RestContext */ public class RestContextBuilder { static class BindPropertiesAndPrincipalContext extends AbstractModule { protected Properties properties; protected BindPropertiesAndPrincipalContext(Properties properties) { this.properties = checkNotNull(properties, "properties"); } @Provides @Singleton @Named("CONSTANTS") protected Multimap constants() { ImmutableMultimap.Builder builder = ImmutableMultimap. builder(); for (Entry entry : properties.entrySet()) if (entry.getValue() != null) builder.put(entry.getKey().toString(), entry.getValue().toString()); return LinkedHashMultimap.create(builder.build()); } @Provides @Singleton @Named("TIMEOUTS") protected Map timeouts() { final ImmutableMap.Builder builder = ImmutableMap. builder(); for (final Entry entry : properties.entrySet()) { final String key = String.valueOf(entry.getKey()); if (key.startsWith(PROPERTY_TIMEOUTS_PREFIX) && entry.getValue() != null) { try { final Long val = Long.valueOf(String.valueOf(entry.getValue())); builder.put(key.replaceFirst(PROPERTY_TIMEOUTS_PREFIX, ""), val); } catch (final Throwable t) {} } } return builder.build(); } @Override protected void configure() { Properties toBind = new Properties(); toBind.putAll(checkNotNull(properties, "properties")); toBind.putAll(System.getProperties()); bindProperties(binder(), toBind); bind(String.class).annotatedWith(Provider.class).toInstance( checkNotNull(toBind.getProperty(PROPERTY_PROVIDER), PROPERTY_PROVIDER)); bind(URI.class).annotatedWith(Provider.class).toInstance( URI.create(checkNotNull(toBind.getProperty(PROPERTY_ENDPOINT), PROPERTY_ENDPOINT))); bind(new TypeLiteral>() { }).annotatedWith(Iso3166.class).toInstance( ImmutableSet.copyOf(filter(on(',').split( checkNotNull(toBind.getProperty(PROPERTY_ISO3166_CODES), PROPERTY_ISO3166_CODES)), not(equalTo(""))))); bind(new TypeLiteral>>() { }).annotatedWith(Iso3166.class).toProvider(ProvideIso3166CodesByLocationIdViaProperties.class); if (toBind.containsKey(PROPERTY_API)) bind(String.class).annotatedWith(Api.class).toInstance(toBind.getProperty(PROPERTY_API)); if (toBind.containsKey(PROPERTY_API_VERSION)) bind(String.class).annotatedWith(ApiVersion.class).toInstance(toBind.getProperty(PROPERTY_API_VERSION)); if (toBind.containsKey(PROPERTY_IDENTITY)) bind(String.class).annotatedWith(Identity.class).toInstance( checkNotNull(toBind.getProperty(PROPERTY_IDENTITY), PROPERTY_IDENTITY)); if (toBind.containsKey(PROPERTY_CREDENTIAL)) bind(String.class).annotatedWith(Credential.class).toInstance(toBind.getProperty(PROPERTY_CREDENTIAL)); } } protected Properties properties; protected List modules = new ArrayList(3); protected Class asyncClientType; protected Class syncClientType; @Inject public RestContextBuilder(Class syncClientClass, Class asyncClientClass, Properties properties) { this.asyncClientType = checkNotNull(asyncClientClass, "asyncClientType"); this.syncClientType = checkNotNull(syncClientClass, "syncClientType"); this.properties = checkNotNull(properties, "properties"); } public RestContextBuilder withModules(Iterable modules) { addAll(this.modules, modules); return this; } public Injector buildInjector() { addContextModule(modules); addClientModuleIfNotPresent(modules); addLoggingModuleIfNotPresent(modules); addHttpModuleIfNeededAndNotPresent(modules); ifHttpConfigureRestOtherwiseGuiceClientFactory(modules); addExecutorServiceIfNotPresent(modules); addCredentialStoreIfNotPresent(modules); modules.add(new BindPropertiesAndPrincipalContext(properties)); return Guice.createInjector(modules); } @VisibleForTesting protected void addLoggingModuleIfNotPresent(List modules) { if (!any(modules, instanceOf(LoggingModule.class))) modules.add(new JDKLoggingModule()); } @VisibleForTesting protected void addHttpModuleIfNeededAndNotPresent(List modules) { if (defaultOrAtLeastOneModuleRequiresHttp(modules) && nothingConfiguresAnHttpService(modules)) modules.add(new JavaUrlHttpCommandExecutorServiceModule()); } private boolean nothingConfiguresAnHttpService(List modules) { return (!any(modules, new Predicate() { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(ConfiguresHttpCommandExecutorService.class); } })); } @VisibleForTesting protected void addContextModuleIfNotPresent(List modules) { if (!any(modules, new Predicate() { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(ConfiguresRestContext.class); } })) { addContextModule(modules); } } @VisibleForTesting protected void addContextModule(List modules) { modules.add(new AbstractModule() { @SuppressWarnings( { "unchecked", "rawtypes" }) @Override protected void configure() { bind( (TypeLiteral) TypeLiteral.get(newParameterizedType(RestContext.class, syncClientType, asyncClientType))).to( TypeLiteral.get(newParameterizedType(RestContextImpl.class, syncClientType, asyncClientType))).in( SINGLETON); } public String toString() { return String.format("configure rest context %s->%s", syncClientType.getSimpleName(), asyncClientType .getSimpleName()); } }); } @VisibleForTesting protected void ifHttpConfigureRestOtherwiseGuiceClientFactory(List modules) { if (defaultOrAtLeastOneModuleRequiresHttp(modules)) { modules.add(new RestModule()); } } private boolean defaultOrAtLeastOneModuleRequiresHttp(List modules) { return atLeastOneModuleRequiresHttp(modules) || !restClientModulePresent(modules); } private boolean atLeastOneModuleRequiresHttp(List modules) { return any(modules, new Predicate() { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(RequiresHttp.class); } }); } @VisibleForTesting protected void addClientModuleIfNotPresent(List modules) { if (!restClientModulePresent(modules)) { addClientModule(modules); } } private boolean restClientModulePresent(List modules) { return any(modules, new Predicate() { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(ConfiguresRestClient.class); } }); } protected void addClientModule(List modules) { modules.add(new RestClientModule(syncClientType, asyncClientType)); } @VisibleForTesting protected void addExecutorServiceIfNotPresent(List modules) { if (!any(modules, new Predicate() { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(ConfiguresExecutorService.class); } } )) { if (any(modules, new Predicate() { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(SingleThreaded.class); } })) { modules.add(new ExecutorServiceModule(MoreExecutors.sameThreadExecutor(), MoreExecutors .sameThreadExecutor())); } else { modules.add(new ExecutorServiceModule()); } } } @VisibleForTesting protected void addCredentialStoreIfNotPresent(List modules) { if (!any(modules, new Predicate() { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(ConfiguresCredentialStore.class); } } )) { modules.add(new CredentialStoreModule()); } } @VisibleForTesting public Properties getProperties() { return properties; } @SuppressWarnings("unchecked") public > T buildContext() { Injector injector = buildInjector(); return (T) injector .getInstance(Key.get(newParameterizedType(RestContext.class, syncClientType, asyncClientType))); } }