Improvments of the producer API callbacks
[nonrtric.git] / enrichment-coordinator-service / src / main / java / org / oransc / enrichment / controllers / producer / ProducerController.java
index c24e559..c670ea4 100644 (file)
@@ -1,9 +1,9 @@
 /*-
  * ========================LICENSE_START=================================
- * ONAP : ccsdk oran
- * ======================================================================
- * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
- * ======================================================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2020 Nordix Foundation
+ * %%
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -33,9 +33,9 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
-import org.oransc.enrichment.clients.ProducerCallbacks;
-import org.oransc.enrichment.clients.ProducerJobInfo;
 import org.oransc.enrichment.controllers.ErrorResponse;
+import org.oransc.enrichment.controllers.VoidResponse;
+import org.oransc.enrichment.controllers.consumer.ConsumerCallbacks;
 import org.oransc.enrichment.controllers.producer.ProducerRegistrationInfo.ProducerEiTypeRegistrationInfo;
 import org.oransc.enrichment.repository.EiJob;
 import org.oransc.enrichment.repository.EiJobs;
@@ -43,7 +43,6 @@ import org.oransc.enrichment.repository.EiProducer;
 import org.oransc.enrichment.repository.EiProducers;
 import org.oransc.enrichment.repository.EiType;
 import org.oransc.enrichment.repository.EiTypes;
-import org.oransc.enrichment.repository.ImmutableEiProducer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -64,9 +63,7 @@ public class ProducerController {
 
     private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-    private static Gson gson = new GsonBuilder() //
-        .serializeNulls() //
-        .create(); //
+    private static Gson gson = new GsonBuilder().create();
 
     @Autowired
     private EiJobs eiJobs;
@@ -80,6 +77,9 @@ public class ProducerController {
     @Autowired
     ProducerCallbacks producerCallbacks;
 
+    @Autowired
+    ConsumerCallbacks consumerCallbacks;
+
     @GetMapping(path = ProducerConsts.API_ROOT + "/eitypes", produces = MediaType.APPLICATION_JSON_VALUE)
     @ApiOperation(value = "EI type identifiers", notes = "")
     @ApiResponses(
@@ -101,7 +101,7 @@ public class ProducerController {
     }
 
     @GetMapping(path = ProducerConsts.API_ROOT + "/eitypes/{eiTypeId}", produces = MediaType.APPLICATION_JSON_VALUE)
-    @ApiOperation(value = "Individual EI Type", notes = "")
+    @ApiOperation(value = "Individual EI type", notes = "")
     @ApiResponses(
         value = { //
             @ApiResponse(code = 200, message = "EI type", response = ProducerEiTypeInfo.class), //
@@ -134,7 +134,7 @@ public class ProducerController {
     ) {
         List<String> result = new ArrayList<>();
         for (EiProducer eiProducer : this.eiProducers.getAllProducers()) {
-            result.add(eiProducer.id());
+            result.add(eiProducer.getId());
         }
 
         return new ResponseEntity<>(gson.toJson(result), HttpStatus.OK);
@@ -146,7 +146,7 @@ public class ProducerController {
     @ApiOperation(value = "Individual EI producer", notes = "")
     @ApiResponses(
         value = { //
-            @ApiResponse(code = 200, message = "EI Jobs", response = ProducerRegistrationInfo.class), //
+            @ApiResponse(code = 200, message = "EI jobs", response = ProducerRegistrationInfo.class), //
             @ApiResponse(
                 code = 404,
                 message = "Enrichment Information producer is not found",
@@ -178,9 +178,9 @@ public class ProducerController {
         try {
             EiProducer producer = this.eiProducers.getProducer(eiProducerId);
             Collection<ProducerJobInfo> producerJobs = new ArrayList<>();
-            for (EiType type : producer.eiTypes()) {
+            for (EiType type : producer.getEiTypes()) {
                 for (EiJob eiJob : this.eiJobs.getJobsForType(type)) {
-                    ProducerJobInfo request = new ProducerJobInfo(eiJob.jobData(), eiJob, eiJob.type());
+                    ProducerJobInfo request = new ProducerJobInfo(eiJob);
                     producerJobs.add(request);
                 }
             }
@@ -191,25 +191,59 @@ public class ProducerController {
         }
     }
 
+    @GetMapping(
+        path = ProducerConsts.API_ROOT + "/eiproducers/{eiProducerId}/status",
+        produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "EI producer status")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "EI jobs", response = ProducerStatusInfo.class), //
+            @ApiResponse(
+                code = 404,
+                message = "Enrichment Information producer is not found",
+                response = ErrorResponse.ErrorInfo.class)})
+    public ResponseEntity<Object> getEiProducerStatus( //
+        @PathVariable("eiProducerId") String eiProducerId) {
+        try {
+            EiProducer producer = this.eiProducers.getProducer(eiProducerId);
+            return new ResponseEntity<>(gson.toJson(producerStatusInfo(producer)), HttpStatus.OK);
+        } catch (Exception e) {
+            return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    private ProducerStatusInfo producerStatusInfo(EiProducer producer) {
+        ProducerStatusInfo.OperationalState opState =
+            producer.isAvailable() ? ProducerStatusInfo.OperationalState.ENABLED
+                : ProducerStatusInfo.OperationalState.DISABLED;
+        this.logger.debug("opState {}", opState);
+        return new ProducerStatusInfo(opState);
+    }
+
     @PutMapping(
         path = ProducerConsts.API_ROOT + "/eiproducers/{eiProducerId}",
         produces = MediaType.APPLICATION_JSON_VALUE)
     @ApiOperation(value = "Individual EI producer", notes = "")
     @ApiResponses(
         value = { //
-            @ApiResponse(code = 201, message = "Producer created", response = void.class), //
-            @ApiResponse(code = 200, message = "Producer updated", response = void.class)}//
+            @ApiResponse(code = 201, message = "Producer created", response = VoidResponse.class), //
+            @ApiResponse(code = 200, message = "Producer updated", response = VoidResponse.class)}//
     )
     public ResponseEntity<Object> putEiProducer( //
         @PathVariable("eiProducerId") String eiProducerId, //
         @RequestBody ProducerRegistrationInfo registrationInfo) {
         try {
-            final EiProducer previousDefinition = this.eiProducers.get(eiProducerId);
+            EiProducer previousDefinition = this.eiProducers.get(eiProducerId);
             if (previousDefinition != null) {
-                deregisterProducer(previousDefinition, false);
+                for (EiType type : previousDefinition.getEiTypes()) {
+                    type.removeProducer(previousDefinition);
+                }
             }
 
             registerProducer(eiProducerId, registrationInfo);
+            if (previousDefinition != null) {
+                purgeTypes(previousDefinition.getEiTypes());
+            }
 
             return new ResponseEntity<>(previousDefinition == null ? HttpStatus.CREATED : HttpStatus.OK);
         } catch (Exception e) {
@@ -217,19 +251,28 @@ public class ProducerController {
         }
     }
 
+    private void purgeTypes(Collection<EiType> types) {
+        for (EiType type : types) {
+            if (type.getProducerIds().isEmpty()) {
+                this.eiTypes.remove(type);
+            }
+        }
+    }
+
     @DeleteMapping(
         path = ProducerConsts.API_ROOT + "/eiproducers/{eiProducerId}",
         produces = MediaType.APPLICATION_JSON_VALUE)
     @ApiOperation(value = "Individual EI producer", notes = "")
     @ApiResponses(
         value = { //
-            @ApiResponse(code = 200, message = "Not used", response = void.class),
-            @ApiResponse(code = 204, message = "Producer deleted", response = void.class),
+            @ApiResponse(code = 200, message = "Not used", response = VoidResponse.class),
+            @ApiResponse(code = 204, message = "Producer deleted", response = VoidResponse.class),
             @ApiResponse(code = 404, message = "Producer is not found", response = ErrorResponse.ErrorInfo.class)})
     public ResponseEntity<Object> deleteEiProducer(@PathVariable("eiProducerId") String eiProducerId) {
         try {
             final EiProducer producer = this.eiProducers.getProducer(eiProducerId);
-            deregisterProducer(producer, true);
+            this.eiProducers.deregisterProducer(producer, this.eiTypes, this.eiJobs);
+            this.consumerCallbacks.notifyConsumersProducerDeleted(producer);
             return new ResponseEntity<>(HttpStatus.NO_CONTENT);
         } catch (Exception e) {
             return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
@@ -241,21 +284,17 @@ public class ProducerController {
         if (type == null) {
             type = new EiType(typeInfo.eiTypeId, typeInfo.jobDataSchema);
             this.eiTypes.put(type);
+            this.consumerCallbacks.notifyConsumersTypeAdded(type);
         }
         return type;
-
     }
 
     EiProducer createProducer(Collection<EiType> types, String producerId, ProducerRegistrationInfo registrationInfo) {
-        return ImmutableEiProducer.builder() //
-            .id(producerId) //
-            .eiTypes(types) //
-            .jobCreationCallbackUrl(registrationInfo.jobCreationCallbackUrl) //
-            .jobDeletionCallbackUrl(registrationInfo.jobDeletionCallbackUrl) //
-            .build();
+        return new EiProducer(producerId, types, registrationInfo.jobCallbackUrl,
+            registrationInfo.producerSupervisionCallbackUrl);
     }
 
-    private void registerProducer(String producerId, ProducerRegistrationInfo registrationInfo) {
+    private EiProducer registerProducer(String producerId, ProducerRegistrationInfo registrationInfo) {
         ArrayList<EiType> types = new ArrayList<>();
         for (ProducerEiTypeRegistrationInfo typeInfo : registrationInfo.types) {
             types.add(registerType(typeInfo));
@@ -265,35 +304,20 @@ public class ProducerController {
 
         for (EiType type : types) {
             for (EiJob job : this.eiJobs.getJobsForType(type)) {
-                this.producerCallbacks.notifyProducerJobStarted(producer, job);
+                this.producerCallbacks.notifyProducerJobStarted(producer, job) //
+                    .subscribe();
             }
             type.addProducer(producer);
         }
-    }
-
-    private void deregisterProducer(EiProducer producer, boolean deleteJobs) {
-        this.eiProducers.remove(producer);
-        for (EiType type : producer.eiTypes()) {
-            boolean removed = type.removeProducer(producer) != null;
-            if (!removed) {
-                this.logger.error("Bug, no producer found");
-            }
-            if (type.getProducerIds().isEmpty() && deleteJobs) {
-                this.eiTypes.remove(type);
-                for (EiJob job : this.eiJobs.getJobsForType(type.getId())) {
-                    this.eiJobs.remove(job);
-                    this.logger.warn("Deleted job {} because no producers left", job.id());
-                }
-            }
-        }
+        return producer;
     }
 
     ProducerRegistrationInfo toEiProducerRegistrationInfo(EiProducer p) {
         Collection<ProducerEiTypeRegistrationInfo> types = new ArrayList<>();
-        for (EiType type : p.eiTypes()) {
+        for (EiType type : p.getEiTypes()) {
             types.add(toEiTypeRegistrationInfo(type));
         }
-        return new ProducerRegistrationInfo(types, p.jobCreationCallbackUrl(), p.jobDeletionCallbackUrl());
+        return new ProducerRegistrationInfo(types, p.getJobCallbackUrl(), p.getProducerSupervisionCallbackUrl());
     }
 
     private ProducerEiTypeRegistrationInfo toEiTypeRegistrationInfo(EiType type) {