Add DMaaP Integration to retrieve AAI-EVENT 59/79459/2
authoraosull01 <adrian.osullivan@huawei.com>
Mon, 25 Feb 2019 16:09:30 +0000 (16:09 +0000)
committeraosull01 <adrian.osullivan@huawei.com>
Fri, 1 Mar 2019 15:02:00 +0000 (15:02 +0000)
Change-Id: I94e5eec12fe22b1785a00de530e080a842f37a40
Issue-ID: EXTAPI-201
Signed-off-by: aosull01 <adrian.osullivan@huawei.com>
14 files changed:
src/main/java/org/onap/nbi/OnapComponentsUrlPaths.java
src/main/java/org/onap/nbi/apis/hub/HubResource.java
src/main/java/org/onap/nbi/apis/hub/model/EventType.java
src/main/java/org/onap/nbi/apis/hub/model/ServiceInstanceEvent.java [new file with mode: 0644]
src/main/java/org/onap/nbi/apis/hub/service/CheckDMaaPEventsManager.java [new file with mode: 0644]
src/main/java/org/onap/nbi/apis/hub/service/DMaaPEventsScheduler.java [new file with mode: 0644]
src/main/java/org/onap/nbi/apis/hub/service/EventFactory.java
src/main/java/org/onap/nbi/apis/hub/service/NotifierService.java
src/main/java/org/onap/nbi/configuration/AppContext.java [new file with mode: 0644]
src/main/resources/application-test.properties
src/main/resources/application.properties
src/test/java/org/onap/nbi/api/listener/ListenerResource.java
src/test/resources/karatetest/features/03--Subscriber.feature
src/test/resources/mappings/dmaap_get_aaievents.json [new file with mode: 0644]

index 9060249..80563d5 100644 (file)
@@ -50,4 +50,8 @@ public final class OnapComponentsUrlPaths {
     public static final String MSO_CREATE_E2ESERVICE_INSTANCE_PATH = "/onap/so/infra/e2eServiceInstances/v3";
     public static final String MSO_DELETE_E2ESERVICE_INSTANCE_PATH = "/onap/so/infra/e2eServiceInstances/v3/";
     public static final String MSO_GET_E2EREQUEST_STATUS_PATH = "/onap/so/infra/e2eServiceInstances/v3/$serviceId/operations/$operationId";
-}
+    
+    // DMaaP Message Router REST Client
+    public static final String DMAAP_CONSUME_EVENTS =
+            "/events/$topic/$consumergroup/$consumerid?timeout=$timeout";
+}
\ No newline at end of file
index 0f94802..ac073c1 100755 (executable)
@@ -1,23 +1,24 @@
 /**
  * Copyright (c) 2018 Orange
  *
- * 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
+ * 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
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
  */
 package org.onap.nbi.apis.hub;
 
-import java.net.URI;
 import java.util.List;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import org.onap.nbi.apis.hub.model.Subscriber;
 import org.onap.nbi.apis.hub.model.Subscription;
+import org.onap.nbi.apis.hub.service.CheckDMaaPEventsManager;
 import org.onap.nbi.apis.hub.service.SubscriptionService;
 import org.onap.nbi.commons.JsonRepresentation;
 import org.onap.nbi.commons.MultiCriteriaRequestBuilder;
