Catalog alignment
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / distribution / engine / CambriaHandler.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.be.components.distribution.engine;
22
23 import com.att.nsa.apiClient.credentials.ApiCredential;
24 import com.att.nsa.apiClient.http.HttpException;
25 import com.att.nsa.apiClient.http.HttpObjectNotFoundException;
26 import com.att.nsa.cambria.client.CambriaBatchingPublisher;
27 import com.att.nsa.cambria.client.CambriaClient;
28 import com.att.nsa.cambria.client.CambriaClient.CambriaApiException;
29 import com.att.nsa.cambria.client.CambriaClientBuilders;
30 import com.att.nsa.cambria.client.CambriaClientBuilders.AbstractAuthenticatedManagerBuilder;
31 import com.att.nsa.cambria.client.CambriaClientBuilders.ConsumerBuilder;
32 import com.att.nsa.cambria.client.CambriaClientBuilders.IdentityManagerBuilder;
33 import com.att.nsa.cambria.client.CambriaClientBuilders.PublisherBuilder;
34 import com.att.nsa.cambria.client.CambriaClientBuilders.TopicManagerBuilder;
35 import com.att.nsa.cambria.client.CambriaConsumer;
36 import com.att.nsa.cambria.client.CambriaIdentityManager;
37 import com.att.nsa.cambria.client.CambriaPublisher.message;
38 import com.att.nsa.cambria.client.CambriaTopicManager;
39 import com.google.common.annotations.VisibleForTesting;
40 import com.google.gson.Gson;
41 import fj.data.Either;
42 import org.apache.http.HttpStatus;
43 import org.openecomp.sdc.be.config.BeEcompErrorManager;
44 import org.openecomp.sdc.be.config.ConfigurationManager;
45 import org.openecomp.sdc.be.distribution.api.client.CambriaOperationStatus;
46 import org.openecomp.sdc.common.log.wrappers.Logger;
47 import org.springframework.stereotype.Component;
48
49 import java.io.IOException;
50 import java.net.MalformedURLException;
51 import java.security.GeneralSecurityException;
52 import java.util.ArrayList;
53 import java.util.Collection;
54 import java.util.List;
55 import java.util.Set;
56 import java.util.regex.Matcher;
57 import java.util.regex.Pattern;
58
59 import static java.util.concurrent.TimeUnit.SECONDS;
60
61 @Component("cambriaHandler")
62 public class CambriaHandler implements ICambriaHandler{
63
64     private static final Logger log = Logger.getLogger(CambriaHandler.class.getName());
65     private static final String PARTITION_KEY = "asdc" + "aa";
66     private static final String SEND_NOTIFICATION = "send notification";
67     private static final String CONSUMER_ID = ConfigurationManager.getConfigurationManager()
68                                                                   .getDistributionEngineConfiguration()
69                                                                   .getDistributionStatusTopic()
70                                                                   .getConsumerId();
71     private static final boolean USE_HTTPS_WITH_DMAAP = ConfigurationManager.getConfigurationManager()
72                                                                     .getDistributionEngineConfiguration()
73                                                                     .isUseHttpsWithDmaap();
74     private final Gson gson = new Gson();
75
76
77     /**
78      * process the response error from Cambria client
79      *
80      * @param message
81      * @return
82      */
83     private Integer processMessageException(String message) {
84
85         String[] patterns = {"(HTTP Status )(\\d\\d\\d)", "(HTTP/\\d.\\d )(\\d\\d\\d)"};
86
87         Integer result = checkPattern(patterns[0], message, 2);
88         if (result != null) {
89             return result;
90         }
91         result = checkPattern(patterns[1], message, 2);
92
93         return result;
94
95     }
96
97     /**
98      * check whether the message has a match with a given pattern inside it
99      *
100      * @param patternStr
101      * @param message
102      * @param groupIndex
103      * @return
104      */
105     private Integer checkPattern(String patternStr, String message, int groupIndex) {
106         Integer result = null;
107
108         Pattern pattern = Pattern.compile(patternStr);
109         Matcher matcher = pattern.matcher(message);
110         boolean find = matcher.find();
111         if (find) {
112             String httpCode = matcher.group(groupIndex);
113             if (httpCode != null) {
114                 try {
115                     result = Integer.valueOf(httpCode);
116                 }
117                 catch (NumberFormatException e) {
118                     log.debug("Failed to parse http code {}", httpCode);
119                 }
120             }
121         }
122         return result;
123     }
124
125     /**
126      * retrieve all topics from U-EB server
127      *
128      * @param hostSet
129      * @return
130      */
131     @Override
132     public Either<Set<String>, CambriaErrorResponse> getTopics(List<String> hostSet) {
133
134         CambriaTopicManager createTopicManager = null;
135         try {
136
137             createTopicManager = buildCambriaClient(createTopicManagerBuilder(hostSet));
138
139             Set<String> topics = createTopicManager.getTopics();
140
141             if (topics == null || topics.isEmpty()) {
142                 CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.NOT_FOUND, null);
143                 return Either.right(cambriaErrorResponse);
144             }
145
146             return Either.left(topics);
147
148         }
149         catch (IOException | GeneralSecurityException e) {
150
151             CambriaErrorResponse cambriaErrorResponse = processError(e);
152
153             log.debug("Failed to fetch topics from U-EB server", e);
154             writeErrorToLog(cambriaErrorResponse, "getTopics", "get topics");
155
156             return Either.right(cambriaErrorResponse);
157         } finally {
158             if (createTopicManager != null) {
159                 createTopicManager.close();
160             }
161         }
162
163     }
164
165     /**
166      * process the error message from Cambria client.
167      * <p>
168      * set Cambria status and http code in case we succeed to fetch it
169      *
170      * @return
171      */
172     private CambriaErrorResponse processError(Exception e) {
173
174         CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse();
175
176         Integer httpCode = processMessageException(e.getMessage());
177
178         if (httpCode != null) {
179             cambriaErrorResponse.setHttpCode(httpCode);
180             switch (httpCode.intValue()) {
181
182                 case 401:
183                     cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.AUTHENTICATION_ERROR);
184                     break;
185                 case 409:
186                     cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.TOPIC_ALREADY_EXIST);
187                     break;
188                 case 500:
189                     cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.INTERNAL_SERVER_ERROR);
190                     break;
191                 default:
192                     cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.CONNNECTION_ERROR);
193             }
194         }
195         else {
196
197             boolean found = false;
198             Throwable throwable = e.getCause();
199             if (throwable != null) {
200                 String message = throwable.getMessage();
201
202                 Throwable cause = throwable.getCause();
203
204                 if (cause != null) {
205                     Class<?> clazz = cause.getClass();
206                     String className = clazz.getName();
207                     if (className.endsWith("UnknownHostException")) {
208                         cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.UNKNOWN_HOST_ERROR);
209                         cambriaErrorResponse.addVariable(message);
210                         found = true;
211                     }
212                 }
213             }
214
215             if (!found) {
216                 cambriaErrorResponse.setOperationStatus(CambriaOperationStatus.CONNNECTION_ERROR);
217                 cambriaErrorResponse.setHttpCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
218             }
219         }
220
221         return cambriaErrorResponse;
222     }
223
224     /**
225      * write the error to the log
226      *  @param cambriaErrorResponse
227      * @param methodName
228      * @param operationDesc
229      */
230     private void writeErrorToLog(CambriaErrorResponse cambriaErrorResponse, String methodName, String operationDesc) {
231
232         String httpCode = cambriaErrorResponse.getHttpCode() == null ? "" : String.valueOf(cambriaErrorResponse.getHttpCode());
233
234         switch (cambriaErrorResponse.getOperationStatus()) {
235             case UNKNOWN_HOST_ERROR:
236                 BeEcompErrorManager.getInstance().logBeUebUnkownHostError(methodName, httpCode);
237                 break;
238             case AUTHENTICATION_ERROR:
239                 BeEcompErrorManager.getInstance().logBeUebAuthenticationError(methodName, httpCode);
240                 break;
241             case CONNNECTION_ERROR:
242                 BeEcompErrorManager.getInstance().logBeUebConnectionError(methodName, httpCode);
243                 break;
244             case INTERNAL_SERVER_ERROR:
245                 BeEcompErrorManager.getInstance().logBeUebSystemError(methodName, operationDesc);
246                 break;
247             default:
248                 break;
249         }
250
251     }
252
253     /**
254      * create a topic if it does not exists in the topicsList
255      *
256      * @param hostSet          - list of U-EB servers
257      * @param apiKey
258      * @param secretKey
259      * @param topicName        - topic to create
260      * @param partitionCount
261      * @param replicationCount
262      * @return
263      */
264     @Override
265     public CambriaErrorResponse createTopic(Collection<String> hostSet, String apiKey, String secretKey, String topicName, int partitionCount, int replicationCount) {
266
267         CambriaTopicManager createTopicManager = null;
268         try {
269
270             AbstractAuthenticatedManagerBuilder<CambriaTopicManager> clientBuilder = createTopicManagerBuilder(hostSet, apiKey, secretKey);
271             createTopicManager = buildCambriaClient(clientBuilder);
272             
273             createTopicManager.createTopic(topicName, "ASDC distribution notification topic", partitionCount, replicationCount);
274
275         }
276         catch (HttpException | IOException | GeneralSecurityException e) {
277
278             log.debug("Failed to create topic {}", topicName, e);
279
280             CambriaErrorResponse cambriaErrorResponse = processError(e);
281
282             if (cambriaErrorResponse.getOperationStatus() != CambriaOperationStatus.TOPIC_ALREADY_EXIST) {
283                 writeErrorToLog(cambriaErrorResponse, "createTopic", "create topic");
284             }
285
286             return cambriaErrorResponse;
287
288         } finally {
289             if (createTopicManager != null) {
290                 createTopicManager.close();
291             }
292         }
293         return new CambriaErrorResponse(CambriaOperationStatus.OK);
294
295     }
296     @Override
297     public CambriaErrorResponse unRegisterFromTopic(Collection<String> hostSet, String managerApiKey, String managerSecretKey, String subscriberApiKey, SubscriberTypeEnum subscriberTypeEnum, String topicName) {
298         String methodName = "unRegisterFromTopic";
299         CambriaTopicManager createTopicManager = null;
300         try {
301             AbstractAuthenticatedManagerBuilder<CambriaTopicManager> clientBuilder = createTopicManagerBuilder(hostSet, managerApiKey, managerSecretKey);
302             
303             createTopicManager = buildCambriaClient(clientBuilder);
304
305             if (subscriberTypeEnum == SubscriberTypeEnum.PRODUCER) {
306                 createTopicManager.revokeProducer(topicName, subscriberApiKey);
307             }
308             else {
309                 createTopicManager.revokeConsumer(topicName, subscriberApiKey);
310             }
311
312         }
313         catch (HttpObjectNotFoundException e) {
314             log.debug("Failed to unregister {} from topic {} as {}", managerApiKey, topicName, subscriberTypeEnum.toString()
315                                                                                                                  .toLowerCase(), e);
316             BeEcompErrorManager.getInstance().logBeUebObjectNotFoundError(methodName, e.getMessage());
317
318             return new CambriaErrorResponse(CambriaOperationStatus.OBJECT_NOT_FOUND, HttpStatus.SC_NOT_FOUND);
319
320         }
321         catch (HttpException | IOException | GeneralSecurityException e) {
322             log.debug("Failed to unregister {} from topic {} as producer", managerApiKey, topicName, e);
323             CambriaErrorResponse cambriaErrorResponse = processError(e);
324
325             writeErrorToLog(cambriaErrorResponse, methodName, "unregister from topic as " + subscriberTypeEnum
326                     .toString()
327                     .toLowerCase());
328
329             return cambriaErrorResponse;
330         } finally {
331             if (createTopicManager != null) {
332                 createTopicManager.close();
333             }
334         }
335
336         return new CambriaErrorResponse(CambriaOperationStatus.OK, HttpStatus.SC_OK);
337     }
338
339     private AbstractAuthenticatedManagerBuilder<CambriaTopicManager> createTopicManagerBuilder(Collection<String> hostSet, String managerApiKey, String managerSecretKey) {
340         AbstractAuthenticatedManagerBuilder<CambriaTopicManager> clientBuilder = createTopicManagerBuilder(hostSet)
341                                                                          .authenticatedBy(managerApiKey, managerSecretKey);
342         if (USE_HTTPS_WITH_DMAAP) {
343             clientBuilder = clientBuilder.usingHttps();
344         }
345         
346         return clientBuilder;
347     }
348
349     private AbstractAuthenticatedManagerBuilder<CambriaTopicManager> createTopicManagerBuilder(Collection<String> hostSet) {
350         return new TopicManagerBuilder().usingHosts(hostSet);
351     }
352
353     /**
354      * register a public key (subscriberId) to a given topic as a CONSUMER or PRODUCER
355      *
356      * @param hostSet
357      * @param managerApiKey
358      * @param managerSecretKey
359      * @param subscriberApiKey
360      * @param subscriberTypeEnum
361      * @param topicName
362      * @return
363      */
364     @Override
365     public CambriaErrorResponse registerToTopic(Collection<String> hostSet, String managerApiKey, String managerSecretKey, String subscriberApiKey, SubscriberTypeEnum subscriberTypeEnum, String topicName) {
366
367         String methodName = "registerToTopic";
368         CambriaTopicManager createTopicManager = null;
369         try {
370             AbstractAuthenticatedManagerBuilder<CambriaTopicManager> clientBuilder = createTopicManagerBuilder(hostSet, managerApiKey, managerSecretKey);
371             createTopicManager = buildCambriaClient(clientBuilder);
372
373             if (subscriberTypeEnum == SubscriberTypeEnum.PRODUCER) {
374                 createTopicManager.allowProducer(topicName, subscriberApiKey);
375             }
376             else {
377                 createTopicManager.allowConsumer(topicName, subscriberApiKey);
378             }
379
380         }
381         catch (HttpObjectNotFoundException e) {
382             log.debug("Failed to register {} to topic {} as {}", managerApiKey, topicName, subscriberTypeEnum.toString()
383                                                                                                              .toLowerCase(), e);
384
385             BeEcompErrorManager.getInstance().logBeUebObjectNotFoundError(methodName, e.getMessage());
386
387             return new CambriaErrorResponse(CambriaOperationStatus.OBJECT_NOT_FOUND, HttpStatus.SC_NOT_FOUND);
388
389         }
390         catch (HttpException | IOException | GeneralSecurityException e) {
391             log.debug("Failed to register {} to topic {} as {}", managerApiKey, topicName, subscriberTypeEnum.toString()
392                                                                                                              .toLowerCase(), e);
393             CambriaErrorResponse cambriaErrorResponse = processError(e);
394
395             writeErrorToLog(cambriaErrorResponse, methodName, "register to topic as " + subscriberTypeEnum
396                     .toString()
397                     .toLowerCase());
398
399             return cambriaErrorResponse;
400         } finally {
401             if (createTopicManager != null) {
402                 createTopicManager.close();
403             }
404         }
405
406         return new CambriaErrorResponse(CambriaOperationStatus.OK, HttpStatus.SC_OK);
407     }
408
409     /**
410      * create and retrieve a Cambria Consumer for a specific topic
411      *
412      * @param hostSet
413      * @param topicName
414      * @param apiKey
415      * @param secretKey
416      * @param consumerId
417      * @param consumerGroup
418      * @param timeoutMS
419      * @return
420      * @throws Exception
421      */
422     @Override
423     public CambriaConsumer createConsumer(Collection<String> hostSet, String topicName, String apiKey, String secretKey, String consumerId, String consumerGroup, int timeoutMS) throws Exception {
424
425         CambriaConsumer consumer = new ConsumerBuilder().authenticatedBy(apiKey, secretKey)
426                                                         .knownAs(consumerGroup, consumerId)
427                                                         .onTopic(topicName)
428                                                         .usingHosts(hostSet)
429                                                         .waitAtServer(timeoutMS)
430                                                         .build();
431         consumer.setApiCredentials(apiKey, secretKey);
432         return consumer;
433     }
434
435     public void closeConsumer(CambriaConsumer consumer) {
436
437         if (consumer != null) {
438             consumer.close();
439         }
440
441     }
442
443     /**
444      * use the topicConsumer to fetch messages from topic. in case no messages were fetched, empty ArrayList will be returned (not error)
445      *
446      * @param topicConsumer
447      * @return
448      */
449     @Override
450     public Either<Iterable<String>, CambriaErrorResponse> fetchFromTopic(CambriaConsumer topicConsumer) {
451
452         String methodName = "fetchFromTopic";
453         try {
454             Iterable<String> messages = topicConsumer.fetch();
455             if (messages == null) {
456                 messages = new ArrayList<>();
457             }
458             return Either.left(messages);
459
460         }
461         catch (IOException e) {
462             CambriaErrorResponse cambriaErrorResponse = processError(e);
463             log.debug("Failed to fetch from U-EB topic. error={}", e.getMessage());
464             writeErrorToLog(cambriaErrorResponse, methodName, "get messages from topic");
465             return Either.right(cambriaErrorResponse);
466
467         }
468         catch (Exception e) {
469             log.debug("Failed to fetch from U-EB topic", e);
470             BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(methodName, e.getMessage());
471             CambriaErrorResponse cambriaErrorResponse = new CambriaErrorResponse(CambriaOperationStatus.INTERNAL_SERVER_ERROR, HttpStatus.SC_INTERNAL_SERVER_ERROR);
472             return Either.right(cambriaErrorResponse);
473         }
474     }
475
476     /**
477      * Publish notification message to a given queue
478      *
479      * @param topicName
480      * @param uebPublicKey
481      * @param uebSecretKey
482      * @param uebServers
483      * @param data
484      * @return
485      */
486     @Override
487     public CambriaErrorResponse sendNotification(String topicName, String uebPublicKey, String uebSecretKey, List<String> uebServers, INotificationData data) {
488
489         CambriaBatchingPublisher createSimplePublisher = null;
490
491         try {
492
493             String json = gson.toJson(data);
494             log.trace("Before sending notification data {} to topic {}", json, topicName);
495
496             createSimplePublisher = new PublisherBuilder().onTopic(topicName).usingHosts(uebServers).build();
497             createSimplePublisher.setApiCredentials(uebPublicKey, uebSecretKey);
498
499             int result = createSimplePublisher.send(PARTITION_KEY, json);
500
501             try {
502                 SECONDS.sleep(1L);
503             }
504             catch (InterruptedException e) {
505                 log.debug("Failed during sleep after sending the message.", e);
506                 Thread.currentThread().interrupt();
507             }
508
509             log.debug("After sending notification data to topic {}. result is {}", topicName, result);
510
511             return new CambriaErrorResponse(CambriaOperationStatus.OK, 200);
512
513         } catch (IOException | GeneralSecurityException e) {
514             log.debug("Failed to send notification {} to topic {} ", data, topicName, e);
515
516             CambriaErrorResponse cambriaErrorResponse = processError(e);
517
518             writeErrorToLog(cambriaErrorResponse, "sendNotification", SEND_NOTIFICATION);
519
520             return cambriaErrorResponse;
521         }
522         finally {
523             if (createSimplePublisher != null) {
524                 log.debug("Before closing publisher");
525                 createSimplePublisher.close();
526                 log.debug("After closing publisher");
527             }
528         }
529     }
530     @Override
531     public CambriaErrorResponse sendNotificationAndClose(String topicName, String uebPublicKey, String uebSecretKey, List<String> uebServers, INotificationData data, long waitBeforeCloseTimeout) {
532         String methodName = "sendNotificationAndClose";
533         CambriaBatchingPublisher createSimplePublisher;
534         CambriaErrorResponse response;
535         try {
536
537             String json = gson.toJson(data);
538             log.debug("Before sending notification data {} to topic {}", json, topicName);
539
540             createSimplePublisher = new PublisherBuilder().onTopic(topicName).usingHosts(uebServers).build();
541             createSimplePublisher.setApiCredentials(uebPublicKey, uebSecretKey);
542
543             int result = createSimplePublisher.send(PARTITION_KEY, json);
544
545             try {
546                 Thread.sleep(1000);
547             }
548             catch (InterruptedException e) {
549                 log.debug("Failed during sleep after sending the message.", e);
550                 Thread.currentThread().interrupt();
551             }
552
553             log.debug("After sending notification data to topic {}. result is {}", topicName, result);
554
555         }
556         catch (IOException | GeneralSecurityException  e) {
557             log.debug("Failed to send notification {} to topic {} ", data, topicName, e);
558
559
560             response = processError(e);
561
562             writeErrorToLog(response, methodName, SEND_NOTIFICATION);
563
564             return response;
565
566         }
567
568         log.debug("Before closing publisher. Maximum timeout is {} seconds", waitBeforeCloseTimeout);
569         try {
570             List<message> messagesInQ = createSimplePublisher.close(waitBeforeCloseTimeout, SECONDS);
571             if (messagesInQ != null && !messagesInQ.isEmpty()) {
572                 log.debug("Cambria client returned {} non sent messages.", messagesInQ.size());
573                 response = new CambriaErrorResponse(CambriaOperationStatus.INTERNAL_SERVER_ERROR, 500);
574                 writeErrorToLog(response, methodName, SEND_NOTIFICATION);
575             }
576             else {
577                 log.debug("No message left in the queue after closing cambria publisher");
578                 response = new CambriaErrorResponse(CambriaOperationStatus.OK, 200);
579             }
580         }
581         catch (InterruptedException e) {
582             log.debug("InterruptedException while closing cambria publisher", e);
583             Thread.currentThread().interrupt();
584             response = new CambriaErrorResponse(CambriaOperationStatus.INTERNAL_SERVER_ERROR, 500);
585             writeErrorToLog(response, methodName, SEND_NOTIFICATION);
586         }
587         catch (IOException e) {
588             log.debug("Failed to close cambria publisher", e);
589             response = new CambriaErrorResponse(CambriaOperationStatus.INTERNAL_SERVER_ERROR, 500);
590             writeErrorToLog(response, methodName, SEND_NOTIFICATION);
591         }
592         log.debug("After closing publisher");
593
594         return response;
595
596     }
597     @Override
598     public CambriaErrorResponse getApiKey(String server, String apiKey) {
599
600         CambriaErrorResponse response;
601         List<String> hostSet = new ArrayList<>();
602         hostSet.add(server);
603         try {
604             CambriaIdentityManager createIdentityManager = buildCambriaClient(new IdentityManagerBuilder().usingHosts(hostSet));
605             createIdentityManager.getApiKey(apiKey);
606
607             response = new CambriaErrorResponse(CambriaOperationStatus.OK, 200);
608
609         }
610         catch (HttpException | IOException | CambriaApiException | GeneralSecurityException e) {
611             log.debug("Failed to fetch api key {} from server {}", apiKey, server, e);
612
613             response = processError(e);
614
615         }
616
617         return response;
618     }
619     @Override
620     public Either<ApiCredential, CambriaErrorResponse> createUebKeys(List<String> hostSet) {
621         Either<ApiCredential, CambriaErrorResponse> result;
622
623         try {
624             CambriaIdentityManager createIdentityManager = buildCambriaClient(new IdentityManagerBuilder().usingHosts(hostSet));
625
626             String description = String.format("ASDC Key for %s", CONSUMER_ID);
627             ApiCredential credential = createIdentityManager.createApiKey("", description);
628             createIdentityManager.setApiCredentials(credential.getApiKey(), credential.getApiSecret());
629             result = Either.left(credential);
630
631         }
632         catch (Exception e) {
633             log.debug("Failed to create ueb keys for servers {}", hostSet, e);
634
635             result = Either.right(processError(e));
636
637         }
638
639         return result;
640     }
641
642     @VisibleForTesting
643     <T extends CambriaClient> T buildCambriaClient(CambriaClientBuilders.AbstractAuthenticatedManagerBuilder<T> client) throws MalformedURLException, GeneralSecurityException {
644         return client.build();
645     }
646 }