1 | /** |
2 | * Licensed to jclouds, Inc. (jclouds) under one or more |
3 | * contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. jclouds licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. 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, |
13 | * software distributed under the License is distributed on an |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | * KIND, either express or implied. See the License for the |
16 | * specific language governing permissions and limitations |
17 | * under the License. |
18 | */ |
19 | package org.jclouds.rest.config; |
20 | |
21 | import javax.inject.Named; |
22 | import javax.inject.Singleton; |
23 | import javax.ws.rs.core.UriBuilder; |
24 | |
25 | import org.jclouds.functions.IdentityFunction; |
26 | import org.jclouds.http.HttpRequest; |
27 | import org.jclouds.http.HttpResponse; |
28 | import org.jclouds.http.TransformingHttpCommand; |
29 | import org.jclouds.http.TransformingHttpCommandExecutorService; |
30 | import org.jclouds.http.TransformingHttpCommandImpl; |
31 | import org.jclouds.http.functions.config.SaxParserModule; |
32 | import org.jclouds.internal.ClassMethodArgs; |
33 | import org.jclouds.json.config.GsonModule; |
34 | import org.jclouds.rest.AsyncClientFactory; |
35 | import org.jclouds.rest.HttpAsyncClient; |
36 | import org.jclouds.rest.HttpClient; |
37 | import org.jclouds.rest.binders.BindToJsonPayloadWrappedWith; |
38 | import org.jclouds.rest.internal.AsyncRestClientProxy; |
39 | import org.jclouds.rest.internal.RestAnnotationProcessor; |
40 | import org.jclouds.rest.internal.SeedAnnotationCache; |
41 | |
42 | import com.google.common.base.Function; |
43 | import com.google.common.cache.Cache; |
44 | import com.google.common.cache.CacheBuilder; |
45 | import com.google.common.cache.CacheLoader; |
46 | import com.google.common.collect.ImmutableMap; |
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 Cache<Class<?>, Boolean> seedAnnotationCache(SeedAnnotationCache seedAnnotationCache) { |
81 | return CacheBuilder.newBuilder().build(seedAnnotationCache); |
82 | } |
83 | |
84 | @Provides |
85 | @Singleton |
86 | @Named("async") |
87 | Cache<ClassMethodArgs, Object> provideAsyncDelegateMap(CreateAsyncClientForCaller createAsyncClientForCaller) { |
88 | return CacheBuilder.newBuilder().build(createAsyncClientForCaller); |
89 | } |
90 | |
91 | static class CreateAsyncClientForCaller extends CacheLoader<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 load(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 | Cache<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get( |
112 | new TypeLiteral<Cache<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 | } |