DCAE-D be initial commit
[sdc/dcae-d/dt-be-main.git] / dcaedt_catalog / service / src / main / java / org / onap / sdc / dcae / catalog / engine / CatalogController.java
1 /*
2  *                        AT&T - PROPRIETARY
3  *          THIS FILE CONTAINS PROPRIETARY INFORMATION OF
4  *        AT&T AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN
5  *             ACCORDANCE WITH APPLICABLE AGREEMENTS.
6  *
7  *          Copyright (c) 2015 AT&T Knowledge Ventures
8  *              Unpublished and Not for Publication
9  *                     All Rights Reserved
10  */
11 package org.onap.sdc.dcae.catalog.engine;
12 /*
13  *          THIS FILE CONTAINS PROPRIETARY INFORMATION OF
14  *        AT&T AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN
15  *             ACCORDANCE WITH APPLICABLE AGREEMENTS.
16  *
17  *          Copyright (c) 2015 AT&T Knowledge Ventures
18  *              Unpublished and Not for Publication
19  *                     All Rights Reserved
20  */
21
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import javax.annotation.PostConstruct;
27 import javax.annotation.PreDestroy;
28
29 import static org.onap.sdc.dcae.catalog.Catalog.*;
30
31 import java.net.URI;
32 import java.net.URISyntaxException;
33
34 import org.json.JSONObject;
35 import org.onap.sdc.common.onaplog.OnapLoggerDebug;
36 import org.onap.sdc.common.onaplog.OnapLoggerError;
37 import org.onap.sdc.common.onaplog.Enums.LogLevel;
38 import org.onap.sdc.dcae.catalog.Catalog;
39 import org.onap.sdc.dcae.catalog.asdc.ASDCCatalog;
40 import org.onap.sdc.dcae.catalog.commons.Future;
41 import org.onap.sdc.dcae.catalog.commons.FutureHandler;
42 import org.onap.sdc.dcae.composition.util.DcaeBeConstants;
43 import org.onap.sdc.dcae.composition.util.SystemProperties;
44 import org.json.JSONArray;
45 import org.springframework.web.bind.annotation.RequestMapping;
46 import org.springframework.web.bind.annotation.PathVariable;
47 import org.springframework.web.bind.annotation.RequestBody;
48 import org.springframework.web.bind.annotation.RequestMethod;
49 import org.springframework.web.bind.annotation.RestController;
50
51 import org.springframework.web.context.request.async.DeferredResult;
52 import org.springframework.beans.factory.annotation.Autowired;
53 import org.springframework.boot.context.properties.ConfigurationProperties;
54
55 import org.springframework.web.bind.annotation.CrossOrigin;
56
57 /**
58  * All requests body:
59  *  {
60  *              "id": optional request uuid,
61  *              "timestamp": optional request timestamp,
62  *              "catalog": optional catalog uri,
63  *              "timeout": optional timeout - default 0 no time limit
64  *  }
65  *
66  * All responses body:
67  *      { "data": {},
68  *    "error": {}
69  *  }
70  *
71  * If a non-2xx reponse is provided and error occured at catalog engine processing level.
72  * If error has occured in data retrieval then the response error object is not empty. 
73  *
74  * Available uris
75  *   /catalog
76  *              /elements       : roots of the catalog; request body is optional but can specify a label under 'startingLabel'
77  *                                                              response contains items under 'data/elements'
78  *              /{itemId}/elements : catalog descendants of the given item, possibly a mix of folders and items  
79  *                                                              response contains items under 'data/elements'
80  *              /lookup.by.name : lookup catalog entries by name.
81                                                                         The request body must contain a 'selector' entry with a 'name' criteria
82  *                                                              response contains items under 'data/elements'
83  *                Example: '{"id":"5d0c1cf4-11aa-11e6-a148-3e1d05defe78","selector":{"name":"Firewall"}}'
84  *              /lookup.by.annotation
85                                                                         The request body must contain a 'annotation' entry and it can have a 'selector' entry 
86  *                                                              with a multiple annotation property criteria
87  *                                                              response contains items under 'data/elements'
88  *              /lookup.by.model.property.value : 
89  *                                                              The request must contain a "selector" entry as a JSONObject containing the selection criteria
90  *                                                              (property name with values) and desired output properties (null values). Example:
91  *                                                                      "selector":{"att-part-number":"L-CSR-50M-APP-3Y",
92  *                                                                                                                      "management-option":"ATT",
93  *                                                                                                                      "vnf-type":null,
94  *                                                                                                                      "vendor-model":null}
95  *                                                              response contains items under 'data/elements'
96  *              /referents : provides generic recommendations
97  *                                                              response contains items under 'data/elements'
98  *              /{itemId}/referents : provides recommendations for the given item
99  *                                                              response contains items under 'data/elements'
100  *              /{itemId}/model : retrieves the TOSCA model for the item with the given id
101  *                                                              response under 'data/model'
102  *
103  */
104
105
106 @RestController
107 //@RequestMapping(value="/catalog",method=RequestMethod.POST)
108 @CrossOrigin(origins="*")
109 //@ConfigurationProperties(prefix="catalogController")
110 public class CatalogController {
111
112         private static OnapLoggerError errLogger = OnapLoggerError.getInstance();
113         private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
114
115
116         @Autowired
117         private SystemProperties systemProperties;
118
119
120         private boolean enableCORS = false;
121         private URI             defaultCatalog;
122         private static Map<URI, Catalog> catalogs = new HashMap<URI, Catalog>();
123
124
125         public void setDefaultCatalog(URI theUri) {
126                 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "set default catalog at {}", theUri);
127                 this.defaultCatalog = theUri;
128         }
129
130         public void setEnableCORS(boolean doEnable) {
131                 this.enableCORS = doEnable;
132         }
133
134 //      @RequestMapping(value="/elements",method={RequestMethod.POST, RequestMethod.GET}, produces = "application/json")
135 //      public DeferredResult<CatalogResponse> items(@RequestBody(required=false) ItemsRequest theRequest) {
136 //
137 //              final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest;
138 //
139 //              Catalog catalog = getCatalog(request.getCatalog());
140 //              DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
141 //
142 //              catalog.rootsByLabel(request.getStartingLabel())
143 //              //catalog.roots()
144 //                      .setHandler(
145 //                              new CatalogHandler<Folders>(request, result) {
146 //                                      public CatalogResponse handleData(Folders theFolders) {
147 //                                              JSONArray ja = new JSONArray();
148 //                                              if (theFolders != null) {       
149 //                                                      for (Folder folder : theFolders) {
150 //                                                              ja.put(patchData(catalog, folder.data()));
151 //                                                      }
152 //                                              }
153 //                                              CatalogResponse response = new CatalogResponse(this.request);
154 //                                              response.data()
155 //                                                                              .put("elements", ja);
156 //                                              return response;        
157 //                                      }
158 //                      });
159 //              return result;
160 //      }
161 //
162 //      @RequestMapping(value="/{theItemId}/elements",method={RequestMethod.POST,RequestMethod.GET}, produces = "application/json")
163 //      public DeferredResult<CatalogResponse> items(@RequestBody(required=false) ItemsRequest theRequest, @PathVariable String theItemId) {
164 //
165 //              final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest;
166 //
167 //              Catalog catalog = getCatalog(request.getCatalog());
168 //              DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
169 //
170 //              catalog
171 ////                    .fetchFolderByItemId(theItemId)
172 //                      .folder(theItemId)
173 //                      .withParts()
174 //                      .withPartAnnotations()
175 //                      .withItems()
176 //                      .withItemAnnotations()
177 //                      .withItemModels()
178 //                      .execute()
179 //                      .setHandler(
180 //                              new CatalogHandler<Folder>(request, result) {
181 //                                      public CatalogResponse handleData(Folder theFolder) {
182 //                                              CatalogResponse response = new CatalogResponse(this.request);
183 //                                              if (theFolder == null) {
184 //                                                      return response;
185 //                                              }
186 //
187 //                                              try {
188 //                                                      Elements folders = theFolder.elements("parts",Folders.class);
189 //                                                      if (folders != null) {
190 //                                                              for (Object folder: folders) {
191 //                                                                      patchData(catalog, ((Element)folder).data());
192 //                                                                      //lots of ephemere proxies created here ..
193 //                                                                      Elements annotations =
194 //                                                                                      ((Element)folder).elements("annotations", Annotations.class);
195 //                                                                      if (annotations != null) {
196 //                                                                              for (Object a: annotations) {
197 //                                                                                      patchData(catalog, ((Annotation)a).data());
198 //                                                                              }
199 //                                                                      }
200 //                                                              }
201 //                                                      }
202 //                                                      Elements items = theFolder.elements("items",Items.class);
203 //                                                      if (items != null) {
204 //                                                              for (Object i: items) {
205 //                                                                      patchData(catalog, ((Element)i).data());
206 //                                                                      //lots of ephemere proxies created here ..
207 //                                                                      Elements annotations =
208 //                                                                                      ((Element)i).elements("annotations", Annotations.class);
209 //                                                                      if (annotations != null) {
210 //                                                                              for (Object a: annotations){
211 //                                                                                      patchData(catalog, ((Annotation)a).data());
212 //                                                                              }
213 //                                                                      }
214 //                                                              }
215 //                                                      }
216 //                                              }
217 //                                              catch(Exception x) {
218 //x.printStackTrace();
219 //                                                      return new CatalogError(this.request, "", x);
220 //                                              }
221 //
222 //                                              response.data()
223 //                                                                              .put("element", theFolder.data());
224 //                                              return response;        
225 //                                      }
226 //                              });
227 //              
228 //              return result;
229 //      }
230 //
231 //      @RequestMapping(value="/lookup.by.name",method=RequestMethod.POST, produces = "application/json")
232 //  public DeferredResult<CatalogResponse> elementsByName(@RequestBody ElementsLookup theRequest) {
233 //              
234 //              Catalog catalog = getCatalog(theRequest.getCatalog());
235 //              DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(theRequest.getTimeout());
236 //              
237 //              catalog
238 //                      .lookup(new JSONObject(theRequest.getSelector()))
239 //                      .setHandler(
240 //                              new CatalogHandler<Mixels>(theRequest, result) {
241 //                                      public CatalogResponse handleData(Mixels theElems) {
242 //                                              JSONArray ja = new JSONArray();
243 //                                              if (theElems != null) {
244 //                                                      for (Object elem : theElems) {
245 //                                                              ja.put(patchData(catalog, ((Element)elem).data()));
246 //                                                      }
247 //                                              }
248 //                                              CatalogResponse response = new CatalogResponse(theRequest);
249 //                                              response.data()
250 //                                                                              .put("elements", ja);
251 //                                              return response;
252 //                                      }
253 //                              });
254 //
255 //              return result;
256 //      }
257 //
258 //      @RequestMapping(value="/lookup.by.annotation",method=RequestMethod.POST, produces = "application/json")
259 //  public DeferredResult<CatalogResponse> elementsByAnnotation(@RequestBody ElementsLookup theRequest) {
260 //              
261 //              Catalog catalog = getCatalog(theRequest.getCatalog());
262 //              DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(theRequest.getTimeout());
263 //
264 //              catalog
265 //                      .lookup(theRequest.getAnnotation(),
266 //                                                      new JSONObject(theRequest.getSelector()))
267 //                      .setHandler(
268 //                              new CatalogHandler<Mixels>(theRequest, result) {
269 //                                      public CatalogResponse handleData(Mixels theElems) {
270 //                                              JSONArray ja = new JSONArray();
271 //                                              if (theElems != null) {
272 //                                                      for (Object elem : theElems) {
273 //                                                              ja.put(patchData(catalog, ((Element)elem).data()));
274 //                                                      }
275 //                                              }
276 //                                              CatalogResponse response = new CatalogResponse(this.request);
277 //                                              response.data()
278 //                                                                              .put("elements", ja);
279 //                                              return response;
280 //                                      }
281 //                              });
282 //      
283 //              return result;
284 //      }
285
286         /**
287    * NeoCatalog specific
288    *//*
289         @RequestMapping(value="/lookup.by.model.property.value",method=RequestMethod.POST, produces = "application/json")
290   public DeferredResult<CatalogResponse> elementsByModelPropertyValue(@RequestBody ElementsLookup theRequest) {
291                 
292                 DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(theRequest.getTimeout());
293                 
294                 NeoCatalog catalog = asNeo(getCatalog(theRequest.getCatalog()));
295                 if (catalog == null) {
296                         result.setErrorResult(
297                                 new CatalogError(
298                                         theRequest,"The selected catalog is not capable of handling this request (lookup.by.model.property.value)"));
299                         return result;
300                 }
301
302                 catalog
303                         .lookupItemsByToscaNodePropertyValue(theRequest.getJSONSelector())
304                         .setHandler(
305                                 new CatalogHandler<Items>(theRequest, result) {
306                                         public CatalogResponse handleData(Items theItems) {
307                                                 JSONArray ja = new JSONArray();
308                                                 if (theItems != null) {
309                                                         for (Item item : theItems) {
310                                                                 ja.put(patchData(catalog, item.data()));
311                                                         }
312                                                 }
313                                                 CatalogResponse response = new CatalogResponse(this.request);
314                                                 response.data()
315                                                                                 .put("elements", ja);
316                                                 return response;
317                                         }
318                                 });
319
320                 return result;
321         }
322 */
323         /**
324    * This follows the current convention that each item will have a single model 
325                 2 stage
326    */
327 //      @RequestMapping(value="/{theItemId}/model",method={RequestMethod.POST,RequestMethod.GET}, produces = "application/json")
328 //  //public DeferredResult<CatalogResponse> model(@RequestBody ElementRequest theRequest) {
329 //  public DeferredResult<CatalogResponse> model(@RequestBody(required=false) ElementRequest theRequest, @PathVariable String theItemId) {
330 //              final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest;
331 //              
332 //              Catalog catalog = getCatalog(request.getCatalog());
333 //              DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
334 //      
335 //              catalog
336 ////                    .fetchItemByItemId(/*theRequest.getProductId()*/theItemId)
337 //                      .item(theItemId)
338 //                      .withModels()
339 //                      .execute()
340 //                      .setHandler(
341 //                              new CatalogHandler<Item>(request, result) {
342 //                                      public CatalogResponse handleData(Item theItem) {
343 //                                              if (theItem == null) {
344 //                                                      return new CatalogError(this.request, "No such item");
345 //                                              }
346 //                                              Templates models = null;
347 //                                              try {
348 //                                                      models = (Templates)theItem.elements("models", Templates.class);
349 //                                              }
350 //                                              catch (Exception x) {
351 //                                                      return new CatalogError(this.request, "Failed to decode templates from result", x);
352 //                                              }
353 //
354 //                                              if (models == null || models.size() == 0) {
355 //                                                      return new CatalogError(this.request, "Item has no models");
356 //                                              }
357 //                                              if (models.size() > 1) {
358 //                                                      return new CatalogError(this.request, "Item has more than one model !?");
359 //                                              }       
360 //                      try{                    
361 //                                              catalog.template(models.get(0).id())
362 //                                                      .withInputs()
363 //                                                      .withOutputs()
364 //                                                      .withNodes()
365 //                                                      .withNodeProperties()
366 //                                                      .withNodePropertiesAssignments()
367 //                                                      .withNodeRequirements()
368 //                                                      .withNodeCapabilities()
369 //                                                      .withNodeCapabilityProperties()
370 //                                                      .withNodeCapabilityPropertyAssignments()
371 //                                                      .withPolicies()
372 //                                                .withPolicyProperties()
373 //                                                .withPolicyPropertiesAssignments()
374 //                                                      .execute()
375 //                                                      .setHandler(
376 //                                                              new CatalogHandler<Template>(this.request, this.result) {
377 //                                                                      public CatalogResponse handleData(Template theTemplate) {
378 //                                                                              CatalogResponse response = new CatalogResponse(this.request);
379 //                                                                              if (theTemplate != null) {
380 //                                                                                      response.data()
381 //                                                                                              .put("model", patchData(catalog, theTemplate.data()));
382 //                                                                              }
383 //                                                                              return response;
384 //                                                                      }
385 //                                                              });
386 //                              }
387 //                              catch (Exception x) {
388 //                                      x.printStackTrace();
389 //                              }               
390 //                                              return null;
391 //                                      }
392 //                              });
393 //
394 //              return result;
395 //      }
396         
397 //      @RequestMapping(value="/{theItemId}/type/{theTypeName}",method={RequestMethod.POST,RequestMethod.GET}, produces = "application/json")
398 //  public DeferredResult<CatalogResponse> model(@RequestBody(required=false) ElementRequest theRequest, @PathVariable String theItemId, @PathVariable String theTypeName) {
399 //              final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest;
400 //      
401 //              Catalog catalog = getCatalog(request.getCatalog());
402 //              DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
403 //      
404 //              catalog.type(theItemId, theTypeName)
405 //                      .withHierarchy()
406 //                      .withCapabilities()
407 //                      .withRequirements()
408 //                      .execute()
409 //                      .setHandler(
410 //                                      new CatalogHandler<Type>(request, result) {
411 //                                                                      public CatalogResponse handleData(Type theType) {
412 //                                                                              CatalogResponse response = new CatalogResponse(this.request);
413 //                                                                              if (theType != null) {
414 //                                                                                      response.data()
415 //                                                                                              .put("type", patchData(catalog, theType.data()));
416 //                                                                              }
417 //                                                                              return response;
418 //                                                                      }
419 //                                                              });
420 //              
421 //              return result;
422 //      }
423
424 /*
425         @RequestMapping(value="/referents",method=RequestMethod.POST, produces = "application/json")
426   public DeferredResult<CatalogResponse> referents(@RequestBody(required=false) ElementRequest theRequest) {
427                 final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest;
428                 DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
429
430                 NeoCatalog catalog = asNeo(getCatalog(theRequest.getCatalog()));
431                 if (catalog == null) {
432                         result.setErrorResult(
433                                 new CatalogError(
434                                         theRequest,"The selected catalog is not capable of handling this request (referents)"));
435                         return result;
436                 }
437
438                 catalog
439                         .defaultRecommendations()
440                         .setHandler(
441                                 new CatalogHandler<Mixels>(request, result) {
442                                         public CatalogResponse handleData(Mixels theElems) {
443                                                 JSONArray ja = new JSONArray();
444                                                 if (theElems != null) {
445                                                         for (Element elem : theElems) {
446                                                                 ja.put(patchData(catalog, elem.data()));
447                                                         }
448                                                 }
449                                                 CatalogResponse response = new CatalogResponse(this.request);
450                                                 response.data()
451                                                                                 .put("elements", ja);
452                                                 return response;
453                                         }
454                                 });
455
456                 return result;
457         }
458 */
459
460 /*      @RequestMapping(value="/{theItemId}/referents",method=RequestMethod.POST, produces = "application/json")
461   public DeferredResult<CatalogResponse> referents(@RequestBody(required=false) ElementRequest theRequest, @PathVariable String theItemId) {
462                 final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest;
463                 DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
464
465                 NeoCatalog catalog = asNeo(getCatalog(theRequest.getCatalog()));
466                 if (catalog == null) {
467                         result.setErrorResult(
468                                 new CatalogError(
469                                         theRequest,"The selected catalog is not capable of handling this request (item referents)"));
470                         return result;
471                 }
472
473                 catalog
474                         .recommendationsForItemId(theItemId)
475                         .setHandler(
476                                 new CatalogHandler<Mixels>(request, result) {
477                                         public CatalogResponse handleData(Mixels theElems) {
478                                                 JSONArray ja = new JSONArray();
479                                                 if (theElems != null) {
480                                                         for (Element elem : theElems) {
481                                                                 ja.put(patchData(catalog, elem.data()));
482                                                         }
483                                                 }
484                                                 CatalogResponse response = new CatalogResponse(this.request);
485                                                 response.data()
486                                                                                 .put("elements", ja);
487                                                 return response;
488                                         }
489                                 });
490
491                 return result;
492         }
493 */
494         @PostConstruct
495         public void initCatalog() {
496                 // Dump some info and construct our configuration objects
497                 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "initCatalog");
498                         
499                 this.defaultCatalog = URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_CATALOG_URL));
500                 // Initialize default catalog connection
501                 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "default catalog at {}", this.defaultCatalog);
502                 getCatalog(null);
503
504                         // Done
505                 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "CatalogEngine started");
506         }
507
508         @PreDestroy
509         public void cleanupCatalog() {
510                 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "destroyCatalog");
511         }
512
513         public Catalog getCatalog(URI theCatalogUri) {
514                 //TODO: Thread safety! Check catalog is alive!
515                 if (theCatalogUri == null)
516                         theCatalogUri = this.defaultCatalog;
517
518                 Catalog cat = catalogs.get(theCatalogUri);
519                 if (cat == null && theCatalogUri != null) {
520                         String scheme = theCatalogUri.getScheme();
521                         URI catalogUri = null;
522                         try {
523                                 catalogUri = new URI(theCatalogUri.getSchemeSpecificPart() + "#" + theCatalogUri.getFragment());
524                         }
525                         catch (URISyntaxException urisx) {
526                                 throw new IllegalArgumentException("Invalid catalog reference '" + theCatalogUri.getSchemeSpecificPart() + "'");
527                         }
528                         debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Build catalog for {}", catalogUri);
529
530                         if ("asdc".equals(scheme)) {
531                                 cat = new ASDCCatalog(catalogUri);
532                         }
533                         else {
534                                 return null;
535                         }
536
537                         catalogs.put(theCatalogUri, cat);
538                 }
539                 return cat;
540         }
541
542 /*      private NeoCatalog asNeo(Catalog theCatalog) {
543                 try {
544                         return (NeoCatalog)theCatalog;
545                 }
546                 catch (ClassCastException ccx) {
547                         return null;
548                 }
549         }*/
550
551         public JSONObject patchData(Catalog theCat, JSONObject theData) {
552                 theData.put("catalog", theCat.getUri());
553                 theData.put("catalogId", theData.optLong("id"));
554                 theData.put("id", theData.optLong("itemId"));
555                 return theData;
556         }
557
558         public abstract class CatalogHandler<T> implements FutureHandler<T> {
559
560                 protected DeferredResult result;
561                 protected CatalogRequest request;
562
563                 public CatalogHandler(CatalogRequest theRequest, DeferredResult theResult) {
564                         this.request = theRequest;
565                         this.result = theResult;
566                 }
567
568                 public abstract CatalogResponse handleData(T theData);
569
570                 //@Override
571                 public void handle(Future<T> theEvent) {
572                         debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "handle");
573
574                         if (this.result.isSetOrExpired()) {
575                                 debugLogger.log(LogLevel.WARN, this.getClass().getName(), "handle, Data is late");
576                                 return;
577                         }
578
579                         if (theEvent.failed()) {
580                                 this.result.setErrorResult(new CatalogError(this.request, "Catalog API failed", theEvent.cause()));
581                         }
582                         else {
583                                 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "handle, got: {}", theEvent.result());
584                                 CatalogResponse response = handleData(theEvent.result());
585                                 //a null result allows the handler to pass the processing onto some other async processing stage
586                                 if (response != null) {
587                                         if (!this.result.setResult(response)) {
588                                                 this.result.setErrorResult(new CatalogError(this.request, "Catalog API call succesful but late"));
589                                         }
590                                 }
591                         }
592                 }
593         }
594 }