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

com.nesscomputing.httpclient.guice.HttpClientModule Maven / Gradle / Ivy

There is a newer version: 2.0.5
Show newest version
/**
 * Copyright (C) 2012 Ness Computing, Inc.
 *
 * Licensed 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 com.nesscomputing.httpclient.guice;


import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nonnull;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import com.nesscomputing.config.ConfigProvider;
import com.nesscomputing.httpclient.HttpClient;
import com.nesscomputing.httpclient.HttpClientDefaults;
import com.nesscomputing.httpclient.HttpClientObserver;
import com.nesscomputing.httpclient.factory.httpclient4.ApacheHttpClient4Factory;
import com.nesscomputing.httpclient.internal.HttpClientFactory;
import com.nesscomputing.lifecycle.LifecycleStage;
import com.nesscomputing.lifecycle.guice.AbstractLifecycleProvider;
import com.nesscomputing.lifecycle.guice.LifecycleAction;

/**
 * Guice module to bind an instance of a HttpClient. Each HttpClient should be annotated or named so that
 * other pieces of code can request a specific instance of the HttpClient.
 */
public class HttpClientModule extends AbstractModule
{
    public static final String DEFAULT_NAME = "default";
    public static final Named DEFAULT_NAMED = Names.named(DEFAULT_NAME);

    private final String clientName;

    /**
     * Bind an anonymous, unannotated HttpClient.  Guice 3.0 actually seems to get it right that this is not
     * exposed for arbitrary requests with annotations.
     */
    public HttpClientModule()
    {
        this.clientName = DEFAULT_NAME;
    }

    /**
     * Bind an named HttpClient instance.
     * @param clientName The name to use. This can be used with the Named annotation in other parts of the code.
     */
    public HttpClientModule(@Nonnull final String clientName)
    {
        Preconditions.checkArgument(clientName != null, "client name can not be null");
        Preconditions.checkArgument(!DEFAULT_NAME.equals(clientName), "client name can not be '%s'", DEFAULT_NAME);

        this.clientName = clientName;
    }

    @Override
    public void configure()
    {
        final Map optionMap = Collections.singletonMap("httpclient_name", clientName);
        final Annotation annotation = Names.named(clientName);

        bind(HttpClientDefaults.class).annotatedWith(annotation).toProvider(ConfigProvider.of(null, HttpClientDefaults.class, optionMap)).in(Scopes.SINGLETON);
        bind(HttpClientFactory.class).annotatedWith(annotation).toProvider(new ApacheHttpClient4FactoryProvider(annotation)).in(Scopes.SINGLETON);
        bind(HttpClient.class).annotatedWith(annotation).toProvider(new HttpClientProvider(annotation)).asEagerSingleton();

        if (clientName.equals(DEFAULT_NAME)) {
            bind(HttpClient.class).toProvider(new HttpClientProvider(annotation)).asEagerSingleton();
        }
    }

    /**
     * Register a HttpClient observer which observes *every* Guice-bound HttpClient.
     * @return the binding builder you should register with
     */
    public static LinkedBindingBuilder bindNewObserver(final Binder binder)
    {
        return Multibinder.newSetBinder(binder, HttpClientObserver.class).addBinding();
    }

    /**
     * Register a HttpClient observer which observes only requests from a HttpClient with the given Guice binding annotation.
     * @return the binding builder you should register with
     */
    public static LinkedBindingBuilder bindNewObserver(final Binder binder, final Annotation annotation)
    {
        return Multibinder.newSetBinder(binder, HttpClientObserver.class, annotation).addBinding();
    }

    /**
     * Provides an instance of a HttpClient. Retrieves all its dependencies based off an annotation.
     */
    static final class HttpClientProvider extends AbstractLifecycleProvider implements Provider
    {
        private HttpClientDefaults  httpClientDefaults = null;
        private HttpClientFactory httpClientFactory = null;

        private final Annotation annotation;

        private HttpClientProvider(@Nonnull final Annotation annotation)
        {
            this.annotation = annotation;

            addAction(LifecycleStage.START_STAGE, new LifecycleAction() {
                @Override
                public void performAction(final HttpClient httpClient) {
                    httpClient.start();
                }
            });

            addAction(LifecycleStage.STOP_STAGE, new LifecycleAction() {
                @Override
                public void performAction(final HttpClient httpClient) {
                    httpClient.stop();
                }
            });
        }

        @Inject
        public void setInjector(final Injector injector)
        {
            this.httpClientDefaults = injector.getInstance(Key.get(HttpClientDefaults.class, annotation));
            this.httpClientFactory = injector.getInstance(Key.get(HttpClientFactory.class, annotation));
        }

        @Override
        public HttpClient internalGet()
        {
            return new HttpClient(httpClientFactory, httpClientDefaults);
        }
    }

    static final class ApacheHttpClient4FactoryProvider implements Provider
    {
        private static final TypeLiteral> OBSERVER_TYPE_LITERAL = new TypeLiteral>() {};
        private final Annotation annotation;

        private HttpClientDefaults httpClientDefaults = null;
        private Set httpClientObservers = null;

        private ApacheHttpClient4FactoryProvider(@Nonnull final Annotation annotation)
        {
            this.annotation = annotation;
        }

        @Inject
        void setInjector(final Injector injector)
        {
            httpClientObservers = Sets.newHashSet();

            httpClientObservers.addAll(findObservers(injector, Key.get(OBSERVER_TYPE_LITERAL)));
            httpClientObservers.addAll(findObservers(injector, Key.get(OBSERVER_TYPE_LITERAL, annotation)));

            httpClientDefaults = injector.getInstance(Key.get(HttpClientDefaults.class, annotation));
        }

        private Set findObservers(final Injector injector, final Key> key)
        {
            if (injector.getExistingBinding(key) != null) {
                return injector.getInstance(key);
            }
            else {
                return Collections.emptySet();
            }
        }

        @Override
        public HttpClientFactory get()
        {
            return new ApacheHttpClient4Factory(httpClientDefaults, httpClientObservers);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy