1 package net.avcompris.commons3.web.it.utils;
2
3 import static com.google.common.base.Preconditions.checkArgument;
4 import static com.google.common.base.Preconditions.checkNotNull;
5 import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
6 import static org.apache.commons.lang3.StringUtils.substringBetween;
7
8 import java.io.IOException;
9 import java.lang.reflect.InvocationHandler;
10 import java.lang.reflect.InvocationTargetException;
11 import java.lang.reflect.Method;
12 import java.lang.reflect.Proxy;
13
14 import org.apache.commons.lang3.NotImplementedException;
15
16 import net.avcompris.commons3.api.EnumRole;
17 import net.avcompris.commons3.api.User;
18 import net.avcompris.commons3.client.SessionPropagator;
19 import net.avcompris.commons3.client.impl.AbstractClient;
20
21 public abstract class WebTestUtils {
22
23 public static Api api(final String apiBaseURL) throws IOException {
24
25 checkNotNull(apiBaseURL, "apiBaseURL");
26
27 return new ApiImpl(apiBaseURL);
28 }
29
30 private static final class ApiImpl implements Api {
31
32 private final String apiBaseURL;
33
34 public ApiImpl(final String apiBaseURL) {
35
36 this.apiBaseURL = checkNotNull(apiBaseURL, "apiBaseURL");
37 }
38
39 @Override
40 public User user(final String authorization) {
41
42 return new UserImpl(authorization);
43 }
44
45 @Override
46 public <U, V extends U> U forge(final Class<U> serviceClass, final String apiBaseURL,
47 final Class<V> serviceClientClass) {
48
49 checkNotNull(serviceClass, "serviceClass");
50 checkNotNull(apiBaseURL, "apiBaseURL");
51 checkNotNull(serviceClientClass, "serviceClientClass");
52
53 checkArgument(apiBaseURL.startsWith("${") && apiBaseURL.endsWith("}"),
54 "apiBaseURL should be of the form \"${...}\", e.g. \"${users.apiBaseURL}\", but was: %s",
55 apiBaseURL);
56
57 final String propertyName = substringBetween(apiBaseURL, "${", "}");
58
59 System.setProperty(propertyName, this.apiBaseURL);
60
61 checkArgument(AbstractClient.class.isAssignableFrom(serviceClientClass),
62 "serviceClientClass shoud extend AbstractClient, but was: %s", serviceClientClass.getName());
63
64 final SessionPropagator sessionPropagator = new SessionPropagator();
65
66 final V client;
67
68 try {
69
70 client = serviceClientClass
71 .getConstructor(SessionPropagator.class)
72 .newInstance(sessionPropagator);
73
74 } catch (final InstantiationException | IllegalAccessException | InvocationTargetException
75 | NoSuchMethodException e) {
76
77 throw new RuntimeException(e);
78 }
79
80 final Object proxy = Proxy.newProxyInstance(
81 serviceClass.getClassLoader(),
82 new Class<?>[] { serviceClass },
83 new InvocationHandler() {
84
85 @Override
86 public Object invoke(final Object proxy, final Method method, final Object[] args)
87 throws Throwable {
88
89 if (serviceClass.equals(method.getDeclaringClass())) {
90
91 return invokeServiceMethod(sessionPropagator, client, method, args);
92
93 } else {
94
95 throw new NotImplementedException(
96 "method: " + method.getName() + "(), serviceClass: " + serviceClass.getName());
97 }
98 }
99 });
100
101 return serviceClass.cast(proxy);
102 }
103
104 private Object invokeServiceMethod(final SessionPropagator sessionPropagator, final Object client,
105 final Method method, final Object[] args) throws Throwable {
106
107 checkArgument(args.length >= 2,
108 "args.length should be >= 2, but was: %s", args.length);
109
110 checkArgument(args[0] == null,
111 "args[0] should be null, but was: %s", args[0]);
112
113 final String correlationId = "C-" + randomAlphanumeric(20);
114
115 args[0] = correlationId;
116
117 final User user = (User) args[1];
118
119 checkArgument(user != null, "user arg should not be null");
120
121 checkArgument(user instanceof UserImpl,
122 "user arg should be obtained through the \"Api#user()\" method, but was: %s",
123 user.getClass().getName());
124
125 final String authorization = ((UserImpl) user).getAuthorization();
126
127 sessionPropagator.setAuthorizationHeader(authorization);
128
129 return method.invoke(client, args);
130 }
131 }
132
133 private static final class UserImpl implements User {
134
135 private final String authorization;
136
137 public UserImpl(final String authorization) {
138
139 this.authorization = checkNotNull(authorization, "authorization");
140 }
141
142 @Override
143 public String getUsername() {
144
145 throw new NotImplementedException("");
146 }
147
148 @Override
149 public EnumRole getRole() {
150
151 throw new NotImplementedException("");
152 }
153
154 public String getAuthorization() {
155
156 return authorization;
157 }
158 }
159 }