]> git.basschouten.com Git - openhab-addons.git/blob
7a88f0c151f6250dfb333cc6f593e7f29f646497
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.helios.internal.handler;
14
15 import static org.openhab.binding.helios.internal.HeliosBindingConstants.*;
16
17 import java.io.IOException;
18 import java.nio.charset.StandardCharsets;
19 import java.security.KeyManagementException;
20 import java.security.NoSuchAlgorithmException;
21 import java.security.cert.CertificateException;
22 import java.security.cert.X509Certificate;
23 import java.text.SimpleDateFormat;
24 import java.util.Arrays;
25 import java.util.Base64;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.concurrent.ScheduledFuture;
32 import java.util.concurrent.TimeUnit;
33
34 import javax.net.ssl.HostnameVerifier;
35 import javax.net.ssl.SSLContext;
36 import javax.net.ssl.X509TrustManager;
37 import javax.ws.rs.ProcessingException;
38 import javax.ws.rs.client.Client;
39 import javax.ws.rs.client.ClientBuilder;
40 import javax.ws.rs.client.ClientRequestContext;
41 import javax.ws.rs.client.ClientRequestFilter;
42 import javax.ws.rs.client.WebTarget;
43 import javax.ws.rs.core.MediaType;
44 import javax.ws.rs.core.MultivaluedMap;
45 import javax.ws.rs.core.Response;
46
47 import org.openhab.binding.helios.internal.ws.rest.RESTError;
48 import org.openhab.binding.helios.internal.ws.rest.RESTEvent;
49 import org.openhab.binding.helios.internal.ws.rest.RESTPort;
50 import org.openhab.binding.helios.internal.ws.rest.RESTSubscribeResponse;
51 import org.openhab.binding.helios.internal.ws.rest.RESTSwitch;
52 import org.openhab.binding.helios.internal.ws.rest.RESTSystemInfo;
53 import org.openhab.core.library.types.DateTimeType;
54 import org.openhab.core.library.types.DecimalType;
55 import org.openhab.core.library.types.OnOffType;
56 import org.openhab.core.library.types.StringType;
57 import org.openhab.core.thing.Channel;
58 import org.openhab.core.thing.ChannelUID;
59 import org.openhab.core.thing.Thing;
60 import org.openhab.core.thing.ThingStatus;
61 import org.openhab.core.thing.ThingStatusDetail;
62 import org.openhab.core.thing.binding.BaseThingHandler;
63 import org.openhab.core.thing.binding.builder.ChannelBuilder;
64 import org.openhab.core.thing.binding.builder.ThingBuilder;
65 import org.openhab.core.thing.type.ChannelTypeUID;
66 import org.openhab.core.types.Command;
67 import org.openhab.core.types.RefreshType;
68 import org.openhab.core.types.UnDefType;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 import com.google.gson.Gson;
73 import com.google.gson.JsonElement;
74 import com.google.gson.JsonObject;
75 import com.google.gson.JsonParser;
76
77 /**
78  * The {@link HeliosHandler221} is responsible for handling commands, which are
79  * sent to one of the channels.
80  *
81  * @author Karel Goderis - Initial contribution
82  */
83
84 public class HeliosHandler221 extends BaseThingHandler {
85
86     private final Logger logger = LoggerFactory.getLogger(HeliosHandler221.class);
87
88     // List of Configuration constants
89     public static final String IP_ADDRESS = "ipAddress";
90     public static final String USERNAME = "username";
91     public static final String PASSWORD = "password";
92
93     // List of all REST API URI, commands, and JSON constants
94     public static final String BASE_URI = "https://{ip}/api/";
95     public static final String SYSTEM_PATH = "system/{cmd}";
96     public static final String FIRMWARE_PATH = "firmware/{cmd}";
97     public static final String LOG_PATH = "log/{cmd}";
98     public static final String SWITCH_PATH = "switch/{cmd}";
99     public static final String PORT_PATH = "io/{cmd}";
100
101     public static final String INFO = "info";
102     public static final String STATUS = "status";
103
104     public static final String SUBSCRIBE = "subscribe";
105     public static final String UNSUBSCRIBE = "unsubscribe";
106     public static final String PULL = "pull";
107     public static final String CAPABILITIES = "caps";
108     public static final String CONTROL = "ctrl";
109
110     public static final String DEVICESTATE = "DeviceState";
111     public static final String AUDIOLOOPTEST = "AudioLoopTest";
112     public static final String MOTIONDETECTED = "MotionDetected";
113     public static final String NOISEDETECTED = "NoiseDetected";
114     public static final String KEYPRESSED = "KeyPressed";
115     public static final String KEYRELEASED = "KeyReleased";
116     public static final String CODEENTERED = "CodeEntered";
117     public static final String CARDENTERED = "CardEntered";
118     public static final String INPUTCHANGED = "InputChanged";
119     public static final String OUTPUTCHANGED = "OutputChanged";
120     public static final String CALLSTATECHANGED = "CallStateChanged";
121     public static final String REGISTRATIONSTATECHANGED = "RegistrationStateChanged";
122     public static final String SWITCHSTATECHANGED = "SwitchStateChanged";
123
124     // REST Client API variables
125     private Client heliosClient;
126     private final ClientBuilder heliosClientBuilder;
127     private WebTarget baseTarget;
128     private WebTarget systemTarget;
129     private WebTarget logTarget;
130     private WebTarget switchTarget;
131     private WebTarget portTarget;
132     private String ipAddress;
133
134     // JSON variables
135     private Gson gson = new Gson();
136
137     private ScheduledFuture<?> logJob;
138     private static final long RESET_INTERVAL = 15;
139     private static final long HELIOS_DURATION = 120;
140     private static final long HELIOS_PULL_DURATION = 10;
141
142     private long logSubscriptionID = 0;
143
144     public HeliosHandler221(Thing thing, ClientBuilder heliosClientBuilder) {
145         super(thing);
146         this.heliosClientBuilder = heliosClientBuilder;
147     }
148
149     @Override
150     public void initialize() {
151         logger.debug("Initializing the Helios IP Vario handler for '{}'.", getThing().getUID().toString());
152
153         ipAddress = (String) getConfig().get(IP_ADDRESS);
154         String username = (String) getConfig().get(USERNAME);
155         String password = (String) getConfig().get(PASSWORD);
156
157         if (ipAddress != null && !ipAddress.isEmpty() && username != null && !username.isEmpty() && password != null
158                 && !password.isEmpty()) {
159             SecureRestClientTrustManager secureRestClientTrustManager = new SecureRestClientTrustManager();
160             SSLContext sslContext = null;
161             try {
162                 sslContext = SSLContext.getInstance("SSL");
163             } catch (NoSuchAlgorithmException e1) {
164                 logger.error("An exception occurred while requesting the SSL encryption algorithm : '{}'",
165                         e1.getMessage(), e1);
166             }
167             try {
168                 if (sslContext != null) {
169                     sslContext.init(null, new javax.net.ssl.TrustManager[] { secureRestClientTrustManager }, null);
170                 }
171             } catch (KeyManagementException e1) {
172                 logger.error("An exception occurred while initialising the SSL context : '{}'", e1.getMessage(), e1);
173             }
174
175             heliosClient = heliosClientBuilder.sslContext(sslContext).hostnameVerifier(new HostnameVerifier() {
176                 @Override
177                 public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
178                     return true;
179                 }
180             }).build();
181             heliosClient.register(new Authenticator(username, password));
182
183             baseTarget = heliosClient.target(BASE_URI.replace("{ip}", ipAddress));
184             systemTarget = baseTarget.path(SYSTEM_PATH);
185             logTarget = baseTarget.path(LOG_PATH);
186             switchTarget = baseTarget.path(SWITCH_PATH);
187
188             Response response = null;
189             try {
190                 response = systemTarget.resolveTemplate("cmd", INFO).request(MediaType.APPLICATION_JSON_TYPE).get();
191             } catch (ProcessingException e) {
192                 logger.debug("An exception occurred while fetching system info of the Helios IP Vario '{}' : '{}'",
193                         getThing().getUID().toString(), e.getMessage(), e);
194                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
195                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
196                 return;
197             }
198
199             if (response == null) {
200                 logger.debug("There is a configuration problem for the Helios IP Vario '{}'",
201                         getThing().getUID().toString());
202                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
203                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
204                 return;
205             }
206
207             JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
208
209             if (logger.isTraceEnabled()) {
210                 logger.trace("initialize() Request : {}", systemTarget.resolveTemplate("ip", ipAddress)
211                         .resolveTemplate("cmd", INFO).getUri().toASCIIString());
212                 if (jsonObject.get("success").toString().equals("true")) {
213                     logger.trace("initialize() Response: {}", jsonObject.get("result"));
214                 }
215                 if (jsonObject.get("success").toString().equals("false")) {
216                     logger.trace("initialize() Response: {}", jsonObject.get("error"));
217                 }
218             }
219
220             if (jsonObject.get("success").toString().equals("false")) {
221                 RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
222                 logger.debug(
223                         "An error occurred while communicating with the Helios IP Vario '{}': code '{}', param '{}' : '{}'",
224                         new Object[] { getThing().getUID().toString(), error.code, error.param, error.description });
225                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
226                         error.code + ":" + error.param + ":" + error.description);
227                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
228                 return;
229             }
230
231             if (jsonObject.get("success").toString().equals("true")) {
232                 if (logJob == null || logJob.isCancelled()) {
233                     logJob = scheduler.scheduleWithFixedDelay(logRunnable, 0, 1, TimeUnit.SECONDS);
234                 }
235
236                 updateStatus(ThingStatus.ONLINE);
237
238                 scheduler.schedule(configureRunnable, 0, TimeUnit.SECONDS);
239             }
240         }
241     }
242
243     @Override
244     public void dispose() {
245         logger.debug("Disposing the Helios IP Vario handler for '{}'.", getThing().getUID().toString());
246         tearDown();
247     }
248
249     private void tearDown() {
250         logger.debug("Tearing down the Helios IP Vario handler for '{}'.", getThing().getUID().toString());
251
252         if (logSubscriptionID != 0) {
253             unsubscribe();
254         }
255
256         if (logJob != null && !logJob.isCancelled()) {
257             logJob.cancel(true);
258             logJob = null;
259         }
260
261         if (heliosClient != null) {
262             heliosClient.close();
263             heliosClient = null;
264         }
265     }
266
267     @Override
268     public void handleCommand(ChannelUID channelUID, Command command) {
269         if (!(command instanceof RefreshType)) {
270             ChannelTypeUID triggerUID = new ChannelTypeUID(BINDING_ID, SWITCH_TRIGGER);
271             ChannelTypeUID enablerUID = new ChannelTypeUID(BINDING_ID, SWITCH_ENABLER);
272             Channel theChannel = getThing().getChannel(channelUID.getId());
273
274             if (theChannel != null) {
275                 ChannelTypeUID channelType = theChannel.getChannelTypeUID();
276                 if (channelType.equals(triggerUID)) {
277                     String switchID = channelUID.getId().substring(6);
278                     triggerSwitch(switchID);
279                 }
280
281                 if (channelType.equals(enablerUID)) {
282                     String switchID = channelUID.getId().substring(6, channelUID.getId().lastIndexOf("active"));
283                     if (command instanceof OnOffType && command == OnOffType.OFF) {
284                         enableSwitch(switchID, false);
285                     } else if (command instanceof OnOffType && command == OnOffType.ON) {
286                         enableSwitch(switchID, true);
287                     }
288                 }
289             }
290         }
291     }
292
293     private long subscribe() {
294         if (getThing().getStatus() == ThingStatus.ONLINE) {
295             logTarget = baseTarget.path(LOG_PATH);
296
297             Response response = null;
298             try {
299                 response = logTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", SUBSCRIBE)
300                         .queryParam("include", "new").queryParam("duration", HELIOS_DURATION)
301                         .request(MediaType.APPLICATION_JSON_TYPE).get();
302             } catch (NullPointerException e) {
303                 logger.debug(
304                         "An exception occurred while subscribing to the log entries of the Helios IP Vario '{}' : '{}'",
305                         getThing().getUID().toString(), e.getMessage(), e);
306                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
307                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
308                 return 0;
309             }
310
311             if (response != null) {
312                 JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
313
314                 if (logger.isTraceEnabled()) {
315                     logger.trace("subscribe() Request : {}",
316                             logTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", SUBSCRIBE)
317                                     .queryParam("include", "new").queryParam("duration", HELIOS_DURATION).getUri()
318                                     .toASCIIString());
319                     if (jsonObject.get("success").toString().equals("true")) {
320                         logger.trace("subscribe() Response: {}", jsonObject.get("result"));
321                     }
322                     if (jsonObject.get("success").toString().equals("false")) {
323                         logger.trace("subscribe() Response: {}", jsonObject.get("error"));
324                     }
325                 }
326
327                 if (jsonObject.get("success").toString().equals("true")) {
328                     RESTSubscribeResponse subscribeResponse = gson.fromJson(jsonObject.get("result").toString(),
329                             RESTSubscribeResponse.class);
330                     logger.debug("The subscription id to pull logs from the Helios IP Vario '{}' is '{}'",
331                             getThing().getUID().toString(), subscribeResponse.id);
332                     return subscribeResponse.id;
333                 } else {
334                     RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
335                     logger.debug(
336                             "An error occurred while communicating with the Helios IP Vario '{}': code '{}', param '{}' : '{}'",
337                             getThing().getUID().toString(), error.code, error.param, error.description);
338                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
339                             error.code + ":" + error.param + ":" + error.description);
340                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
341                     return 0;
342                 }
343             } else {
344                 logger.debug("An error occurred while subscribing to the log entries of the Helios IP Vario '{}'",
345                         getThing().getUID().toString());
346                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
347                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
348                 return 0;
349             }
350         }
351
352         return 0;
353     }
354
355     private void unsubscribe() {
356         if (getThing().getStatus() == ThingStatus.ONLINE) {
357             logTarget = baseTarget.path(LOG_PATH);
358
359             Response response = null;
360             try {
361                 response = logTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", UNSUBSCRIBE)
362                         .queryParam("id", logSubscriptionID).request(MediaType.APPLICATION_JSON_TYPE).get();
363             } catch (Exception e) {
364                 logger.debug(
365                         "An exception occurred while unsubscribing from the log entries of the Helios IP Vario '{}' : {}",
366                         getThing().getUID().toString(), e.getMessage(), e);
367                 logSubscriptionID = 0;
368                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
369                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
370                 return;
371             }
372
373             if (response != null) {
374                 JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
375
376                 if (logger.isTraceEnabled()) {
377                     logger.trace("unsubscribe() Request : {}",
378                             logTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", UNSUBSCRIBE)
379                                     .queryParam("id", logSubscriptionID).getUri().toASCIIString());
380                     if (jsonObject.get("success").toString().equals("true")) {
381                         logger.trace("unsubscribe() Response: {}", jsonObject.get("result"));
382                     }
383                     if (jsonObject.get("success").toString().equals("false")) {
384                         logger.trace("unsubscribe() Response: {}", jsonObject.get("error"));
385                     }
386                 }
387
388                 if (jsonObject.get("success").toString().equals("true")) {
389                     logger.debug("Successfully unsubscribed from the log entries of the Helios IP Vario '{}'",
390                             getThing().getUID().toString());
391                 } else {
392                     RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
393                     logger.debug(
394                             "An error occurred while communicating with the Helios IP Vario '{}' : code '{}', param '{}' : '{}'",
395                             getThing().getUID().toString(), error.code, error.param, error.description);
396                     logSubscriptionID = 0;
397                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
398                             error.code + ":" + error.param + ":" + error.description);
399                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
400                     return;
401                 }
402             } else {
403                 logger.debug("An error occurred while unsubscribing from the log entries of the Helios IP Vario '{}'",
404                         getThing().getUID().toString());
405                 logSubscriptionID = 0;
406                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
407                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
408                 return;
409             }
410         }
411     }
412
413     private List<RESTEvent> pullLog(long logSubscriptionID) {
414         if (getThing().getStatus() == ThingStatus.ONLINE && heliosClient != null) {
415             logTarget = baseTarget.path(LOG_PATH);
416
417             Response response = null;
418             try {
419                 long now = System.currentTimeMillis();
420                 response = logTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", PULL)
421                         .queryParam("id", logSubscriptionID).queryParam("timeout", HELIOS_PULL_DURATION)
422                         .request(MediaType.APPLICATION_JSON_TYPE).get();
423                 logger.trace("Pulled logs in {} millseconds from {}", System.currentTimeMillis() - now,
424                         getThing().getUID());
425             } catch (NullPointerException e) {
426                 logger.debug("An exception occurred while pulling log entries from the Helios IP Vario '{}' : '{}'",
427                         getThing().getUID().toString(), e.getMessage(), e);
428                 this.logSubscriptionID = 0;
429                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
430                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
431                 return null;
432             }
433
434             if (response != null) {
435                 JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
436
437                 if (logger.isTraceEnabled()) {
438                     logger.trace("pullLog() Request : {}",
439                             logTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", PULL)
440                                     .queryParam("id", logSubscriptionID).queryParam("timeout", HELIOS_PULL_DURATION)
441                                     .getUri().toASCIIString());
442                     if (jsonObject.get("success").toString().equals("true")) {
443                         logger.trace("pullLog() Response: {}", jsonObject.get("result"));
444                     }
445                     if (jsonObject.get("success").toString().equals("false")) {
446                         logger.trace("pullLog() Response: {}", jsonObject.get("error"));
447                     }
448                 }
449
450                 if (jsonObject.get("success").toString().equals("true")) {
451                     logger.trace("Successfully pulled log entries from the Helios IP Vario '{}'",
452                             getThing().getUID().toString());
453                     JsonObject js = (JsonObject) jsonObject.get("result");
454                     RESTEvent[] eventArray = gson.fromJson(js.getAsJsonArray("events"), RESTEvent[].class);
455                     return Arrays.asList(eventArray);
456                 } else {
457                     RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
458                     logger.debug(
459                             "An error occurred while communicating with the Helios IP Vario '{}' : code '{}', param '{}' : '{}'",
460                             getThing().getUID().toString(), error.code, error.param, error.description);
461                     this.logSubscriptionID = 0;
462                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
463                             error.code + ":" + error.param + ":" + error.description);
464                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
465                     return null;
466                 }
467             } else {
468                 logger.debug("An error occurred while polling log entries from the Helios IP Vario '{}'",
469                         getThing().getUID().toString());
470                 this.logSubscriptionID = 0;
471                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
472                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
473                 return null;
474             }
475         }
476
477         return null;
478     }
479
480     private List<RESTSwitch> getSwitches() {
481         switchTarget = baseTarget.path(SWITCH_PATH);
482
483         Response response = null;
484         try {
485             response = switchTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", CAPABILITIES)
486                     .request(MediaType.APPLICATION_JSON_TYPE).get();
487         } catch (NullPointerException e) {
488             logger.debug(
489                     "An exception occurred while requesting switch capabilities from the Helios IP Vario '{}' : '{}'",
490                     getThing().getUID().toString(), e.getMessage(), e);
491             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
492             scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
493             return null;
494         }
495
496         if (response != null) {
497             JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
498
499             if (logger.isTraceEnabled()) {
500                 logger.trace("getSwitches() Request : {}", switchTarget.resolveTemplate("ip", ipAddress)
501                         .resolveTemplate("cmd", CAPABILITIES).getUri().toASCIIString());
502                 if (jsonObject.get("success").toString().equals("true")) {
503                     logger.trace("getSwitches() Response: {}", jsonObject.get("result"));
504                 }
505                 if (jsonObject.get("success").toString().equals("false")) {
506                     logger.trace("getSwitches() Response: {}", jsonObject.get("error"));
507                 }
508             }
509
510             if (jsonObject.get("success").toString().equals("true")) {
511                 logger.debug("Successfully requested switch capabilities from the Helios IP Vario '{}'",
512                         getThing().getUID().toString());
513                 String result = jsonObject.get("result").toString();
514                 result = result.replace("switch", "id");
515                 JsonObject js = JsonParser.parseString(result).getAsJsonObject();
516                 RESTSwitch[] switchArray = gson.fromJson(js.getAsJsonArray("ides"), RESTSwitch[].class);
517                 if (switchArray != null) {
518                     return Arrays.asList(switchArray);
519                 }
520             } else {
521                 RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
522                 logger.debug(
523                         "An error occurred while communicating with the Helios IP Vario '{}' : code '{}', param '{}' : '{}'",
524                         getThing().getUID().toString(), error.code, error.param, error.description);
525                 if ("8".equals(error.code)) {
526                     logger.debug(
527                             "The API is not supported by the Helios hardware or current license, or the Authentication method is not set to Basic");
528                 } else {
529                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
530                             error.code + ":" + error.param + ":" + error.description);
531                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
532                 }
533                 return null;
534             }
535         } else {
536             logger.debug("An error occurred while requesting switch capabilities from the Helios IP Vario '{}'",
537                     getThing().getUID().toString());
538             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
539             scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
540         }
541
542         return null;
543     }
544
545     private void triggerSwitch(String id) {
546         if (getThing().getStatus() == ThingStatus.ONLINE) {
547             switchTarget = baseTarget.path(SWITCH_PATH);
548
549             Response response = null;
550             try {
551                 response = switchTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", CONTROL)
552                         .queryParam("switch", id).queryParam("action", "trigger")
553                         .request(MediaType.APPLICATION_JSON_TYPE).get();
554             } catch (NullPointerException e) {
555                 logger.debug("An exception occurred while triggering a switch  on the Helios IP Vario '{}' : '{}'",
556                         getThing().getUID().toString(), e.getMessage(), e);
557                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
558                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
559                 return;
560             }
561
562             if (response != null) {
563                 JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
564
565                 if (logger.isTraceEnabled()) {
566                     logger.trace("triggerSwitch() Request : {}",
567                             switchTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", CONTROL)
568                                     .queryParam("switch", id).queryParam("action", "trigger").getUri().toASCIIString());
569                     if (jsonObject.get("success").toString().equals("true")) {
570                         logger.trace("triggerSwitch() Response: {}", jsonObject.get("result"));
571                     }
572                     if (jsonObject.get("success").toString().equals("false")) {
573                         logger.trace("triggerSwitch() Response: {}", jsonObject.get("error"));
574                     }
575                 }
576
577                 if (jsonObject.get("success").toString().equals("true")) {
578                     logger.debug("Successfully triggered a switch on the Helios IP Vario '{}'",
579                             getThing().getUID().toString());
580                 } else {
581                     RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
582                     logger.error(
583                             "An error occurred while communicating with the Helios IP Vario '{}' : code '{}', param '{}' : '{}'",
584                             getThing().getUID().toString(), error.code, error.param, error.description);
585                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
586                             error.code + ":" + error.param + ":" + error.description);
587                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
588                     return;
589                 }
590             } else {
591                 logger.warn("An error occurred while triggering a switch on the Helios IP Vario '{}'",
592                         getThing().getUID().toString());
593                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
594                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
595                 return;
596             }
597         }
598     }
599
600     private void enableSwitch(String id, boolean flag) {
601         if (getThing().getStatus() == ThingStatus.ONLINE) {
602             switchTarget = baseTarget.path(SWITCH_PATH);
603
604             Response response = null;
605             try {
606                 response = switchTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", CONTROL)
607                         .queryParam("switch", id).queryParam("action", flag ? "on" : "off")
608                         .request(MediaType.APPLICATION_JSON_TYPE).get();
609             } catch (NullPointerException e) {
610                 logger.error("An exception occurred while dis/enabling a switch  on the Helios IP Vario '{}' : '{}'",
611                         getThing().getUID().toString(), e.getMessage(), e);
612                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
613                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
614                 return;
615             }
616
617             if (response != null) {
618                 JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
619
620                 if (logger.isTraceEnabled()) {
621                     logger.trace("enableSwitch() Request : {}",
622                             switchTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", CONTROL)
623                                     .queryParam("switch", id).queryParam("action", flag ? "on" : "off").getUri()
624                                     .toASCIIString());
625                     if (jsonObject.get("success").toString().equals("true")) {
626                         logger.trace("enableSwitch() Response: {}", jsonObject.get("result"));
627                     }
628                     if (jsonObject.get("success").toString().equals("false")) {
629                         logger.trace("enableSwitch() Response: {}", jsonObject.get("error"));
630                     }
631                 }
632
633                 if (jsonObject.get("success").toString().equals("true")) {
634                     logger.debug("Successfully dis/enabled a  switch on the Helios IP Vario '{}'",
635                             getThing().getUID().toString());
636                 } else {
637                     RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
638                     logger.error(
639                             "An error occurred while communicating with the Helios IP Vario '{}': code '{}', param '{}' : '{}'",
640                             getThing().getUID().toString(), error.code, error.param, error.description);
641                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
642                             error.code + ":" + error.param + ":" + error.description);
643                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
644                     return;
645                 }
646             } else {
647                 logger.warn("An error occurred while dis/enabling a switch on the Helios IP Vario '{}'",
648                         getThing().getUID().toString());
649                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
650                 scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
651                 return;
652             }
653         }
654     }
655
656     private List<RESTPort> getPorts() {
657         portTarget = baseTarget.path(PORT_PATH);
658
659         Response response = null;
660         try {
661             response = portTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", CAPABILITIES)
662                     .request(MediaType.APPLICATION_JSON_TYPE).get();
663         } catch (NullPointerException e) {
664             logger.error(
665                     "An exception occurred while requesting port capabilities from the Helios IP Vario '{}' : '{}'",
666                     getThing().getUID().toString(), e.getMessage(), e);
667             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
668             scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
669             return null;
670         }
671
672         if (response != null) {
673             JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
674
675             if (logger.isTraceEnabled()) {
676                 logger.trace("getPorts() Request : {}", portTarget.resolveTemplate("ip", ipAddress)
677                         .resolveTemplate("cmd", CAPABILITIES).getUri().toASCIIString());
678                 if (jsonObject.get("success").toString().equals("true")) {
679                     logger.trace("getPorts() Response: {}", jsonObject.get("result"));
680                 }
681                 if (jsonObject.get("success").toString().equals("false")) {
682                     logger.trace("getPorts() Response: {}", jsonObject.get("error"));
683                 }
684             }
685
686             if (jsonObject.get("success").toString().equals("true")) {
687                 logger.debug("Successfully requested port capabilities from the Helios IP Vario '{}'",
688                         getThing().getUID().toString());
689                 JsonObject js = (JsonObject) jsonObject.get("result");
690                 RESTPort[] portArray = gson.fromJson(js.getAsJsonArray("ports"), RESTPort[].class);
691                 if (portArray != null) {
692                     return Arrays.asList(portArray);
693                 }
694             } else {
695                 RESTError error = gson.fromJson(jsonObject.get("error").toString(), RESTError.class);
696                 logger.error(
697                         "An error occurred while communicating with the Helios IP Vario '{}': code '{}', param '{}' : '{}'",
698                         getThing().getUID().toString(), error.code, error.param, error.description);
699                 if ("8".equals(error.code)) {
700                     logger.debug(
701                             "The API is not supported by the Helios hardware or current license, or the Authentication method is not set to Basic");
702                 } else {
703                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
704                             error.code + ":" + error.param + ":" + error.description);
705                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
706                 }
707                 return null;
708             }
709         } else {
710             logger.warn("An error occurred while requesting port capabilities from the Helios IP Vario '{}'",
711                     getThing().getUID().toString());
712             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
713             scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
714         }
715
716         return null;
717     }
718
719     protected Runnable resetRunnable = () -> {
720         logger.debug("Resetting the Helios IP Vario handler for '{}'", getThing().getUID());
721         tearDown();
722         initialize();
723     };
724
725     protected Runnable configureRunnable = () -> {
726         logger.debug("Fetching the configuration of the Helios IP Vario '{}' ", getThing().getUID().toString());
727
728         Response response = null;
729         try {
730             response = systemTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", INFO)
731                     .request(MediaType.APPLICATION_JSON_TYPE).get();
732         } catch (NullPointerException e) {
733             logger.error("An exception occurred while fetching system info of the Helios IP Vario '{}' : '{}'",
734                     getThing().getUID().toString(), e.getMessage(), e);
735             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
736             scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
737             return;
738         }
739
740         if (response != null) {
741             JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
742
743             if (logger.isTraceEnabled()) {
744                 logger.trace("configureRunnable Request : {}", systemTarget.resolveTemplate("ip", ipAddress)
745                         .resolveTemplate("cmd", INFO).getUri().toASCIIString());
746                 if (jsonObject.get("success").toString().equals("true")) {
747                     logger.trace("configureRunnable Response: {}", jsonObject.get("result"));
748                 }
749                 if (jsonObject.get("success").toString().equals("false")) {
750                     logger.trace("configureRunnable Response: {}", jsonObject.get("error"));
751                 }
752             }
753
754             RESTSystemInfo systemInfo = gson.fromJson(jsonObject.get("result").toString(), RESTSystemInfo.class);
755
756             Map<String, String> properties = editProperties();
757             properties.put(VARIANT, systemInfo.variant);
758             properties.put(SERIAL_NUMBER, systemInfo.serialNumber);
759             properties.put(HW_VERSION, systemInfo.hwVersion);
760             properties.put(SW_VERSION, systemInfo.swVersion);
761             properties.put(BUILD_TYPE, systemInfo.buildType);
762             properties.put(DEVICE_NAME, systemInfo.deviceName);
763             updateProperties(properties);
764         }
765
766         List<RESTSwitch> switches = getSwitches();
767
768         if (switches != null) {
769             for (RESTSwitch aSwitch : switches) {
770                 if (aSwitch.enabled.equals("true")) {
771                     logger.debug("Adding a channel to the Helios IP Vario '{}' for the switch with id '{}'",
772                             getThing().getUID().toString(), aSwitch.id);
773                     ThingBuilder thingBuilder = editThing();
774                     ChannelTypeUID enablerUID = new ChannelTypeUID(BINDING_ID, SWITCH_ENABLER);
775                     ChannelTypeUID triggerUID = new ChannelTypeUID(BINDING_ID, SWITCH_TRIGGER);
776                     ChannelUID activeSwitchChannelUID = new ChannelUID(getThing().getUID(),
777                             "switch" + aSwitch.id + "active");
778                     ChannelUID switchChannelUID = new ChannelUID(getThing().getUID(), "switch" + aSwitch.id);
779
780                     if (this.getThing().getChannel(activeSwitchChannelUID) == null) {
781                         logger.trace(
782                                 "Adding a channel with id '{}' to the Helios IP Vario '{}' for the switch with id '{}'",
783                                 activeSwitchChannelUID, getThing().getUID().toString(), aSwitch.id);
784                         Channel channel = ChannelBuilder.create(activeSwitchChannelUID, "Switch").withType(enablerUID)
785                                 .build();
786                         thingBuilder.withChannel(channel);
787                     }
788                     if (this.getThing().getChannel(switchChannelUID) == null) {
789                         logger.trace(
790                                 "Adding a channel with id '{}' to the Helios IP Vario '{}' for the switch with id '{}'",
791                                 switchChannelUID, getThing().getUID().toString(), aSwitch.id);
792                         Channel channel = ChannelBuilder.create(switchChannelUID, "Switch").withType(triggerUID)
793                                 .build();
794                         thingBuilder.withChannel(channel);
795                     }
796                     updateThing(thingBuilder.build());
797                 }
798             }
799         }
800
801         List<RESTPort> ports = getPorts();
802
803         if (ports != null) {
804             for (RESTPort aPort : ports) {
805                 logger.debug("Adding a channel to the Helios IP Vario '{}' for the IO port with id '{}'",
806                         getThing().getUID().toString(), aPort.port);
807                 ThingBuilder thingBuilder = editThing();
808                 ChannelTypeUID triggerUID = new ChannelTypeUID(BINDING_ID, IO_TRIGGER);
809                 ChannelUID ioChannelUID = new ChannelUID(getThing().getUID(), "io" + aPort.port);
810
811                 Map<String, String> channelProperties = new HashMap<>();
812                 channelProperties.put("type", aPort.type);
813
814                 if (this.getThing().getChannel(ioChannelUID) == null) {
815                     logger.trace(
816                             "Adding a channel with id '{}' to the Helios IP Vario '{}' for the switch with id '{}'",
817                             ioChannelUID.getId(), getThing().getUID().toString(), aPort.port);
818                     Channel channel = ChannelBuilder.create(ioChannelUID, "Switch").withType(triggerUID)
819                             .withProperties(channelProperties).build();
820                     thingBuilder.withChannel(channel);
821                 }
822                 updateThing(thingBuilder.build());
823             }
824         }
825     };
826
827     protected Runnable logRunnable = () -> {
828         if (getThing().getStatus() == ThingStatus.ONLINE) {
829             if (logSubscriptionID == 0) {
830                 logSubscriptionID = subscribe();
831             }
832
833             SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
834
835             while (logSubscriptionID != 0) {
836                 try {
837                     List<RESTEvent> events = pullLog(logSubscriptionID);
838
839                     if (events != null) {
840                         for (RESTEvent event : events) {
841                             Date date = new Date(Long.valueOf(event.utcTime));
842                             DateTimeType stampType = new DateTimeType(dateFormatter.format(date));
843
844                             logger.debug("Received the event for Helios IP Vario '{}' with ID '{}' of type '{}' on {}",
845                                     getThing().getUID().toString(), event.id, event.event, dateFormatter.format(date));
846
847                             switch (event.event) {
848                                 case DEVICESTATE: {
849                                     StringType valueType = new StringType(event.params.get("state").getAsString());
850                                     updateState(DEVICE_STATE, valueType);
851                                     updateState(DEVICE_STATE_STAMP, stampType);
852                                     break;
853                                 }
854                                 case AUDIOLOOPTEST: {
855                                     if (event.params.get("result").getAsString().equals("passed")) {
856                                         updateState(AUDIO_LOOP_TEST, OnOffType.ON);
857                                     } else if (event.params.get("result").getAsString().equals("failed")) {
858                                         updateState(AUDIO_LOOP_TEST, OnOffType.OFF);
859                                     } else {
860                                         updateState(AUDIO_LOOP_TEST, UnDefType.UNDEF);
861                                     }
862
863                                     updateState(AUDIO_LOOP_TEST_STAMP, stampType);
864                                     break;
865                                 }
866                                 case MOTIONDETECTED: {
867                                     if (event.params.get("state").getAsString().equals("in")) {
868                                         updateState(MOTION, OnOffType.ON);
869                                     } else if (event.params.get("state").getAsString().equals("out")) {
870                                         updateState(MOTION, OnOffType.OFF);
871                                     } else {
872                                         updateState(MOTION, UnDefType.UNDEF);
873                                     }
874
875                                     updateState(MOTION_STAMP, stampType);
876                                     break;
877                                 }
878                                 case NOISEDETECTED: {
879                                     if (event.params.get("state").getAsString().equals("in")) {
880                                         updateState(NOISE, OnOffType.ON);
881                                     } else if (event.params.get("state").getAsString().equals("out")) {
882                                         updateState(NOISE, OnOffType.OFF);
883                                     } else {
884                                         updateState(NOISE, UnDefType.UNDEF);
885                                     }
886
887                                     updateState(NOISE_STAMP, stampType);
888                                     break;
889                                 }
890                                 case KEYPRESSED: {
891                                     triggerChannel(KEY_PRESSED, event.params.get("key").getAsString());
892
893                                     updateState(KEY_PRESSED_STAMP, stampType);
894                                     break;
895                                 }
896                                 case KEYRELEASED: {
897                                     triggerChannel(KEY_RELEASED, event.params.get("key").getAsString());
898
899                                     updateState(KEY_RELEASED_STAMP, stampType);
900                                     break;
901                                 }
902                                 case CODEENTERED: {
903                                     triggerChannel(CODE, event.params.get("code").getAsString());
904
905                                     if (event.params.get("valid").getAsString().equals("true")) {
906                                         updateState(CODE_VALID, OnOffType.ON);
907                                     } else if (event.params.get("valid").getAsString().equals("false")) {
908                                         updateState(CODE_VALID, OnOffType.OFF);
909                                     } else {
910                                         updateState(CODE_VALID, UnDefType.UNDEF);
911                                     }
912
913                                     updateState(CODE_STAMP, stampType);
914                                     break;
915                                 }
916                                 case CARDENTERED: {
917                                     triggerChannel(CARD, event.params.get("uid").getAsString());
918
919                                     if (event.params.get("valid").getAsString().equals("true")) {
920                                         updateState(CARD_VALID, OnOffType.ON);
921                                     } else if (event.params.get("valid").getAsString().equals("false")) {
922                                         updateState(CARD_VALID, OnOffType.OFF);
923                                     } else {
924                                         updateState(CARD_VALID, UnDefType.UNDEF);
925                                     }
926
927                                     updateState(CARD_STAMP, stampType);
928                                     break;
929                                 }
930                                 case INPUTCHANGED: {
931                                     ChannelUID inputChannel = new ChannelUID(getThing().getUID(),
932                                             "io" + event.params.get("port").getAsString());
933
934                                     if (event.params.get("state").getAsString().equals("true")) {
935                                         updateState(inputChannel, OnOffType.ON);
936                                     } else if (event.params.get("state").getAsString().equals("false")) {
937                                         updateState(inputChannel, OnOffType.OFF);
938                                     } else {
939                                         updateState(inputChannel, UnDefType.UNDEF);
940                                     }
941                                     break;
942                                 }
943                                 case OUTPUTCHANGED: {
944                                     ChannelUID inputChannel = new ChannelUID(getThing().getUID(),
945                                             "io" + event.params.get("port").getAsString());
946
947                                     if (event.params.get("state").getAsString().equals("true")) {
948                                         updateState(inputChannel, OnOffType.ON);
949                                     } else if (event.params.get("state").getAsString().equals("false")) {
950                                         updateState(inputChannel, OnOffType.OFF);
951                                     } else {
952                                         updateState(inputChannel, UnDefType.UNDEF);
953                                     }
954                                     break;
955                                 }
956                                 case CALLSTATECHANGED: {
957                                     StringType valueType = new StringType(event.params.get("state").getAsString());
958                                     updateState(CALL_STATE, valueType);
959
960                                     valueType = new StringType(event.params.get("direction").getAsString());
961                                     updateState(CALL_DIRECTION, valueType);
962
963                                     updateState(CALL_STATE_STAMP, stampType);
964                                     break;
965                                 }
966                                 case REGISTRATIONSTATECHANGED: {
967                                     break;
968                                 }
969                                 case SWITCHSTATECHANGED: {
970                                     if (event.params.get("state").getAsString().equals("true")) {
971                                         updateState(SWITCH_STATE, OnOffType.ON);
972                                     } else if (event.params.get("state").getAsString().equals("false")) {
973                                         updateState(SWITCH_STATE, OnOffType.OFF);
974                                     } else {
975                                         updateState(SWITCH_STATE, UnDefType.UNDEF);
976                                     }
977
978                                     if (event.params.get("originator") != null) {
979                                         StringType originatorType = new StringType(
980                                                 event.params.get("originator").getAsString());
981                                         updateState(SWITCH_STATE_ORIGINATOR, originatorType);
982                                     }
983
984                                     DecimalType switchType = new DecimalType(event.params.get("switch").getAsString());
985                                     updateState(SWITCH_STATE_SWITCH, switchType);
986
987                                     updateState(SWITCH_STATE_STAMP, stampType);
988                                     break;
989                                 }
990                                 default: {
991                                     logger.debug("Unrecognised event type : '{}'", event.event);
992                                     Set<Map.Entry<String, JsonElement>> entrySet = event.params.entrySet();
993                                     for (Map.Entry<String, JsonElement> entry : entrySet) {
994                                         logger.debug("Key '{}', Value '{}'", entry.getKey(),
995                                                 event.params.get(entry.getKey()).getAsString().replace("\"", ""));
996                                     }
997                                 }
998                             }
999                         }
1000                     } else {
1001                         if (logger.isTraceEnabled()) {
1002                             logger.trace("No events were retrieved");
1003                         }
1004                     }
1005                 } catch (ProcessingException e) {
1006                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
1007                     logger.trace("An underlying exception forced the Helios IP Vario to go offline : '{}'",
1008                             e.getMessage(), e);
1009                     scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS);
1010                 } catch (Exception e) {
1011                     logger.error("An exception occurred while processing an event : '{}'", e.getMessage(), e);
1012                 }
1013             }
1014         }
1015     };
1016
1017     protected class Authenticator implements ClientRequestFilter {
1018
1019         private final String user;
1020         private final String password;
1021
1022         public Authenticator(String user, String password) {
1023             this.user = user;
1024             this.password = password;
1025         }
1026
1027         @Override
1028         public void filter(ClientRequestContext requestContext) throws IOException {
1029             MultivaluedMap<String, Object> headers = requestContext.getHeaders();
1030             final String basicAuthentication = getBasicAuthentication();
1031             headers.add("Authorization", basicAuthentication);
1032         }
1033
1034         private String getBasicAuthentication() {
1035             String token = this.user + ":" + this.password;
1036             return "Basic " + Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8));
1037         }
1038     }
1039
1040     public class SecureRestClientTrustManager implements X509TrustManager {
1041
1042         @Override
1043         public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
1044         }
1045
1046         @Override
1047         public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
1048         }
1049
1050         @Override
1051         public X509Certificate[] getAcceptedIssuers() {
1052             return new X509Certificate[0];
1053         }
1054
1055         public boolean isClientTrusted(X509Certificate[] arg0) {
1056             return true;
1057         }
1058
1059         public boolean isServerTrusted(X509Certificate[] arg0) {
1060             return true;
1061         }
1062     }
1063 }