diff options
author | 2018-08-06 17:02:39 +0300 | |
---|---|---|
committer | 2018-08-06 17:02:39 +0300 | |
commit | 86457ed120fc236b1485ad3251589aedad2401bd (patch) | |
tree | a473c2faf16ffbb34aad75d4fef8afc3b2541f21 /dcaedt_be | |
parent | 735b58119b37ead5013c40afd941d63ef28ca053 (diff) |
Changing the dcae dt main code
Updating DCAE-dt-main code for Dockerizing the DCAE-CI code
Change-Id: Ia50d24e60e9ddc9bbc58dd8651d7a4f7e0dc8270
Issue-ID: SDC-1605
Signed-off-by: Eran (ev672n), Vosk <ev672n@att.com>
Diffstat (limited to 'dcaedt_be')
57 files changed, 1532 insertions, 657 deletions
diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java index ee8f5c6..f6f2cd0 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java @@ -53,7 +53,9 @@ public class CompositionConfig { public static class FlowType { + @JsonProperty("entryPhase") private String entryPointPhaseName; + @JsonProperty("publishPhase") private String lastPhaseName; public String getEntryPointPhaseName() { @@ -81,7 +83,7 @@ public class CompositionConfig { Type map = new TypeToken<Map<String, FlowType>>(){}.getType(); flowTypesMap = new Gson().fromJson(flowTypes, map); } catch (Exception e) { - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error – Failed to read flow type definitions"); + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error – Failed to read flow type definitions. message: {}", e); } } }
\ No newline at end of file diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java index 0d638d9..5d5c1e0 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java @@ -25,7 +25,7 @@ public class BlueprintController extends BaseController { * @param requestId * @return ResponseEntity */ - @RequestMapping(value = "{context}/createBluePrint/{VFCMTUuid}/{serviceUuid}/{instanceName}", method = RequestMethod.POST) + @RequestMapping(value = "{context}/createBluePrint/{VFCMTUuid}/{serviceUuid}/{instanceName:.*}", method = RequestMethod.POST) public ResponseEntity createBlueprint( @RequestHeader("USER_ID") String userId, @PathVariable String context, @@ -37,7 +37,7 @@ public class BlueprintController extends BaseController { } @Deprecated - @RequestMapping(value = "/createBluePrint/{VFCMTUuid}/{serviceUuid}/{instanceName}/{monitoringFlowType}", method = RequestMethod.POST) + @RequestMapping(value = "/createBluePrint/{VFCMTUuid}/{serviceUuid}/{instanceName}/{monitoringFlowType:.*}", method = RequestMethod.POST) public ResponseEntity createBluePrintWithFlowType( @RequestHeader("USER_ID") String userId, @PathVariable("VFCMTUuid") String vfcmtUuid, diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java index dbcbcc9..aad0250 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java @@ -11,24 +11,15 @@ import org.onap.sdc.dcae.composition.restmodels.ReferenceUUID; import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; import org.onap.sdc.dcae.composition.util.DcaeBeConstants; -import org.onap.sdc.dcae.enums.LifecycleOperationType; -import org.onap.sdc.dcae.errormng.ActionStatus; -import org.onap.sdc.dcae.errormng.ErrConfMgr; import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - @RestController @EnableAutoConfiguration @CrossOrigin @@ -40,78 +31,77 @@ public class CompositionController extends BaseController { @Autowired private CompositionBusinessLogic compositionBusinessLogic; - @Deprecated - @RequestMapping(value = { "/utils/clone/{assetType}/{sourceId}/{targetId}" }, method = { RequestMethod.GET }, produces = { "application/json" }) - public ResponseEntity clone(@RequestHeader("USER_ID") String userId, - @PathVariable("assetType") String theAssetType, @PathVariable("sourceId") String theSourceId, @PathVariable("targetId") String theTargetId, @ModelAttribute("requestId") String requestId) { - MessageResponse response = new MessageResponse(); - - try { - // fetch the source and assert it is a vfcmt containing clone worthy artifacts (composition + rules) - ResourceDetailed sourceVfcmt = baseBusinessLogic.getSdcRestClient().getResource(theSourceId, requestId); - baseBusinessLogic.checkVfcmtType(sourceVfcmt); - List<Artifact> artifactsToClone = CollectionUtils.isEmpty(sourceVfcmt.getArtifacts()) ? - null : - sourceVfcmt.getArtifacts().stream().filter(p -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(p.getArtifactName()) || p.getArtifactName().endsWith(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX)) - .collect(Collectors.toList()); - if (CollectionUtils.isEmpty(artifactsToClone)) { - response.setSuccessResponse("Nothing to clone"); - return new ResponseEntity<>(response, HttpStatus.NO_CONTENT); - } - - // fetch the target - ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(theTargetId, requestId); - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); - baseBusinessLogic.checkVfcmtType(vfcmt); - baseBusinessLogic.checkUserIfResourceCheckedOut(userId, vfcmt); - boolean isTargetNeed2Checkout = baseBusinessLogic.isNeedToCheckOut(vfcmt.getLifecycleState()); - if (isTargetNeed2Checkout) { - ResourceDetailed targetVfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT before clone", requestId); - if (null == targetVfcmt) { - return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERAL_ERROR); - } - theTargetId = targetVfcmt.getUuid(); - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New targetVfcmt (for artifact clone) after checkoutVfcmt is: {}", theTargetId); - } - - Map<String, Artifact> currentArtifacts = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? new HashMap<>() : vfcmt.getArtifacts().stream().collect(Collectors.toMap(Artifact::getArtifactName, Function.identity())); - - //TODO target VFCMT rule artifacts should be removed - for (Artifact artifactToClone : artifactsToClone) { - String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(theSourceId, artifactToClone.getArtifactUUID(), requestId); - baseBusinessLogic.cloneArtifactToTarget(userId, theTargetId, payload, artifactToClone, currentArtifacts.get(artifactToClone.getArtifactName()), requestId); - } - - baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKIN.name(), "check in VFCMT after clone", requestId); - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Cloning {} from {} has finished successfully", theSourceId, theTargetId); - response.setSuccessResponse("Clone VFCMT complete"); - return new ResponseEntity<>(response, HttpStatus.OK); - } catch (Exception e) { - return handleException(e, ApiType.CLONE_VFCMT); - } - } - - @RequestMapping(value = "/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") - public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest) { - return compositionCatalogBusinessLogic.getItems(theRequest); +// @Deprecated +// @RequestMapping(value = { "/utils/clone/{assetType}/{sourceId}/{targetId}" }, method = { RequestMethod.GET }, produces = { "application/json" }) +// public ResponseEntity clone(@RequestHeader("USER_ID") String userId, +// @PathVariable("assetType") String theAssetType, @PathVariable("sourceId") String theSourceId, @PathVariable("targetId") String theTargetId, @ModelAttribute("requestId") String requestId) { +// MessageResponse response = new MessageResponse(); +// +// try { +// // fetch the source and assert it is a vfcmt containing clone worthy artifacts (composition + rules) +// ResourceDetailed sourceVfcmt = baseBusinessLogic.getSdcRestClient().getResource(theSourceId, requestId); +// baseBusinessLogic.checkVfcmtType(sourceVfcmt); +// List<Artifact> artifactsToClone = CollectionUtils.isEmpty(sourceVfcmt.getArtifacts()) ? +// null : +// sourceVfcmt.getArtifacts().stream().filter(p -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(p.getArtifactName()) || p.getArtifactName().endsWith(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX)) +// .collect(Collectors.toList()); +// if (CollectionUtils.isEmpty(artifactsToClone)) { +// response.setSuccessResponse("Nothing to clone"); +// return new ResponseEntity<>(response, HttpStatus.NO_CONTENT); +// } +// +// // fetch the target +// ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(theTargetId, requestId); +// debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); +// baseBusinessLogic.checkVfcmtType(vfcmt); +// baseBusinessLogic.checkUserIfResourceCheckedOut(userId, vfcmt); +// boolean isTargetNeed2Checkout = baseBusinessLogic.isNeedToCheckOut(vfcmt.getLifecycleState()); +// if (isTargetNeed2Checkout) { +// ResourceDetailed targetVfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT before clone", requestId); +// if (null == targetVfcmt) { +// return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERAL_ERROR); +// } +// theTargetId = targetVfcmt.getUuid(); +// debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New targetVfcmt (for artifact clone) after checkoutVfcmt is: {}", theTargetId); +// } +// +// Map<String, Artifact> currentArtifacts = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? new HashMap<>() : vfcmt.getArtifacts().stream().collect(Collectors.toMap(Artifact::getArtifactName, Function.identity())); +// +// //TODO target VFCMT rule artifacts should be removed +// for (Artifact artifactToClone : artifactsToClone) { +// String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(theSourceId, artifactToClone.getArtifactUUID(), requestId); +// baseBusinessLogic.cloneArtifactToTarget(userId, theTargetId, payload, artifactToClone, currentArtifacts.get(artifactToClone.getArtifactName()), requestId); +// } +// +// baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKIN.name(), "check in VFCMT after clone", requestId); +// debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Cloning {} from {} has finished successfully", theSourceId, theTargetId); +// response.setSuccessResponse("Clone VFCMT complete"); +// return new ResponseEntity<>(response, HttpStatus.OK); +// } catch (Exception e) { +// return handleException(e, ApiType.CLONE_VFCMT); +// } +// } + + @RequestMapping(value = "/{theItemId}/model", method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity model(@ModelAttribute("requestId") String requestId, @PathVariable String theItemId) { + return compositionCatalogBusinessLogic.getModelById(requestId, theItemId); } - @RequestMapping(value = "/{theItemId}/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") - public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest, @PathVariable String theItemId) { - return compositionCatalogBusinessLogic.getItemById(theRequest, theItemId); + @RequestMapping(value = "/{theItemId}/type/{theTypeName:.*}", method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity typeInfo(@ModelAttribute("requestId") String requestId, @PathVariable String theItemId, @PathVariable String theTypeName) { + return compositionCatalogBusinessLogic.getTypeInfo(theItemId, theTypeName); } - @RequestMapping(value = "/{theItemId}/model", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") - public DeferredResult model(@RequestBody(required = false) ElementRequest theRequest, @PathVariable String theItemId) { - return compositionCatalogBusinessLogic.getModelById(theRequest, theItemId); - } - - @RequestMapping(value = "/{theItemId}/type/{theTypeName}", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") - public DeferredResult<CatalogResponse> model(@RequestBody(required = false) ElementRequest theRequest, @PathVariable String theItemId, @PathVariable String theTypeName) { - return compositionCatalogBusinessLogic.getTypeInfo(theRequest, theItemId, theTypeName); + @RequestMapping(value = "/catalog", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getCatalog(@ModelAttribute("requestId") String requestId) { + try { + return new ResponseEntity<>(compositionCatalogBusinessLogic.getCatalog(requestId), HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_MODEL); + } } - @RequestMapping(value = { "/getComposition/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = { "application/json" }) + @RequestMapping(value = { "/getComposition/{vfcmtUuid}" }, method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity getComposition(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) { MessageResponse response = new MessageResponse(); try { @@ -131,7 +121,7 @@ public class CompositionController extends BaseController { } - @RequestMapping(value = { "/getMC/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + @RequestMapping(value = { "/getMC/{vfcmtUuid}" }, method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity getMC(@PathVariable String vfcmtUuid, @ModelAttribute String requestId) { try { return new ResponseEntity<>(compositionBusinessLogic.getDataAndComposition(vfcmtUuid, requestId), HttpStatus.OK); diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java index 65663f6..ffedde8 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java @@ -13,10 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; @@ -59,5 +56,21 @@ public class ConfigurationController extends BaseController { } } + @RequestMapping(value = "/getPhases/{flowType}", method = RequestMethod.GET) + public ResponseEntity getPhasesByFlowType(@PathVariable String flowType) { + try { + CompositionConfig.FlowType phases = compositionConfig.getFlowTypesMap().get(flowType); + if(null == phases) { + phases = new CompositionConfig.FlowType(); + phases.setEntryPointPhaseName(""); + phases.setLastPhaseName(""); + } + return new ResponseEntity<>(phases, HttpStatus.OK); + } catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Exception:{}",e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.FLOW_TYPES_CONFIGURATION_ERROR); + } + } + } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java index d7ddd6f..1e93cf5 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java @@ -2,8 +2,10 @@ package org.onap.sdc.dcae.composition.controller; import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.dcae.composition.impl.RuleEditorBusinessLogic; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.TranslateRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -76,10 +78,35 @@ public class RuleEditorController extends BaseController { @PathVariable("configParam") String configParam, @ModelAttribute("requestId") String requestId) { - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting getRules", vfcmtUuid); - return ruleEditorBusinessLogic.getRules(vfcmtUuid, dcaeCompLabel, nid, configParam, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting getRulesAndSchema", vfcmtUuid); + return ruleEditorBusinessLogic.getRulesAndSchema(vfcmtUuid, dcaeCompLabel, nid, configParam, requestId); } + @RequestMapping(value = "/export/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam:.*}", method = {RequestMethod.GET}, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public ResponseEntity downloadRules( + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam, + @ModelAttribute("requestId") String requestId) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting exportRules", vfcmtUuid); + return ruleEditorBusinessLogic.downloadRules(vfcmtUuid, dcaeCompLabel, nid, configParam, requestId); + } + + @RequestMapping(value = "/import/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam:.*}", method = {RequestMethod.POST}, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity importRules( + @RequestBody String json, @ModelAttribute("requestId") String requestId, + @RequestHeader("USER_ID") String userId, + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting importRules", json); + return ruleEditorBusinessLogic.importRules(json, requestId, userId, vfcmtUuid, dcaeCompLabel, nid, configParam); + } + /** * This endpoint functions as a 'delete' service for the rule editor UI * @@ -104,30 +131,54 @@ public class RuleEditorController extends BaseController { return ruleEditorBusinessLogic.deleteRule(userId, vfcmtUuid, dcaeCompLabel, nid, configParam, ruleUid, requestId); } + + /** + * This endpoint functions as a 'delete' service for the rule editor UI + * + * @param vfcmtUuid - VFCMT that the rule editor ui is saved in + * @param dcaeCompLabel - the name of the DCAE Component which the group is applied to + * @param nid - A unique id of the DCAE Component which the group is applied to - exists also in the cdump + * @param configParam - the name of the DCAE Component configuration property the rules are linked to + * @param groupId - the unique id of the group to delete + * @return operation result + */ + @RequestMapping(value = "/group/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}/{groupId}", method = {RequestMethod.DELETE}, produces = "application/json") + public ResponseEntity deleteGroup( + @RequestHeader("USER_ID") String userId, + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam, + @PathVariable("groupId") String groupId, + @ModelAttribute("requestId") String requestId) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting deleteRule", vfcmtUuid); + return ruleEditorBusinessLogic.deleteGroupOfRules(userId, vfcmtUuid, dcaeCompLabel, nid, configParam, groupId, requestId); + } + /** * This endpoint functions as a 'translate' service for the rule editor UI * - * @param vfcmtUuid - VFCMT that the rule editor ui is saved in - * @param dcaeCompLabel - the name of the DCAE Component which the rule is applied to - * @param nid - A unique id of the DCAE Component which the rule is applied to - exists also in the cdump - * @param configParam - the name of the DCAE Component configuration property the rule is linked to - * @param flowType - the mapping rules flow type (SNMP,Syslog,FOI) + * @param body (vfcmtUuid) - VFCMT that the rule editor ui is saved in + * @param body (dcaeCompLabel) - the name of the DCAE Component which the rule is applied to + * @param body (nid) - A unique id of the DCAE Component which the rule is applied to - exists also in the cdump + * @param body (configParam) - the name of the DCAE Component configuration property the rule is linked to + * @param body (entryPhase) - the global entry phase name + * @param body (publishPhase) - the global publish phase name * @return translateJson representing the translated Rules * Validations: * 1. That the user is able to edit the VFCMT * 2. That the cdump holds a dcae component with such nid (to avoid orphan rules) * 3. Check that the fetched VFCMT is actually a VFCMT and not a regular VF */ - @RequestMapping(value = "/rule/translate/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam:.*}", method = {RequestMethod.GET}, produces = "application/json") - public ResponseEntity translateRules(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId, - @PathVariable("dcaeCompLabel") String dcaeCompLabel, - @PathVariable("nid") String nid, - @PathVariable("configParam") String configParam, - @RequestParam("flowType") String flowType) { - - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting translateRules", vfcmtUuid); - return ruleEditorBusinessLogic.translateRules(vfcmtUuid, requestId, dcaeCompLabel, nid, configParam, flowType); - } + + @RequestMapping(value = "/rule/translate", method = {RequestMethod.POST}, produces = "application/json") + public ResponseEntity translateRules(@RequestBody String body, @ModelAttribute("requestId") String requestId) + { + TranslateRequest request = gson.fromJson(body, TranslateRequest.class); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting translateRules"); + return ruleEditorBusinessLogic.translateRules(request, requestId); + } @RequestMapping(value = "/getExistingRuleTargets/{vfcmtUuid}/{dcaeCompLabel}/{nid:.*}", method = {RequestMethod.GET}, produces = "application/json") diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java index 4fbce49..725bd85 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java @@ -178,4 +178,9 @@ public class VfcmtController extends BaseController{ } } + @RequestMapping(value = { "/{contextType}/{serviceUuid}/{vfiName}/{vfcmtUuid}/getLatestMcUuid" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getLatestMcUuid(@RequestHeader("USER_ID") String userId, @PathVariable String contextType, @PathVariable String serviceUuid, @PathVariable String vfiName, @PathVariable String vfcmtUuid, @ModelAttribute String requestId) { + return referenceBusinessLogic.checkoutAndBindToServiceIfCertified(userId, contextType, serviceUuid, vfiName, vfcmtUuid, requestId); + } + } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java index 6779257..6b0ec93 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java @@ -25,7 +25,13 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.util.Base64Utils; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; @Component public class BaseBusinessLogic { @@ -130,7 +136,7 @@ public class BaseBusinessLogic { } - public void checkUserIfResourceCheckedOut(String userId, Asset asset) { + void checkUserIfResourceCheckedOut(String userId, Asset asset) { if (DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT == DcaeBeConstants.LifecycleStateEnum.findState(asset.getLifecycleState())) { String lastUpdaterUserId = asset.getLastUpdaterUserId(); if (lastUpdaterUserId != null && !lastUpdaterUserId.equals(userId)) { @@ -141,11 +147,11 @@ public class BaseBusinessLogic { } } - public boolean isNeedToCheckOut(String lifecycleState) { + boolean isNeedToCheckOut(String lifecycleState) { return DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT != DcaeBeConstants.LifecycleStateEnum.findState(lifecycleState); } - public void checkVfcmtType(ResourceDetailed vfcmt) { + void checkVfcmtType(ResourceDetailed vfcmt) { if (AssetType.VFCMT != getValidAssetTypeOrNull(vfcmt.getResourceType()) || !"Template".equals(vfcmt.getCategory())) { ResponseFormat responseFormat = ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.RESOURCE_NOT_VFCMT_ERROR, null, vfcmt.getUuid()); throw new DcaeException(HttpStatus.BAD_REQUEST, responseFormat.getRequestError()); @@ -161,4 +167,15 @@ public class BaseBusinessLogic { } } + + byte[] extractFile(ZipInputStream zis) throws IOException { + byte[] buffer = new byte[1024]; + try (ByteArrayOutputStream os = new ByteArrayOutputStream()){ + int len; + while ((len = zis.read(buffer)) > 0) { + os.write(buffer, 0, len); + } + return os.toByteArray(); + } + } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BlueprintBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BlueprintBusinessLogic.java index 7a6f9a7..fba8245 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BlueprintBusinessLogic.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BlueprintBusinessLogic.java @@ -1,42 +1,42 @@ package org.onap.sdc.dcae.composition.impl; +import com.google.gson.Gson; import org.apache.commons.lang.StringUtils; import org.onap.sdc.common.onaplog.Enums.LogLevel; -import org.onap.sdc.dcae.catalog.asdc.ASDC; -import org.onap.sdc.dcae.catalog.asdc.ASDCUtils; -import org.onap.sdc.dcae.catalog.asdc.Blueprinter; +import org.onap.sdc.dcae.catalog.commons.Recycler; import org.onap.sdc.dcae.composition.restmodels.MessageResponse; import org.onap.sdc.dcae.composition.restmodels.VfcmtData; import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; -import org.onap.sdc.dcae.composition.util.DcaeBeConstants; import org.onap.sdc.dcae.errormng.ActionStatus; import org.onap.sdc.dcae.errormng.ErrConfMgr; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.http.HttpEntity; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; +import org.springframework.web.client.RestTemplate; +import org.yaml.snakeyaml.Yaml; -import javax.annotation.PostConstruct; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.StringReader; -import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; @Component +@ConfigurationProperties(prefix="blueprinter") public class BlueprintBusinessLogic extends CompositionBusinessLogic { - @Autowired - private Blueprinter blueprinter; - @Autowired - private ASDC asdc; - - - @PostConstruct - public void init() { - URI sdcUri = URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.URI)); - asdc.setUri(sdcUri); - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "SDC uri: {}", sdcUri); - } + private String uri; + public void setUri(String uri) { + this.uri = uri; + } public ResponseEntity generateAndSaveBlueprint(String userId, String context, String vfcmtUuid, String serviceUuid, String vfiName, String flowType, String requestId) { try { @@ -50,7 +50,13 @@ public class BlueprintBusinessLogic extends CompositionBusinessLogic { debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Found the cdump (composition.yml) on top of VFCMT {}", vfcmtUuid); String cdump = cdumpArtifactData.getPayloadData(); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to use python procedure to create a blueprint...."); - String resultBlueprintCreation = generateBlueprintViaToscaLab(cdump); + + String input = prepareInput(cdump, requestId); + if (null == input) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SUBMIT_BLUEPRINT_ERROR); + } + String resultBlueprintCreation = new RestTemplate().postForObject(uri, new HttpEntity<>(input), String.class); + if (StringUtils.isEmpty(resultBlueprintCreation)) { errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occurred during blueprint generation"); return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERATE_BLUEPRINT_ERROR, "", vfcmt.getName()); @@ -80,17 +86,65 @@ public class BlueprintBusinessLogic extends CompositionBusinessLogic { } } - private String generateBlueprintViaToscaLab(String cdump) { - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "---------------------------------------------------------------CDUMP: -----------------------------------------------------------------------------"); - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), cdump); - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "---------------------------------------------------------------------------------------------------------------------------------------------------"); - ASDCUtils utils = new ASDCUtils(asdc, blueprinter); - String resultBlueprintCreation = null; - try{ - resultBlueprintCreation = utils.buildBlueprintViaToscaLab(new StringReader(cdump)).waitForResult().waitForResult(); - }catch (Exception e){ - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Generate blueprint via tosca lab error: {}", e); - } - return resultBlueprintCreation; - } + private String prepareInput(String cdump, String requestId) throws IOException { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "fetched cdump payload: {}", cdump); + Map cdumpToTosca = new Recycler().recycle(new StringReader(cdump)); + Set<String> dcaeComponentsUuids = extractComponentUuids(cdumpToTosca); + List<Map> extractedModels = Collections.synchronizedSet(dcaeComponentsUuids).parallelStream().map(id -> fetchAndExtractModel(id, requestId)).filter(Objects::nonNull).collect(Collectors.toList()); + // aggregation of parallel stream fetch results - exceptions are swallowed and we check the final size to verify no errors occurred + if(dcaeComponentsUuids.size() != extractedModels.size()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "error: {} distinct DCAE components were mapped to {} tosca lab input models.", dcaeComponentsUuids.size(), extractedModels.size()); + return null; + } + return new Gson().toJson(new ToscaLabInput(Base64Utils.encodeToString(new Yaml().dump(cdumpToTosca).getBytes()), extractedModels)); + } + + private Set<String> extractComponentUuids(Map cdump) { + //the node description contains the UUID of the resource declaring it + //if the description is the URI the resource uuid is the 5th path element (backward compatibility) + // TODO there has to be a better way + Map<String, Map<String, Object>> nodes = (Map<String, Map<String, Object>>)((Map<String, Object>)cdump.get("topology_template")).get("node_templates"); + return nodes.values().stream() + .map(n -> (String)n.get("description")) + .filter(StringUtils::isNotBlank) + .map(d -> StringUtils.substringBetween(d, "resources/", "/")) + .collect(Collectors.toSet()); + } + + + private class ToscaLabInput { + private String template; + private List<Map> models; + + ToscaLabInput(String template, List<Map> models){ + this.template = template; + this.models = models; + } + } + + private Map<String, String> fetchAndExtractModel(String uuid, String requestId) { + try { + return extractModelFromCsar(sdcRestClient.getResourceToscaModel(uuid, requestId)); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "model extraction error: {}", e); + return null; + } + } + + private Map<String, String> extractModelFromCsar(byte[] csar) throws IOException { + //we are only interested in unzipping the 3 files under Artifacts/Deployment/DCAE_TOSCA/ + String dcaeToscaDir = "Artifacts/Deployment/DCAE_TOSCA/"; + Map<String, String> extracted = new HashMap<>(); + try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(csar))) { + ZipEntry ze = zis.getNextEntry(); + while (ze != null && 3 != extracted.size()) { + if(ze.getName().startsWith(dcaeToscaDir)) { + extracted.put(ze.getName().replace(dcaeToscaDir,"").split("\\.")[0], Base64Utils.encodeToString(extractFile(zis))); + } + ze = zis.getNextEntry(); + } + return extracted; + } + } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogic.java index ff596b5..d970778 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogic.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogic.java @@ -1,205 +1,119 @@ package org.onap.sdc.dcae.composition.impl; -import org.json.JSONArray; -import org.json.JSONException; import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.common.onaplog.OnapLoggerError; import org.onap.sdc.dcae.catalog.Catalog; -import org.onap.sdc.dcae.catalog.engine.*; +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.engine.CatalogController; +import org.onap.sdc.dcae.catalog.engine.CatalogResponse; +import org.onap.sdc.dcae.catalog.engine.ElementRequest; +import org.onap.sdc.dcae.composition.restmodels.canvas.DcaeComponentCatalog; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.Resource; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import org.springframework.web.context.request.async.DeferredResult; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; @Component -public class CompositionCatalogBusinessLogic { +public class CompositionCatalogBusinessLogic extends BaseBusinessLogic { @Autowired private CatalogController catalogController; protected OnapLoggerError errLogger = OnapLoggerError.getInstance(); - public DeferredResult<CatalogResponse> getItems(ItemsRequest theRequest) { - - final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; - - Catalog catalog = catalogController.getCatalog(request.getCatalog()); - DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout()); + public ResponseEntity getModelById(String requestId, String theItemId) { - catalog.rootsByLabel(request.getStartingLabel()).setHandler(catalogController.new CatalogHandler<Catalog.Folders>(request, result) { - public CatalogResponse handleData(Catalog.Folders theFolders) { - JSONArray ja = new JSONArray(); - if (theFolders != null) { - for (Catalog.Folder folder : theFolders) { - ja.put(catalogController.patchData(catalog, folder.data())); - } - } - CatalogResponse response = new CatalogResponse(this.request); - try { - response.data().put("elements", ja); - } catch (JSONException e) { - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting json elements to response {}", e); - } - return response; + try { + ResourceDetailed resourceDetailed = fetchAndExtractTemplateAndSchema(theItemId, requestId); + Future<Catalog.Template> modelFuture = catalogController.getCatalog().template(resourceDetailed).withInputs().withOutputs().withNodes().withNodeProperties().withNodePropertiesAssignments().withNodeRequirements().withNodeCapabilities().withNodeCapabilityProperties() + .withNodeCapabilityPropertyAssignments().withPolicies().withPolicyProperties().withPolicyPropertiesAssignments().execute(); + if(modelFuture.succeeded()) { + CatalogResponse response = new CatalogResponse(ElementRequest.EMPTY_REQUEST); + response.data().put("model", modelFuture.result().data()); + return ResponseEntity.ok().body(response); } - }); - return result; - } + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERAL_ERROR, modelFuture.cause().getMessage()); - public DeferredResult<CatalogResponse> getItemById(ItemsRequest theRequest, String theItemId) { - - final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; - - Catalog catalog = catalogController.getCatalog(request.getCatalog()); - DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout()); - - catalog.folder(theItemId).withParts().withPartAnnotations().withItems().withItemAnnotations().withItemModels().execute().setHandler(new FolderHandler(catalog, request, result)); - return result; + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error fetching catalog model with id {}. Message: {}", theItemId, e); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.GET_MODEL, theItemId); + } } - public DeferredResult getModelById(ElementRequest theRequest, String theItemId) { - final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest; - - Catalog catalog = catalogController.getCatalog(request.getCatalog()); - DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout()); -// try { - catalog.item(theItemId).withModels().execute().setHandler(new ItemHandler(catalog, request, result)); -// } catch (IllegalArgumentException e) { -// errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error fetching catalog model with id {}. Message: {}", theItemId, e); -// result.setErrorResult(new CatalogError(request, "Catalog API failed", e)); -// } - return result; - } + public ResponseEntity getTypeInfo(String theItemId, String theTypeName) { - public DeferredResult<CatalogResponse> getTypeInfo(ElementRequest theRequest, String theItemId, String theTypeName) { - final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest; - - Catalog catalog = catalogController.getCatalog(request.getCatalog()); - DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout()); - - catalog.type(theItemId, theTypeName).withHierarchy().withCapabilities().withRequirements().execute().setHandler(catalogController.new CatalogHandler<Catalog.Type>(request, result) { - public CatalogResponse handleData(Catalog.Type theType) { - CatalogResponse response = new CatalogResponse(this.request); - if (theType != null) { - try { - response.data().put("type", catalogController.patchData(catalog, theType.data())); - } catch (JSONException e) { - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", e); - } - } - return response; + try { + Future<Catalog.Type> theTypeInfoFuture = catalogController.getCatalog().type(theItemId, theTypeName).withHierarchy().withCapabilities().withRequirements().execute(); + if(theTypeInfoFuture.succeeded()) { + CatalogResponse response = new CatalogResponse(ElementRequest.EMPTY_REQUEST); + response.data().put("type", theTypeInfoFuture.result().data()); + return ResponseEntity.ok().body(response); } - }); - return result; - } - - /// Nested Catalog Data Handlers /// - - private class FolderHandler extends CatalogController.CatalogHandler<Catalog.Folder> { - - private Catalog catalog; + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERAL_ERROR, theTypeInfoFuture.cause().getMessage()); - private FolderHandler(Catalog catalog, ItemsRequest request, DeferredResult result) { - catalogController.super(request, result); - this.catalog = catalog; - } - - private void patchCatalogData(Catalog.Elements folders, Catalog catalog) { - if (folders != null) { - folders.forEach(folder -> { - catalogController.patchData(catalog, ((Catalog.Element) folder).data()); - // lots of ephemere proxies created here .. - Catalog.Elements annotations = ((Catalog.Element) folder).elements("annotations", Catalog.Annotations.class); - if (annotations != null) { - annotations.forEach(a -> catalogController.patchData(catalog, ((Catalog.Annotation) a).data())); - } - }); - } - } - - public CatalogResponse handleData(Catalog.Folder theFolder) { - CatalogResponse response = new CatalogResponse(this.request); - if (theFolder == null) { - return response; - } - try { - Catalog.Elements folders = theFolder.elements("parts", Catalog.Folders.class); - patchCatalogData(folders, catalog); - Catalog.Elements items = theFolder.elements("items", Catalog.Items.class); - patchCatalogData(items, catalog); - } catch (Exception x) { - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", x); - return new CatalogError(this.request, "", x); - } - try { - response.data().put("element", theFolder.data()); - } catch (JSONException e) { - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting element to response {}", e); - } - return response; + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", e); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.GET_MODEL, theItemId); } } - private class ItemHandler extends CatalogController.CatalogHandler<Catalog.Item> { - - private Catalog catalog; - - private ItemHandler(Catalog catalog, ElementRequest request, DeferredResult result) { - catalogController.super(request, result); - this.catalog = catalog; - } - - public CatalogResponse handleData(Catalog.Item theItem) { - if (theItem == null) { - return new CatalogError(this.request, "No such item"); - } - Catalog.Templates models; - try { - models = (Catalog.Templates) theItem.elements("models", Catalog.Templates.class); - } catch (Exception x) { - return new CatalogError(this.request, "Failed to decode templates from result", x); - } - if (models == null || models.isEmpty()) { - return new CatalogError(this.request, "Item has no models"); - } - if (models.size() > 1) { - return new CatalogError(this.request, "Item has more than one model !?"); - } - try { - catalog.template(models.get(0).id()).withInputs().withOutputs().withNodes().withNodeProperties().withNodePropertiesAssignments().withNodeRequirements().withNodeCapabilities().withNodeCapabilityProperties() - .withNodeCapabilityPropertyAssignments().withPolicies().withPolicyProperties().withPolicyPropertiesAssignments().execute().setHandler(new TemplateHandler(this.catalog, this.request, this.result)); - } catch (Exception e) { - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception caught during Catalog Item Handler: {}", e); - } - return null; - } + public DcaeComponentCatalog getCatalog(String requestId) { + List<DcaeComponentCatalog.SubCategoryFolder> folders = sdcRestClient.getResources(AssetType.VF.name(), "DCAE Component", null, requestId).stream() + .filter(r -> DcaeBeConstants.LifecycleStateEnum.CERTIFIED == DcaeBeConstants.LifecycleStateEnum.findState(r.getLifecycleState())) + .collect(Collectors.groupingBy(Resource::getSubCategory)).entrySet().stream() + .map(e -> new DcaeComponentCatalog.SubCategoryFolder(e.getKey(), e.getValue())).collect(Collectors.toList()); + DcaeComponentCatalog catalog = new DcaeComponentCatalog(); + catalog.setElements(folders); + return catalog; } - private class TemplateHandler extends CatalogController.CatalogHandler<Catalog.Template> { - - private Catalog catalog; - private TemplateHandler(Catalog catalog, CatalogRequest request, DeferredResult result) { - catalogController.super(request, result); - this.catalog = catalog; + private ResourceDetailed fetchAndExtractTemplateAndSchema(String uuid, String requestId) throws IOException { + String toscaModelPath = "/sdc/v1/catalog/resources/".concat(uuid).concat("/toscaModel/"); + if(!catalogController.getCatalog().hasCachedItem(uuid)){ + ResourceDetailed resourceDetailed = new ResourceDetailed(); + resourceDetailed.setUuid(uuid); + resourceDetailed.setToscaModelURL(toscaModelPath); + resourceDetailed.setArtifacts(extractToscaArtifactsFromCsar(sdcRestClient.getResourceToscaModel(uuid, requestId), toscaModelPath)); + return resourceDetailed; } + ResourceDetailed cachedVf = sdcRestClient.getResource(uuid, requestId); + cachedVf.getArtifacts().forEach(a -> a.setArtifactURL(toscaModelPath.concat(a.getArtifactName()))); + return cachedVf; + } - public CatalogResponse handleData(Catalog.Template theTemplate) { - CatalogResponse response = new CatalogResponse(this.request); - if (theTemplate != null) { - try { - response.data().put("model", catalogController.patchData(catalog, theTemplate.data())); - } catch (JSONException e) { - errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting model to response {}", e); + private List<Artifact> extractToscaArtifactsFromCsar(byte[] csar, String toscaModelPath) throws IOException { + //we are only interested in unzipping files under Artifacts/Deployment/DCAE_TOSCA/ + String dcaeToscaDir = "Artifacts/Deployment/DCAE_TOSCA/"; + List<Artifact> extracted = new ArrayList<>(); + try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(csar))) { + ZipEntry ze = zis.getNextEntry(); + while (ze != null) { + if(ze.getName().startsWith(dcaeToscaDir)) { + String artifactName = ze.getName().replace(dcaeToscaDir,""); + extracted.add(SdcRestClientUtils.generateCatalogDcaeToscaArtifact(artifactName, toscaModelPath.concat(artifactName), extractFile(zis))); } + ze = zis.getNextEntry(); } - return response; + return extracted; } } -} - - - - +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java index 9c950b6..224fc24 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java @@ -2,9 +2,13 @@ package org.onap.sdc.dcae.composition.impl; import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.dcae.composition.restmodels.MonitoringComponent; +import org.onap.sdc.dcae.composition.restmodels.ReferenceUUID; +import org.onap.sdc.dcae.composition.restmodels.VfcmtData; import org.onap.sdc.dcae.composition.restmodels.sdc.ExternalReferencesMap; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceInstance; import org.onap.sdc.dcae.composition.restmodels.sdc.ServiceDetailed; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; import org.onap.sdc.dcae.errormng.ActionStatus; import org.onap.sdc.dcae.errormng.ErrConfMgr; import org.onap.sdc.dcae.utils.Normalizers; @@ -74,4 +78,26 @@ public class ReferenceBusinessLogic extends BaseBusinessLogic { return result; } + + // defect fix/workaround - rule editor may perform lazy checkout on a certified MC without binding it to the service. This is a preemptive measure + public ResponseEntity checkoutAndBindToServiceIfCertified(String userId, String contextType, String serviceUuid, String vfiName, String vfcmtUuid, String requestId) { + try { + ResourceDetailed vfcmt = sdcRestClient.getResource(vfcmtUuid, requestId); + DcaeBeConstants.LifecycleStateEnum initialState = DcaeBeConstants.LifecycleStateEnum.findState(vfcmt.getLifecycleState()); + if(DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT != initialState) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "about to checkout vfcmt {} {} version {}", vfcmtUuid, vfcmt.getLifecycleState(), vfcmt.getVersion()); + vfcmt = checkoutVfcmt(userId, vfcmtUuid, requestId); + } + //this is the only case in which the uuid will change. This UI call is followed by a save/import/delete rule request. + if(DcaeBeConstants.LifecycleStateEnum.CERTIFIED == initialState) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "about to create reference for new vfcmt {} version {}", vfcmt.getUuid(), vfcmt.getVersion()); + sdcRestClient.addExternalMonitoringReference(userId, contextType, serviceUuid, vfiName, new ReferenceUUID(vfcmt.getUuid()), requestId); + } + return new ResponseEntity<>(new VfcmtData(vfcmt), HttpStatus.OK); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(),"Failed to during getLatestMcUuid request for vfcmt {}. message: {}", vfcmtUuid, e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SAVE_RULE_FAILED, e.getMessage()); + } + } + } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogic.java index 298ffac..94133e4 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogic.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogic.java @@ -3,10 +3,8 @@ package org.onap.sdc.dcae.composition.impl; import com.fasterxml.jackson.core.JsonProcessingException; import com.google.gson.JsonParseException; import org.apache.commons.collections.ListUtils; -import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.onap.sdc.common.onaplog.Enums.LogLevel; -import org.onap.sdc.dcae.composition.CompositionConfig; import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; @@ -17,6 +15,7 @@ import org.onap.sdc.dcae.errormng.ErrConfMgr; import org.onap.sdc.dcae.errormng.ServiceException; import org.onap.sdc.dcae.rule.editor.impl.RulesBusinessLogic; import org.onap.sdc.dcae.rule.editor.utils.RulesPayloadUtils; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; import org.onap.sdc.dcae.utils.Normalizers; import org.onap.sdc.dcae.utils.SdcRestClientUtils; import org.onap.sdc.dcae.ves.VesDataItemsDefinition; @@ -24,7 +23,9 @@ import org.onap.sdc.dcae.ves.VesDataTypeDefinition; import org.onap.sdc.dcae.ves.VesSimpleTypesEnum; import org.onap.sdc.dcae.ves.VesStructureLoader; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.util.Base64Utils; @@ -39,8 +40,6 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { @Autowired private RulesBusinessLogic rulesBusinessLogic; - @Autowired - private CompositionConfig compositionConfig; private static final String EXCEPTION = "Exception {}"; @@ -49,7 +48,7 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { try { Rule rule = RulesPayloadUtils.parsePayloadToRule(json); if (null == rule) { - return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT, "", ""); } List<ServiceException> errors = rulesBusinessLogic.validateRule(rule); @@ -71,19 +70,18 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { .filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))) .findAny().orElse(null); - // exception thrown if vfcmt is checked out and current user is not its owner - // performs checkoutVfcmt if required - String vfcmtId = assertOwnershipOfVfcmtId(userId, vfcmt, requestId); // new mappingRules artifact, validate nid exists in composition before creating new artifact if (null == artifactFound) { if (cdumpContainsNid(vfcmt, nid, requestId)) { - return saveNewRulesArtifact(rule, vfcmtId, generateMappingRulesFileName(dcaeCompLabel, nid, configParam), artifactLabel, userId, requestId); + MappingRules body = new MappingRules(rule); + saveNewRulesArtifact(body, vfcmtUuid, generateMappingRulesFileName(dcaeCompLabel, nid, configParam), artifactLabel, userId, requestId); + return checkInAndReturnSaveArtifactResult(rule.toJson(), vfcmtUuid, userId, requestId); } return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.NODE_NOT_FOUND, "", dcaeCompLabel); } //update artifact flow - append new rule or edit existing rule - return addOrEditRuleInArtifact(rule, vfcmtId, userId, artifactFound, requestId); + return addOrEditRuleInArtifact(rule, vfcmtUuid, userId, artifactFound, requestId); } catch (JsonParseException je) { errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error: Rule format is invalid: {}", je); @@ -91,35 +89,59 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { } catch (Exception e) { return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.SAVE_RULE_ARTIFACT); } - } - public ResponseEntity getRules(String vfcmtUuid, String dcaeCompLabel, String nid, String configParam, String requestId) { + public ResponseEntity getRulesAndSchema(String vfcmtUuid, String dcaeCompLabel, String nid, String configParam, String requestId) { try { - ResourceDetailed vfcmt = getSdcRestClient().getResource(vfcmtUuid, requestId); - if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { - return new ResponseEntity<>("{}", HttpStatus.OK); - } - String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); - - // check for MappingRules artifact in existing artifacts - Artifact artifactListed = vfcmt.getArtifacts().stream().filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))).findAny().orElse(null); - if (null == artifactListed) { - return new ResponseEntity<>("{}", HttpStatus.OK); - } - String ruleFile = getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactListed.getArtifactUUID(), requestId); - + ResourceDetailed vfcmt = getSdcRestClient().getResource(vfcmtUuid, requestId); + Artifact rulesArtifact = fetchRulesArtifact(vfcmt, dcaeCompLabel, nid, configParam, requestId); + if(null == rulesArtifact) { + return new ResponseEntity<>("{}", HttpStatus.OK); + } // To avoid opening the file for reading we search for the eventType and SchemaVer from the artifact metadata's description - SchemaInfo schemainfo = RulesPayloadUtils.extractInfoFromDescription(artifactListed); + SchemaInfo schemainfo = RulesPayloadUtils.extractInfoFromDescription(rulesArtifact); List<EventTypeDefinitionUI> schema = null == schemainfo ? new ArrayList<>() : getEventTypeDefinitionUIs(schemainfo.getVersion(), schemainfo.getEventType()); - return new ResponseEntity<>(RulesPayloadUtils.buildSchemaAndRulesResponse(ruleFile, schema), HttpStatus.OK); + return new ResponseEntity<>(RulesPayloadUtils.buildSchemaAndRulesResponse(rulesArtifact.getPayloadData(), schema), HttpStatus.OK); } catch (Exception e) { return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.GET_RULE_ARTIFACT); } - } + //1810 US423581 export rules + public ResponseEntity downloadRules(String vfcmtUuid, String dcaeCompLabel, String nid, String configParam, String requestId) { + + try { + ResourceDetailed vfcmt = getSdcRestClient().getResource(vfcmtUuid, requestId); + Artifact rulesArtifact = fetchRulesArtifact(vfcmt, dcaeCompLabel, nid, configParam, requestId); + if(null == rulesArtifact) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"requested rules artifact not found"); + return new ResponseEntity(HttpStatus.NOT_FOUND); + } + return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM) + .header(HttpHeaders.CONTENT_DISPOSITION, generateMappingRulesFileNameHeader(vfcmt.getName(), dcaeCompLabel, configParam)) + .body(rulesArtifact.getPayloadData()); + } catch (Exception e) { + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.GET_RULE_ARTIFACT); + } + } + + private Artifact fetchRulesArtifact(ResourceDetailed vfcmt, String dcaeCompLabel, String nid, String configParam, String requestId) { + + if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + return null; + } + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // check for MappingRules artifact in existing artifacts + Artifact artifactListed = vfcmt.getArtifacts().stream().filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))).findAny().orElse(null); + if (null == artifactListed) { + return null; + } + artifactListed.setPayloadData(getSdcRestClient().getResourceArtifact(vfcmt.getUuid(), artifactListed.getArtifactUUID(), requestId)); + return artifactListed; + } + public ResponseEntity deleteRule(String userId, String vfcmtUuid, String dcaeCompLabel, String nid, String configParam, String ruleUid, String requestId) { try { @@ -140,8 +162,7 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); } - String vfcmtId = assertOwnershipOfVfcmtId(userId, vfcmt, requestId); - String payload = getSdcRestClient().getResourceArtifact(vfcmtId, mappingRuleFile.getArtifactUUID(), requestId); + String payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, mappingRuleFile.getArtifactUUID(), requestId); MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); Rule removedRule = rulesBusinessLogic.deleteRule(rules, ruleUid); if (null == removedRule) { @@ -149,55 +170,89 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); } if (rules.isEmpty()) { // if file doesn't contain any rules after last deletion -> let's delete the file - getSdcRestClient().deleteResourceArtifact(userId, vfcmtId, mappingRuleFile.getArtifactUUID(), requestId); + getSdcRestClient().deleteResourceArtifact(userId, vfcmtUuid, mappingRuleFile.getArtifactUUID(), requestId); } else { - updateRulesArtifact(vfcmtId, userId, mappingRuleFile, rules, requestId); + updateRulesArtifact(vfcmtUuid, userId, mappingRuleFile, rules, requestId); } - return checkInAndReturnSaveArtifactResult(removedRule, vfcmtId, userId, requestId); + return checkInAndReturnSaveArtifactResult(removedRule.toJson(), vfcmtUuid, userId, requestId); } catch (Exception e) { return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.SAVE_RULE_ARTIFACT); } - } - public ResponseEntity translateRules(String vfcmtUuid, String requestId, String dcaeCompLabel, String nid, String configParam, String flowType) { + public ResponseEntity deleteGroupOfRules(String userId, String vfcmtUuid, String dcaeCompLabel, String nid, String configParam, String groupId, String requestId) { + + try { + ResourceDetailed vfcmt = getSdcRestClient().getResource(vfcmtUuid, requestId); + if (null == vfcmt.getArtifacts()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "VFCMT {} doesn't have artifacts", vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); + } + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // check for MappingRules artifact in existing artifacts + Artifact mappingRuleFile = vfcmt.getArtifacts().stream() + .filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))) + .findAny().orElse(null); + + if (null == mappingRuleFile) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "{} doesn't exist for VFCMT {}", artifactLabel, vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); + } + + String payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, mappingRuleFile.getArtifactUUID(), requestId); + MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); + List<Rule> removedRules = rulesBusinessLogic.deleteGroupOfRules(rules, groupId); + if (removedRules.isEmpty()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Group {} not found.", groupId); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); + } + if (rules.isEmpty()) { // if file doesn't contain any rules after last deletion -> let's delete the file + getSdcRestClient().deleteResourceArtifact(userId, vfcmtUuid, mappingRuleFile.getArtifactUUID(), requestId); + } else { + updateRulesArtifact(vfcmtUuid, userId, mappingRuleFile, rules, requestId); + } + return checkInAndReturnSaveArtifactResult(removedRules, vfcmtUuid, userId, requestId); + } catch (Exception e) { + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.SAVE_RULE_ARTIFACT); + } + + } + + public ResponseEntity translateRules(TranslateRequest request, String requestId) { try { - - if (StringUtils.isBlank(flowType) || MapUtils.isEmpty(compositionConfig.getFlowTypesMap()) || null == compositionConfig.getFlowTypesMap().get(flowType)) { - return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "Flow type " + flowType + " not found"); + if(!rulesBusinessLogic.validateTranslateRequestFields(request)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Invalid translate request. request: {}", request); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "please enter valid request parameters"); } - - // extract entry phase name and last phase name from configuration: - String entryPointPhaseName = compositionConfig.getFlowTypesMap().get(flowType).getEntryPointPhaseName(); - String lastPhaseName = compositionConfig.getFlowTypesMap().get(flowType).getLastPhaseName(); - - ResourceDetailed vfcmt = getSdcRestClient().getResource(vfcmtUuid, requestId); + ResourceDetailed vfcmt = getSdcRestClient().getResource(request.getVfcmtUuid(), requestId); checkVfcmtType(vfcmt); if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { - return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "No rules found on VFCMT " + vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "No rules found on VFCMT " + request.getVfcmtUuid()); } - String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + String artifactLabel = Normalizers.normalizeArtifactLabel(request.getDcaeCompLabel() + request.getNid() + request.getConfigParam()); // check for MappingRules artifact in existing artifacts Artifact rulesArtifact = vfcmt.getArtifacts().stream().filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))).findAny().orElse(null); if (rulesArtifact == null) { - return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", artifactLabel + " doesn't exist on VFCMT " + vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", artifactLabel + " doesn't exist on VFCMT " + request.getVfcmtUuid()); } - String payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, rulesArtifact.getArtifactUUID(), requestId); + String payload = getSdcRestClient().getResourceArtifact(request.getVfcmtUuid(), rulesArtifact.getArtifactUUID(), requestId); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Retrieved mapping rules artifact {}, start parsing rules...", artifactLabel); MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); + rulesBusinessLogic.updateGlobalTranslationFields(rules, request, vfcmt.getName()); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished parsing rules, calling validator..."); - List<ServiceException> errors = rulesBusinessLogic.validateRules(rules); + List<ServiceException> errors = rulesBusinessLogic.validateRulesBeforeTranslate(rules); if (!errors.isEmpty()) { return ErrConfMgr.INSTANCE.buildErrorArrayResponse(errors); } debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Validation completed successfully, calling translator..."); - String translateJson = rulesBusinessLogic.translateRules(rules, entryPointPhaseName, lastPhaseName, vfcmt.getName()); + String translateJson = rulesBusinessLogic.translateRules(rules); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Translation completed successfully"); return new ResponseEntity<>(translateJson, HttpStatus.OK); } catch (Exception e) { @@ -205,6 +260,50 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { } } + public ResponseEntity importRules(String json, String requestId, String userId, String vfcmtUuid, String dcaeCompLabel, String nid, String configParam) { + try { + MappingRulesResponse mappingRules = RulesPayloadUtils.parsePayloadToMappingRules(json); + List<ServiceException> errors = rulesBusinessLogic.validateImportedRules(mappingRules); + if (!errors.isEmpty()) { + // this will return the first violation found by the validator to the UI view as a regular error and all violations to the console view + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT, errors.stream().map(ServiceException::getFormattedErrorMessage).collect(Collectors.joining(", ")), errors.get(0).getFormattedErrorMessage()); + } + + ResourceDetailed vfcmt = getSdcRestClient().getResource(vfcmtUuid, requestId); + checkVfcmtType(vfcmt); + + if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SAVE_RULE_FAILED); + } + + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // check for MappingRules artifact in existing artifacts + Artifact artifactFound = vfcmt.getArtifacts().stream() + .filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))) + .findAny().orElse(null); + + // new mappingRules artifact, validate nid exists in composition before creating new artifact + if (null == artifactFound) { + if (!cdumpContainsNid(vfcmt, nid, requestId)) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.NODE_NOT_FOUND, "", dcaeCompLabel); + } + saveNewRulesArtifact(mappingRules, vfcmtUuid, generateMappingRulesFileName(dcaeCompLabel, nid, configParam), artifactLabel, userId, requestId); + } else { + updateRulesArtifact(vfcmtUuid, userId, artifactFound, mappingRules, requestId); + } + mappingRules.setSchema(getEventTypeDefinitionUIs(mappingRules.getVersion(), mappingRules.getEventType())); + return checkInAndReturnSaveArtifactResult(mappingRules, vfcmtUuid, userId, requestId); + + } catch (JsonParseException je) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error: Rule format is invalid: {}", je); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT, "", je.getMessage()); + } catch (Exception e) { + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.SAVE_RULE_ARTIFACT); + } + + } + public ResponseEntity getExistingRuleTargets(String vfcmtUuid, String requestId, String dcaeCompLabel, String nid) { try { @@ -260,19 +359,6 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { ///////////////////PRIVATE METHODS//////////////////////////////////////////////////////////////////////// - private String assertOwnershipOfVfcmtId(String userId, ResourceDetailed vfcmt, String requestId) { - checkUserIfResourceCheckedOut(userId, vfcmt); - String newVfcmtId = vfcmt.getUuid(); // may change after checking out a certified vfcmt - if (isNeedToCheckOut(vfcmt.getLifecycleState())) { - ResourceDetailed result = checkoutVfcmt(userId, newVfcmtId, requestId); - if (result != null) { - newVfcmtId = result.getUuid(); - debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New resource after checkoutVfcmt is: {}", newVfcmtId); - } - } - return newVfcmtId; - } - // called after validating vfcmt.getArtifacts() is not null private boolean cdumpContainsNid(ResourceDetailed vfcmt, String nid, String requestId) { Artifact cdump = vfcmt.getArtifacts().stream() @@ -295,40 +381,44 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { return true; } - private ResponseEntity<String> saveNewRulesArtifact(Rule rule, String vfcmtUuid, String artifactFileName, String artifactLabel, String userId, String requestId) throws JsonProcessingException { - MappingRules body = new MappingRules(rule); - Artifact artifact = SdcRestClientUtils.generateDeploymentArtifact(body.describe(), artifactFileName, ArtifactType.OTHER.name(), artifactLabel, body.convertToPayload()); - getSdcRestClient().createResourceArtifact(userId, vfcmtUuid, artifact, requestId); - return checkInAndReturnSaveArtifactResult(rule, vfcmtUuid, userId, requestId); - } + + private void saveNewRulesArtifact(MappingRules mappingRules, String vfcmtUuid, String artifactFileName, String artifactLabel, String userId, String requestId) throws JsonProcessingException { + Artifact artifact = SdcRestClientUtils.generateDeploymentArtifact(mappingRules.describe(), artifactFileName, ArtifactType.OTHER.name(), artifactLabel, mappingRules.convertToPayload()); + getSdcRestClient().createResourceArtifact(userId, vfcmtUuid, artifact, requestId); + } private ResponseEntity addOrEditRuleInArtifact(Rule rule, String vfcmtUuid, String userId, Artifact rulesArtifact, String requestId) throws JsonProcessingException { String payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, rulesArtifact.getArtifactUUID(), requestId); MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); - // in case the rule id is passed but the rule doesn't exist on the mapping rule file: - if (!rulesBusinessLogic.addOrEditRule(rules, rule)) { + // 1810 US427299 support user defined phase names + boolean supportGroups = ValidationUtils.validateNotEmpty(rule.getGroupId()); + if(!rulesBusinessLogic.validateGroupDefinitions(rules, supportGroups)) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT, "", "invalid group definitions"); + } + // in case the rule id is passed but the rule doesn't exist on the mapping rule file or if there's a mismatch in group definitions: + if (!rulesBusinessLogic.addOrEditRule(rules, rule, supportGroups)) { return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SAVE_RULE_FAILED); } updateRulesArtifact(vfcmtUuid, userId, rulesArtifact, rules, requestId); - return checkInAndReturnSaveArtifactResult(rule, vfcmtUuid, userId, requestId); + return checkInAndReturnSaveArtifactResult(rule.toJson(), vfcmtUuid, userId, requestId); } // regardless of check in result, return save artifact success - private ResponseEntity<String> checkInAndReturnSaveArtifactResult(Rule rule, String vfcmtUuid, String userId, String requestId) { + private ResponseEntity checkInAndReturnSaveArtifactResult(Object response, String vfcmtUuid, String userId, String requestId) { try { checkinVfcmt(userId, vfcmtUuid, requestId); } catch (Exception e) { // swallowing the exception intentionally since it is on the check in action errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occurred while performing check in on VFCMT {}:{}", vfcmtUuid, e); } - return new ResponseEntity<>(rule.toJson(), HttpStatus.OK); + return new ResponseEntity<>(response, HttpStatus.OK); } private void updateRulesArtifact(String vfcmtUuid, String userId, Artifact artifactInfo, MappingRules rules, String requestId) throws JsonProcessingException { artifactInfo.setPayloadData(Base64Utils.encodeToString(rules.convertToPayload())); // POST must contain 'description' while GET returns 'artifactDescription' - artifactInfo.setDescription(artifactInfo.getArtifactDescription()); + artifactInfo.setDescription(rules.describe()); getSdcRestClient().updateResourceArtifact(userId, vfcmtUuid, artifactInfo, requestId); } @@ -378,6 +468,17 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { return dcaeCompLabel + "_" + nid + "_" + configParam + DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX; } + private String generateMappingRulesFileNameHeader(String vfcmtName, String dcaeCompLabel, String configParam) { + return "attachment; filename=\"" + .concat(vfcmtName) + .concat("_") + .concat(dcaeCompLabel) + .concat("_") + .concat(configParam) + .concat(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX) + .concat("\""); + } + private List<EventTypeDefinitionUI> getEventTypeDefinitionUIs(String version, String eventType) { List<String> eventNamesToReturn = ListUtils.union(EventTypesByVersionUI.DEFAULT_EVENTS, Arrays.asList(eventType)); Map<String, VesDataTypeDefinition> eventDefs = VesStructureLoader.getEventListenerDefinitionByVersion(version); @@ -385,4 +486,6 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { return convertToEventTypeDefinition(filteredEvents, null, "event"); } + + } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrConfMgr.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrConfMgr.java index de1d06b..2aa721f 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrConfMgr.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrConfMgr.java @@ -146,6 +146,7 @@ public enum ErrConfMgr { map.put("SVC4127", "SVC6021"); map.put("SVC4086", AS_IS); map.put("SVC4301", AS_IS); + map.put("SVC4083", AS_IS); sdcDcaeMsgIdMap.put(ApiType.SAVE_CDUMP, map); } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormatManager.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormatManager.java index ada790f..58d76be 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormatManager.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormatManager.java @@ -97,7 +97,7 @@ public class ResponseFormatManager { } } - public ResponseFormatManager(){ + private ResponseFormatManager(){ } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/OperatorTypeEnum.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/OperatorTypeEnum.java index 2cd03a7..9a9658f 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/OperatorTypeEnum.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/OperatorTypeEnum.java @@ -3,26 +3,41 @@ package org.onap.sdc.dcae.rule.editor.enums; import java.util.Arrays; public enum OperatorTypeEnum { - EQUALS("Equals", "OneOf"), - NOT_EQUAL("NotEqual", "NotOneOf"), - CONTAINS("Contains", null), - ENDS_WITH("EndsWith", null), - STARTS_WITH("StartsWith", null); + + EQUALS("Equals"), NOT_EQUAL("NotEqual"), CONTAINS("Contains"), ENDS_WITH("EndsWith"), STARTS_WITH("StartsWith"), ONE_OF("OneOf"), NOT_ONE_OF("NotOneOf"), ASSIGNED("Assigned"), UNASSIGNED("Unassigned"); private String type; - private String modifiedType; - OperatorTypeEnum(String type, String modifiedType) { + OperatorTypeEnum(String type) { this.type = type; - this.modifiedType = modifiedType; } public String getType() { return type; } - public String getModifiedType() { - return modifiedType; + public OperatorTypeEnum getModifiedType() { + switch (this) { + case EQUALS: + case ONE_OF: + return ONE_OF; + case NOT_EQUAL: + case NOT_ONE_OF: + return NOT_ONE_OF; + default: + return null; + } + } + + public String getConditionType() { + switch (this) { + case CONTAINS: + case STARTS_WITH: + case ENDS_WITH: + return "Condition"; // comparing strings + default: + return "FieldCondition"; // comparing any type + } } public static OperatorTypeEnum getTypeByName(String name) { diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/RuleEditorElementType.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/RuleEditorElementType.java index a5e4a39..231c208 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/RuleEditorElementType.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/RuleEditorElementType.java @@ -1,11 +1,10 @@ package org.onap.sdc.dcae.rule.editor.enums; -import java.util.Arrays; - -import org.onap.sdc.dcae.composition.restmodels.ruleeditor.LogEventAction; import org.onap.sdc.dcae.rule.editor.translators.*; import org.onap.sdc.dcae.rule.editor.validators.*; +import java.util.Arrays; + public enum RuleEditorElementType { COPY("Copy", CopyActionValidator.getInstance(), CopyActionTranslator.getInstance()), CONCAT("Concat", ConcatActionValidator.getInstance(), CopyActionTranslator.getInstance()), @@ -17,13 +16,18 @@ public enum RuleEditorElementType { REPLACE_TEXT("ReplaceText", ReplaceActionValidator.getInstance(), ReplaceActionTranslator.getInstance()), LOG_EVENT("LogEvent", LogEventValidator.getInstance(), LogEventTranslator.getInstance()), LOG_TEXT("LogText", LogTextValidator.getInstance(), LogTextTranslator.getInstance()), + //1810 US420763 additional hp processors support + CLEAR_NSF("ClearNSF", ClearActionValidator.getInstance(), ClearActionTranslator.getInstance()), + HP_METRIC("HpMetric", HpMetricValidator.getInstance(), HpMetricTranslator.getInstance()), + STRING_TRANSFORM("StringTransform", StringTransformValidator.getInstance(), StringTransformTranslator.getInstance()), + TOPO_SEARCH("TopologySearch", TopoSearchValidator.getInstance(), TopoSearchTranslator.getInstance()), CONDITION("Condition", ConditionValidator.getInstance(), ConditionTranslator.getInstance()), FIELD_CONDITION("FieldCondition", ConditionValidator.getInstance(), FieldConditionTranslator.getInstance()), CONDITION_GROUP("ConditionGroup", ConditionGroupValidator.getInstance(), ConditionGroupTranslator.getInstance()), RULE("Rule", RuleValidator.getInstance(), RuleTranslator.getInstance()), - MAPPING_RULES("MappingRules", null, MappingRulesTranslator.getInstance()); + MAPPING_RULES("MappingRules", MappingRulesValidator.getInstance(), MappingRulesTranslator.getInstance()); private String elementType; private IRuleElementValidator validator; diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogic.java index 5270a18..468a6d5 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogic.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogic.java @@ -12,6 +12,8 @@ import org.onap.sdc.dcae.errormng.ResponseFormat; import org.onap.sdc.dcae.errormng.ServiceException; import org.onap.sdc.dcae.rule.editor.translators.MappingRulesTranslator; import org.onap.sdc.dcae.rule.editor.utils.EmptyStringTranslationSerializer; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; +import org.onap.sdc.dcae.rule.editor.validators.MappingRulesValidator; import org.onap.sdc.dcae.rule.editor.validators.RuleValidator; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -20,12 +22,14 @@ import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; @Component public class RulesBusinessLogic { protected OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); private RuleValidator ruleValidator = RuleValidator.getInstance(); + private MappingRulesValidator mappingRulesValidator = MappingRulesValidator.getInstance(); private MappingRulesTranslator mappingRulesTranslator = MappingRulesTranslator.getInstance(); private static Gson gsonTranslator = new GsonBuilder().registerTypeAdapter(String.class, new EmptyStringTranslationSerializer()).enableComplexMapKeySerialization().create(); @@ -37,30 +41,58 @@ public class RulesBusinessLogic { return errors.stream().map(r -> r.getRequestError().getServiceException()).collect(Collectors.toList()); } - public List<ServiceException> validateRules(MappingRules rules) { + public List<ServiceException> validateImportedRules(MappingRules rules) { List<ResponseFormat> errors = new ArrayList<>(); - detectAndResolveRuleDependencies(rules, errors); + if(mappingRulesValidator.validate(rules, errors)){ + rules.getRules().forEach((k,v) -> { + v.setUid(k); + detectAndResolveActionDependencies(v, errors); + }); + } + return errors.stream().map(r -> r.getRequestError().getServiceException()).collect(Collectors.toList()); + } + + + public List<ServiceException> validateRulesBeforeTranslate(MappingRules rules) { + List<ResponseFormat> errors = new ArrayList<>(); + if(mappingRulesValidator.validateTranslationPhaseNames(rules, errors)) { + detectAndResolveRuleDependencies(rules, errors); + } return errors.stream().map(r -> r.getRequestError().getServiceException()).collect(Collectors.toList()); } - public String translateRules(MappingRules rules, String entryPointPhase, String lastPhase, String runPhase) { + public String translateRules(MappingRules rules) { debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Start translating mapping rules"); - return gsonTranslator.toJson(mappingRulesTranslator.translateToHpJson(rules, entryPointPhase, lastPhase, runPhase)); + return gsonTranslator.toJson(mappingRulesTranslator.translateToHpJson(rules)); } - public boolean addOrEditRule(MappingRules rules, Rule rule) { + public boolean addOrEditRule(MappingRules rules, Rule rule, boolean supportGroups) { // in case the rule id is passed but the rule doesn't exist on the mapping rule file: if(StringUtils.isNotBlank(rule.getUid()) && !rules.ruleExists(rule)) { return false; } + // 1810 US427299 support user defined phase names - propagate update to all group members + if(supportGroups) { + rules.getRules().values().stream().filter(p -> rule.getGroupId().equals(p.getGroupId())).forEach(r -> r.setPhase(rule.getPhase())); + } rules.addOrReplaceRule(rule); return true; } + + public boolean validateGroupDefinitions(MappingRules rules, boolean supportGroups) { + return supportGroups == rules.getRules().values().stream().anyMatch(r -> ValidationUtils.validateNotEmpty(r.getGroupId())); + } + public Rule deleteRule(MappingRules rules, String ruleUid) { return rules.removeRule(ruleUid); } + public List<Rule> deleteGroupOfRules(MappingRules rules, String groupId) { + List<Rule> rulesByGroupId = rules.getRules().values().stream().filter(p -> groupId.equals(p.getGroupId())).collect(Collectors.toList()); + return rulesByGroupId.stream().map(rule -> rules.removeRule(rule.getUid())).collect(Collectors.toList()); + } + private <T> List<T> detectDependentItemsByDependencyDefinition(Collection<T> allItems, BiFunction<T, Collection<T>, Boolean> dependencyDefinition) { return allItems.stream().filter(i -> dependencyDefinition.apply(i, allItems)).collect(Collectors.toList()); } @@ -127,6 +159,7 @@ public class RulesBusinessLogic { } } + private String extractDependentActionTargetsFromRules(List<Rule> dependentRules) { List<BaseAction> allActions = dependentRules.stream().map(Rule::getActions).flatMap(List::stream).collect(Collectors.toList()); // option 1: circular dependency between actions @@ -150,4 +183,19 @@ public class RulesBusinessLogic { }, LinkedHashMap::new)); rules.setRules(rulesMap); } + + public boolean validateTranslateRequestFields(TranslateRequest request) { + return Stream.of(request.getVfcmtUuid(), request.getDcaeCompLabel(), request.getNid(), request.getConfigParam(), request.getPublishPhase(), request.getEntryPhase()).allMatch(ValidationUtils::validateNotEmpty) + && !request.getEntryPhase().equalsIgnoreCase(request.getPublishPhase()); + } + + public void updateGlobalTranslationFields(MappingRules mappingRules, TranslateRequest request, String vfcmtName) { + mappingRules.setEntryPhase(request.getEntryPhase()); + mappingRules.setPublishPhase(request.getPublishPhase()); + mappingRules.setNotifyId(request.getNotifyId()); + if(validateGroupDefinitions(mappingRules, false)) { + // 1806 US349308 assign Vfcmt name as rule phaseName + mappingRules.getRules().forEach((k,v) -> v.setPhase(vfcmtName)); + } + } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ActionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ActionTranslator.java index 0ad33ce..c3f5c89 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ActionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ActionTranslator.java @@ -3,7 +3,9 @@ package org.onap.sdc.dcae.rule.editor.translators; import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseAction; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; abstract class ActionTranslator<A extends BaseAction> implements IRuleElementTranslator<A> { @@ -12,4 +14,13 @@ abstract class ActionTranslator<A extends BaseAction> implements IRuleElementTra processors.add(translateToHpJson(action)); return true; } + + class CopyActionSetTranslation extends ProcessorTranslation { + protected Map<String, String> updates = new LinkedHashMap<>(); + + CopyActionSetTranslation(String target, String from) { + clazz = "Set"; + updates.put(target, from); + } + } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ClearActionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ClearActionTranslator.java index 31a3fdc..8b4368a 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ClearActionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ClearActionTranslator.java @@ -1,5 +1,6 @@ package org.onap.sdc.dcae.rule.editor.translators; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.ActionTypeEnum; import org.onap.sdc.dcae.composition.restmodels.ruleeditor.UnaryFieldAction; import java.util.List; @@ -15,7 +16,7 @@ public class ClearActionTranslator extends ActionTranslator<UnaryFieldAction> { private ClearActionTranslator(){} public Object translateToHpJson(UnaryFieldAction action) { - return new ClearActionTranslation(action); + return ActionTypeEnum.CLEAR == ActionTypeEnum.getTypeByName(action.getActionType()) ? new ClearActionTranslation(action) : new ClearNSFActionTranslation(action); } @@ -24,7 +25,17 @@ public class ClearActionTranslator extends ActionTranslator<UnaryFieldAction> { ClearActionTranslation(UnaryFieldAction action) { clazz = "Clear"; - fields = action.getFromValues(); + fields = action.fromValues(); + } + } + + + private class ClearNSFActionTranslation extends ProcessorTranslation { + private List<String> reservedFields; + + ClearNSFActionTranslation(UnaryFieldAction action) { + clazz = "ClearNoneStandardFields"; + reservedFields = action.fromValues(); } } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionGroupTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionGroupTranslator.java index 86f55c9..c735723 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionGroupTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionGroupTranslator.java @@ -1,9 +1,11 @@ package org.onap.sdc.dcae.rule.editor.translators; -import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseCondition; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Condition; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.ConditionGroup; import org.onap.sdc.dcae.rule.editor.enums.ConditionTypeEnum; import org.onap.sdc.dcae.rule.editor.enums.OperatorTypeEnum; -import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; +import org.onap.sdc.dcae.rule.editor.enums.RuleEditorElementType; import java.util.List; import java.util.Map; @@ -30,8 +32,12 @@ public class ConditionGroupTranslator implements IRuleElementTranslator<Conditio private IRuleElementTranslator getConditionTranslator(BaseCondition condition){ - return condition instanceof ConditionGroup ? ConditionGroupTranslator.getInstance() : - ValidationUtils.validateNotEmpty(OperatorTypeEnum.getTypeByName(((Condition)condition).getOperator()).getModifiedType()) ? FieldConditionTranslator.getInstance() : ConditionTranslator.getInstance(); + return condition instanceof ConditionGroup ? ConditionGroupTranslator.getInstance() : getSimpleConditionTranslator((Condition) condition); + } + + private IRuleElementTranslator getSimpleConditionTranslator(Condition condition) { + String conditionType = OperatorTypeEnum.getTypeByName(condition.getOperator()).getConditionType(); + return RuleEditorElementType.getElementTypeByName(conditionType).getTranslator(); } private Object getTranslation(BaseCondition condition) { diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionTranslator.java index aa30fc3..81dc010 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionTranslator.java @@ -20,15 +20,20 @@ public class ConditionTranslator implements IRuleElementTranslator<Condition> { private String string; private String value; - private StringFilterTranslation(Condition condition, String value){ - this.clazz = OperatorTypeEnum.getTypeByName(condition.getOperator()).getType(); - this.string = condition.getLeft(); + private StringFilterTranslation(String clazz, String string, String value){ + this.clazz = clazz; + this.string = string; this.value = value; } + private StringFilterTranslation(Condition condition, String value) { + this(OperatorTypeEnum.getTypeByName(condition.getOperator()).getType(), condition.getLeft(), value); + } + private StringFilterTranslation(Condition condition){ this(condition, condition.getRight().get(0)); } + } public Object translateToHpJson(Condition condition) { @@ -36,5 +41,7 @@ public class ConditionTranslator implements IRuleElementTranslator<Condition> { .map(r -> new StringFilterTranslation(condition, r)).collect(Collectors.toList())); } - + Object notifyOidTranslation(String notifyOid) { + return new StringFilterTranslation(OperatorTypeEnum.STARTS_WITH.getType(),"${notify OID}", notifyOid); + } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/CopyActionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/CopyActionTranslator.java index 4226eba..3e42b60 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/CopyActionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/CopyActionTranslator.java @@ -3,9 +3,7 @@ package org.onap.sdc.dcae.rule.editor.translators; import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseCopyAction; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; public class CopyActionTranslator extends ActionTranslator<BaseCopyAction> { @@ -15,10 +13,10 @@ public class CopyActionTranslator extends ActionTranslator<BaseCopyAction> { return copyActionTranslator; } - CopyActionTranslator(){} + private CopyActionTranslator(){} public Object translateToHpJson(BaseCopyAction action) { - return new CopyActionSetTranslation(action.getTarget(), action.getFromValue()); + return new CopyActionSetTranslation(action.getTarget(), action.fromValue()); } @Override @@ -28,17 +26,9 @@ public class CopyActionTranslator extends ActionTranslator<BaseCopyAction> { processors.add(translateToHpJson(action)); } else { - ((CopyActionSetTranslation) processors.get(processors.size() - 1)).updates.put(action.getTarget(), action.getFromValue()); + ((CopyActionSetTranslation) processors.get(processors.size() - 1)).updates.put(action.getTarget(), action.fromValue()); } return false; } - class CopyActionSetTranslation extends ProcessorTranslation { - Map<String, String> updates = new LinkedHashMap<>(); - CopyActionSetTranslation(String target, String from) { - clazz = "Set"; - updates.put(target, from); - } - } - } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/DateFormatterTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/DateFormatterTranslator.java index 449dbf0..dbbf6a1 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/DateFormatterTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/DateFormatterTranslator.java @@ -22,12 +22,12 @@ public class DateFormatterTranslator extends ActionTranslator<DateFormatterActio private DateFormatterTranslation(DateFormatterAction action){ clazz = "DateFormatter"; - fromFormat = action.getFromFormat(); - fromTz = action.getFromTz(); + fromFormat = action.fromFormat(); + fromTz = action.fromTz(); toField = action.getTarget(); - toFormat = action.getToFormat(); - toTz = action.getToTz(); - value = action.getFromValue(); + toFormat = action.toFormat(); + toTz = action.toTz(); + value = action.fromValue(); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/FieldConditionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/FieldConditionTranslator.java index dddbc89..a8afd51 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/FieldConditionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/FieldConditionTranslator.java @@ -19,25 +19,45 @@ public class FieldConditionTranslator implements IRuleElementTranslator<Conditio private String field; private String value; - private FieldFilterTranslation(Condition condition) { - clazz = OperatorTypeEnum.getTypeByName(condition.getOperator()).getType(); + private FieldFilterTranslation(Condition condition, OperatorTypeEnum operatorType) { + clazz = operatorType.getType(); field = condition.getLeft(); value = condition.getRight().get(0); } } + private class UnaryFilterTranslation extends ProcessorTranslation { + private String field; + private boolean emptyIsAssigned; + + private UnaryFilterTranslation(Condition condition, OperatorTypeEnum operatorType) { + clazz = operatorType.getType(); + field = condition.getLeft(); + emptyIsAssigned = condition.isEmptyIsAssigned(); + } + } + private class MultiFieldFilterTranslation extends ProcessorTranslation { private String field; private List<String> values; - private MultiFieldFilterTranslation(Condition condition) { + private MultiFieldFilterTranslation(Condition condition, OperatorTypeEnum operatorType) { field = condition.getLeft(); values = condition.getRight(); - clazz = OperatorTypeEnum.getTypeByName(condition.getOperator()).getModifiedType(); + clazz = operatorType.getModifiedType().getType(); } } public Object translateToHpJson(Condition condition) { - return 1 == condition.getRight().size() ? new FieldFilterTranslation(condition) : new MultiFieldFilterTranslation(condition); + OperatorTypeEnum operatorType = OperatorTypeEnum.getTypeByName(condition.getOperator()); + if(OperatorTypeEnum.UNASSIGNED == operatorType || OperatorTypeEnum.ASSIGNED == operatorType) { + return new UnaryFilterTranslation(condition, operatorType); + } + return 1 == condition.getRight().size() && !alwaysUseMultipleRightValues(operatorType)? new FieldFilterTranslation(condition, operatorType) : new MultiFieldFilterTranslation(condition, operatorType); } + + private boolean alwaysUseMultipleRightValues(OperatorTypeEnum operatorType) { + return operatorType.equals(operatorType.getModifiedType()); + } + } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/HpMetricTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/HpMetricTranslator.java new file mode 100644 index 0000000..31df164 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/HpMetricTranslator.java @@ -0,0 +1,18 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.HpMetricAction; + +public class HpMetricTranslator extends ActionTranslator<HpMetricAction> { + + private static HpMetricTranslator hpMetricTranslator = new HpMetricTranslator(); + + public static HpMetricTranslator getInstance() { + return hpMetricTranslator; + } + + private HpMetricTranslator(){} + + public Object translateToHpJson(HpMetricAction action) { + return new CopyActionSetTranslation("parserType", action.getSelectedHpMetric()); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/IRuleElementTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/IRuleElementTranslator.java index 97269ef..eeffda2 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/IRuleElementTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/IRuleElementTranslator.java @@ -33,7 +33,7 @@ public interface IRuleElementTranslator<T> { class RuleTranslation { protected String phase; protected Object filter; - protected List<Object> processors = new ArrayList<>(); + protected List<ProcessorTranslation> processors = new ArrayList<>(); } class RunPhaseProcessorsTranslation extends ProcessorTranslation { diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogEventTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogEventTranslator.java index 8c29070..959a98e 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogEventTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogEventTranslator.java @@ -22,7 +22,7 @@ public class LogEventTranslator extends ActionTranslator<LogEventAction> { LogEventTranslation(LogEventAction action) { clazz = "LogEvent"; - title = action.getTitle(); + title = action.logTitle(); } } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogTextTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogTextTranslator.java index a9ed5bb..dada486 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogTextTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/LogTextTranslator.java @@ -24,9 +24,9 @@ public class LogTextTranslator extends ActionTranslator<LogTextAction> { private LogTextTranslation(LogTextAction action) { clazz = "LogText"; - logLevel = action.getLevel(); - logName = action.getName(); - logText = action.getText(); + logLevel = action.logLevel(); + logName = action.logName(); + logText = action.logText(); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MapActionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MapActionTranslator.java index d493abb..b83f646 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MapActionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MapActionTranslator.java @@ -27,7 +27,7 @@ public class MapActionTranslator extends ActionTranslator<MapAction> { private MapActionTranslation(MapAction action) { clazz = "MapAlarmValues"; Default = action.getMapDefaultValue(); - field = action.getFromValue(); + field = action.fromValue(); toField = action.getTarget(); map = action.transformToMap(); } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MappingRulesTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MappingRulesTranslator.java index 91a1ab0..cefb429 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MappingRulesTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MappingRulesTranslator.java @@ -1,9 +1,11 @@ package org.onap.sdc.dcae.rule.editor.translators; -import java.util.List; -import java.util.stream.Collectors; - import org.onap.sdc.dcae.composition.restmodels.ruleeditor.MappingRules; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Rule; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; + +import java.util.*; +import java.util.stream.Collectors; public class MappingRulesTranslator implements IRuleElementTranslator<MappingRules> { @@ -17,15 +19,14 @@ public class MappingRulesTranslator implements IRuleElementTranslator<MappingRul } private RuleTranslator ruleTranslator = RuleTranslator.getInstance(); + private ConditionTranslator conditionTranslator = ConditionTranslator.getInstance(); public Object translateToHpJson(MappingRules mappingRules) { return new MappingRulesTranslation(mappingRules); } - public Object translateToHpJson(MappingRules mappingRules, String entryPointPhaseName, String lastPhaseName, String runPhase) { - // 1806 US349308 assign Vfcmt name as rule phaseName - mappingRules.getRules().forEach((k,v) -> v.setPhase(runPhase)); - return new MappingRulesTranslation(mappingRules, entryPointPhaseName, lastPhaseName, runPhase); + private List<Object> getPhaseTranslation(Collection<Rule> currentPhase) { + return currentPhase.stream().map(ruleTranslator::translateToHpJson).collect(Collectors.toList()); } private class MappingRulesTranslation { @@ -33,26 +34,50 @@ public class MappingRulesTranslator implements IRuleElementTranslator<MappingRul private List<Object> processing; private MappingRulesTranslation(MappingRules mappingRules) { - processing = mappingRules.getRules().values().stream().map(ruleTranslator::translateToHpJson).collect(Collectors.toList()); - } - - private MappingRulesTranslation(MappingRules mappingRules, String entryPointPhaseName, String lastPhaseName, String runPhase) { - this(mappingRules); - //hardcoded entry point processor - processing.add(0, new RunPhaseRuleTranslation(entryPointPhaseName, runPhase)); - //hardcoded map_publish processor - processing.add(new RunPhaseRuleTranslation(runPhase, lastPhaseName)); + String firstRunPhase; + // single phase + if(mappingRules.getRules().values().stream().noneMatch(r -> ValidationUtils.validateNotEmpty(r.getGroupId()))) { + processing = getPhaseTranslation(mappingRules.getRules().values()); + firstRunPhase = mappingRules.getRules().values().iterator().next().getPhase(); + } else { + // 1810 US427299 phase grouping - support user defined phase names + Map<String, List<Rule>> reorderByGroupId = mappingRules.getRules().values().stream().collect(Collectors.groupingBy(Rule::getGroupId, LinkedHashMap::new, Collectors.toList())); + List<String> phaseNames = new ArrayList<>(); + processing = new ArrayList<>(); + reorderByGroupId.forEach((k,v) -> { + String currentPhaseName = v.get(0).getPhase(); + // if phase name already triggered no need to call RunPhase processor again. + if(!processing.isEmpty() && !phaseNames.contains(currentPhaseName)) { + ((RuleTranslation)processing.get(processing.size()-1)).processors.add(new RunPhaseProcessorsTranslation(currentPhaseName)); + } + processing.addAll(getPhaseTranslation(v)); + phaseNames.add(currentPhaseName); + }); + firstRunPhase = phaseNames.get(0); + } + //hardcoded entry point processor - added as a phase unit + processing.add(0, new RunPhaseRuleTranslation(mappingRules.getEntryPhase(), firstRunPhase, mappingRules.getNotifyId())); + //hardcoded map_publish processor - added as processor unit to last phase unit + ((RuleTranslation)processing.get(processing.size()-1)).processors.add(new RunPhaseProcessorsTranslation(mappingRules.getPublishPhase())); } } + private class RunPhaseRuleTranslation extends RuleTranslation { private RunPhaseRuleTranslation(String phaseName, String runPhase) { phase = phaseName; + processors.add(new RunPhaseProcessorsTranslation(runPhase)); + } + + private RunPhaseRuleTranslation(String phaseName, String runPhase, String notifyOid) { + this(phaseName, runPhase); if("snmp_map".equals(phaseName)) { - processors.add(new SnmpConvertor()); + processors.add(0, new SnmpConvertor()); + } + if(ValidationUtils.validateTargetField(notifyOid)) { + filter = conditionTranslator.notifyOidTranslation(notifyOid); } - processors.add(new RunPhaseProcessorsTranslation(runPhase)); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RegexActionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RegexActionTranslator.java index 85fdf1d..f8da7cb 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RegexActionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RegexActionTranslator.java @@ -22,9 +22,9 @@ public class RegexActionTranslator extends ActionTranslator<BaseCopyAction> { private RegexCopyActionTranslation(BaseCopyAction action) { clazz = "ExtractText"; - regex = action.getRegexValue(); + regex = action.regexValue(); field = action.getTarget(); - value = action.getFromValue(); + value = action.fromValue(); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ReplaceActionTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ReplaceActionTranslator.java index 3069df3..8087760 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ReplaceActionTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ReplaceActionTranslator.java @@ -24,9 +24,9 @@ public class ReplaceActionTranslator extends ActionTranslator<ReplaceTextAction> ReplaceActionTranslation(ReplaceTextAction action) { clazz = "ReplaceText"; - field = action.getFromValue(); - find = action.getFind(); - replace = action.getReplace(); + field = action.fromValue(); + find = action.find(); + replace = action.replace(); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RuleTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RuleTranslator.java index b98050d..bce3980 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RuleTranslator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RuleTranslator.java @@ -39,12 +39,18 @@ public class RuleTranslator implements IRuleElementTranslator<Rule> { private IRuleElementTranslator getConditionTranslator(BaseCondition condition){ return condition instanceof ConditionGroup ? ConditionGroupTranslator.getInstance() : - ValidationUtils.validateNotEmpty(OperatorTypeEnum.getTypeByName(((Condition)condition).getOperator()).getModifiedType()) ? FieldConditionTranslator.getInstance() : ConditionTranslator.getInstance(); + getSimpleConditionTranslator((Condition) condition); } + private IRuleElementTranslator getSimpleConditionTranslator(Condition condition) { + String conditionType = OperatorTypeEnum.getTypeByName(condition.getOperator()).getConditionType(); + return RuleEditorElementType.getElementTypeByName(conditionType).getTranslator(); + } + + private ActionTranslator getActionTranslator(BaseAction action) { ActionTypeEnum type = ActionTypeEnum.getTypeByName(action.getActionType()); - if(ActionTypeEnum.COPY == type && ValidationUtils.validateNotEmpty(((BaseCopyAction)action).getRegexValue())) { + if(ActionTypeEnum.COPY == type && ValidationUtils.validateNotEmpty(((BaseCopyAction)action).regexValue())) { return RegexActionTranslator.getInstance(); } return (ActionTranslator) RuleEditorElementType.getElementTypeByName(type.getType()).getTranslator(); diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/StringTransformTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/StringTransformTranslator.java new file mode 100644 index 0000000..de326d1 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/StringTransformTranslator.java @@ -0,0 +1,34 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.StringTransformAction; + +public class StringTransformTranslator extends ActionTranslator<StringTransformAction> { + + private static StringTransformTranslator stringTransformTranslator = new StringTransformTranslator(); + + public static StringTransformTranslator getInstance() { + return stringTransformTranslator; + } + + private StringTransformTranslator() { + } + + private class StringTransformTranslation extends ProcessorTranslation { + private String targetCase; + private String trim; + private String toField; + private String value; + + private StringTransformTranslation(StringTransformAction action) { + clazz = "StringTransform"; + targetCase = action.targetCase(); + trim = String.valueOf(action.trim()); + toField = action.getTarget(); + value = action.fromValue(); + } + } + + public Object translateToHpJson(StringTransformAction action) { + return new StringTransformTranslation(action); + } +}
\ No newline at end of file diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/TopoSearchTranslator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/TopoSearchTranslator.java new file mode 100644 index 0000000..005b005 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/TopoSearchTranslator.java @@ -0,0 +1,60 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Condition; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.TopoSearchAction; +import org.onap.sdc.dcae.rule.editor.enums.OperatorTypeEnum; +import org.onap.sdc.dcae.rule.editor.enums.RuleEditorElementType; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class TopoSearchTranslator extends ActionTranslator<TopoSearchAction> { + + private static TopoSearchTranslator topoSearchTranslator = new TopoSearchTranslator(); + + public static TopoSearchTranslator getInstance() { + return topoSearchTranslator; + } + + private TopoSearchTranslator() { + } + + private class TopoSearchTranslation extends ProcessorTranslation { + private String searchField; + private String searchValue; + private Object searchFilter; + private Map <String, Object> updates; + private List<String> enrichFields; + private String enrichPrefix; + + private TopoSearchTranslation(TopoSearchAction action) { + clazz = "TopoSearch"; + searchField = action.searchField(); + searchValue = action.searchValue(); + if(action.conditionalSearch()) { + searchFilter = getSimpleConditionTranslation(action.searchFilter()); + } + if(action.doEnrich()){ + enrichFields = action.enrichFields(); + enrichPrefix = action.enrichPrefix(); + } else { + updates = new LinkedHashMap<>(); + updates.putAll(action.updatesMap()); + updates.put("isEnriched", true); + } + } + } + + private Object getSimpleConditionTranslation(Condition condition) { + String conditionType = OperatorTypeEnum.getTypeByName(condition.getOperator()).getConditionType(); + IRuleElementTranslator<Condition> translator = RuleEditorElementType.getElementTypeByName(conditionType).getTranslator(); + return translator.translateToHpJson(condition); + } + + + public Object translateToHpJson(TopoSearchAction action) { + return new TopoSearchTranslation(action); + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/RulesPayloadUtils.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/RulesPayloadUtils.java index 33f9e92..8391d76 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/RulesPayloadUtils.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/RulesPayloadUtils.java @@ -2,6 +2,8 @@ package org.onap.sdc.dcae.rule.editor.utils; import java.util.List; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.common.onaplog.OnapLoggerError; import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; @@ -10,29 +12,39 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; public class RulesPayloadUtils { - private static Gson gson = new GsonBuilder().serializeNulls() - .registerTypeAdapter(BaseAction.class, new ActionDeserializer()) - .registerTypeAdapter(BaseCondition.class, new ConditionDeserializer()).create(); - public static Rule parsePayloadToRule(String payload) throws JsonParseException { - return gson.fromJson(payload, Rule.class); - } + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); - public static MappingRules parseMappingRulesArtifactPayload(String payload) throws JsonParseException { - return gson.fromJson(payload, MappingRules.class); - } + private static Gson gson = new GsonBuilder().serializeNulls() + .registerTypeAdapter(BaseAction.class, new ActionDeserializer()) + .registerTypeAdapter(BaseCondition.class, new ConditionDeserializer()).create(); - public static SchemaInfo extractInfoFromDescription(Artifact rulesArtifact) { - try { - return gson.fromJson(rulesArtifact.getArtifactDescription(), SchemaInfo.class); - }catch (JsonParseException e) { - return null; - } - } + private RulesPayloadUtils(){} - public static String buildSchemaAndRulesResponse(String payload, List<EventTypeDefinitionUI> schema) { - return "{\"schema\":"+gson.toJson(schema)+","+payload.replaceFirst("\\{", ""); + public static Rule parsePayloadToRule(String payload) { + return gson.fromJson(payload, Rule.class); + } + + public static MappingRules parseMappingRulesArtifactPayload(String payload) { + return gson.fromJson(payload, MappingRules.class); + } + + public static MappingRulesResponse parsePayloadToMappingRules(String payload) { + return gson.fromJson(payload, MappingRulesResponse.class); } + public static SchemaInfo extractInfoFromDescription(Artifact rulesArtifact) { + try { + return gson.fromJson(rulesArtifact.getArtifactDescription(), SchemaInfo.class); + }catch (JsonParseException e) { + errLogger.log(LogLevel.ERROR, RulesPayloadUtils.class.getName(), "Exception thrown while parsing rule artifact description: {}", e); + return null; + } + } + + public static String buildSchemaAndRulesResponse(String payload, List<EventTypeDefinitionUI> schema) { + return "{\"schema\":"+gson.toJson(schema)+","+payload.replaceFirst("\\{", ""); + } + } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/ValidationUtils.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/ValidationUtils.java index 7a3b206..fd5e954 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/ValidationUtils.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/ValidationUtils.java @@ -14,7 +14,4 @@ public class ValidationUtils { public static boolean validateTargetField(String value) { return validateNotEmpty(value) && !EXPLICIT_EMPTY.equals(value); } - - - } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/BaseActionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/BaseActionValidator.java new file mode 100644 index 0000000..18a1291 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/BaseActionValidator.java @@ -0,0 +1,20 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseAction; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; + +import java.util.List; + +public abstract class BaseActionValidator<A extends BaseAction> implements IRuleElementValidator<A> { + + public boolean validate(A action, List<ResponseFormat> errors) { + if(!ValidationUtils.validateNotEmpty(action.getId())) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_RULE_FORMAT, "", "missing action id")); + return false; + } + return true; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/BaseConditionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/BaseConditionValidator.java new file mode 100644 index 0000000..896648a --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/BaseConditionValidator.java @@ -0,0 +1,20 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseCondition; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; + +import java.util.List; + +public abstract class BaseConditionValidator<C extends BaseCondition> implements IRuleElementValidator<C> { + + public boolean validate(C condition, List<ResponseFormat> errors) { + if(!ValidationUtils.validateNotEmpty(condition.getLevel()) || !ValidationUtils.validateNotEmpty(condition.getId()) || !ValidationUtils.validateNotEmpty(condition.getName())) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_RULE_FORMAT, "", "missing condition information")); + return false; + } + return true; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ClearActionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ClearActionValidator.java index 8be49b5..3991bb2 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ClearActionValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ClearActionValidator.java @@ -4,10 +4,11 @@ import org.onap.sdc.dcae.composition.restmodels.ruleeditor.UnaryFieldAction; import org.onap.sdc.dcae.errormng.ActionStatus; import org.onap.sdc.dcae.errormng.ErrConfMgr; import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; import java.util.List; -public class ClearActionValidator implements IRuleElementValidator<UnaryFieldAction> { +public class ClearActionValidator extends BaseActionValidator<UnaryFieldAction> { private static ClearActionValidator clearActionValidator = new ClearActionValidator(); @@ -17,11 +18,12 @@ public class ClearActionValidator implements IRuleElementValidator<UnaryFieldAct private ClearActionValidator(){} + @Override public boolean validate(UnaryFieldAction action, List<ResponseFormat> errors) { - if(action.getFromValues().isEmpty()) { + if(action.fromValues().isEmpty() || !action.fromValues().stream().allMatch(ValidationUtils::validateNotEmpty)) { errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from", action.getActionType(), action.strippedTarget())); return false; } - return true; + return super.validate(action, errors); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConcatActionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConcatActionValidator.java index 956ac51..934dea5 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConcatActionValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConcatActionValidator.java @@ -20,7 +20,7 @@ public class ConcatActionValidator extends CopyActionValidator<BaseCopyAction> { @Override protected boolean validateFromValue(BaseCopyAction action, List<ResponseFormat> errors) { - if(!ValidationUtils.validateNotEmpty(action.getFromValue()) || 2 > action.getFromValues().size()) { + if(!ValidationUtils.validateNotEmpty(action.fromValue()) || 2 > action.fromValues().size()) { errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_CONCAT_VALUE, null, action.getTarget())); return false; } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionGroupValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionGroupValidator.java index 995a817..0a420d9 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionGroupValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionGroupValidator.java @@ -11,7 +11,7 @@ import org.springframework.util.CollectionUtils; import java.util.List; -public class ConditionGroupValidator implements IRuleElementValidator<ConditionGroup> { +public class ConditionGroupValidator extends BaseConditionValidator<ConditionGroup> { private static ConditionGroupValidator conditionGroupValidator = new ConditionGroupValidator(); @@ -21,8 +21,9 @@ public class ConditionGroupValidator implements IRuleElementValidator<ConditionG private ConditionGroupValidator(){} + @Override public boolean validate(ConditionGroup condition, List<ResponseFormat> errors) { - boolean valid = true; + boolean valid = super.validate(condition, errors); if(!ValidationUtils.validateNotEmpty(condition.getType()) || null == ConditionTypeEnum.getTypeByName(condition.getType())) { valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_GROUP_CONDITION, null, condition.getType())); diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionValidator.java index 1b4ae94..9ba4479 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionValidator.java @@ -10,7 +10,7 @@ import org.springframework.util.CollectionUtils; import java.util.List; -public class ConditionValidator implements IRuleElementValidator<Condition> { +public class ConditionValidator extends BaseConditionValidator<Condition> { private static ConditionValidator conditionValidator = new ConditionValidator(); @@ -20,19 +20,26 @@ public class ConditionValidator implements IRuleElementValidator<Condition> { private ConditionValidator(){} + @Override public boolean validate(Condition condition, List<ResponseFormat> errors) { + return validateConditionalAction(condition, errors) && super.validate(condition, errors); + } + + + public boolean validateConditionalAction(Condition condition, List<ResponseFormat> errors) { boolean valid = true; if(!ValidationUtils.validateNotEmpty(condition.getLeft())) { valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_OPERAND, null, "left")); } - if(CollectionUtils.isEmpty(condition.getRight())) { + OperatorTypeEnum operatorTypeEnum = OperatorTypeEnum.getTypeByName(condition.getOperator()); + if(null == operatorTypeEnum) { valid = false; - errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_OPERAND, null, "right")); + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_OPERATOR, null, condition.getOperator())); } - if(!ValidationUtils.validateNotEmpty(condition.getOperator()) || null == OperatorTypeEnum.getTypeByName(condition.getOperator())) { + if(OperatorTypeEnum.ASSIGNED != operatorTypeEnum && OperatorTypeEnum.UNASSIGNED != operatorTypeEnum && (condition.getRight().isEmpty() || !condition.getRight().stream().allMatch(ValidationUtils::validateNotEmpty))) { valid = false; - errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_OPERATOR, null, condition.getOperator())); + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_OPERAND, null, "right")); } return valid; } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/CopyActionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/CopyActionValidator.java index 74102a6..42d86ae 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/CopyActionValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/CopyActionValidator.java @@ -8,7 +8,7 @@ import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; import java.util.List; -public class CopyActionValidator<A extends BaseCopyAction> implements IRuleElementValidator<A> { +public class CopyActionValidator<A extends BaseCopyAction> extends BaseActionValidator<A> { private static CopyActionValidator copyActionValidator = new CopyActionValidator(); @@ -18,6 +18,7 @@ public class CopyActionValidator<A extends BaseCopyAction> implements IRuleEleme CopyActionValidator(){} + @Override public boolean validate(A action, List<ResponseFormat> errors) { // validate from is populated @@ -27,14 +28,19 @@ public class CopyActionValidator<A extends BaseCopyAction> implements IRuleEleme valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "target", action.getActionType(), action.getTarget())); } - return valid; + return valid && super.validate(action, errors); } protected boolean validateFromValue(A action, List<ResponseFormat> errors) { - if(!ValidationUtils.validateNotEmpty(action.getFromValue())) { + if(!ValidationUtils.validateNotEmpty(action.fromValue())) { errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from", action.getActionType(), action.getTarget())); return false; } + //1810 US423851 validate imported input + if(!ValidationUtils.validateNotEmpty(action.regexState())) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_RULE_FORMAT, "", "missing regex state field")); + return false; + } return true; } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/DateFormatterValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/DateFormatterValidator.java index 19af40c..2776c8b 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/DateFormatterValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/DateFormatterValidator.java @@ -20,19 +20,19 @@ public class DateFormatterValidator extends CopyActionValidator<DateFormatterAct @Override public boolean validate(DateFormatterAction action, List<ResponseFormat> errors) { boolean valid = super.validate(action, errors); - if(!ValidationUtils.validateNotEmpty(action.getFromFormat())){ + if(!ValidationUtils.validateNotEmpty(action.fromFormat())){ valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from format", action.getActionType(), action.getTarget())); } - if(!ValidationUtils.validateNotEmpty(action.getFromTz())){ + if(!ValidationUtils.validateNotEmpty(action.fromTz())){ valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from timezone", action.getActionType(), action.getTarget())); } - if(!ValidationUtils.validateNotEmpty(action.getToFormat())){ + if(!ValidationUtils.validateNotEmpty(action.toFormat())){ valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "to format", action.getActionType(), action.getTarget())); } - if(!ValidationUtils.validateNotEmpty(action.getToTz())){ + if(!ValidationUtils.validateNotEmpty(action.toTz())){ valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "to timezone", action.getActionType(), action.getTarget())); } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/HpMetricValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/HpMetricValidator.java new file mode 100644 index 0000000..7bd382c --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/HpMetricValidator.java @@ -0,0 +1,29 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.HpMetricAction; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; + +import java.util.List; + +public class HpMetricValidator extends BaseActionValidator<HpMetricAction> { + + private static HpMetricValidator hpMetricValidator = new HpMetricValidator(); + + public static HpMetricValidator getInstance() { + return hpMetricValidator; + } + + private HpMetricValidator(){} + + @Override + public boolean validate(HpMetricAction action, List<ResponseFormat> errors) { + if(!ValidationUtils.validateNotEmpty(action.getSelectedHpMetric())){ + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "HP Metric", action.getActionType(), action.strippedTarget())); + return false; + } + return super.validate(action, errors); + } +}
\ No newline at end of file diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogEventValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogEventValidator.java index 1bbf07a..96393dd 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogEventValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogEventValidator.java @@ -8,7 +8,7 @@ import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; import java.util.List; -public class LogEventValidator implements IRuleElementValidator<LogEventAction> { +public class LogEventValidator extends BaseActionValidator<LogEventAction> { private static LogEventValidator logEventValidator = new LogEventValidator(); @@ -16,13 +16,14 @@ public class LogEventValidator implements IRuleElementValidator<LogEventAction> return logEventValidator; } - LogEventValidator(){} + private LogEventValidator(){} + @Override public boolean validate(LogEventAction action, List<ResponseFormat> errors) { - if(!ValidationUtils.validateNotEmpty(action.getTitle())){ + if(!ValidationUtils.validateNotEmpty(action.logTitle())){ errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "title", action.getActionType(), action.strippedTarget())); return false; } - return true; + return super.validate(action, errors); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogTextValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogTextValidator.java index 711692f..45c04db 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogTextValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/LogTextValidator.java @@ -8,7 +8,7 @@ import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; import java.util.List; -public class LogTextValidator implements IRuleElementValidator<LogTextAction> { +public class LogTextValidator extends BaseActionValidator<LogTextAction> { private static LogTextValidator logTextValidator = new LogTextValidator(); @@ -16,13 +16,14 @@ public class LogTextValidator implements IRuleElementValidator<LogTextAction> { return logTextValidator; } - LogTextValidator(){} + private LogTextValidator(){} + @Override public boolean validate(LogTextAction action, List<ResponseFormat> errors) { - if(!ValidationUtils.validateNotEmpty(action.getText())){ + if(!ValidationUtils.validateNotEmpty(action.logText())){ errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "text", action.getActionType(), action.strippedTarget())); return false; } - return true; + return super.validate(action, errors); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MapActionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MapActionValidator.java index 130e428..64c2088 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MapActionValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MapActionValidator.java @@ -46,6 +46,6 @@ public class MapActionValidator extends CopyActionValidator<MapAction> { } private boolean validateMapValues(MapAction action) { - return action.transformToMap().entrySet().stream().noneMatch(p -> !ValidationUtils.validateNotEmpty(p.getKey()) || !ValidationUtils.validateNotEmpty(p.getValue())); + return action.transformToMap().entrySet().stream().allMatch(p -> ValidationUtils.validateNotEmpty(p.getKey()) && ValidationUtils.validateNotEmpty(p.getValue())); } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MappingRulesValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MappingRulesValidator.java new file mode 100644 index 0000000..90fda4d --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MappingRulesValidator.java @@ -0,0 +1,73 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.MappingRules; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Rule; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; +import org.onap.sdc.dcae.ves.VesStructureLoader; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class MappingRulesValidator implements IRuleElementValidator<MappingRules> { + + private RuleValidator ruleValidator = RuleValidator.getInstance(); + + private static MappingRulesValidator mappingRulesValidator = new MappingRulesValidator(); + + public static MappingRulesValidator getInstance() { + return mappingRulesValidator; + } + + private MappingRulesValidator(){} + + public boolean validate(MappingRules rules, List<ResponseFormat> errors) { + return validateVersionAndType(rules, errors) && validateImportedGroupDefinitions(rules, errors) && rules.getRules().values().stream().map(r -> ruleValidator.validate(r, errors)) + .reduce(true, (x,y) -> x && y); + // TODO consider using 'allMatch' which will stop on the first error + } + + private boolean validateVersionAndType(MappingRules rules, List<ResponseFormat> errors) { + Map<String, Set<String>> supportedVersions = VesStructureLoader.getAvailableVersionsAndEventTypes(); + boolean valid = ValidationUtils.validateNotEmpty(rules.getVersion()) && supportedVersions.containsKey(rules.getVersion()) && ValidationUtils.validateNotEmpty(rules.getEventType()) && supportedVersions.get(rules.getVersion()).contains(rules.getEventType()); + errLogger.log(LogLevel.INFO, this.getClass().getName(), "validate mapping rules fields: eventType/version {}", valid); + if(!valid) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.VES_SCHEMA_NOT_FOUND, null)); + } + return valid; + } + + private boolean validateImportedGroupDefinitions(MappingRules rules, List<ResponseFormat> errors) { + boolean valid = !rules.isEmpty() && (rules.getRules().values().stream().noneMatch(r -> ValidationUtils.validateNotEmpty(r.getGroupId()) || ValidationUtils.validateNotEmpty(r.getPhase())) || validateGroupDefinitions(rules)); + errLogger.log(LogLevel.INFO, this.getClass().getName(), "validate group definitions {}", valid); + if(!valid) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_RULE_FORMAT, null, "invalid phase definitions")); + } + return valid; + } + + private boolean validateGroupDefinitions(MappingRules rules) { + return rules.getRules().values().stream().allMatch(r -> ValidationUtils.validateNotEmpty(r.getGroupId()) && ValidationUtils.validateNotEmpty(r.getPhase())) + && rules.getRules().values().stream().collect(Collectors.groupingBy(Rule::getGroupId, Collectors.mapping(Rule::getPhase, Collectors.toSet()))).values().stream().allMatch(p -> 1 == p.size()); + } + + + public boolean validateTranslationPhaseNames(MappingRules rules, List<ResponseFormat> errors) { + boolean valid = true; + Set<String> phases = rules.getRules().values().stream().map(Rule::getPhase).collect(Collectors.toSet()); + if(phases.contains(rules.getEntryPhase())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.TRANSLATE_FAILED, null, "entry phase name already exists")); + } + if(phases.contains(rules.getPublishPhase())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.TRANSLATE_FAILED, null, "publish phase name already exists")); + } + return valid; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ReplaceActionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ReplaceActionValidator.java index d9aea82..1f879f6 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ReplaceActionValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ReplaceActionValidator.java @@ -8,7 +8,7 @@ import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; import java.util.List; -public class ReplaceActionValidator implements IRuleElementValidator<ReplaceTextAction> { +public class ReplaceActionValidator extends BaseActionValidator<ReplaceTextAction> { private static ReplaceActionValidator replaceActionValidator = new ReplaceActionValidator(); @@ -19,16 +19,16 @@ public class ReplaceActionValidator implements IRuleElementValidator<ReplaceText private ReplaceActionValidator(){} public boolean validate(ReplaceTextAction action, List<ResponseFormat> errors) { - boolean valid = true; - if(!ValidationUtils.validateNotEmpty(action.getFromValue())) { + boolean valid = super.validate(action, errors); + if(!ValidationUtils.validateNotEmpty(action.fromValue())) { valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from", action.getActionType(), action.strippedTarget())); } - if(!ValidationUtils.validateNotEmpty(action.getFind())) { + if(!ValidationUtils.validateNotEmpty(action.find())) { valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "find", action.getActionType(), action.strippedTarget())); } - if(!ValidationUtils.validateNotEmpty(action.getReplace())) { + if(!ValidationUtils.validateNotEmpty(action.replace())) { valid = false; errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "replace", action.getActionType(), action.strippedTarget())); } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/RuleValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/RuleValidator.java index 33e1b33..5f577c8 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/RuleValidator.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/RuleValidator.java @@ -21,9 +21,11 @@ public class RuleValidator implements IRuleElementValidator<Rule> { private RuleValidator(){} public boolean validate(Rule rule, List<ResponseFormat> errors) { - boolean valid = true; - if(rule.isConditionalRule()) { - valid = getConditionValidator(rule.getCondition()).validate(rule.getCondition(), errors); + boolean valid = !rule.isConditionalRule() || getConditionValidator(rule.getCondition()).validate(rule.getCondition(), errors); + // 1810 US427299 phase grouping - support user defined phase names + if(ValidationUtils.validateNotEmpty(rule.getGroupId()) && !ValidationUtils.validateNotEmpty(rule.getPhase())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_RULE_FORMAT, "", "please define group name")); } if(!ValidationUtils.validateNotEmpty(rule.getDescription())) { valid = false; diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/StringTransformValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/StringTransformValidator.java new file mode 100644 index 0000000..a53b3f2 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/StringTransformValidator.java @@ -0,0 +1,38 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.StringTransformAction; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; + +import java.util.List; + +public class StringTransformValidator extends BaseActionValidator<StringTransformAction> { + + private static StringTransformValidator stringTransformValidator = new StringTransformValidator(); + + public static StringTransformValidator getInstance() { + return stringTransformValidator; + } + + private StringTransformValidator(){} + + @Override + public boolean validate(StringTransformAction action, List<ResponseFormat> errors) { + boolean valid = super.validate(action, errors); + if(!ValidationUtils.validateNotEmpty(action.targetCase())){ + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "target case", action.getActionType(), action.getTarget())); + } + if (!ValidationUtils.validateTargetField(action.getTarget())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "target", action.getActionType(), action.getTarget())); + } + if (!ValidationUtils.validateTargetField(action.startValue())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "value", action.getActionType(), action.getTarget())); + } + return valid; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/TopoSearchValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/TopoSearchValidator.java new file mode 100644 index 0000000..1abc2d8 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/TopoSearchValidator.java @@ -0,0 +1,69 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.TopoSearchAction; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; + +import java.util.List; + +public class TopoSearchValidator extends BaseActionValidator<TopoSearchAction> { + + private static TopoSearchValidator topoSearchValidator = new TopoSearchValidator(); + + public static TopoSearchValidator getInstance() { + return topoSearchValidator; + } + + private TopoSearchValidator() { + } + + private ConditionValidator conditionValidator = ConditionValidator.getInstance(); + + @Override + public boolean validate(TopoSearchAction action, List<ResponseFormat> errors) { + + boolean valid = super.validate(action, errors); + if (action.conditionalSearch() && !conditionValidator.validateConditionalAction(action.searchFilter(), errors)) { + valid = false; + } + if (!ValidationUtils.validateNotEmpty(action.searchField())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "search field", action.getActionType(), action.strippedTarget())); + } + if (!ValidationUtils.validateNotEmpty(action.searchValue())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "search value", action.getActionType(), action.strippedTarget())); + } + return validateEnrichOrUpdates(action, errors) && valid; + } + + + private boolean validateEnrichOrUpdates(TopoSearchAction action, List<ResponseFormat> errors) { + if (!action.doEnrich()) { + return validateUpdatesMap(action, errors); + } + if (action.enrichFields().isEmpty() || !action.enrichFields().stream().allMatch(ValidationUtils::validateNotEmpty)) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "enrich fields", action.getActionType(), action.strippedTarget())); + return false; + } + return true; + } + + private boolean validateUpdatesMap(TopoSearchAction action, List<ResponseFormat> errors) { + boolean valid = true; + try { + if (!action.updatesMap().entrySet().stream().allMatch(p -> ValidationUtils.validateNotEmpty(p.getKey()) && ValidationUtils.validateNotEmpty(p.getValue()))) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "key/value", action.getActionType(), action.strippedTarget())); + } + } catch (IllegalStateException err) { + valid = false; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "updates validation error: {}", err); + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.DUPLICATE_KEY, null)); + } + return valid; + } +} diff --git a/dcaedt_be/src/main/webapp/WEB-INF/config/dcae-be/application.properties b/dcaedt_be/src/main/webapp/WEB-INF/config/dcae-be/application.properties index b833be9..2bb725d 100644 --- a/dcaedt_be/src/main/webapp/WEB-INF/config/dcae-be/application.properties +++ b/dcaedt_be/src/main/webapp/WEB-INF/config/dcae-be/application.properties @@ -33,6 +33,12 @@ compositionConfig.flowTypes={"Syslog":{"entryPointPhaseName":"syslog_map","lastP "SNMP PM Poller":{"entryPointPhaseName":"docker_map","lastPhaseName":"docker_publilsh"},\ "Discovery and MIB Poller":{"entryPointPhaseName":"snmp_pm_map","lastPhaseName":"snmp_pm_publish"},\ "Nagios docker MSE":{"entryPointPhaseName":"docker_map","lastPhaseName":"docker_publish"},\ + "Discovery Poller":{"entryPointPhaseName":"snmp_pm_map","lastPhaseName":"snmp_pm_publish"},\ + "MIB Poller":{"entryPointPhaseName":"snmp_pm_map","lastPhaseName":"snmp_pm_publish"},\ + "VES Fault SE":{"entryPointPhaseName":"ves_fault_map","lastPhaseName":"ves_fault_publish"},\ + "Docker Supplement":{"entryPointPhaseName":"docker_map","lastPhaseName":"docker_publish"},\ + "Docker Enrich":{"entryPointPhaseName":"docker_map","lastPhaseName":"docker_publish"},\ + "VES Collector":{"entryPointPhaseName":"sam_collector_map","lastPhaseName":"sam_collector_publish"},\ "VES Fault":{"entryPointPhaseName":"ves_fault_map","lastPhaseName":"ves_fault_publish"},\ "VES Heartbeat":{"entryPointPhaseName":"ves_heartbeat_map","lastPhaseName":"ves_heartbeat_publish"},\ "VES Measurement":{"entryPointPhaseName":"ves_measurement_map","lastPhaseName":"ves_measurement_publish"},\ diff --git a/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogicTest.java b/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogicTest.java index ac12f8d..25bf1f1 100644 --- a/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogicTest.java +++ b/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/CompositionCatalogBusinessLogicTest.java @@ -7,68 +7,84 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.sdc.dcae.catalog.asdc.ASDCCatalog; +import org.onap.sdc.dcae.catalog.asdc.ASDCException; import org.onap.sdc.dcae.catalog.engine.CatalogController; import org.onap.sdc.dcae.catalog.engine.CatalogError; import org.onap.sdc.dcae.catalog.engine.CatalogResponse; +import org.onap.sdc.dcae.client.ISdcClient; +import org.onap.sdc.dcae.composition.restmodels.canvas.DcaeComponentCatalog; +import org.onap.sdc.dcae.composition.restmodels.sdc.Resource; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.errormng.ErrorConfigurationLoader; +import org.onap.sdc.dcae.errormng.RequestError; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.errormng.ServiceException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.context.request.async.DeferredResult; -import java.net.URI; +import java.util.Arrays; +import java.util.List; import java.util.UUID; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; public class CompositionCatalogBusinessLogicTest { + private final String REQUEST_ID = "123456"; + private ASDCCatalog asdcCatalog = new ASDCCatalog(); + @Mock private CatalogController catalogController; - private ASDCCatalog asdcCatalog = new ASDCCatalog(URI.create("https://mockUri:8888#mock")); + @Mock + private ISdcClient sdcRestClient; @InjectMocks - private CompositionCatalogBusinessLogic compositionCatalogBusinessLogic = new CompositionCatalogBusinessLogic(); + private CompositionCatalogBusinessLogic compositionCatalogBusinessLogic; @Before public void init() throws JSONException { MockitoAnnotations.initMocks(this); - when(catalogController.getCatalog(any())).thenReturn(asdcCatalog); + when(catalogController.getCatalog()).thenReturn(asdcCatalog); + new ErrorConfigurationLoader(System.getProperty("user.dir")+"/src/main/webapp/WEB-INF"); + mockCatalog(); } @Test - public void getItemsTest() { - compositionCatalogBusinessLogic.getItems(null).getResult(); - verify(catalogController, times(7)).patchData(any(), any()); + public void getCatalogTest() { + DcaeComponentCatalog catalog = compositionCatalogBusinessLogic.getCatalog(REQUEST_ID); + assertEquals(1, catalog.getElements().size()); + assertEquals(1, catalog.getElements().get(0).getItems().size()); } - @Test - public void getItemByIdNoSuchFolderFailureTest() { - DeferredResult<CatalogResponse> result = compositionCatalogBusinessLogic.getItemById(null, "No Such Category"); - verify(catalogController).getCatalog(any()); - verify(catalogController, times(0)).patchData(any(), any()); - CatalogError error = (CatalogError)result.getResult(); - assertEquals("{\"exception\":\"java.lang.RuntimeException: No such folder No Such Category\",\"message\":\"Catalog API failed\"}", error.getError()); - } @Test public void getModelByIdInvalidUuidFailureTest() { - try { - compositionCatalogBusinessLogic.getModelById(null, "Invalid-UUID"); - } catch (IllegalArgumentException e) { - assertEquals("Invalid UUID string: Invalid-UUID", e.getMessage()); - verify(catalogController).getCatalog(any()); - verify(catalogController, times(0)).patchData(any(), any()); - } + ResponseEntity result = compositionCatalogBusinessLogic.getModelById(REQUEST_ID, "invalidId"); + assertEquals("Invalid UUID string: invalidId", ((ResponseFormat)result.getBody()).getNotes()); } @Test public void getTypeInfoModelNotLoadedFailureTest() { - // this is pretty awful. you cannot call 'getTypeInfo' unless it is preceded by a 'getModel' call of the containing model, so that the 'catalogs' item is populated by the container model id. String uuid = UUID.randomUUID().toString(); - DeferredResult<CatalogResponse> result = compositionCatalogBusinessLogic.getTypeInfo(null, uuid, "tosca.nodes.Root"); - verify(catalogController).getCatalog(any()); - verify(catalogController, times(0)).patchData(any(), any()); - CatalogError error = (CatalogError)result.getResult(); - assertEquals("{\"exception\":\"java.lang.Exception: No catalog available for resource " + uuid + ". You might want to fetch the model first.\",\"message\":\"Catalog API failed\"}", error.getError()); + // this is pretty awful. you cannot call 'getTypeInfo' unless it is preceded by a 'getModel' call of the containing model, so that the 'catalogs' item is populated by the container model id. + ResponseEntity result = compositionCatalogBusinessLogic.getTypeInfo(uuid, "tosca.nodes.Root"); + assertEquals("No catalog available for resource " + uuid + ". You might want to fetch the model first.", ((ResponseFormat)result.getBody()).getNotes()); + } + + private void mockCatalog() { + String subcategory1 = "subcategory1"; + String subcategory2 = "subcategory2"; + List<Resource> resources = Arrays.asList(buildVf(subcategory1, DcaeBeConstants.LifecycleStateEnum.CERTIFIED.name()), buildVf(subcategory1, DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()), buildVf(subcategory2, DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())); + when(sdcRestClient.getResources(anyString(), anyString(), eq(null), anyString())).thenReturn(resources); + } + + private Resource buildVf(String subcategory, String lifecycleState) { + Resource vf = new Resource(); + vf.setLifecycleState(lifecycleState); + vf.setSubCategory(subcategory); + return vf; } }
\ No newline at end of file diff --git a/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogicTest.java b/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogicTest.java index d421113..3c6d1dd 100644 --- a/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogicTest.java +++ b/dcaedt_be/src/test/java/org/onap/sdc/dcae/composition/impl/RuleEditorBusinessLogicTest.java @@ -1,31 +1,37 @@ package org.onap.sdc.dcae.composition.impl; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.onap.sdc.dcae.catalog.asdc.ASDCException; import org.onap.sdc.dcae.client.ISdcClient; -import org.onap.sdc.dcae.composition.CompositionConfig; -import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; -import org.onap.sdc.dcae.composition.restmodels.sdc.*; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.MappingRules; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Rule; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.SchemaInfo; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; import org.onap.sdc.dcae.composition.util.DcaeBeConstants; import org.onap.sdc.dcae.errormng.ErrorConfigurationLoader; +import org.onap.sdc.dcae.errormng.RequestError; import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.errormng.ServiceException; import org.onap.sdc.dcae.rule.editor.impl.RulesBusinessLogic; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.testng.Assert; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; public class RuleEditorBusinessLogicTest { // DEFAULT PROPERTIES - private String justAString = "aStringForAllSeasons"; + private String justAString = "aStringForAllSeasons"; private String userId = "gc786h"; private String vfcmtUuid = "26e8d4b5-f087-4821-a75a-0b9514b5a7ab"; private String dcaeCompLabel = "dMp.DockerMap"; @@ -34,12 +40,10 @@ public class RuleEditorBusinessLogicTest { private String artifactUuid = "9b00ba74-da02-4706-8db0-ac3c11d1d47b"; private String configParam = "aaf_username"; private String requestId = "9a89b5c7-33b2-4f7e-a404-66bf4115f510"; - private String flowTypeName = "SNMP MSE"; private String ruleUuid = "sadsads"; private String categoryName = "Template"; private String resourceType = "VFCMT"; private String saveRulesJsonRequest = "{\n\"version\":\"4.1\",\n\"eventType\":\"syslogFields\",\n\"uid\":\"\",\n\"description\":\"sfasfsaf\",\n\"actions\":[\n{\n\"id\":\"6e0175a0-581f-11e8-82eb-53bb060b790a\",\n\"actionType\":\"copy\",\n\"from\":{\n\"value\":\"asfsf\",\n\"regex\":\"\",\n\"state\":\"closed\",\n\"values\":[\n{\n" + "\"value\":\"\"\n" + "},\n" + "{\n\"value\":\"\"\n}\n]\n},\n\"target\":\"event.commonEventHeader.eventType\",\n\"map\":{\n\"values\":[\n{\n\"key\":\"\",\n\"value\":\"\"\n}\n],\n\"haveDefault\":false,\n\"default\":\"\"\n},\n\"dateFormatter\":{\n\"fromFormat\":\"\",\n\"toFormat\":\"\",\n\"fromTimezone\":\"\",\n\"toTimezone\":\"\"\n},\n\"replaceText\":{\n\"find\":\"\",\n\"replace\":\"\"\n},\n\"logText\":{\n\"name\":\"\",\n\"level\":\"\",\n\"text\":\"\"\n},\n\"logEvent\":{\n\"title\":\"\"\n}\n}\n],\n\"condition\":null\n}"; - private String artifactJson = "{\n \"artifactName\":\"composition.yml\",\n \"artifactType\":\"DCAE_TOSCA\",\n \"artifactURL\":\"/sdc/v1/catalog/resources/c2877686-616a-48ca-a37b-7e311bf83adc/artifacts/9b00ba74-da02-4706-8db0-ac3c11d1d47b\",\n \"artifactDescription\":\"createReferenceArtifact\",\n \"artifactTimeout\":null,\n \"artifactChecksum\":\"MjhhYTAwOTIxZGZkMGMyMmFjYmEzYjI1NTIwYjA3YzM=\",\n \"artifactUUID\":\"9b00ba74-da02-4706-8db0-ac3c11d1d47b\",\n \"artifactVersion\":\"1\",\n \"generatedFromUUID\":null,\n \"artifactLabel\":\"servicereference\",\n \"artifactGroupType\":\"DEPLOYMENT\",\n \"payloadData\":null,\n \"description\":null\n" + "}"; private String defaultPayload = "{eventType:syslogFields,version:4.1,rules:{'test':{'version':'4.1'}}}"; @@ -47,9 +51,7 @@ public class RuleEditorBusinessLogicTest { private ISdcClient sdcClientMock = Mockito.mock(ISdcClient.class); private ResourceDetailed vfcmt = Mockito.mock(ResourceDetailed.class); private SchemaInfo schemaInfo = Mockito.mock(SchemaInfo.class); - private CompositionConfig compositionConfig = Mockito.mock(CompositionConfig.class); private RulesBusinessLogic rulesBusinessLogic = Mockito.mock(RulesBusinessLogic.class); - private CompositionConfig.FlowType flowType = Mockito.mock(CompositionConfig.FlowType.class); @InjectMocks private RuleEditorBusinessLogic ruleEditorBusinessLogic = new RuleEditorBusinessLogic(); @@ -67,11 +69,9 @@ public class RuleEditorBusinessLogicTest { when(vfcmt.getResourceType()).thenReturn(resourceType); when(vfcmt.getCategory()).thenReturn(categoryName); - when(ruleEditorBusinessLogic.getSdcRestClient().getResource(anyString(), anyString())).thenReturn(vfcmt); + when(sdcClientMock.getResource(anyString(), anyString())).thenReturn(vfcmt); when(schemaInfo.getVersion()).thenReturn("0.2"); - /* PowerMockito.doReturn(vs).when(VesStructureLoader.class); - when(vs.getEventListenerDefinitionByVersion(anyString())).thenReturn(null);*/ } @Test @@ -79,29 +79,55 @@ public class RuleEditorBusinessLogicTest { emulateMockListOfArtifacts(dcaeCompLabel, nId, configParam, true); - when(ruleEditorBusinessLogic.getSdcRestClient().getResourceArtifact(resourceUuid, artifactUuid, requestId)).thenReturn(defaultPayload); - when(rulesBusinessLogic.addOrEditRule(any(MappingRules.class), any(Rule.class))).thenReturn(true); + when(sdcClientMock.getResourceArtifact(resourceUuid, artifactUuid, requestId)).thenReturn(defaultPayload); + when(rulesBusinessLogic.addOrEditRule(any(MappingRules.class), any(Rule.class), anyBoolean())).thenReturn(true); + when(rulesBusinessLogic.validateGroupDefinitions(any(MappingRules.class), anyBoolean())).thenReturn(true); ResponseEntity result = ruleEditorBusinessLogic.saveRule(saveRulesJsonRequest, requestId, userId, vfcmtUuid, dcaeCompLabel, nId, configParam); assertEquals(200,result.getStatusCodeValue()); - Assert.assertTrue(result.getBody().toString().contains("6e0175a0-581f-11e8-82eb-53bb060b790a")); - verify(rulesBusinessLogic,times(1)).addOrEditRule(any(MappingRules.class), any(Rule.class)); + assertTrue(result.getBody().toString().contains("6e0175a0-581f-11e8-82eb-53bb060b790a")); + verify(rulesBusinessLogic,times(1)).addOrEditRule(any(MappingRules.class), any(Rule.class), anyBoolean()); } + @Test + public void test_exportRules_resourceNotFound() throws Exception { + RequestError requestError = new RequestError(); + requestError.setServiceException(new ServiceException("SVC4063", "", null)); + when(sdcClientMock.getResource(resourceUuid, requestId)).thenThrow(new ASDCException(HttpStatus.NOT_FOUND, requestError)); + + ResponseEntity result = ruleEditorBusinessLogic.downloadRules(vfcmtUuid, dcaeCompLabel, nId, configParam, requestId); + assertEquals(404,result.getStatusCodeValue()); + } + + + @Test + public void invalidRuleFormatImportRulesFailureTest() throws Exception { + String invalidInput = "{rules:[blahblahblah]}"; + String expectedError = "Error - Rule format is invalid: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 9 path $.rules[0]."; + ResponseEntity<ResponseFormat> result = ruleEditorBusinessLogic.importRules(invalidInput, requestId, userId, vfcmtUuid, dcaeCompLabel, nId, configParam); + assertEquals(400,result.getStatusCodeValue()); + assertEquals(expectedError, result.getBody().getRequestError().getServiceException().getFormattedErrorMessage()); + verify(rulesBusinessLogic, times(0)).validateImportedRules(any()); + verify(sdcClientMock, times(0)).getResource(anyString(), anyString()); + verify(sdcClientMock, times(0)).createResourceArtifact(anyString(), anyString(), any(), anyString()); + verify(sdcClientMock, times(0)).updateResourceArtifact(anyString(), anyString(), any(), anyString()); + verify(sdcClientMock, times(0)).changeResourceLifecycleState(anyString(), anyString(), anyString(), anyString(), anyString()); + } + @Test public void test_saveRules_artifactNotFound() throws Exception { emulateMockListOfArtifacts(dcaeCompLabel, nId, configParam, false); - when(rulesBusinessLogic.addOrEditRule(any(MappingRules.class), any(Rule.class))).thenReturn(true); + when(rulesBusinessLogic.addOrEditRule(any(MappingRules.class), any(Rule.class), anyBoolean())).thenReturn(true); String payload = "{eventType:syslogFields,version:4.1,rules:{'test':{'version':'4.1'}},\"nid\":\"n.1525864440166.30}"; when(ruleEditorBusinessLogic.getSdcRestClient().getResourceArtifact(anyString(),anyString(), anyString())).thenReturn(payload); ResponseEntity result = ruleEditorBusinessLogic.saveRule(saveRulesJsonRequest, requestId, userId, vfcmtUuid, dcaeCompLabel, nId, configParam); assertEquals(200,result.getStatusCodeValue()); - Assert.assertTrue(result.getBody().toString().contains("6e0175a0-581f-11e8-82eb-53bb060b790a")); - verify(rulesBusinessLogic,times(0)).addOrEditRule(any(MappingRules.class), any(Rule.class)); + assertTrue(result.getBody().toString().contains("6e0175a0-581f-11e8-82eb-53bb060b790a")); + verify(rulesBusinessLogic,times(0)).addOrEditRule(any(MappingRules.class), any(Rule.class), anyBoolean()); } @@ -116,7 +142,7 @@ public class RuleEditorBusinessLogicTest { assertEquals(400,result.getStatusCodeValue()); assertEquals("SVC6114",result.getBody().getRequestError().getServiceException().getMessageId()); assertEquals("DCAE component %1 not found in composition",result.getBody().getRequestError().getServiceException().getText()); - verify(rulesBusinessLogic,times(0)).addOrEditRule(any(MappingRules.class), any(Rule.class)); + verify(rulesBusinessLogic,times(0)).addOrEditRule(any(MappingRules.class), any(Rule.class), anyBoolean()); } @@ -125,12 +151,9 @@ public class RuleEditorBusinessLogicTest { emulateMockListOfArtifacts(dcaeCompLabel, nId, configParam, true); - when(ruleEditorBusinessLogic.getSdcRestClient().getResourceArtifact(resourceUuid, artifactUuid, requestId)) - .thenReturn(defaultPayload); - - ResponseEntity result = ruleEditorBusinessLogic.getRules(vfcmtUuid, dcaeCompLabel, nId, configParam, requestId); + ResponseEntity result = ruleEditorBusinessLogic.getRulesAndSchema(vfcmtUuid, dcaeCompLabel, nId, configParam, requestId); assertEquals(200,result.getStatusCodeValue()); - Assert.assertTrue(result.getBody().toString().contains("eventType:syslogFields,version:4.1,rules:{'test':{'version':'4.1'")); + assertTrue(result.getBody().toString().contains("eventType:syslogFields,version:4.1,rules:{'test':{'version':'4.1'")); } @@ -147,33 +170,13 @@ public class RuleEditorBusinessLogicTest { } - @Test - public void test_translate() throws Exception { - - emulateMockListOfArtifacts(dcaeCompLabel, nId, configParam, true); - - when(ruleEditorBusinessLogic.getSdcRestClient().getResourceArtifact(resourceUuid, artifactUuid, requestId)).thenReturn(defaultPayload); - Map<String, CompositionConfig.FlowType> flowTypeMap = new HashMap<>(); - flowTypeMap.put("SNMP MSE", flowType); - when(compositionConfig.getFlowTypesMap()).thenReturn(flowTypeMap); - when(compositionConfig.getFlowTypesMap().get("SNMP MSE").getEntryPointPhaseName()).thenReturn("testName"); - when(compositionConfig.getFlowTypesMap().get("SNMP MSE").getLastPhaseName()).thenReturn("testLastName"); - - when(rulesBusinessLogic.translateRules(any(MappingRules.class), anyString(), anyString(), anyString())).thenReturn("testLastName"); - ResponseEntity result = ruleEditorBusinessLogic.translateRules(vfcmtUuid, requestId, dcaeCompLabel, nId, configParam, flowTypeName); - verify(compositionConfig,times(6)).getFlowTypesMap(); - verify(rulesBusinessLogic,times(1)).translateRules(any(MappingRules.class), anyString(), anyString(), anyString()); - - assertEquals(200,result.getStatusCodeValue()); - - } @Test public void test_deleteRule() throws Exception { emulateMockListOfArtifacts(dcaeCompLabel, nId, configParam, true); - when(ruleEditorBusinessLogic.getSdcRestClient().getResourceArtifact(resourceUuid, artifactUuid, requestId)).thenReturn(defaultPayload); + when(sdcClientMock.getResourceArtifact(resourceUuid, artifactUuid, requestId)).thenReturn(defaultPayload); when(rulesBusinessLogic.deleteRule(any(MappingRules.class), anyString())).thenReturn(new Rule()); ResponseEntity result = ruleEditorBusinessLogic.deleteRule(userId, vfcmtUuid, dcaeCompLabel, nId, configParam, ruleUuid, requestId); @@ -181,18 +184,16 @@ public class RuleEditorBusinessLogicTest { } - @Test - public void test_getDefinition(){ - + @Test + public void test_deleteGroupOfRules() throws Exception { -/* - PowerMockito.mockStatic(VesStructureLoader.class); - when(VesStructureLoader.getEventListenerDefinitionByVersion(anyString())).thenReturn(null); -*/ + emulateMockListOfArtifacts(dcaeCompLabel, nId, configParam, true); + when(sdcClientMock.getResourceArtifact(resourceUuid, artifactUuid, requestId)).thenReturn(defaultPayload); + when(rulesBusinessLogic.deleteGroupOfRules(any(MappingRules.class), anyString())).thenReturn(Collections.singletonList(new Rule())); + ResponseEntity result = ruleEditorBusinessLogic.deleteGroupOfRules(userId, vfcmtUuid, dcaeCompLabel, nId, configParam, ruleUuid, requestId); + assertEquals(200,result.getStatusCodeValue()); + } - ResponseEntity res = ruleEditorBusinessLogic.getDefinition("4.1","syslogFields"); - - } private void emulateMockListOfArtifacts(String dcaeCompLabel, String nid, String configParam, boolean isApprovedArtifact) { List<Artifact> listOfArtifactCompositionYml = new ArrayList<>(); @@ -208,10 +209,10 @@ public class RuleEditorBusinessLogicTest { when(artifact.getArtifactType()).thenReturn("DCAE_TOSCA"); when(artifact.getArtifactUUID()).thenReturn(artifactUuid); when(artifact.getArtifactDescription()).thenReturn("createmapArtifact"); + when(artifact.getPayloadData()).thenReturn(defaultPayload); listOfArtifactCompositionYml.add(artifact); when(vfcmt.getArtifacts()).thenReturn(listOfArtifactCompositionYml); } - } diff --git a/dcaedt_be/src/test/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogicTest.java b/dcaedt_be/src/test/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogicTest.java index bc03632..3b7181d 100644 --- a/dcaedt_be/src/test/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogicTest.java +++ b/dcaedt_be/src/test/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogicTest.java @@ -5,23 +5,30 @@ import com.google.gson.GsonBuilder; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; import org.onap.sdc.dcae.errormng.ErrorConfigurationLoader; import org.onap.sdc.dcae.errormng.ResponseFormatManager; import org.onap.sdc.dcae.errormng.ServiceException; +import org.onap.sdc.dcae.rule.editor.validators.MappingRulesValidator; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; public class RulesBusinessLogicTest { private static Gson gson = new GsonBuilder() .registerTypeAdapter(BaseAction.class, new ActionDeserializer()) .registerTypeAdapter(BaseCondition.class, new ConditionDeserializer()).create(); + private String mockUiInput = "mockUiInput"; + private MappingRulesValidator mappingRulesValidator = Mockito.mock(MappingRulesValidator.class); + @InjectMocks private RulesBusinessLogic rulesBusinessLogic = new RulesBusinessLogic(); private ResponseFormatManager responseFormatManager = null; @@ -36,33 +43,57 @@ public class RulesBusinessLogicTest { @Test public void translateSingleRuleSingleCopyActionAddSnmpHeader() throws Exception { String expectedTranslation = "{\"processing\":[{\"phase\":\"snmp_map\",\"processors\":[{\"array\":\"varbinds\",\"datacolumn\":\"varbind_value\",\"keycolumn\":\"varbind_oid\",\"class\":\"SnmpConvertor\"}," - + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\"},\"class\":\"Set\"}]}," - + "{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\"},\"class\":\"Set\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; Rule rule = new Rule(); rule.setActions(new ArrayList<>()); rule.getActions().add(buildCopyAction("2.0","event.commonEventHeader.version")); rule.setDescription("description"); + rule.setPhase("phase_1"); MappingRules mr = new MappingRules(rule); - List<ServiceException> errors = rulesBusinessLogic.validateRules(mr); + mr.setEntryPhase("snmp_map"); + mr.setPublishPhase("map_publish"); + List<ServiceException> errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); assertTrue(errors.isEmpty()); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "snmp_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); + } + + @Test + public void translateSingleRuleSingleCopyActionWithNotifyOidFilter() throws Exception { + String expectedTranslation = "{\"processing\":[{\"phase\":\"foi_map\",\"filter\":{\"string\":\"${notify OID}\",\"value\":\"someValue\",\"class\":\"StartsWith\"},\"processors\":[{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]}," + + "{\"phase\":\"phase_1\",\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\"},\"class\":\"Set\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + Rule rule = new Rule(); + rule.setActions(new ArrayList<>()); + rule.getActions().add(buildCopyAction("2.0","event.commonEventHeader.version")); + rule.setDescription("description"); + rule.setPhase("phase_1"); + rule.setNotifyId("someValue"); + rule.setEntryPhase("foi_map"); + rule.setPublishPhase("map_publish"); + MappingRules mr = new MappingRules(rule); + List<ServiceException> errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); + assertTrue(errors.isEmpty()); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test public void translateSingleRuleSingleDateFormatterActionSnmpFlow() throws Exception { String expectedTranslation = "{\"processing\":[{\"phase\":\"snmp_map\",\"processors\":[{\"array\":\"varbinds\",\"datacolumn\":\"varbind_value\",\"keycolumn\":\"varbind_oid\",\"class\":\"SnmpConvertor\"}," - + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"fromFormat\":\"fromFormat\",\"fromTz\":\"fromTZ\",\"toField\":\"targetField\",\"toFormat\":\"toFormat\",\"toTz\":\"toTz\",\"value\":\"fromField\",\"class\":\"DateFormatter\"}]}," - + "{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"fromFormat\":\"fromFormat\",\"fromTz\":\"fromTZ\",\"toField\":\"targetField\",\"toFormat\":\"toFormat\",\"toTz\":\"toTz\",\"value\":\"fromField\",\"class\":\"DateFormatter\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; Rule rule = new Rule(); rule.setActions(new ArrayList<>()); rule.getActions().add(buildDateFormatterAction()); rule.setDescription("description"); + rule.setPhase("phase_1"); + rule.setNotifyId(""); + rule.setEntryPhase("snmp_map"); + rule.setPublishPhase("map_publish"); MappingRules mr = new MappingRules(rule); - List<ServiceException> errors = rulesBusinessLogic.validateRules(mr); + List<ServiceException> errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); assertTrue(errors.isEmpty()); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "snmp_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test @@ -70,12 +101,12 @@ public class RulesBusinessLogicTest { String expectedTranslation = "{\"processing\":[{\"phase\":\"snmp_map\",\"processors\":[{\"array\":\"varbinds\",\"datacolumn\":\"varbind_value\",\"keycolumn\":\"varbind_oid\",\"class\":\"SnmpConvertor\"}," + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\"," + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\",\"event.commonEventHeader.eventId\":\"${event.commonEventHeader.sourceName}_${eventGroup}\"},\"class\":\"Set\"}," - + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; MappingRules mr = new MappingRules(buildRuleWithMultipleCopyActions()); - List<ServiceException> errors = rulesBusinessLogic.validateRules(mr); + List<ServiceException> errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); assertTrue(errors.isEmpty()); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "snmp_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test @@ -85,36 +116,36 @@ public class RulesBusinessLogicTest { + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\",\"event.commonEventHeader.eventId\":\"${event.commonEventHeader.sourceName}_${eventGroup}\"},\"class\":\"Set\"}," + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"}]},{\"phase\":\"phase_1\"," + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\",\"event.commonEventHeader.eventId\":\"${event.commonEventHeader.sourceName}_${eventGroup}\"},\"class\":\"Set\"}," - + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; MappingRules mr = new MappingRules(buildRuleWithMultipleCopyActions()); mr.addOrReplaceRule(buildRuleWithMultipleCopyActions()); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "snmp_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test public void emptyStringTest() throws Exception { String expectedTranslation = "{\"processing\":[{\"phase\":\"snmp_map\",\"processors\":[{\"array\":\"varbinds\",\"datacolumn\":\"varbind_value\",\"keycolumn\":\"varbind_oid\",\"class\":\"SnmpConvertor\"}," - + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"map\":{\"\":\"\"},\"field\":\"\",\"toField\":\"mapTargetField\",\"default\":\"\",\"class\":\"MapAlarmValues\"}]}," - + "{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; - String ruleRequestBody = "{version:4.1,eventType:syslogFields,description:description,actions:[{actionType:map,from:{value:'\"\"'},target:mapTargetField,map:{values:[{key:'\"\"',value:'\"\"'}],haveDefault:true,default:'\"\"'}}]}"; + + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"map\":{\"\":\"\"},\"field\":\"\",\"toField\":\"mapTargetField\",\"default\":\"\",\"class\":\"MapAlarmValues\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + String ruleRequestBody = "{entryPhase:snmp_map,publishPhase:map_publish,phase:phase_1,version:4.1,eventType:syslogFields,description:description,actions:[{actionType:map,from:{value:'\"\"'},target:mapTargetField,map:{values:[{key:'\"\"',value:'\"\"'}],haveDefault:true,default:'\"\"'}}]}"; Rule myRule = gson.fromJson(ruleRequestBody, Rule.class); MappingRules mr = new MappingRules(myRule); - List<ServiceException> errors = rulesBusinessLogic.validateRules(mr); + List<ServiceException> errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); assertTrue(errors.isEmpty()); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "snmp_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test public void singleStringConditionTranslationTest() throws Exception { String expectedTranslation = "{\"processing\":[{\"phase\":\"syslog_map\",\"processors\":[{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"filter\":{\"string\":\"left\",\"value\":\"right\",\"class\":\"Contains\"}," + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\",\"event.commonEventHeader.eventId\":\"${event.commonEventHeader.sourceName}_${eventGroup}\"},\"class\":\"Set\"}," - + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; String input = "{operator:contains,left:left,right:[right]}"; Rule rule = buildRuleWithMultipleCopyActions(); rule.setCondition(gson.fromJson(input, BaseCondition.class)); MappingRules mr = new MappingRules(rule); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "syslog_map", "map_publish", "phase_1")); + mr.setEntryPhase("syslog_map"); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test @@ -122,12 +153,13 @@ public class RulesBusinessLogicTest { String expectedTranslation = "{\"processing\":[{\"phase\":\"foi_map\",\"processors\":[{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]}," + "{\"phase\":\"phase_1\",\"filter\":{\"filters\":[{\"string\":\"left\",\"value\":\"right1\",\"class\":\"Contains\"},{\"string\":\"left\",\"value\":\"right2\",\"class\":\"Contains\"}],\"class\":\"Or\"}," + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\",\"event.commonEventHeader.eventId\":\"${event.commonEventHeader.sourceName}_${eventGroup}\"},\"class\":\"Set\"}," - + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; String input = "{operator:contains,left:left,right:[right1, right2]}"; Rule rule = buildRuleWithMultipleCopyActions(); rule.setCondition(gson.fromJson(input, BaseCondition.class)); MappingRules mr = new MappingRules(rule); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "foi_map", "map_publish", "phase_1")); + mr.setEntryPhase("foi_map"); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test @@ -135,12 +167,12 @@ public class RulesBusinessLogicTest { String expectedTranslation = "{\"processing\":[{\"phase\":\"snmp_map\",\"processors\":[{\"array\":\"varbinds\",\"datacolumn\":\"varbind_value\",\"keycolumn\":\"varbind_oid\",\"class\":\"SnmpConvertor\"}," + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"filter\":{\"field\":\"left\",\"value\":\"right\",\"class\":\"Equals\"}," + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\",\"event.commonEventHeader.eventId\":\"${event.commonEventHeader.sourceName}_${eventGroup}\"},\"class\":\"Set\"}," - + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; String input = "{operator:equals,left:left,right:[right]}"; Rule rule = buildRuleWithMultipleCopyActions(); rule.setCondition(gson.fromJson(input, BaseCondition.class)); MappingRules mr = new MappingRules(rule); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "snmp_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test @@ -148,12 +180,12 @@ public class RulesBusinessLogicTest { String expectedTranslation = "{\"processing\":[{\"phase\":\"snmp_map\",\"processors\":[{\"array\":\"varbinds\",\"datacolumn\":\"varbind_value\",\"keycolumn\":\"varbind_oid\",\"class\":\"SnmpConvertor\"}," + "{\"phase\":\"phase_1\",\"class\":\"RunPhase\"}]},{\"phase\":\"phase_1\",\"filter\":{\"field\":\"left\",\"values\":[\"right1\",\"right2\"],\"class\":\"NotOneOf\"}," + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\",\"event.commonEventHeader.eventId\":\"${event.commonEventHeader.sourceName}_${eventGroup}\"},\"class\":\"Set\"}," - + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "{\"regex\":\"([^:]*):.*\",\"field\":\"targetField\",\"value\":\"extractFromHere\",\"class\":\"ExtractText\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; String input = "{operator:notequal,left:left,right:[right1,right2]}"; Rule rule = buildRuleWithMultipleCopyActions(); rule.setCondition(gson.fromJson(input, BaseCondition.class)); MappingRules mr = new MappingRules(rule); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr, "snmp_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(mr)); } @Test @@ -173,6 +205,66 @@ public class RulesBusinessLogicTest { } @Test + public void reorderRuleWithConditionalActionDuringValidationSuccessTest() { + Rule rule1 = buildValidRuleWithDependentSearchAndTransformActions(); + Rule rule2 = buildValidRuleWithDependentSearchAndTransformActions(); + assertEquals(rule1, rule2); + List<ServiceException> errors = rulesBusinessLogic.validateRule(rule1); + assertTrue(errors.isEmpty()); + assertNotEquals(rule1, rule2); + //after validation actions are reordered: 5, 2, 4, 1, 3 + rule2.getActions().add(0, rule2.getActions().get(4)); // 1, 2, 3, 4, 5 -> 5, 1, 2, 3, 4, 5 + rule2.getActions().remove(5); // 5, 1, 2, 3, 4, 5 -> 5, 1, 2, 3, 4 + rule2.getActions().add(1, rule2.getActions().get(2)); // 5, 1, 2, 3, 4 -> 5, 2, 1, 2, 3, 4 + rule2.getActions().remove(3); // 5, 2, 1, 2, 3, 4 -> 5, 2, 1, 3, 4 + rule2.getActions().add(2, rule2.getActions().get(4)); // 5, 2, 1, 3, 4 -> 5, 2, 4, 1, 3, 4 + rule2.getActions().remove(5); // 5, 2, 4, 1, 3, 4 -> 5, 2, 4, 1, 3 + assertEquals(rule1, rule2); + } + + @Test + public void importMappingRulesAndReorderActionsDuringImportValidationSuccessTest() { + // as this top level validator uses external ves configuration it is mocked. + // dependency validations are conducted in the class under test and verified with the control rule + when(mappingRulesValidator.validate(any(), any())).thenReturn(true); + Rule importedRule = buildValidRuleWithDependentActions(); + Rule controlRule = buildValidRuleWithDependentActions(); + MappingRules mappingRules = new MappingRules(importedRule); + // copying the generated uuid to the control rule to sustain equality + controlRule.setUid(importedRule.getUid()); + assertEquals(importedRule, controlRule); + + List<ServiceException> errors = rulesBusinessLogic.validateImportedRules(mappingRules); + assertTrue(errors.isEmpty()); + assertNotEquals(importedRule, controlRule); + //after validation actions are reordered: 1, 3, 4, 2, 5 + controlRule.getActions().add(1, controlRule.getActions().get(2)); // 1, 2, 3, 4, 5 -> 1, 3, 2, 3, 4, 5 + controlRule.getActions().remove(3); // 1, 3, 2, 3, 4, 5 -> 1, 3, 2, 4, 5 + controlRule.getActions().add(2, controlRule.getActions().get(3)); // 1, 3, 2, 4, 5 -> 1, 3, 4, 2, 4, 5 + controlRule.getActions().remove(4); // 1, 3, 4, 2, 4, 5 -> 1, 3, 4, 2, 5 + assertEquals(importedRule, controlRule); + } + + @Test + public void supportGroupDefinitionTest() { + + Rule rule = buildRuleWithMultipleCopyActions(); + List<ServiceException> errors = rulesBusinessLogic.validateRule(rule); + assertTrue(errors.isEmpty()); + MappingRules mappingRules = new MappingRules(rule); + // first rule dictates whether or not user defined phases should be supported (supportGroups = false) + assertTrue(rulesBusinessLogic.validateGroupDefinitions(mappingRules, false)); + assertFalse(rulesBusinessLogic.validateGroupDefinitions(mappingRules, true)); + // add group definitions (supportGroups = true) + rule.setGroupId("mapPhaseId"); + errors = rulesBusinessLogic.validateRule(rule); + assertTrue(errors.isEmpty()); + assertTrue(rulesBusinessLogic.validateGroupDefinitions(mappingRules, true)); + assertFalse(rulesBusinessLogic.validateGroupDefinitions(mappingRules, false)); + } + + + @Test public void reorderRuleActionsDuringValidationFailureTest() { String expectedError = "A circular dependency was detected between actions. The following fields should be resolved: event.commonEventHeader.eventId, event.commonEventHeader.sourceName, invalidSelfDependency, circularDependencyTarget_3"; Rule rule1 = buildRuleWithCircularActionDependencies(); @@ -182,22 +274,39 @@ public class RulesBusinessLogicTest { @Test - public void reorderMappingRulesByDependencySuccessTest() { - MappingRules mr = new MappingRules(buildRuleWithMultipleCopyActions()); - Rule rule = new Rule(); - rule.setDescription("description"); - rule.setActions(new ArrayList<>()); + public void reorderMappingRulesByDependencyOnlyInSamePhaseSuccessTest() { + when(mappingRulesValidator.validateTranslationPhaseNames(any(), any())).thenReturn(true); + when(mappingRulesValidator.validate(any(), any())).thenReturn(true); + Rule rule1 = buildRuleWithMultipleCopyActions(); + MappingRules mr = new MappingRules(rule1); + Rule rule2 = new Rule(); + rule2.setDescription("description"); + rule2.setActions(new ArrayList<>()); // create a dependency between rules - rule.getActions().add(buildCopyAction("${event.commonEventHeader.someField}","event.commonEventHeader.sourceName")); - mr.addOrReplaceRule(rule); + rule2.getActions().add(buildCopyAction("${event.commonEventHeader.someField}","event.commonEventHeader.sourceName")); + rule2.setPhase("phase_1"); + mr.addOrReplaceRule(rule2); + mr.setPublishPhase("map_publish"); + mr.setEntryPhase("snmp_map"); List<String> ruleUids = new ArrayList<>(mr.getRules().keySet()); - String translateBefore = rulesBusinessLogic.translateRules(mr,"snmp_map", "map_publish", "phase_1"); - List<ServiceException> errors = rulesBusinessLogic.validateRules(mr); + String translateBefore = rulesBusinessLogic.translateRules(mr); + //separate the rules into two phases, call import validator and translate + rule1.setGroupId("group_1"); + rule2.setGroupId("group_2"); + List<ServiceException> errors = rulesBusinessLogic.validateImportedRules(mr); + assertTrue(errors.isEmpty()); + errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); + assertTrue(errors.isEmpty()); + assertEquals(translateBefore, rulesBusinessLogic.translateRules(mr)); + //revert to single phase + rule1.setGroupId(""); + rule2.setGroupId(""); + errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); assertTrue(errors.isEmpty()); List<String> ruleUidsMod = new ArrayList<>(mr.getRules().keySet()); assertEquals(ruleUids.get(0), ruleUidsMod.get(1)); assertEquals(ruleUids.get(1), ruleUidsMod.get(0)); - assertNotEquals(translateBefore, rulesBusinessLogic.translateRules(mr,"snmp_map", "map_publish", "phase_1")); + assertNotEquals(translateBefore, rulesBusinessLogic.translateRules(mr)); } @Test @@ -213,9 +322,9 @@ public class RulesBusinessLogicTest { @Test public void reorderMappingRulesCircularDependencyFailureTest() { - + when(mappingRulesValidator.validateTranslationPhaseNames(any(), any())).thenReturn(true); MappingRules mr = new MappingRules(buildRuleWithMultipleCopyActions()); - List<ServiceException> errors = rulesBusinessLogic.validateRules(mr); + List<ServiceException> errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); assertTrue(errors.isEmpty()); Rule rule = new Rule(); rule.setDescription("description"); @@ -224,8 +333,9 @@ public class RulesBusinessLogicTest { rule.getActions().add(buildCopyAction("${event.commonEventHeader.version}","event.commonEventHeader.sourceName")); String input = "{operator:equals,left:\"${event.commonEventHeader.version}\",right:[\"${event.commonEventHeader.eventId}\"]}"; rule.setCondition(gson.fromJson(input, BaseCondition.class)); - assertTrue(rulesBusinessLogic.addOrEditRule(mr, rule)); - errors = rulesBusinessLogic.validateRules(mr); + rule.setPhase("phase_1"); + assertTrue(rulesBusinessLogic.addOrEditRule(mr, rule, false)); + errors = rulesBusinessLogic.validateRulesBeforeTranslate(mr); assertFalse(errors.isEmpty()); String expectedError = String.format("A circular dependency was detected between rules: %s, %s within fields: event.commonEventHeader.sourceName, event.commonEventHeader.version, event.commonEventHeader.eventId", mr.getRules().keySet().toArray()); assertEquals(expectedError, errors.get(0).getFormattedErrorMessage()); @@ -238,18 +348,21 @@ public class RulesBusinessLogicTest { + "{\"phase\":\"phase_1\",\"filter\":{\"filters\":[{\"field\":\"${event.commonEventHeader.version}\",\"value\":\"${event.commonEventHeader.eventId}\",\"class\":\"Equals\"}," + "{\"filters\":[{\"field\":\"left\",\"value\":\"right\",\"class\":\"NotEqual\"},{\"string\":\"${XXX}\",\"value\":\"right1\",\"class\":\"Contains\"}," + "{\"string\":\"${XXX}\",\"value\":\"right2\",\"class\":\"Contains\"}],\"class\":\"Or\"}],\"class\":\"And\"}," - + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\"},\"class\":\"Set\"}]},{\"phase\":\"phase_1\",\"processors\":[{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; + + "\"processors\":[{\"updates\":{\"event.commonEventHeader.version\":\"2.0\"},\"class\":\"Set\"},{\"phase\":\"map_publish\",\"class\":\"RunPhase\"}]}]}"; Rule rule = new Rule(); rule.setActions(new ArrayList<>()); rule.getActions().add(buildCopyAction("2.0","event.commonEventHeader.version")); rule.setDescription("description"); - String condition = "{type:All,children:[{operator:equals,left:\"${event.commonEventHeader.version}\",right:[\"${event.commonEventHeader.eventId}\"]}," - + "{type:Any,children:[{operator:contains,left:\"${XXX}\",right:[right1,right2]},{operator:notEqual,left:left,right:[right]}]}]}"; + String condition = "{id:123456,level:1,name:elvis,type:All,children:[{id:123456,level:1,name:elvis,operator:equals,left:\"${event.commonEventHeader.version}\",right:[\"${event.commonEventHeader.eventId}\"]}," + + "{id:123456,level:1,name:elvis,type:Any,children:[{id:123456,level:1,name:elvis,operator:contains,left:\"${XXX}\",right:[right1,right2]},{id:123456,level:1,name:elvis,operator:notEqual,left:left,right:[right]}]}]}"; rule.setCondition(gson.fromJson(condition, BaseCondition.class)); + rule.setPublishPhase("map_publish"); + rule.setEntryPhase("foi_map"); + rule.setPhase("phase_1"); List<ServiceException> errors = rulesBusinessLogic.validateRule(rule); assertTrue(errors.isEmpty()); - assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(new MappingRules(rule),"foi_map", "map_publish", "phase_1")); + assertEquals(expectedTranslation, rulesBusinessLogic.translateRules(new MappingRules(rule))); } private Rule buildRuleWithMultipleCopyActions() { @@ -260,6 +373,9 @@ public class RulesBusinessLogicTest { actions.add(buildConcatAction(Arrays.asList("${event.commonEventHeader.sourceName}","_","${eventGroup}"), "event.commonEventHeader.eventId")); actions.add(buildRegexAction("extractFromHere", "targetField", "([^:]*):.*")); rule.setActions(actions); + rule.setPhase("phase_1"); + rule.setEntryPhase("snmp_map"); + rule.setPublishPhase("map_publish"); return rule; } @@ -270,6 +386,23 @@ public class RulesBusinessLogicTest { return rule; } + private Rule buildValidRuleWithDependentSearchAndTransformActions() { + Rule rule = buildRuleWithMultipleCopyActions(); + rule.getActions().add(0, buildStringTransformAction()); + rule.getActions().add(0, buildConditionalTopoSearchAction()); + return rule; + } + + private StringTransformAction buildStringTransformAction() { + String stringTransform = "{actionType:\"string Transform\",id:76,target:searchString,stringTransform:{targetCase:same,startValue:\"${event.otherFields.otherSiteId}${targetField}${event.commonEventHeader.sourceName}\"}}"; + return gson.fromJson(stringTransform, StringTransformAction.class); + } + + private TopoSearchAction buildConditionalTopoSearchAction() { + String topoSearch = "{actionType:\"Topology Search\",id:76,search:{searchField:sourceToSearch,searchValue:\"${searchString}\",radio:'',searchFilter:{left:\"${event.commonEventHeader.eventId}\",right:[rightO],operator:OneOf},enrich:{fields:[{value:e_field1},{value:e_field2}],prefix:e_prefix}}}"; + return gson.fromJson(topoSearch, TopoSearchAction.class); + } + private Rule buildRuleWithCircularActionDependencies() { Rule rule = buildValidRuleWithDependentActions(); rule.getActions().add(buildCopyAction("${invalidSelfDependency}", "invalidSelfDependency")); @@ -282,6 +415,7 @@ public class RulesBusinessLogicTest { action.setActionType("copy"); action.setFrom(from); action.setTarget(to); + mockUiGeneratedFields(action); return action; } @@ -289,6 +423,7 @@ public class RulesBusinessLogicTest { LogTextAction logTextAction = new LogTextAction(); logTextAction.setActionType("Log Text"); logTextAction.setLogText("a name", "a level", ""); + logTextAction.setId(mockUiInput); return logTextAction; } @@ -297,6 +432,7 @@ public class RulesBusinessLogicTest { action.setActionType("concat"); action.setFrom(from); action.setTarget(to); + mockUiGeneratedFields(action); return action; } @@ -305,6 +441,7 @@ public class RulesBusinessLogicTest { action.setActionType("copy"); action.setFrom(from, regex); action.setTarget(to); + mockUiGeneratedFields(action); return action; } @@ -317,6 +454,12 @@ public class RulesBusinessLogicTest { action.setToFormat("toFormat"); action.setFromTz("fromTZ"); action.setToTz("toTz"); + mockUiGeneratedFields(action); return action; } + + private void mockUiGeneratedFields(UnaryFieldAction action) { + action.setId(mockUiInput); + action.regexState(mockUiInput); + } }
\ No newline at end of file |