@@ -42,67 +43,80 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 
 @RestController
 @RequestMapping("/hub")
 @EnableScheduling
 public class HubResource extends ResourceManagement {
 
-    Logger logger = LoggerFactory.getLogger(HubResource.class);
+  Logger logger = LoggerFactory.getLogger(HubResource.class);
 
-    @Autowired
-    MongoTemplate mongoTemplate;
+  @Autowired
+  MongoTemplate mongoTemplate;
 
-    @Autowired
-    SubscriptionService subscriptionService;
+  @Autowired
+  SubscriptionService subscriptionService;
 
-    @Autowired
-    MultiCriteriaRequestBuilder multiCriteriaRequestBuilder;
+  @Autowired
+  MultiCriteriaRequestBuilder multiCriteriaRequestBuilder;
 
-    @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Object> createEventSubscription(@RequestBody Subscription subscription,
-        @RequestParam MultiValueMap<String, String> params) {
-        logger.debug("POST request for subscription : {}", subscription);
-        Subscriber subscriber = subscriptionService.createSubscription(subscription);
-        JsonRepresentation filter = new JsonRepresentation(params);
-        return this.createResponse(Subscription.createFromSubscriber(subscriber), filter);
-
-    }
-
-    @GetMapping(value = "/{subscriptionId}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Subscription> getSubscription(@PathVariable String subscriptionId) {
+  @Autowired
+  CheckDMaaPEventsManager checkDMaaPEventMAnager;
 
+  @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<Object> createEventSubscription(@RequestBody Subscription subscription,
+      @RequestParam MultiValueMap<String, String> params) {
+    logger.debug("POST request for subscription : {}", subscription);
+    Subscriber subscriber = subscriptionService.createSubscription(subscription);
+    JsonRepresentation filter = new JsonRepresentation(params);
+    return this.createResponse(Subscription.createFromSubscriber(subscriber), filter);
 
-        Optional<Subscriber> optionalSubscriber = subscriptionService.findSubscriptionById(subscriptionId);
-        if (!optionalSubscriber.isPresent()) {
-            return ResponseEntity.notFound().build();
-        }
-        return ResponseEntity.ok(Subscription.createFromSubscriber(optionalSubscriber.get()));
-    }
-
-    @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Object> findSubscribers(@RequestParam MultiValueMap<String, String> params) {
+  }
 
-        Query query = multiCriteriaRequestBuilder.buildRequest(params);
-        List<Subscriber> subscribers = mongoTemplate.find(query, Subscriber.class);
-        JsonRepresentation filter = new JsonRepresentation(params);
-        long totalCount = subscriptionService.countSubscription();
-        HttpHeaders headers = new HttpHeaders();
-        headers.add("X-Total-Count", String.valueOf(totalCount));
-        headers.add("X-Result-Count", String.valueOf(subscribers.size()));
-        List<Subscription> subscriptions = subscribers.stream()
-            .map(Subscription::createFromSubscriber)
-            .collect(Collectors.toList());
+  @GetMapping(value = "/{subscriptionId}", produces = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<Subscription> getSubscription(@PathVariable String subscriptionId) {
 
-        return this.findResponse(subscriptions, filter, headers);
 
+    Optional<Subscriber> optionalSubscriber =
+        subscriptionService.findSubscriptionById(subscriptionId);
+    if (!optionalSubscriber.isPresent()) {
+      return ResponseEntity.notFound().build();
     }
+    return ResponseEntity.ok(Subscription.createFromSubscriber(optionalSubscriber.get()));
+  }
+
+  @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<Object> findSubscribers(
+      @RequestParam MultiValueMap<String, String> params) {
+
+    Query query = multiCriteriaRequestBuilder.buildRequest(params);
+    List<Subscriber> subscribers = mongoTemplate.find(query, Subscriber.class);
+    JsonRepresentation filter = new JsonRepresentation(params);
+    long totalCount = subscriptionService.countSubscription();
+    HttpHeaders headers = new HttpHeaders();
+    headers.add("X-Total-Count", String.valueOf(totalCount));
+    headers.add("X-Result-Count", String.valueOf(subscribers.size()));
+    List<Subscription> subscriptions =
+        subscribers.stream().map(Subscription::createFromSubscriber).collect(Collectors.toList());
+
+    return this.findResponse(subscriptions, filter, headers);
+
+  }
+
+  /*
+   * Resource to test for DMaaP Integration for subscribing to AAI-EVENTs
+   */
+  @GetMapping("/testaaievents")
+  @ResponseStatus(HttpStatus.OK)
+  public void testAAIEventListener() {
+    checkDMaaPEventMAnager.checkForDMaaPAAIEvents();
+  }
+
+  @DeleteMapping("/{subscriptionId}")
+  @ResponseStatus(HttpStatus.NO_CONTENT)
+  public void deleteSubscription(@PathVariable String subscriptionId) {
+    logger.debug("DELETE request for subscription id #{}", subscriptionId);
+    subscriptionService.deleteSubscription(subscriptionId);
+  }
 
-    @DeleteMapping("/{subscriptionId}")
-    @ResponseStatus(HttpStatus.NO_CONTENT)
-    public void deleteSubscription(@PathVariable String subscriptionId) {
-        logger.debug("DELETE request for subscription id #{}", subscriptionId);
-        subscriptionService.deleteSubscription(subscriptionId);
-    }
 }
index 1702347..b4e1f1a 100644 (file)
@@ -1,17 +1,15 @@
 /**
- *     Copyright (c) 2018 Orange
+ * Copyright (c) 2018 Orange
  *
- *     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
+ * 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
  *
- *         http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- *     Unless required by applicable law or agreed to in writing, software
- *     distributed under the License is distributed on an "AS IS" BASIS,
- *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *     See the License for the specific language governing permissions and
- *     limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
  */
 package org.onap.nbi.apis.hub.model;
 
@@ -20,36 +18,42 @@ import com.fasterxml.jackson.annotation.JsonValue;
 
 public enum EventType {
 
-    SERVICE_ORDER_CREATION("ServiceOrderCreationNotification"),
+  SERVICE_ORDER_CREATION("ServiceOrderCreationNotification"),
 
-    SERVICE_ORDER_STATE_CHANGE("ServiceOrderStateChangeNotification"),
+  SERVICE_ORDER_STATE_CHANGE("ServiceOrderStateChangeNotification"),
 
-    SERVICE_ORDER_ITEM_STATE_CHANGE("ServiceOrderItemStateChangeNotification");
+  SERVICE_ORDER_ITEM_STATE_CHANGE("ServiceOrderItemStateChangeNotification"),
 
-    private String value;
+  SERVICE_CREATION("ServiceCreationNotification"),
 
-    EventType(String value) {
-        this.value = value;
-    }
+  SERVICE_ATTRIBUTE_VALUE_CHANGE("ServiceAttributeValueChangeNotification"),
 
-    @Override
-    public String toString() {
-        return String.valueOf(value);
-    }
+  SERVICE_REMOVE("ServiceRemoveNotification");
 
-    @JsonCreator
-    public static EventType fromValue(String text) {
-        for (EventType b : EventType.values()) {
-            if (String.valueOf(b.value).equals(text)) {
-                return b;
-            }
-        }
-        return null;
-    }
+  private String value;
 
-    @JsonValue
-    public String value() {
-        return this.value;
+  EventType(String value) {
+    this.value = value;
+  }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
+
+  @JsonCreator
+  public static EventType fromValue(String text) {
+    for (EventType b : EventType.values()) {
+      if (String.valueOf(b.value).equals(text)) {
+        return b;
+      }
     }
+    return null;
+  }
+
+  @JsonValue
+  public String value() {
+    return this.value;
+  }
 
 }
diff --git a/src/main/java/org/onap/nbi/apis/hub/model/ServiceInstanceEvent.java b/src/main/java/org/onap/nbi/apis/hub/model/ServiceInstanceEvent.java
new file mode 100644 (file)
index 0000000..4bbafdc
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2019 Huawei
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.onap.nbi.apis.hub.model;
+
+import org.onap.nbi.apis.serviceorder.model.RelatedParty;
+import org.springframework.data.annotation.Id;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ServiceInstanceEvent {
+
+  @Id
+  @JsonProperty("id")
+  private String id = null;
+
+  @JsonProperty("href")
+  private String href = null;
+
+  @JsonProperty("name")
+  private String name = null;
+
+  @JsonProperty("type")
+  private String type = "service-instance";
+
+  @JsonProperty("state")
+  private String state = null;
+
+  @JsonProperty("relatedParty")
+  private RelatedParty relatedParty = null;
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public String getHref() {
+    return href;
+  }
+
+  public void setHref(String href) {
+    this.href = href;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(String type) {
+    this.type = type;
+  }
+
+  public String getState() {
+    return state;
+  }
+
+  public void setState(String state) {
+    this.state = state;
+  }
+
+  public RelatedParty getRelatedParty() {
+    return relatedParty;
+  }
+
+  public void setRelatedParty(RelatedParty relatedParty) {
+    this.relatedParty = relatedParty;
+  }
+
+}
diff --git a/src/main/java/org/onap/nbi/apis/hub/service/CheckDMaaPEventsManager.java b/src/main/java/org/onap/nbi/apis/hub/service/CheckDMaaPEventsManager.java
new file mode 100644 (file)
index 0000000..6e2811f
--- /dev/null
@@ -0,0 +1,199 @@
+/**
+ * Copyright (c) 2019 Huawei
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.onap.nbi.apis.hub.service;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import org.onap.nbi.OnapComponentsUrlPaths;
+import org.onap.nbi.apis.hub.model.Event;
+import org.onap.nbi.apis.hub.model.EventType;
+import org.onap.nbi.apis.hub.model.ServiceInstanceEvent;
+import org.onap.nbi.apis.hub.repository.SubscriberRepository;
+import org.onap.nbi.apis.serviceorder.model.RelatedParty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+
+@Service
+public class CheckDMaaPEventsManager {
+
+  public static final String RESPONSE_STATUS = "response status : ";
+  public static final String RETURNS = " returns ";
+  public static final String ERROR_ON_CALLING = "error on calling ";
+
+  @Autowired
+  private RestTemplate restTemplate;
+
+  @Autowired
+  private SubscriberRepository subscriberRepository;
+
+  @Autowired
+  private NotifierService notifier;
+
+  @Value("${dmaap.host}")
+  private String dmaapHostname;
+
+  @Value("${dmaap.topic}")
+  private String topic;
+
+  @Value("${dmaap.consumergroup}")
+  private String consumerGroup;
+
+  @Value("${dmaap.consumerid}")
+  private String consumerId;
+
+  @Value("${dmaap.timeout}")
+  private String timeout;
+
+  private final Logger logger = LoggerFactory.getLogger(CheckDMaaPEventsManager.class);
+
+  private String dmaapGetEventsUrl;
+
+  @PostConstruct
+  private void setUpAndLogDMaaPUrl() {
+    dmaapGetEventsUrl = new StringBuilder().append(dmaapHostname)
+        .append(OnapComponentsUrlPaths.DMAAP_CONSUME_EVENTS).toString();
+    logger.info("DMaaP Get Events url :  " + dmaapGetEventsUrl);
+  }
+
+  public void checkForDMaaPAAIEvents() {
+    ObjectMapper mapper = new ObjectMapper();
+
+
+    String dmaapGetEventsUrlFormated = dmaapGetEventsUrl.replace("$topic", topic);
+    dmaapGetEventsUrlFormated = dmaapGetEventsUrlFormated.replace("$consumergroup", consumerGroup);
+    dmaapGetEventsUrlFormated = dmaapGetEventsUrlFormated.replace("$consumerid", consumerId);
+    dmaapGetEventsUrlFormated = dmaapGetEventsUrlFormated.replace("$timeout", timeout);
+
+    List<String> dmaapResponse = callDMaaPGetEvents(dmaapGetEventsUrlFormated);
+    if (!CollectionUtils.isEmpty(dmaapResponse)) {
+      for (int i = 0; i < dmaapResponse.size(); i++) {
+        String aaiEventString = dmaapResponse.get(i);
+        if (logger.isDebugEnabled()) {
+          logger.debug("aai event returned was {}", aaiEventString);
+        }
+        try {
+          JsonNode jsonNode = mapper.readValue(aaiEventString, JsonNode.class);
+          JsonNode eventHeader = jsonNode.get("event-header");
+          String aaiEventEntityType = eventHeader.get("entity-type").asText();
+          String action = eventHeader.get("action").asText();
+          if (logger.isDebugEnabled()) {
+            logger.debug("aaiEventEntityType is {} and action is {}", aaiEventEntityType, action);
+          }
+          if (aaiEventEntityType.equals("service-instance")) {
+            {
+              // parse the AAI-EVENT service-instance tree
+              ServiceInstanceEvent serviceInstanceEvent = new ServiceInstanceEvent();
+              RelatedParty relatedParty = new RelatedParty();
+              JsonNode entity = jsonNode.get("entity");
+              relatedParty.setId(entity.get("global-customer-id").asText());
+              relatedParty.setName(entity.get("subscriber-name").asText());
+              serviceInstanceEvent.setRelatedParty(relatedParty);
+              JsonNode childServiceSubscription = entity.get("service-subscriptions");
+              JsonNode serviceSubscriptions = childServiceSubscription.get("service-subscription");
+              JsonNode serviceSubscription = serviceSubscriptions.get(0);
+              String serviceSubscriptionPrint = serviceSubscription.toString();
+              JsonNode childserviceInstances = serviceSubscription.get("service-instances");
+              JsonNode serviceInstances = childserviceInstances.get("service-instance");
+              JsonNode serviceInstance = serviceInstances.get(0);
+              serviceInstanceEvent.setId(serviceInstance.get("service-instance-id").asText());
+              serviceInstanceEvent.setState(serviceInstance.get("orchestration-status").asText());
+              if (action.equals("CREATE")) {
+                if (logger.isDebugEnabled()) {
+                  logger.debug("sending service inventory event to listeners");
+                }
+                processEvent(
+                    EventFactory.getEvent(EventType.SERVICE_CREATION, serviceInstanceEvent));
+              } else if (action.equals("DELETE")) {
+                processEvent(EventFactory.getEvent(EventType.SERVICE_REMOVE, serviceInstanceEvent));
+              } else if (action.equals("UPDATE")) {
+                processEvent(EventFactory.getEvent(EventType.SERVICE_ATTRIBUTE_VALUE_CHANGE,
+                    serviceInstanceEvent));
+              }
+
+
+            }
+
+          }
+
+        } catch (JsonParseException e) {
+          logger.error(" unable to Parse AAI Event JSON String {}, exception is", aaiEventString,
+              e.getMessage());
+        } catch (JsonMappingException e) {
+          logger.error(" unable to Map AAI Event JSON String {} to Java Pojo, exception is",
+              aaiEventString, e.getMessage());
+        } catch (IOException e) {
+          logger.error("IO Error when parsing AAI Event JSON String {} ", aaiEventString,
+              e.getMessage());
+        }
+      }
+    }
+  }
+
+  public List<String> callDMaaPGetEvents(String dmaapGetEventsUrlFormated) {
+
+    if (logger.isDebugEnabled()) {
+      logger.debug("Calling DMaaP Url : " + dmaapGetEventsUrlFormated);
+    }
+    UriComponentsBuilder callURI = UriComponentsBuilder.fromHttpUrl(dmaapGetEventsUrlFormated);
+    ResponseEntity<Object> response = callDMaaP(callURI.build().encode().toUri());
+    return (List<String>) response.getBody();
+
+  }
+
+  private ResponseEntity<Object> callDMaaP(URI callURI) {
+    ResponseEntity<Object> response =
+        restTemplate.exchange(callURI, HttpMethod.GET, buildRequestHeader(), Object.class);
+
+    if (logger.isDebugEnabled()) {
+      logger.debug("response body : {} ", response.getBody().toString());
+      logger.debug("response status : {}", response.getStatusCodeValue());
+    }
+    return response;
+  }
+
+  private HttpEntity<String> buildRequestHeader() {
+    HttpHeaders httpHeaders = new HttpHeaders();
+    httpHeaders.add("Accept", "application/json");
+    httpHeaders.add("Content-Type", "application/json");
+    return new HttpEntity<>("parameters", httpHeaders);
+  }
+
+  /**
+   * Retrieve subscribers that match an event and fire notification asynchronously
+   * 
+   * @param event
+   */
+  private void processEvent(Event event) {
+    subscriberRepository.findSubscribersUsingEvent(event).forEach(sub -> notifier.run(sub, event));
+  }
+
+}
diff --git a/src/main/java/org/onap/nbi/apis/hub/service/DMaaPEventsScheduler.java b/src/main/java/org/onap/nbi/apis/hub/service/DMaaPEventsScheduler.java
new file mode 100644 (file)
index 0000000..20bc2d9
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2019 Huawei
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.onap.nbi.apis.hub.service;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+@Profile("default")
+@Service
+@EnableScheduling
+public class DMaaPEventsScheduler {
+
+  @Autowired
+  CheckDMaaPEventsManager checkDMaaPEventsManager;
+
+  @Scheduled(fixedDelayString = "${dmaapCheck.schedule}",
+      initialDelayString = "${dmaapCheck.initial}")
+  private void processDMaaPEvents() {
+      checkDMaaPEventsManager.checkForDMaaPAAIEvents();
+    
+  }
+}
+
index e935a1c..ed34322 100644 (file)
@@ -1,75 +1,95 @@
 /**
  * Copyright (c) 2018 Orange
  *
- * 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
+ * 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
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
  */
 package org.onap.nbi.apis.hub.service;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.MappingJsonFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.UUID;
 import org.onap.nbi.apis.hub.model.Event;
 import org.onap.nbi.apis.hub.model.EventType;
+import org.onap.nbi.apis.hub.model.ServiceInstanceEvent;
 import org.onap.nbi.apis.serviceorder.model.ServiceOrder;
 import org.onap.nbi.apis.serviceorder.model.ServiceOrderItem;
 import org.onap.nbi.commons.JacksonFilter;
 import org.onap.nbi.commons.JsonRepresentation;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.MappingJsonFactory;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 
 public class EventFactory {
 
-    private static final ObjectMapper mapper = new ObjectMapper(new MappingJsonFactory());
+  private static final ObjectMapper mapper = new ObjectMapper(new MappingJsonFactory());
 
-    public static Event getEvent(EventType eventType, ServiceOrder serviceOrder, ServiceOrderItem serviceOrderItem) {
-        Event event = new Event();
-        event.setEventId(UUID.randomUUID().toString());
-        event.setEventDate(new Date());
-        event.setEventType(eventType.value());
+  public static Event getEvent(EventType eventType, ServiceOrder serviceOrder,
+      ServiceOrderItem serviceOrderItem) {
+    Event event = new Event();
+    event.setEventId(UUID.randomUUID().toString());
+    event.setEventDate(new Date());
+    event.setEventType(eventType.value());
 
-        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
-        mapper.setDateFormat(df);
+    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+    mapper.setDateFormat(df);
 
-        JsonNode serviceOrderJson = mapper.valueToTree(filterServiceOrder(serviceOrder));
+    JsonNode serviceOrderJson = mapper.valueToTree(filterServiceOrder(serviceOrder));
 
-        if (EventType.SERVICE_ORDER_ITEM_STATE_CHANGE.equals(eventType)) {
-            JsonNode serviceOrderItemJson = mapper.valueToTree(serviceOrderItem);
-            ((ObjectNode) serviceOrderJson).putArray("orderItem").add(serviceOrderItemJson);
-        }
+    if (EventType.SERVICE_ORDER_ITEM_STATE_CHANGE.equals(eventType)) {
+      JsonNode serviceOrderItemJson = mapper.valueToTree(serviceOrderItem);
+      ((ObjectNode) serviceOrderJson).putArray("orderItem").add(serviceOrderItemJson);
+    }
 
-        event.setEvent(serviceOrderJson);
+    event.setEvent(serviceOrderJson);
 
-        return event;
-    }
+    return event;
+  }
+
+  public static Event getEvent(EventType eventType, ServiceInstanceEvent serviceInstanceEvent) {
+    Event event = new Event();
+    event.setEventId(UUID.randomUUID().toString());
+    event.setEventDate(new Date());
+    event.setEventType(eventType.value());
+
+    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+    mapper.setDateFormat(df);
 
+    JsonNode serviceInstanceJson = mapper.valueToTree(serviceInstanceEvent);
 
-    /**
-     * Filter ServiceOrderObject to produce a lightweight object that fit the eventBody specification
-     * @param serviceOrder
-     * @return
-     */
-    private static Object filterServiceOrder(final ServiceOrder serviceOrder) {
+    event.setEvent(serviceInstanceJson);
 
-        Object filteredServiceOrder = null;
+    return event;
+  }
 
-        if (serviceOrder != null) {
-            JsonRepresentation jsonRepresentation = new JsonRepresentation();
-            jsonRepresentation.add("id").add("href").add("externalId").add("state").add("orderDate").add
-                ("completionDateTime").add("orderItem");
 
-            filteredServiceOrder = JacksonFilter.createNode(serviceOrder, jsonRepresentation);
-        }
+  /**
+   * Filter ServiceOrderObject to produce a lightweight object that fit the eventBody specification
+   * 
+   * @param serviceOrder
+   * @return
+   */
+  private static Object filterServiceOrder(final ServiceOrder serviceOrder) {
 
-        return filteredServiceOrder;
+    Object filteredServiceOrder = null;
+
+    if (serviceOrder != null) {
+      JsonRepresentation jsonRepresentation = new JsonRepresentation();
+      jsonRepresentation.add("id").add("href").add("externalId").add("state").add("orderDate")
+          .add("completionDateTime").add("orderItem");
+
+      filteredServiceOrder = JacksonFilter.createNode(serviceOrder, jsonRepresentation);
     }
+
+    return filteredServiceOrder;
+  }
 }
index 90cc7a4..80b6331 100755 (executable)
@@ -1,14 +1,15 @@
 /**
  * Copyright (c) 2018 Orange
  *
- * 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
+ * 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
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
  */
 package org.onap.nbi.apis.hub.service;
 
@@ -26,19 +27,19 @@ import org.springframework.web.client.RestTemplate;
 @Service
 public class NotifierService {
 
-    private final Logger logger = LoggerFactory.getLogger(NotifierService.class);
+  private final Logger logger = LoggerFactory.getLogger(NotifierService.class);
 
-    @Autowired
-    RestTemplate restTemplate;
-
-    @Async
-    public void run(Subscriber subscriber, @Valid Event event) {
-        try {
-            restTemplate.postForEntity(subscriber.getCallback(), event, Object.class);
-        } catch (BackendFunctionalException e) {
-            logger.error(" unable to post event to {} , receive {}, {}", subscriber.getCallback(), e.getHttpStatus(),
-                e.getBodyResponse());
-        }
+  @Autowired
+  RestTemplate restTemplate;
 
+  @Async
+  public void run(Subscriber subscriber, @Valid Event event) {
+    try {
+      restTemplate.postForEntity(subscriber.getCallback(), event, Object.class);
+    } catch (BackendFunctionalException e) {
+      logger.error(" unable to post event to {} , receive {}, {}", subscriber.getCallback(),
+          e.getHttpStatus(), e.getBodyResponse());
     }
+
+  }
 }
diff --git a/src/main/java/org/onap/nbi/configuration/AppContext.java b/src/main/java/org/onap/nbi/configuration/AppContext.java
new file mode 100644 (file)
index 0000000..fb26799
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2019 Huawei
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.onap.nbi.configuration;
+
+import java.util.concurrent.Executor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
+
+@Configuration
+@EnableAsync
+public class AppContext extends WebMvcConfigurationSupport {
+  @Bean
+  public Executor taskExecutor() {
+    return new SimpleAsyncTaskExecutor();
+  }
+}
index b959b47..ca04a05 100644 (file)
@@ -60,6 +60,13 @@ so.owning.entity.id                 = 6b5b6b70-4e9a-4f6f-8b7b-cbd7cf990c6e
 so.owning.entity.name               = OE-generic
 so.project.name                     = Project-generic
 
+# DMAAP
+dmaap.host                           = http://127.0.0.1:8091
+dmaap.topic                          = AAI-EVENT
+dmaap.consumergroup                  = NBICG1
+dmaap.consumerid                     = NBIC1
+dmaap.timeout                        = 2000
+
 # MSB
 msb.enabled                         = false
 
index 633e029..70d640c 100644 (file)
@@ -44,6 +44,8 @@ serviceOrder.schedule                = 5000
 serviceOrder.initial                 = 1
 executionTask.schedule               = 2000
 executionTask.initial                = 1
+dmaapCheck.schedule               = 10000
+dmaapCheck.initial                = 1
 
 # SDC
 sdc.host                             = http://10.0.3.1:8080
@@ -64,6 +66,13 @@ so.owning.entity.id                  = 6b5b6b70-4e9a-4f6f-8b7b-cbd7cf990c6e
 so.owning.entity.name                = OE-generic
 so.project.name                      = Project-generic
 
+# DMAAP
+dmaap.host                           = http://10.0.6.1:3904
+dmaap.topic                          = AAI-EVENT
+dmaap.consumergroup                  = NBICG1
+dmaap.consumerid                     = NBIC1
+dmaap.timeout                        = 2000
+
 # MSB
 msb.enabled                          = true
 msb.discovery.host                   = msb_discovery
index 1b60109..8fb276d 100644 (file)
@@ -1,18 +1,18 @@
 /**
  * Copyright (c) 2019 Orange
  *
- * 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
+ * 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
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
  */
 package org.onap.nbi.api.listener;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -34,81 +34,97 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+import com.fasterxml.jackson.databind.JsonNode;
 
 @RestController
 @RequestMapping("/test/listener")
 public class ListenerResource extends ResourceManagement {
 
-    Logger logger = LoggerFactory.getLogger(ListenerResource.class);
-
-    static Map<String, JsonNode> events = new ConcurrentHashMap<>();
+  Logger logger = LoggerFactory.getLogger(ListenerResource.class);
 
-    /*
-        listener resource test for hub resource
-     */
-    @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<JsonNode> postListener(@RequestBody JsonNode event) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("POST event from nbi : {}", event.toString());
-        }
-        String eventId = event.get("eventId").asText();
-        events.put(eventId, event);
-
-        URI location = ServletUriComponentsBuilder
-            .fromCurrentRequest()
-            .path("/{id}")
-            .buildAndExpand(eventId)
-            .toUri();
+  static Map<String, JsonNode> events = new ConcurrentHashMap<>();
 
-        return ResponseEntity.created(location).body(event);
+  /*
+   * listener resource test for hub resource
+   */
+  @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<JsonNode> postListener(@RequestBody JsonNode event) {
+    if (logger.isDebugEnabled()) {
+      logger.debug("POST event from nbi : {}", event.toString());
     }
-
-
-    @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Collection<JsonNode>> findEvents(@RequestParam MultiValueMap<String, String> params) {
-        Collection<JsonNode> values = new ArrayList<>();
-        String serviceOrderId = params.getFirst("serviceOrderId");
-        if(StringUtils.isNotEmpty(serviceOrderId)) {
-            for (JsonNode jsonNode : events.values()) {
-                String id = jsonNode.get("event").get("id").asText();
-                logger.info("found event with service order id : "+id);
-                if(id.equals(serviceOrderId)) {
-                    values.add(jsonNode);
-                }
-            }
-            if(!values.isEmpty()) {
-                return ResponseEntity.ok(values);
-            } else {
-                logger.error("cannot found events with service order id : "+serviceOrderId);
-                return ResponseEntity.notFound().build();
-            }
-        } else {
-            values=events.values();
+    String eventId = event.get("eventId").asText();
+    logger.info("putting eventId {} in the events map", eventId);
+    events.put(eventId, event);
+
+    URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
+        .buildAndExpand(eventId).toUri();
+
+    return ResponseEntity.created(location).body(event);
+  }
+
+
+  @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<Collection<JsonNode>> findEvents(
+      @RequestParam MultiValueMap<String, String> params) {
+    logger.info("called listener get with params {} : " + params.toString());
+    Collection<JsonNode> values = new ArrayList<>();
+    String serviceOrderId = params.getFirst("serviceOrderId");
+    String serviceInstanceId = params.getFirst("serviceInstanceId");
+    if (StringUtils.isNotEmpty(serviceOrderId)) {
+      for (JsonNode jsonNode : events.values()) {
+        String id = jsonNode.get("event").get("id").asText();
+        logger.info("found event with service order id : " + id);
+        if (id.equals(serviceOrderId)) {
+          values.add(jsonNode);
+        }
+      }
+      if (!values.isEmpty()) {
+        return ResponseEntity.ok(values);
+      } else {
+        logger.error("cannot found events with service order id : " + serviceOrderId);
+        return ResponseEntity.notFound().build();
+      }
+    } else if (StringUtils.isNotEmpty(serviceInstanceId)) {
+      for (JsonNode jsonNode : events.values()) {
+        String id = jsonNode.get("event").get("id").asText();
+        logger.info("found event with service Instance id : " + id);
+        if (id.equals(serviceInstanceId)) {
+          values.add(jsonNode);
         }
+      }
+      if (!values.isEmpty()) {
         return ResponseEntity.ok(values);
+      } else {
+        logger.error("cannot found events with service instance id : " + serviceInstanceId);
+        return ResponseEntity.notFound().build();
+      }
+    } else {
+      values = events.values();
     }
+    return ResponseEntity.ok(values);
+  }
 
-    @GetMapping(value = "/{eventId}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Object> getEvent(@PathVariable String eventId) {
+  @GetMapping(value = "/{eventId}", produces = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<Object> getEvent(@PathVariable String eventId) {
 
-        return ResponseEntity.ok(events.get(eventId));
+    return ResponseEntity.ok(events.get(eventId));
 
-    }
+  }
 
-    @DeleteMapping(value = "/{eventId}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Object> deleteEvent(@PathVariable String eventId) {
+  @DeleteMapping(value = "/{eventId}", produces = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<Object> deleteEvent(@PathVariable String eventId) {
 
-        events.remove(eventId);
-        return ResponseEntity.noContent().build();
+    events.remove(eventId);
+    return ResponseEntity.noContent().build();
 
-    }
+  }
 
-    @DeleteMapping(produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<Object> deleteEvents() {
+  @DeleteMapping(produces = MediaType.APPLICATION_JSON_VALUE)
+  public ResponseEntity<Object> deleteEvents() {
 
-        events.clear();
-        return ResponseEntity.noContent().build();
+    events.clear();
+    return ResponseEntity.noContent().build();
 
-    }
+  }
 
 }
index 6e4b884..e4704ea 100644 (file)
@@ -154,4 +154,98 @@ When method delete
 Then status 204
 Given path 'serviceOrder',serviceOrderId
 When method delete
+Then status 204
+
+
+Scenario: testSubscriberWithTestListenerForServiceInventorCreationEvents
+* def listenerUrl = nbiBaseUrl + "/test/listener"
+Given path 'test/listener'
+When method delete
+Then status 204
+Given path 'hub'
+And request { id : 'id', callback : '#(listenerUrl)' , query : 'eventType = ServiceCreationNotification' }
+When method post
+Then status 201
+Given path 'hub'
+When method get
+And def hubId = $[0].id
+Given path 'hub/testaaievents'
+Then status 200
+When method get
+Given path 'test/listener'
+And params {serviceInstanceId : 'new-test5'}
+And retry until responseStatus == 200
+When method get
+And assert response.length == 1
+And match $[0] contains { eventId : '#notnull' , eventType : 'ServiceCreationNotification' , eventDate : '#notnull' , event :'#notnull'}
+And def eventId = $[0].eventId
+And def eventDate = $[0].eventDate
+And call checkDateFormat(eventDate)
+Given path 'hub',hubId
+When method delete
+Then status 204
+Given path 'test/listener',eventId
+When method delete
+Then status 204
+
+Scenario: testSubscriberWithTestListenerForServiceInventoryUpdateEvents
+* def listenerUrl = nbiBaseUrl + "/test/listener"
+Given path 'test/listener'
+When method delete
+Then status 204
+Given path 'hub'
+And request { id : 'id', callback : '#(listenerUrl)' , query : 'eventType = ServiceAttributeValueChangeNotification' }
+When method post
+Then status 201
+Given path 'hub'
+When method get
+And def hubId = $[0].id
+Given path 'hub/testaaievents'
+Then status 200
+When method get
+Given path 'test/listener'
+And params {serviceInstanceId : 'new-test5'}
+And retry until responseStatus == 200
+When method get
+And assert response.length == 1
+And match $[0] contains { eventId : '#notnull' , eventType : 'ServiceAttributeValueChangeNotification' , eventDate : '#notnull' , event :'#notnull'}
+And def eventId = $[0].eventId
+And def eventDate = $[0].eventDate
+And call checkDateFormat(eventDate)
+Given path 'hub',hubId
+When method delete
+Then status 204
+Given path 'test/listener',eventId
+When method delete
+Then status 204
+
+Scenario: testSubscriberWithTestListenerForServiceInventoryRemoveEvents
+* def listenerUrl = nbiBaseUrl + "/test/listener"
+Given path 'test/listener'
+When method delete
+Then status 204
+Given path 'hub'
+And request { id : 'id', callback : '#(listenerUrl)' , query : 'eventType = ServiceRemoveNotification' }
+When method post
+Then status 201
+Given path 'hub'
+When method get
+And def hubId = $[0].id
+Given path 'hub/testaaievents'
+Then status 200
+When method get
+Given path 'test/listener'
+And params {serviceInstanceId : 'new-test5'}
+And retry until responseStatus == 200
+When method get
+And assert response.length == 1
+And match $[0] contains { eventId : '#notnull' , eventType : 'ServiceRemoveNotification' , eventDate : '#notnull' , event :'#notnull'}
+And def eventId = $[0].eventId
+And def eventDate = $[0].eventDate
+And call checkDateFormat(eventDate)
+Given path 'hub',hubId
+When method delete
+Then status 204
+Given path 'test/listener',eventId
+When method delete
 Then status 204
\ No newline at end of file
diff --git a/src/test/resources/mappings/dmaap_get_aaievents.json b/src/test/resources/mappings/dmaap_get_aaievents.json
new file mode 100644 (file)
index 0000000..6b5c630
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "request": {
+    "method": "GET",
+    "url": "/events/AAI-EVENT/NBICG1/NBIC1?timeout=2000"
+  },
+  "response": {
+    "status": 200,
+    "jsonBody": [
+    "{\"cambria.partition\":\"AAI\",\"event-header\":{\"severity\":\"NORMAL\",\"entity-type\":\"service-instance\",\"top-entity-type\":\"customer\",\"entity-link\":\"/aai/v14/business/customers/customer/testcustomer2/service-subscriptions/service-subscription/HSIA_Service/service-instances/service-instance/new-test5\",\"event-type\":\"AAI-EVENT\",\"domain\":\"dev\",\"action\":\"CREATE\",\"sequence-number\":\"0\",\"id\":\"c3654954-9802-4b46-a397-6e12c74d2254\",\"source-name\":\"AAI\",\"version\":\"v14\",\"timestamp\":\"20190301-10:20:47:154\"},\"entity\":{\"global-customer-id\":\"testcustomer2\",\"subscriber-name\":\"testcustomer2\",\"service-subscriptions\":{\"service-subscription\":[{\"service-type\":\"HSIA_Service\",\"service-instances\":{\"service-instance\":[{\"service-instance-id\":\"new-test5\",\"resource-version\":\"1551435647134\",\"service-instance-name\":\"testname\",\"orchestration-status\":\"assigned\"}]}}]}}}",
+    "{\"cambria.partition\":\"AAI\",\"event-header\":{\"severity\":\"NORMAL\",\"entity-type\":\"service-instance\",\"top-entity-type\":\"customer\",\"entity-link\":\"/aai/v14/business/customers/customer/testcustomer2/service-subscriptions/service-subscription/HSIA_Service/service-instances/service-instance/new-test5\",\"event-type\":\"AAI-EVENT\",\"domain\":\"dev\",\"action\":\"UPDATE\",\"sequence-number\":\"0\",\"id\":\"a746584a-72b7-4994-97b2-bc43ec24fd35\",\"source-name\":\"AAI\",\"version\":\"v14\",\"timestamp\":\"20190301-13:50:34:121\"},\"entity\":{\"global-customer-id\":\"testcustomer2\",\"subscriber-name\":\"testcustomer2\",\"service-subscriptions\":{\"service-subscription\":[{\"service-type\":\"HSIA_Service\",\"service-instances\":{\"service-instance\":[{\"service-instance-id\":\"new-test5\",\"resource-version\":\"1551448234103\",\"service-instance-name\":\"testname\",\"orchestration-status\":\"active\"}]}}]}}}","{\"cambria.partition\":\"AAI\",\"event-header\":{\"severity\":\"NORMAL\",\"entity-type\":\"service-instance\",\"top-entity-type\":\"customer\",\"entity-link\":\"/aai/v14/business/customers/customer/testcustomer2/service-subscriptions/service-subscription/HSIA_Service/service-instances/service-instance/new-test5\",\"event-type\":\"AAI-EVENT\",\"domain\":\"dev\",\"action\":\"DELETE\",\"sequence-number\":\"0\",\"id\":\"011c139e-d00f-4a55-b1fc-b319f16e0f70\",\"source-name\":\"AAI\",\"version\":\"v14\",\"timestamp\":\"20190301-13:53:09:590\"},\"entity\":{\"global-customer-id\":\"testcustomer2\",\"subscriber-name\":\"testcustomer2\",\"service-subscriptions\":{\"service-subscription\":[{\"service-type\":\"HSIA_Service\",\"service-instances\":{\"service-instance\":[{\"service-instance-id\":\"new-test5\",\"resource-version\":\"1551448234103\",\"service-instance-name\":\"testname\",\"orchestration-status\":\"active\"}]}}]}}}"
+    ],
+    "headers": {
+      "Content-Type": "application/json"
+    }
+  }
+}