1 package com.trendmicro.grid.acl.client;
2
3 import com.trendmicro.grid.acl.PublicServiceDiscovery;
4 import com.trendmicro.grid.acl.Service;
5 import com.trendmicro.grid.acl.l0.*;
6 import com.trendmicro.grid.acl.l0.datatypes.FileIdentifier;
7 import net.sf.tinyjee.streams.ByteBufferOutputStream;
8 import net.sf.tinyjee.ws.client.ClientServiceContext;
9
10 import javax.xml.ws.WebServiceFeature;
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.OutputStream;
15 import java.net.*;
16 import java.security.DigestInputStream;
17 import java.security.MessageDigest;
18 import java.security.NoSuchAlgorithmException;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.UUID;
23
24 import static java.util.logging.Level.WARNING;
25 import static java.util.logging.Logger.getLogger;
26
27
28
29
30
31
32 public class ServiceClient {
33
34 static final int STREAM_BUFFER_SIZE = 8 * 1024;
35
36
37
38
39
40 static {
41 if (!Boolean.getBoolean("gacl.jaxws.verbose")) {
42 getLogger("com.sun.xml.ws").setLevel(WARNING);
43 getLogger("javax.enterprise.resource.webservices").setLevel(WARNING);
44 }
45 }
46
47 private final String defaultHost;
48 private int defaultPortNumber;
49 private boolean defaultSecure;
50
51 private final ClientServiceContext context = new ClientServiceContext();
52
53
54
55
56 public ServiceClient() {
57 this(null, null);
58 }
59
60
61
62
63
64
65
66
67 public ServiceClient(String defaultHost, UUID apiKey) {
68
69 addDefinition(CacheControlService.class, "/ws/level-0/internal/cache-control", apiKey);
70 addDefinition(FileRequestService.class, "/ws/level-0/internal/filecontent-request", apiKey);
71 addDefinition(FileService.class, "/ws/level-0/internal/files", apiKey);
72 addDefinition(PackageService.class, "/ws/level-0/internal/packages", apiKey);
73 addDefinition(ProcessingService.class, "/ws/level-0/internal/processing", apiKey);
74 addDefinition(PublicAuthenticationService.class, "/ws/level-0/authentication", apiKey);
75 addDefinition(PublicCategoryService.class, "/ws/level-0/categories", apiKey);
76 addDefinition(PublicFileService.class, "/ws/level-0/files", apiKey);
77 addDefinition(PublicPackageService.class, "/ws/level-0/packages", apiKey);
78 addDefinition(PublicReportService.class, "/ws/level-0/reporting", apiKey);
79 addDefinition(SourceService.class, "/ws/level-0/internal/sources", apiKey);
80
81
82 addDefinition(PublicServiceDiscovery.class, "/ws/discovery", apiKey);
83
84 this.defaultHost = defaultHost;
85 defaultSecure = apiKey != null;
86 }
87
88
89
90
91
92
93
94
95 public ServiceClient(String defaultHost, int defaultPortNumber, boolean defaultSecure) {
96 this(defaultHost, defaultPortNumber, defaultSecure, null);
97 }
98
99
100
101
102
103
104
105
106
107 public ServiceClient(String defaultHost, int defaultPortNumber, boolean defaultSecure, UUID apiKey) {
108 this(defaultHost, apiKey);
109 this.defaultPortNumber = defaultPortNumber;
110 this.defaultSecure = defaultSecure;
111 }
112
113 private void addDefinition(Class<? extends Service> endpointInterface, String path, UUID apiKey) {
114 if (!path.startsWith("/")) path = '/' + path;
115 if (apiKey != null) path += ";api-key=" + apiKey;
116
117 context.addDefinition(endpointInterface, endpointInterface.getSimpleName(), URI.create("http://localhost" + path + "?wsdl"));
118 }
119
120
121
122
123
124
125 public ClientServiceContext getContext() {
126 return context;
127 }
128
129
130
131
132
133
134
135
136 public static FileIdentifier generateFileIdentifier(URL source) throws IOException {
137 final MessageDigest sha1, md5;
138 try {
139 sha1 = MessageDigest.getInstance("SHA1");
140 md5 = MessageDigest.getInstance("MD5");
141 } catch (NoSuchAlgorithmException e) {
142 throw new IOException(e);
143 }
144
145 final DigestInputStream sha1Stream = new DigestInputStream(source.openStream(), sha1);
146 final DigestInputStream md5Stream = new DigestInputStream(sha1Stream, md5);
147
148 copyAndClose(md5Stream, null);
149
150 return new FileIdentifier(sha1Stream.getMessageDigest().digest(), md5Stream.getMessageDigest().digest());
151 }
152
153
154
155
156
157
158
159
160 public static FileIdentifier generateFileIdentifier(File source) throws IOException {
161 return generateFileIdentifier(source.toURI().toURL());
162 }
163
164
165
166
167
168
169
170
171 public InputStream getFromUrl(URL sourceUrl) throws IOException {
172 final URLConnection urlConnection = sourceUrl.openConnection();
173 configureWithSessionCookies(urlConnection);
174
175 return urlConnection.getInputStream();
176 }
177
178
179
180
181
182
183
184
185
186
187
188 public void getFromUrl(URL sourceUrl, OutputStream targetStream) throws IOException {
189 final HttpURLConnection huc = (HttpURLConnection) sourceUrl.openConnection();
190 configureWithSessionCookies(huc);
191
192 try {
193 copyAndClose(huc.getInputStream(), targetStream);
194 if (huc.getResponseCode() >= 400) throw new IOException("Unexpected response code, should be < 400");
195 } catch (IOException e) {
196 String message = "Failed to GET content from URL '" + sourceUrl + '\'';
197 convertHttpErrorStream(huc, message, e);
198 }
199 }
200
201
202
203
204
205
206
207
208 public void putToUrl(InputStream inputStream, URL targetUrl) throws IOException {
209 HttpURLConnection huc = preparePutToUrl(targetUrl);
210
211 try {
212 copyAndClose(inputStream, huc.getOutputStream());
213 if (huc.getResponseCode() >= 400) throw new IOException("Unexpected response code, should be < 400");
214 } catch (IOException e) {
215 String message = "Failed to send content via PUT to URL '" + targetUrl + '\'';
216 convertHttpErrorStream(huc, message, e);
217 }
218 }
219
220
221
222
223
224
225
226
227 public HttpURLConnection preparePutToUrl(URL targetUrl) throws IOException {
228 HttpURLConnection huc = (HttpURLConnection) targetUrl.openConnection();
229 huc.setRequestMethod("PUT");
230 huc.setDoOutput(true);
231 huc.setChunkedStreamingMode(STREAM_BUFFER_SIZE);
232
233 configureWithSessionCookies(huc);
234
235 return huc;
236 }
237
238
239
240
241
242
243
244 public void configureWithSessionCookies(URLConnection urlConnection) throws IOException {
245 try {
246 final CookieManager manager = context.getSessionHandler().getCookieManager();
247 final Map<String, List<String>> cookies = manager.get(urlConnection.getURL().toURI(), urlConnection.getRequestProperties());
248 for (Map.Entry<String, List<String>> entry : cookies.entrySet()) {
249 for (String cookieValue : entry.getValue())
250 urlConnection.addRequestProperty(entry.getKey(), cookieValue);
251 }
252 } catch (URISyntaxException e) {
253 throw new IOException(e);
254 }
255 }
256
257 public String getDefaultHost() {
258 return defaultHost;
259 }
260
261 public int getDefaultPortNumber() {
262 return defaultPortNumber;
263 }
264
265 public boolean isDefaultSecure() {
266 return defaultSecure;
267 }
268
269
270
271
272
273
274
275
276
277
278 public <T extends Service> T getPort(Class<T> endpointInterface) {
279 return context.getPort(endpointInterface, defaultHost, defaultPortNumber, defaultSecure);
280 }
281
282
283
284
285
286
287
288
289
290
291
292 public <T extends Service> T getPort(Class<T> endpointInterface, String host) {
293 return context.getPort(endpointInterface, host);
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310 public <T extends Service> T getPort(Class<T> endpointInterface, String host, int port, boolean secure, WebServiceFeature... features) {
311 return context.getPort(endpointInterface, host, port, secure, features);
312 }
313
314
315
316
317
318
319 @SuppressWarnings("unchecked")
320 public Collection<Class<? extends Service>> getDefinedPorts() {
321 return (Collection) context.getDefinedPorts();
322 }
323
324 private static void copyAndClose(InputStream in, OutputStream out) throws IOException {
325 try {
326 int r;
327 byte[] buffer = new byte[STREAM_BUFFER_SIZE];
328 while ((r = in.read(buffer)) != -1)
329 if (out != null) out.write(buffer, 0, r);
330 } finally {
331 in.close();
332 if (out != null) out.close();
333 }
334 }
335
336 private static void convertHttpErrorStream(HttpURLConnection huc, String message, IOException originalException) throws IOException {
337 String detailedErrorMessage = "--failed-to-retrieve-error-details--";
338 try {
339 ByteBufferOutputStream messageBuffer = new ByteBufferOutputStream();
340 copyAndClose(huc.getErrorStream(), messageBuffer);
341 detailedErrorMessage = messageBuffer.toString();
342 } catch (IOException ignore) {
343 }
344
345 throw new IOException(message + "; The server replied with:\n" +
346 huc.getResponseCode() + ' ' + huc.getResponseMessage() +
347 "\n\n" + detailedErrorMessage, originalException);
348 }
349 }