1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.fosstrak.epcis.queryclient;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.rmi.RemoteException;
31 import java.security.KeyStore;
32 import java.security.SecureRandom;
33 import java.security.cert.CertificateException;
34 import java.security.cert.X509Certificate;
35 import java.util.Arrays;
36 import java.util.List;
37 import java.util.Properties;
38
39 import javax.net.ssl.KeyManagerFactory;
40 import javax.net.ssl.TrustManager;
41 import javax.net.ssl.X509TrustManager;
42 import javax.xml.bind.JAXBContext;
43 import javax.xml.bind.JAXBElement;
44 import javax.xml.bind.JAXBException;
45 import javax.xml.bind.Unmarshaller;
46 import javax.xml.namespace.QName;
47 import javax.xml.ws.Service;
48 import javax.xml.ws.soap.SOAPBinding;
49
50 import org.apache.cxf.Bus;
51 import org.apache.cxf.bus.CXFBusFactory;
52 import org.apache.cxf.configuration.jsse.TLSClientParameters;
53 import org.apache.cxf.configuration.security.AuthorizationPolicy;
54 import org.apache.cxf.endpoint.Client;
55 import org.apache.cxf.frontend.ClientProxy;
56 import org.apache.cxf.transport.http.ClientOnlyHTTPTransportFactory;
57 import org.apache.cxf.transport.http.HTTPConduit;
58 import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
59 import org.fosstrak.epcis.model.EmptyParms;
60 import org.fosstrak.epcis.model.GetSubscriptionIDs;
61 import org.fosstrak.epcis.model.Poll;
62 import org.fosstrak.epcis.model.QueryResults;
63 import org.fosstrak.epcis.model.Subscribe;
64 import org.fosstrak.epcis.model.Unsubscribe;
65 import org.fosstrak.epcis.soap.DuplicateSubscriptionExceptionResponse;
66 import org.fosstrak.epcis.soap.EPCISServicePortType;
67 import org.fosstrak.epcis.soap.ImplementationExceptionResponse;
68 import org.fosstrak.epcis.soap.InvalidURIExceptionResponse;
69 import org.fosstrak.epcis.soap.NoSuchNameExceptionResponse;
70 import org.fosstrak.epcis.soap.NoSuchSubscriptionExceptionResponse;
71 import org.fosstrak.epcis.soap.QueryParameterExceptionResponse;
72 import org.fosstrak.epcis.soap.QueryTooComplexExceptionResponse;
73 import org.fosstrak.epcis.soap.QueryTooLargeExceptionResponse;
74 import org.fosstrak.epcis.soap.SecurityExceptionResponse;
75 import org.fosstrak.epcis.soap.SubscribeNotPermittedExceptionResponse;
76 import org.fosstrak.epcis.soap.SubscriptionControlsExceptionResponse;
77 import org.fosstrak.epcis.soap.ValidationExceptionResponse;
78 import org.fosstrak.epcis.utils.AuthenticationType;
79
80
81
82
83
84
85
86
87 public class QueryControlClient implements QueryControlInterface, X509TrustManager {
88
89 private static final String PROPERTY_FILE = "/queryclient.properties";
90 private static final String PROP_QUERY_URL = "default.url";
91 private static final String DEFAULT_QUERY_URL = "http://demo.fosstrak.org/epcis/query";
92
93 private static final QName SERVICE = new QName("urn:epcglobal:epcis:wsdl:1", "EPCglobalEPCISService");
94 private static final QName PORT = new QName("urn:epcglobal:epcis:wsdl:1", "EPCglobalEPCISServicePort");
95
96 private String queryUrl;
97
98
99
100
101 private EPCISServicePortType servicePort;
102
103
104
105
106 private boolean serviceConfigured = false;
107
108
109
110
111
112
113
114 public QueryControlClient() {
115 this(null, null);
116 }
117
118
119
120
121
122
123
124 public QueryControlClient(String url) {
125 this(url, null);
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158 public QueryControlClient(String url, Object[] authenticationOptions) {
159 if (url != null) {
160 this.queryUrl = url;
161 } else {
162 Properties props = loadProperties();
163 this.queryUrl = props.getProperty(PROP_QUERY_URL, DEFAULT_QUERY_URL);
164 try {
165 new URL(queryUrl);
166 } catch (MalformedURLException e) {
167 queryUrl = DEFAULT_QUERY_URL;
168 }
169 }
170 try {
171 configureService(new URL(queryUrl), authenticationOptions);
172 } catch (Exception e) {
173 throw new RuntimeException("unable to configure QueryControlClient: " + e.getMessage(), e);
174 }
175 }
176
177
178
179
180 private Properties loadProperties() {
181 Properties props = new Properties();
182 InputStream is = getClass().getResourceAsStream(PROPERTY_FILE);
183 if (is != null) {
184 try {
185 props.load(is);
186 is.close();
187 } catch (IOException e) {
188 System.out.println("Unable to load queryclient properties from "
189 + QueryControlClient.class.getResource(PROPERTY_FILE).toString() + ". Using defaults.");
190 }
191 } else {
192 System.out.println("Unable to load queryclient properties from " + PROPERTY_FILE + ". Using defaults.");
193 }
194 return props;
195 }
196
197
198
199
200 public boolean isServiceConfigured() {
201 return serviceConfigured;
202 }
203
204 public String getQueryUrl() {
205 return queryUrl;
206 }
207
208 private boolean isEmpty(String s) {
209 return s == null || "".equals(s);
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 public void configureService(URL endpointAddress, Object[] authenticationOptions) throws Exception {
241
242
243 serviceConfigured = false;
244
245
246 setUpBus();
247
248
249
250 Service service = Service.create(SERVICE);
251 service.addPort(PORT, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress.toString());
252 servicePort = service.getPort(PORT, EPCISServicePortType.class);
253
254
255 Client client = ClientProxy.getClient(servicePort);
256 HTTPConduit httpConduit = (HTTPConduit) client.getConduit();
257 HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
258 httpClientPolicy.setAllowChunking(false);
259 httpConduit.setClient(httpClientPolicy);
260
261
262 if (authenticationOptions != null) {
263 if (AuthenticationType.BASIC.equals(authenticationOptions[0])) {
264
265
266
267 String username = (String) authenticationOptions[1];
268 String password = (String) authenticationOptions[2];
269
270 if (isEmpty(username) || isEmpty(password)) {
271 throw new Exception("Authentication method " + authenticationOptions[0]
272 + " requires a valid user name and password");
273 }
274
275 AuthorizationPolicy ap = httpConduit.getAuthorization();
276 ap.setUserName(username);
277 ap.setPassword(password);
278 } else if (AuthenticationType.HTTPS_WITH_CLIENT_CERT.equals(authenticationOptions[0])) {
279
280
281
282 if (!"HTTPS".equalsIgnoreCase(endpointAddress.getProtocol())) {
283 throw new Exception("Authentication method " + authenticationOptions[0]
284 + " requires the use of HTTPS");
285 }
286
287 String keyStoreFile = (String) authenticationOptions[1];
288 String password = (String) authenticationOptions[2];
289
290 if (isEmpty(keyStoreFile) || isEmpty(password)) {
291 throw new Exception("Authentication method " + authenticationOptions[0]
292 + " requires a valid keystore (PKCS12 or JKS) and password");
293 }
294
295 KeyStore keyStore = KeyStore.getInstance(keyStoreFile.endsWith(".p12") ? "PKCS12" : "JKS");
296 keyStore.load(new FileInputStream(new File(keyStoreFile)), password.toCharArray());
297 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
298 keyManagerFactory.init(keyStore, password.toCharArray());
299
300 TLSClientParameters tlscp = new TLSClientParameters();
301 tlscp.setKeyManagers(keyManagerFactory.getKeyManagers());
302 tlscp.setSecureRandom(new SecureRandom());
303 tlscp.setDisableCNCheck(true);
304 tlscp.setTrustManagers(new TrustManager[] { this });
305
306 httpConduit.setTlsClientParameters(tlscp);
307 }
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330 serviceConfigured = true;
331 }
332
333 private void setUpBus() {
334 Bus bus = CXFBusFactory.getDefaultBus();
335 ClientOnlyHTTPTransportFactory httpTransport = new ClientOnlyHTTPTransportFactory();
336
337 httpTransport.setBus(bus);
338 List<String> transportIds = Arrays.asList(new String[] {
339 "http://schemas.xmlsoap.org/wsdl/soap/http", "http://schemas.xmlsoap.org/soap/http",
340 "http://www.w3.org/2003/05/soap/bindings/HTTP/", "http://schemas.xmlsoap.org/wsdl/http/",
341 "http://cxf.apache.org/transports/http/configuration", "http://cxf.apache.org/bindings/xformat", });
342 httpTransport.setTransportIds(transportIds);
343 httpTransport.registerWithBindingManager();
344
345 }
346
347
348
349
350
351 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
352 }
353
354 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
355 }
356
357 public X509Certificate[] getAcceptedIssuers() {
358 return null;
359 }
360
361
362
363
364
365
366 public List<String> getQueryNames() throws ImplementationExceptionResponse, SecurityExceptionResponse,
367 ValidationExceptionResponse {
368 if (!serviceConfigured) {
369 throw new QueryClientNotConfiguredException(
370 "Please configure service by calling configureService(URL, String[]).");
371 }
372 return servicePort.getQueryNames(new EmptyParms()).getString();
373 }
374
375
376
377
378
379
380 public String getStandardVersion() throws ImplementationExceptionResponse, SecurityExceptionResponse,
381 ValidationExceptionResponse {
382 if (!serviceConfigured) {
383 throw new QueryClientNotConfiguredException(
384 "Please configure service by calling configureService(URL, String[]).");
385 }
386 return servicePort.getStandardVersion(new EmptyParms());
387 }
388
389
390
391
392
393
394 public List<String> getSubscriptionIds(final String queryName) throws ImplementationExceptionResponse,
395 SecurityExceptionResponse, ValidationExceptionResponse, NoSuchNameExceptionResponse {
396 if (!serviceConfigured) {
397 throw new QueryClientNotConfiguredException(
398 "Please configure service by calling configureService(URL, String[]).");
399 }
400 GetSubscriptionIDs parms = new GetSubscriptionIDs();
401 parms.setQueryName(queryName);
402 return servicePort.getSubscriptionIDs(parms).getString();
403 }
404
405
406
407
408
409
410 public String getVendorVersion() throws ImplementationExceptionResponse, SecurityExceptionResponse,
411 ValidationExceptionResponse {
412 if (!serviceConfigured) {
413 throw new QueryClientNotConfiguredException(
414 "Please configure service by calling configureService(URL, String[]).");
415 }
416 return servicePort.getVendorVersion(new EmptyParms());
417 }
418
419
420
421
422
423
424 public QueryResults poll(final Poll poll) throws ImplementationExceptionResponse, QueryTooComplexExceptionResponse,
425 QueryTooLargeExceptionResponse, SecurityExceptionResponse, ValidationExceptionResponse,
426 NoSuchNameExceptionResponse, QueryParameterExceptionResponse {
427 if (!serviceConfigured) {
428 throw new QueryClientNotConfiguredException(
429 "Please configure service by calling configureService(URL, String[]).");
430 }
431 return servicePort.poll(poll);
432 }
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454 public QueryResults poll(final String query) throws QueryTooComplexExceptionResponse,
455 QueryTooLargeExceptionResponse, SecurityExceptionResponse, ValidationExceptionResponse,
456 NoSuchNameExceptionResponse, QueryParameterExceptionResponse, IOException, ImplementationExceptionResponse {
457 InputStream is = new ByteArrayInputStream(query.getBytes());
458 return poll(is);
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483 public QueryResults poll(final InputStream queryStream) throws ImplementationExceptionResponse,
484 QueryTooComplexExceptionResponse, QueryTooLargeExceptionResponse, SecurityExceptionResponse,
485 ValidationExceptionResponse, NoSuchNameExceptionResponse, QueryParameterExceptionResponse, IOException {
486 try {
487 JAXBContext context = JAXBContext.newInstance("org.fosstrak.epcis.model");
488 Unmarshaller unmarshaller = context.createUnmarshaller();
489
490
491 JAXBElement<?> elem = (JAXBElement<?>) unmarshaller.unmarshal(queryStream);
492 Poll poll = (Poll) elem.getValue();
493 return poll(poll);
494 } catch (JAXBException e) {
495
496
497 IOException ioe = new IOException(e.getMessage());
498 ioe.setStackTrace(e.getStackTrace());
499 throw ioe;
500 }
501 }
502
503
504
505
506
507
508 public void subscribe(final Subscribe subscribe) throws DuplicateSubscriptionExceptionResponse,
509 ImplementationExceptionResponse, QueryTooComplexExceptionResponse, SecurityExceptionResponse,
510 InvalidURIExceptionResponse, ValidationExceptionResponse, SubscribeNotPermittedExceptionResponse,
511 NoSuchNameExceptionResponse, SubscriptionControlsExceptionResponse, QueryParameterExceptionResponse {
512 if (!serviceConfigured) {
513 throw new QueryClientNotConfiguredException(
514 "Please configure service by calling configureService(URL, String[]).");
515 }
516 servicePort.subscribe(subscribe);
517 }
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540 public void subscribe(final String query) throws DuplicateSubscriptionExceptionResponse,
541 ImplementationExceptionResponse, QueryTooComplexExceptionResponse, SecurityExceptionResponse,
542 InvalidURIExceptionResponse, ValidationExceptionResponse, SubscribeNotPermittedExceptionResponse,
543 NoSuchNameExceptionResponse, SubscriptionControlsExceptionResponse, QueryParameterExceptionResponse,
544 IOException {
545 InputStream is = new ByteArrayInputStream(query.getBytes());
546 subscribe(is);
547 }
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572 public void subscribe(final InputStream query) throws DuplicateSubscriptionExceptionResponse,
573 ImplementationExceptionResponse, QueryTooComplexExceptionResponse, SecurityExceptionResponse,
574 InvalidURIExceptionResponse, ValidationExceptionResponse, SubscribeNotPermittedExceptionResponse,
575 NoSuchNameExceptionResponse, SubscriptionControlsExceptionResponse, QueryParameterExceptionResponse,
576 IOException {
577 try {
578 JAXBContext context = JAXBContext.newInstance("org.fosstrak.epcis.model");
579 Unmarshaller unmarshaller = context.createUnmarshaller();
580 JAXBElement<?> elem = (JAXBElement<?>) unmarshaller.unmarshal(query);
581 Subscribe subscribe = (Subscribe) elem.getValue();
582 subscribe(subscribe);
583 } catch (JAXBException e) {
584
585
586 IOException ioe = new IOException(e.getMessage());
587 ioe.setStackTrace(e.getStackTrace());
588 throw ioe;
589 }
590 }
591
592
593
594
595
596
597 public void unsubscribe(final String subscriptionId) throws ImplementationExceptionResponse,
598 SecurityExceptionResponse, ValidationExceptionResponse, NoSuchSubscriptionExceptionResponse {
599 if (!serviceConfigured) {
600 throw new QueryClientNotConfiguredException(
601 "Please configure service by calling configureService(URL, String[]).");
602 }
603 Unsubscribe parms = new Unsubscribe();
604 parms.setSubscriptionID(subscriptionId);
605 servicePort.unsubscribe(parms);
606 }
607
608
609
610
611
612
613
614
615
616
617
618
619 public void unsubscribe(final InputStream unsubscribeIs) throws ImplementationExceptionResponse,
620 SecurityExceptionResponse, ValidationExceptionResponse, NoSuchSubscriptionExceptionResponse, IOException {
621 try {
622 JAXBContext context = JAXBContext.newInstance("org.fosstrak.epcis.model");
623 Unmarshaller unmarshaller = context.createUnmarshaller();
624 JAXBElement<?> elem = (JAXBElement<?>) unmarshaller.unmarshal(unsubscribeIs);
625 Unsubscribe unsubscribe = (Unsubscribe) elem.getValue();
626 unsubscribe(unsubscribe.getSubscriptionID());
627 } catch (JAXBException e) {
628
629
630 IOException ioe = new IOException(e.getMessage());
631 ioe.setStackTrace(e.getStackTrace());
632 throw ioe;
633 }
634 }
635 }