View Javadoc

1   /**
2    *
3    * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4    *
5    * ====================================================================
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   * ====================================================================
18   */
19  package org.jclouds.rest.config;
20  
21  import java.util.concurrent.ConcurrentMap;
22  
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  import javax.ws.rs.core.UriBuilder;
26  
27  import org.jclouds.functions.IdentityFunction;
28  import org.jclouds.http.HttpRequest;
29  import org.jclouds.http.HttpResponse;
30  import org.jclouds.http.TransformingHttpCommand;
31  import org.jclouds.http.TransformingHttpCommandExecutorService;
32  import org.jclouds.http.TransformingHttpCommandImpl;
33  import org.jclouds.http.functions.config.SaxParserModule;
34  import org.jclouds.internal.ClassMethodArgs;
35  import org.jclouds.json.config.GsonModule;
36  import org.jclouds.rest.AsyncClientFactory;
37  import org.jclouds.rest.HttpAsyncClient;
38  import org.jclouds.rest.HttpClient;
39  import org.jclouds.rest.binders.BindToJsonPayloadWrappedWith;
40  import org.jclouds.rest.internal.AsyncRestClientProxy;
41  import org.jclouds.rest.internal.RestAnnotationProcessor;
42  import org.jclouds.rest.internal.SeedAnnotationCache;
43  
44  import com.google.common.base.Function;
45  import com.google.common.collect.ImmutableMap;
46  import com.google.common.collect.MapMaker;
47  import com.google.inject.AbstractModule;
48  import com.google.inject.Inject;
49  import com.google.inject.Injector;
50  import com.google.inject.Key;
51  import com.google.inject.Provides;
52  import com.google.inject.Scopes;
53  import com.google.inject.TypeLiteral;
54  import com.google.inject.assistedinject.FactoryModuleBuilder;
55  import com.google.inject.name.Names;
56  import com.google.inject.util.Types;
57  import com.sun.jersey.api.uri.UriBuilderImpl;
58  
59  /**
60   * 
61   * @author Adrian Cole
62   */
63  public class RestModule extends AbstractModule {
64  
65     @Override
66     protected void configure() {
67        install(new SaxParserModule());
68        install(new GsonModule());
69        install(new FactoryModuleBuilder().build(BindToJsonPayloadWrappedWith.Factory.class));
70        bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE);
71        bind(UriBuilder.class).to(UriBuilderImpl.class);
72        bind(AsyncRestClientProxy.Factory.class).to(Factory.class).in(Scopes.SINGLETON);
73        BinderUtils.bindAsyncClient(binder(), HttpAsyncClient.class);
74        BinderUtils.bindClient(binder(), HttpClient.class, HttpAsyncClient.class, ImmutableMap.<Class<?>, Class<?>> of(
75                 HttpClient.class, HttpAsyncClient.class));
76     }
77  
78     @Provides
79     @Singleton
80     protected ConcurrentMap<Class<?>, Boolean> seedAnnotationCache(SeedAnnotationCache seedAnnotationCache) {
81        return new MapMaker().makeComputingMap(seedAnnotationCache);
82     }
83  
84     @Provides
85     @Singleton
86     @Named("async")
87     ConcurrentMap<ClassMethodArgs, Object> provideAsyncDelegateMap(CreateAsyncClientForCaller createAsyncClientForCaller) {
88        return new MapMaker().makeComputingMap(createAsyncClientForCaller);
89     }
90  
91     static class CreateAsyncClientForCaller implements Function<ClassMethodArgs, Object> {
92        private final Injector injector;
93        private final AsyncRestClientProxy.Factory factory;
94  
95        @Inject
96        CreateAsyncClientForCaller(Injector injector, AsyncRestClientProxy.Factory factory) {
97           this.injector = injector;
98           this.factory = factory;
99        }
100 
101       @SuppressWarnings( { "unchecked", "rawtypes" })
102       @Override
103       public Object apply(final ClassMethodArgs from) {
104          Class clazz = from.getAsyncClass();
105          TypeLiteral typeLiteral = TypeLiteral.get(clazz);
106          RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key.get(TypeLiteral.get(Types
107                   .newParameterizedType(RestAnnotationProcessor.class, clazz))));
108          // cannot use child injectors due to the super coarse guice lock on
109          // Singleton
110          util.setCaller(from);
111          ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
112                   new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
113                   }, Names.named("async")));
114          AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector, factory, util, typeLiteral, delegateMap);
115          injector.injectMembers(proxy);
116          return AsyncClientFactory.create(clazz, proxy);
117       }
118    }
119 
120    private static class Factory implements AsyncRestClientProxy.Factory {
121       @Inject
122       private TransformingHttpCommandExecutorService executorService;
123 
124       @SuppressWarnings( { "unchecked", "rawtypes" })
125       @Override
126       public TransformingHttpCommand<?> create(HttpRequest request, Function<HttpResponse, ?> transformer) {
127          return new TransformingHttpCommandImpl(executorService, request, transformer);
128       }
129 
130    }
131 
132 }