1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.gridsystems.innergrid.api;
18
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.net.ConnectException;
23 import java.net.SocketException;
24 import java.net.URL;
25 import java.net.UnknownHostException;
26 import java.rmi.RemoteException;
27 import java.util.HashSet;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.StringTokenizer;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33
34 import javax.xml.rpc.Stub;
35
36 import org.apache.axis.AxisFault;
37 import org.apache.axis.MessageContext;
38 import org.apache.axis.client.Call;
39 import org.apache.axis.transport.http.HTTPConstants;
40
41 import com.gridsystems.innergrid.kernel.KernelException;
42
43
44
45
46
47
48
49
50
51
52 public class ClientApiProxy extends HTTPConstants implements InvocationHandler {
53
54
55
56
57 private static final Set<Class<?>> IFACES = new HashSet<Class<?>>();
58
59 static {
60 IFACES.add(Object.class);
61 IFACES.add(javax.xml.rpc.Stub.class);
62 IFACES.add(org.apache.axis.client.Stub.class);
63 }
64
65
66
67
68 private final Stub stub;
69
70
71
72
73 private final Connection con;
74
75
76
77
78 private final String apiName;
79
80
81
82
83
84
85
86
87
88
89 ClientApiProxy(Class<?> iface, Stub stub, Connection con) {
90 this.stub = stub;
91 this.con = con;
92
93
94 String name = iface.getSimpleName();
95 int pos = name.lastIndexOf('.');
96 name = name.substring(pos + 1);
97 this.apiName = name;
98 }
99
100
101
102
103
104
105
106
107
108
109
110 public Object invoke(Object o, Method method, Object[] args)
111 throws Throwable {
112
113
114 synchronized (stub) {
115 if (IFACES.contains(method.getDeclaringClass())) {
116
117 return method.invoke(stub, args);
118 } else {
119
120 int retry = 0;
121 while (true) {
122 retry++;
123 try {
124 setup();
125 Object object = method.invoke(stub, args);
126 con.success();
127 return object;
128 } catch (Exception e) {
129 con.manageException(processException(e), retry);
130 }
131 }
132 }
133 }
134 }
135
136
137
138
139
140
141 @SuppressWarnings("unchecked")
142 private void setup() throws KernelException {
143
144 Map headers = (Map)stub._getProperty(REQUEST_HEADERS);
145 if (con.isChunkedTransferEnabled()) {
146 headers.put(HEADER_TRANSFER_ENCODING, HEADER_TRANSFER_ENCODING_CHUNKED);
147 } else {
148 headers.remove(HEADER_TRANSFER_ENCODING);
149 }
150 stub._setProperty(MessageContext.HTTP_TRANSPORT_VERSION, HEADER_PROTOCOL_V11);
151
152
153 if (con.isKeepAliveEnabled()) {
154 stub._setProperty(HEADER_CONNECTION, HEADER_CONNECTION_KEEPALIVE);
155 } else {
156 stub._setProperty(HEADER_CONNECTION, HEADER_CONNECTION_CLOSE);
157 }
158
159
160 stub._setProperty(Call.CONNECTION_TIMEOUT_PROPERTY, con.getTimeout());
161
162
163 if (con.getAttachmentFormat() != null) {
164 stub._setProperty(Call.ATTACHMENT_ENCAPSULATION_FORMAT, con.getAttachmentFormat());
165 }
166
167 Credentials credentials = this.con.getCredentials();
168 if (credentials != null) {
169 credentials.setup(stub);
170 }
171 URL url = this.con.getUrl(apiName);
172 stub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, url.toString());
173 }
174
175
176
177
178
179
180
181
182 private KernelException processException(Throwable e) {
183
184 if (e instanceof InvocationTargetException) {
185 e = ((InvocationTargetException)e).getTargetException();
186 }
187 if (e instanceof KernelException) {
188 return (KernelException)e;
189 } else if (e instanceof AxisFault) {
190 AxisFault af = (AxisFault) e;
191
192 Throwable cause = af.getCause();
193 if (cause != null) {
194 String host = this.con.getHost();
195 String port = String.valueOf(this.con.getPort());
196
197
198 if (cause instanceof ConnectException) {
199
200 return new CKernelException(e, "CLT001", port, host);
201 } else if (cause instanceof UnknownHostException) {
202
203 return new CKernelException(e, "CLT000", host);
204 } else if (cause instanceof SocketException) {
205
206 return new CKernelException(e, "CLT002", host);
207 }
208 }
209 if (af.getFaultCode().getLocalPart().equals("Server.NoService")) {
210
211 String reason = af.getFaultReason();
212 String apiname = "?";
213 if (reason != null) {
214 int pos = reason.lastIndexOf(' ');
215 if (pos != -1) {
216 apiname = reason.substring(pos + 1);
217 }
218 }
219 return new CKernelException(e, "CLT003", apiname);
220 } else if (af.getFaultCode().getLocalPart().equals("CLT004")) {
221 return new CKernelException(e, "CLT004", e.getMessage());
222 } else if (af.getFaultString().indexOf(
223 "could not find deserializer for type") != -1) {
224 return getDeserializationException(af);
225 } else if (af.getFaultString().startsWith("(404)/kernel/api")) {
226 return new CKernelException("CLT006");
227 }
228 }
229
230 if (e instanceof RemoteException) {
231 RemoteException re = (RemoteException) e;
232 return KernelException.fromRemoteException(re);
233 } else {
234
235 return new CKernelException(e, "UNK000", e.getMessage());
236 }
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250
251 private CKernelException getDeserializationException(AxisFault axisFault) {
252
253
254 final int groupCount = 3;
255
256 Pattern pat = Pattern.compile("'in(\\d+).+http\\:\\/\\/([\\w\\.]*)}(\\w+)$");
257 Matcher mat = pat.matcher(axisFault.getFaultString());
258 String[] params = new String[2];
259 if (mat.find() && (mat.groupCount() == groupCount)) {
260 params[0] = mat.group(1);
261
262
263 String packageName = namespaceToClass(mat.group(2), mat.group(groupCount));
264 params[1] = packageName + mat.group(groupCount);
265 } else {
266 params[0] = "?";
267 params[1] = "?";
268 }
269 return new CKernelException(axisFault, "CLT005", params);
270 }
271
272
273
274
275
276
277
278
279
280 private String namespaceToClass(String namespace, String localName) {
281 StringBuffer sb = new StringBuffer(localName);
282 for (StringTokenizer st = new StringTokenizer(namespace, "."); st.hasMoreTokens();) {
283 sb.insert(0, ".");
284 sb.insert(0, st.nextToken());
285 }
286 return sb.toString();
287 }
288
289
290
291
292
293
294 public Connection getConnection() {
295 return this.con;
296 }
297
298
299
300
301
302
303
304
305 public static void init() {
306 }
307 }