EMMA Coverage Report (generated Wed Aug 10 12:30:04 EDT 2011)
[all classes][org.jclouds.concurrent.internal]

COVERAGE SUMMARY FOR SOURCE FILE [SyncProxy.java]

nameclass, %method, %block, %line, %
SyncProxy.java100% (1/1)75%  (6/8)84%  (279/331)75%  (46/61)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SyncProxy100% (1/1)75%  (6/8)84%  (279/331)75%  (46/61)
equals (Object): boolean 0%   (0/1)0%   (0/26)0%   (0/8)
hashCode (): int 0%   (0/1)0%   (0/4)0%   (0/1)
invoke (Object, Method, Object []): Object 100% (1/1)82%  (97/119)70%  (14/20)
<static initializer> 100% (1/1)100% (5/5)100% (1/1)
SyncProxy (Class, Object, ConcurrentMap, Map): void 100% (1/1)100% (145/145)100% (27/27)
convertToNanos (Timeout): long 100% (1/1)100% (9/9)100% (2/2)
proxy (Class, SyncProxy): Object 100% (1/1)100% (11/11)100% (1/1)
toString (): String 100% (1/1)100% (12/12)100% (1/1)

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 */
19package org.jclouds.concurrent.internal;
20 
21import static com.google.common.base.Preconditions.checkState;
22 
23import java.lang.reflect.InvocationHandler;
24import java.lang.reflect.Method;
25import java.lang.reflect.Proxy;
26import java.util.Arrays;
27import java.util.Map;
28import java.util.Set;
29import java.util.concurrent.ConcurrentMap;
30import java.util.concurrent.ExecutionException;
31import java.util.concurrent.TimeUnit;
32 
33import javax.inject.Inject;
34import javax.inject.Named;
35 
36import org.jclouds.concurrent.Timeout;
37import org.jclouds.internal.ClassMethodArgs;
38import org.jclouds.rest.annotations.Delegate;
39import org.jclouds.util.Throwables2;
40 
41import com.google.common.collect.ImmutableSet;
42import com.google.common.collect.Maps;
43import com.google.common.util.concurrent.ListenableFuture;
44import com.google.inject.ProvisionException;
45 
46/**
47 * Generates RESTful clients from appropriately annotated interfaces.
48 * 
49 * @author Adrian Cole
50 */
51@SuppressWarnings("deprecation")
52public class SyncProxy implements InvocationHandler {
53 
54   @SuppressWarnings("unchecked")
55   public static <T> T proxy(Class<T> clazz, SyncProxy proxy) throws IllegalArgumentException, SecurityException,
56         NoSuchMethodException {
57      return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, proxy);
58   }
59 
60   private final Object delegate;
61   private final Class<?> declaring;
62   private final Map<Method, Method> methodMap;
63   private final Map<Method, Method> syncMethodMap;
64   private final Map<Method, Long> timeoutMap;
65   private final ConcurrentMap<ClassMethodArgs, Object> delegateMap;
66   private final Map<Class<?>, Class<?>> sync2Async;
67   private static final Set<Method> objectMethods = ImmutableSet.of(Object.class.getMethods());
68 
69   @Inject
70   public SyncProxy(Class<?> declaring, Object async,
71         @Named("sync") ConcurrentMap<ClassMethodArgs, Object> delegateMap, Map<Class<?>, Class<?>> sync2Async)
72         throws SecurityException, NoSuchMethodException {
73      this.delegateMap = delegateMap;
74      this.delegate = async;
75      this.declaring = declaring;
76      this.sync2Async = sync2Async;
77      if (!declaring.isAnnotationPresent(Timeout.class)) {
78         throw new IllegalArgumentException(String.format("type %s does not specify a default @Timeout", declaring));
79      }
80      Timeout typeTimeout = declaring.getAnnotation(Timeout.class);
81      long typeNanos = convertToNanos(typeTimeout);
82 
83      methodMap = Maps.newHashMap();
84      syncMethodMap = Maps.newHashMap();
85      timeoutMap = Maps.newHashMap();
86      for (Method method : declaring.getMethods()) {
87         if (!objectMethods.contains(method)) {
88            Method delegatedMethod = delegate.getClass().getMethod(method.getName(), method.getParameterTypes());
89            if (!Arrays.equals(delegatedMethod.getExceptionTypes(), method.getExceptionTypes()))
90               throw new IllegalArgumentException(String.format(
91                     "method %s has different typed exceptions than delegated method %s", method, delegatedMethod));
92            if (delegatedMethod.getReturnType().isAssignableFrom(ListenableFuture.class)) {
93               if (method.isAnnotationPresent(Timeout.class)) {
94                  Timeout methodTimeout = method.getAnnotation(Timeout.class);
95                  long methodNanos = convertToNanos(methodTimeout);
96                  timeoutMap.put(method, methodNanos);
97               } else {
98                  timeoutMap.put(method, typeNanos);
99               }
100               methodMap.put(method, delegatedMethod);
101            } else {
102               syncMethodMap.put(method, delegatedMethod);
103            }
104         }
105      }
106   }
107 
108   static long convertToNanos(Timeout timeout) {
109      long methodNanos = TimeUnit.NANOSECONDS.convert(timeout.duration(), timeout.timeUnit());
110      return methodNanos;
111   }
112 
113   public Object invoke(Object o, Method method, Object[] args) throws Throwable {
114      if (method.getName().equals("equals")) {
115         return this.equals(o);
116      } else if (method.getName().equals("hashCode")) {
117         return this.hashCode();
118      } else if (method.getName().equals("toString")) {
119         return this.toString();
120      } else if (method.isAnnotationPresent(Delegate.class)) {
121         Class<?> asyncClass = sync2Async.get(method.getReturnType());
122         checkState(asyncClass != null, "please configure corresponding async class for " + method.getReturnType()
123               + " in your RestClientModule");
124         Object returnVal = delegateMap.get(new ClassMethodArgs(asyncClass, method, args));
125         return returnVal;
126      } else if (syncMethodMap.containsKey(method)) {
127         return syncMethodMap.get(method).invoke(delegate, args);
128      } else {
129         try {
130            return ((ListenableFuture<?>) methodMap.get(method).invoke(delegate, args)).get(timeoutMap.get(method),
131                  TimeUnit.NANOSECONDS);
132         } catch (ProvisionException e) {
133            throw Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(method.getExceptionTypes(), e);
134         } catch (ExecutionException e) {
135            throw Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(method.getExceptionTypes(), e);
136         } catch (Exception e) {
137            throw Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(method.getExceptionTypes(), e);
138         }
139      }
140   }
141 
142   @Override
143   public boolean equals(Object obj) {
144      if (obj == null || !(obj instanceof SyncProxy))
145         return false;
146      SyncProxy other = (SyncProxy) obj;
147      if (other == this)
148         return true;
149      if (other.declaring != this.declaring)
150         return false;
151      return super.equals(obj);
152   }
153 
154   @Override
155   public int hashCode() {
156      return declaring.hashCode();
157   }
158 
159   public String toString() {
160      return "Sync Proxy for: " + delegate.getClass().getSimpleName();
161   }
162}

[all classes][org.jclouds.concurrent.internal]
EMMA 2.0.5312 (C) Vladimir Roubtsov