diff options
author | Manor, Yanir (ym903w) <ym903w@intl.att.com> | 2018-10-21 10:20:53 +0300 |
---|---|---|
committer | Manor, Yanir (ym903w) <ym903w@intl.att.com> | 2018-10-21 13:35:08 +0300 |
commit | f53d4650e18007ab7820efd84638edac90b61090 (patch) | |
tree | b27d22bd8ad1343f9ed69091f9d6496a174f6c89 /dcaedt_be/src/main | |
parent | b1b380c5e83b044605bddfc390b80bedafd359f5 (diff) |
upgrade dace-be
Change-Id: Iaef6ef0d37e2e216321f141d10692edcaf26ffab
Issue-ID: DCAEGEN2-836
Signed-off-by: Manor, Yanir (ym903w) <ym903w@intl.att.com>
Diffstat (limited to 'dcaedt_be/src/main')
12 files changed, 305 insertions, 98 deletions
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 5d5c1e0..c677c67 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 @@ -36,6 +36,19 @@ public class BlueprintController extends BaseController { return blueprintBusinessLogic.generateAndSaveBlueprint(userId, context, vfcmtUuid, serviceUuid, instanceName, "", requestId); } + // 1810 US436244 MC table + @RequestMapping(value = "{context}/createBluePrint/{vfcmtUuid}/{revertedUuid}/{serviceUuid}/{instanceName:.*}", method = RequestMethod.POST) + public ResponseEntity createBlueprint( + @RequestHeader("USER_ID") String userId, + @PathVariable String context, + @PathVariable String vfcmtUuid, + @PathVariable String revertedUuid, + @PathVariable String serviceUuid, + @PathVariable String instanceName, + @ModelAttribute("requestId") String requestId) { + return blueprintBusinessLogic.generateAndSaveBlueprint(userId, context, vfcmtUuid, serviceUuid, instanceName, "", requestId); + } + @Deprecated @RequestMapping(value = "/createBluePrint/{VFCMTUuid}/{serviceUuid}/{instanceName}/{monitoringFlowType:.*}", method = RequestMethod.POST) public ResponseEntity createBluePrintWithFlowType( 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 e13990d..13eb724 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 @@ -3,6 +3,7 @@ package org.onap.sdc.dcae.composition.controller; import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.dcae.composition.impl.CompositionBusinessLogic; import org.onap.sdc.dcae.composition.impl.CompositionCatalogBusinessLogic; +import org.onap.sdc.dcae.composition.restmodels.CreateMcResponse; import org.onap.sdc.dcae.composition.restmodels.MessageResponse; import org.onap.sdc.dcae.composition.restmodels.ReferenceUUID; import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; @@ -27,57 +28,6 @@ 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 = "/{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); @@ -85,7 +35,7 @@ public class CompositionController extends BaseController { @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); + return compositionCatalogBusinessLogic.getTypeInfo(theItemId, theTypeName, requestId); } @RequestMapping(value = "/catalog", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @@ -116,7 +66,6 @@ public class CompositionController extends BaseController { } } - @RequestMapping(value = { "/getMC/{vfcmtUuid}" }, method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity getMC(@PathVariable String vfcmtUuid, @ModelAttribute String requestId) { try { @@ -126,6 +75,18 @@ public class CompositionController extends BaseController { } } + // 1810 US436244 MC table + @RequestMapping(value = { "/getMC/{vfcmtUuid}/{revertedUuid}" }, method = RequestMethod.GET , produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getSubmittedMcWithRevertedReference(@PathVariable String vfcmtUuid, @PathVariable String revertedUuid, @ModelAttribute String requestId) { + try { + CreateMcResponse res = compositionBusinessLogic.getDataAndComposition(vfcmtUuid, requestId); + res.getVfcmt().setUuid(vfcmtUuid.concat("/").concat(revertedUuid)); + return new ResponseEntity<>(res, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_VFCMT); + } + } + @RequestMapping(value = "/saveComposition/{vfcmtUuid}", method = RequestMethod.POST) public ResponseEntity saveComposition(@RequestHeader("USER_ID") String userId, @RequestBody String theCdump, @PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) { @@ -151,4 +112,21 @@ public class CompositionController extends BaseController { } return res; } + + @RequestMapping(value = "/{contextType}/{serviceUuid}/{vfiName}/saveComposition/{vfcmtUuid}/{revertedUuid}", method = RequestMethod.POST) + public ResponseEntity overwriteRevertedComposition(@RequestHeader("USER_ID") String userId, @RequestBody String theCdump, + @PathVariable String contextType, @PathVariable String serviceUuid, @PathVariable String vfiName, @PathVariable String vfcmtUuid, @PathVariable String revertedUuid, @ModelAttribute String requestId) { + try { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Reverted MC version {} is about to be overwritten with submitted MC version {}", revertedUuid, vfcmtUuid); + ResponseEntity res = compositionBusinessLogic.overwriteRevertedMC(userId, vfcmtUuid, revertedUuid, theCdump, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Reverted MC version {} overwrite result status code: {}", revertedUuid, res.getStatusCodeValue()); + if(HttpStatus.OK == res.getStatusCode()) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "About to undo revert of external monitoring reference from service {} to MC {}", serviceUuid, revertedUuid); + compositionBusinessLogic.undoRevert(userId, contextType, serviceUuid, vfiName, revertedUuid, requestId); + } + return res; + } catch (Exception e) { + return handleException(e, ApiType.SAVE_CDUMP); + } + } }
\ No newline at end of file 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 f929c30..084775e 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 @@ -100,6 +100,20 @@ public class RuleEditorController extends BaseController { return ruleEditorBusinessLogic.getRulesAndSchema(vfcmtUuid, dcaeCompLabel, nid, configParam, requestId); } + // 1810 US436244 MC table + @RequestMapping(value = "/rule/{vfcmtUuid}/{revertedUuid}/{dcaeCompLabel}/{nid}/{configParam:.*}", method = {RequestMethod.GET}, produces = "application/json") + public ResponseEntity getRules( + @PathVariable String vfcmtUuid, + @PathVariable String revertedUuid, + @PathVariable String dcaeCompLabel, + @PathVariable String nid, + @PathVariable String configParam, + @ModelAttribute("requestId") String 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, @@ -112,6 +126,20 @@ public class RuleEditorController extends BaseController { return ruleEditorBusinessLogic.downloadRules(vfcmtUuid, dcaeCompLabel, nid, configParam, requestId); } + // 1810 US436244 MC table + @RequestMapping(value = "/export/{vfcmtUuid}/{revertedUuid}/{dcaeCompLabel}/{nid}/{configParam:.*}", method = {RequestMethod.GET}, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public ResponseEntity downloadRules( + @PathVariable String vfcmtUuid, + @PathVariable String revertedUuid, + @PathVariable String dcaeCompLabel, + @PathVariable String nid, + @PathVariable 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}/{supportGroups}", method = {RequestMethod.POST}, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity importRules( @RequestBody String json, @ModelAttribute("requestId") String requestId, @@ -224,4 +252,11 @@ public class RuleEditorController extends BaseController { debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting getExistingRuleTargets ", vfcmtUuid); return ruleEditorBusinessLogic.getExistingRuleTargets(vfcmtUuid, requestId, dcaeCompLabel, nid); } + + // 1810 US436244 MC table + @RequestMapping(value = "/getExistingRuleTargets/{vfcmtUuid}/{revertedUuid}/{dcaeCompLabel}/{nid:.*}", method = {RequestMethod.GET}, produces = "application/json") + public ResponseEntity getExistingRuleTargets(@PathVariable String vfcmtUuid, @PathVariable String revertedUuid, @PathVariable String dcaeCompLabel, @PathVariable String nid, @ModelAttribute("requestId") String requestId) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting getExistingRuleTargets ", vfcmtUuid); + return ruleEditorBusinessLogic.getExistingRuleTargets(vfcmtUuid, requestId, dcaeCompLabel, nid); + } } 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 725bd85..8d29412 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 @@ -169,6 +169,43 @@ public class VfcmtController extends BaseController{ return referenceBusinessLogic.deleteVfcmtReferenceBlueprint(userId, contextType, monitoringComponentName, serviceUuid, vfiName, vfcmtUuid, requestId); } + // 1810 US436244 MC table functionality + @RequestMapping(value = { "/{contextType}/{monitoringComponentName}/{serviceUuid}/{vfiName}/{vfcmtUuid}/{revertedUuid}/deleteVfcmtReference" }, method = { RequestMethod.DELETE }, produces = {"application/json" }) + public ResponseEntity deleteVfcmtReferenceWithBlueprint(@RequestHeader("USER_ID") String userId, + @PathVariable String contextType, + @PathVariable String monitoringComponentName, + @PathVariable String serviceUuid, + @PathVariable String vfiName, + @PathVariable String vfcmtUuid, + @PathVariable String revertedUuid, + @ModelAttribute String requestId) { + try { + referenceBusinessLogic.deleteVfcmtReference(userId, contextType, serviceUuid, vfiName, vfcmtUuid, revertedUuid, requestId); + } catch (Exception e) { + return handleException(e, ApiType.DELETE_VFCMT_REFERENCE); + } + return referenceBusinessLogic.deleteVfcmtReferenceBlueprint(userId, contextType, monitoringComponentName, serviceUuid, vfiName, vfcmtUuid, requestId); + } + + // 1810 US436244 MC table functionality + @RequestMapping(value = { "/{contextType}/{monitoringComponentName}/{serviceUuid}/{vfiName}/{vfcmtUuid}/deleteVfcmtReference/{submittedUuid}" }, method = { RequestMethod.DELETE }, produces = {"application/json" }) + public ResponseEntity deleteVfcmtReferencesWithBlueprint(@RequestHeader("USER_ID") String userId, + @PathVariable String contextType, + @PathVariable String monitoringComponentName, + @PathVariable String serviceUuid, + @PathVariable String vfiName, + @PathVariable String vfcmtUuid, + @PathVariable String submittedUuid, + @ModelAttribute String requestId) { + try { + referenceBusinessLogic.deleteVfcmtReference(userId, contextType, serviceUuid, vfiName, vfcmtUuid, requestId); + referenceBusinessLogic.deleteVfcmtReference(userId, contextType, serviceUuid, vfiName, submittedUuid, requestId); + } catch (Exception e) { + return handleException(e, ApiType.DELETE_VFCMT_REFERENCE); + } + return referenceBusinessLogic.deleteVfcmtReferenceBlueprint(userId, contextType, monitoringComponentName, serviceUuid, vfiName, submittedUuid, requestId); + } + @RequestMapping(value = { "/getVfcmtReferenceData/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) public ResponseEntity getVfcmtReferenceData(@PathVariable String vfcmtUuid, @ModelAttribute String requestId) { try { @@ -183,4 +220,24 @@ public class VfcmtController extends BaseController{ return referenceBusinessLogic.checkoutAndBindToServiceIfCertified(userId, contextType, serviceUuid, vfiName, vfcmtUuid, requestId); } + // 1810 US436244 MC table functionality + @RequestMapping(value = { "/{contextType}/{serviceUuid}/{vfiName}/{vfcmtUuid}/{revertedUuid}/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, @PathVariable String revertedUuid, @ModelAttribute String requestId) { + return referenceBusinessLogic.checkoutAndUndoRevertMC(userId, contextType, serviceUuid, vfiName, vfcmtUuid, revertedUuid, requestId); + } + + @RequestMapping(value = { "/{contextType}/{serviceUuid}/{vfiName}/{vfcmtUuid}/revert/{submittedUuid}" }, method = { RequestMethod.POST }, produces = {"application/json" }) + public ResponseEntity revertToSubmittedMC(@RequestHeader("USER_ID") String userId, + @PathVariable String contextType, + @PathVariable String serviceUuid, + @PathVariable String vfiName, + @PathVariable String vfcmtUuid, + @PathVariable String submittedUuid, + @ModelAttribute String requestId) { + try { + return ResponseEntity.ok(referenceBusinessLogic.revertToSubmittedMC(userId, contextType, serviceUuid, vfiName, vfcmtUuid, submittedUuid, requestId)); + } catch (Exception e) { + return handleException(e, ApiType.ATTACH_TO_SERVICE); + } + } } diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java index 609480d..9cb8801 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java @@ -1,29 +1,22 @@ package org.onap.sdc.dcae.composition.controller.health; -import java.net.URI; -import java.util.Collections; - +import com.google.gson.Gson; +import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.common.onaplog.OnapLoggerDebug; import org.onap.sdc.common.onaplog.OnapLoggerError; -import org.onap.sdc.common.onaplog.Enums.LogLevel; -import org.onap.sdc.dcae.composition.restmodels.health.ComponentsInfo; -import org.onap.sdc.dcae.catalog.commons.Future; import org.onap.sdc.dcae.catalog.commons.Http; +import org.onap.sdc.dcae.composition.restmodels.health.ComponentsInfo; import org.onap.sdc.dcae.composition.util.DcaeBeConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; -import com.google.gson.Gson; +import java.net.URI; +import java.util.Collections; @Configuration @EnableAsync @@ -50,20 +43,22 @@ public class HealthPoller { ComponentsInfo toscaLabHealthRes = null; ResponseEntity<String> healthRes = null; try { - for(int i=0; i<Integer.valueOf(hcretrynum); i++){ // 3 tries + for (int i = 0; i < Integer.valueOf(hcretrynum); i++) { // 3 tries healthRes = sendHealthCheck(); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Try #{}: {}", i, healthRes); - if(healthRes.getStatusCode()==HttpStatus.OK){ - String result = (String) healthRes.getBody(); + if (healthRes.getStatusCode() == HttpStatus.OK) { + String result = healthRes.getBody(); toscaLabHealthRes = gson.fromJson(result, ComponentsInfo.class); break; } } } catch (Exception e) { toscaLabHealthRes = getNegativeHealth(e.getMessage()); + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "HealthCheck Exception: {}", e); } - if(toscaLabHealthRes == null){ - toscaLabHealthRes = getNegativeHealth(healthRes.getBody() + "-" + healthRes.getStatusCode()); + if (toscaLabHealthRes == null) { + String msg = null != healthRes ? healthRes.getBody() + "-" + healthRes.getStatusCode() : ""; + toscaLabHealthRes = getNegativeHealth(msg); } toscaLabHealthState.setToscaLabHealthResponse(toscaLabHealthRes); } 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 6b0ec93..66e2783 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 @@ -8,6 +8,7 @@ import org.onap.sdc.common.onaplog.OnapLoggerDebug; import org.onap.sdc.common.onaplog.OnapLoggerError; import org.onap.sdc.dcae.client.ISdcClient; import org.onap.sdc.dcae.composition.restmodels.CreateMcResponse; +import org.onap.sdc.dcae.composition.restmodels.ReferenceUUID; import org.onap.sdc.dcae.composition.restmodels.VfcmtData; import org.onap.sdc.dcae.composition.restmodels.sdc.*; import org.onap.sdc.dcae.composition.util.DcaeBeConstants; @@ -25,12 +26,14 @@ 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.ArrayList; +import java.util.List; import java.util.Map; -import java.util.zip.ZipEntry; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.zip.ZipInputStream; @Component @@ -45,6 +48,8 @@ public class BaseBusinessLogic { protected static OnapLoggerError errLogger = OnapLoggerError.getInstance(); protected static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + protected static final String REVERTED_REF = "_reverted"; + public ISdcClient getSdcRestClient() { return sdcRestClient; } @@ -62,7 +67,44 @@ public class BaseBusinessLogic { return sdcRestClient.createResourceArtifact(userId, targetId, cloned, requestId); } - public void cloneArtifactToTarget(String userId, String targetId, String payload, Artifact artifactToClone, Artifact artifactToOverride, String requestId) throws JsonProcessingException { + public void undoRevert(String userId, String contextType, String serviceUuid, String vfiName, String revertedUuid, String requestId) { + sdcRestClient.updateExternalMonitoringReference(userId, contextType, serviceUuid, vfiName, revertedUuid.concat(REVERTED_REF), new ReferenceUUID(revertedUuid), requestId); + } + + // 1810 US436244 Update MC table version representations and actions + void cloneArtifactsToRevertedMC(String userId, String vfcmtUuid, String revertedUuid, String requestId, boolean cloneComposition) throws JsonProcessingException { + List<String> exclude = new ArrayList<>(); + exclude.add(DcaeBeConstants.Composition.fileNames.SVC_REF); + if(!cloneComposition) { + exclude.add(DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + } + ResourceDetailed sourceVfcmt = sdcRestClient.getResource(vfcmtUuid, requestId); + ResourceDetailed targetVfcmt = sdcRestClient.getResource(revertedUuid, requestId); + Map<String, Artifact> currentArtifacts = targetVfcmt.getArtifacts().stream().collect(Collectors.toMap(Artifact::getArtifactName, Function.identity())); + debugLogger.log(LogLevel.DEBUG,this.getClass().getName(), "latest MC version artifact names: {}", currentArtifacts.keySet()); + Predicate<Artifact> predicate = p -> !exclude.contains(p.getArtifactName()) && (null == currentArtifacts.get(p.getArtifactName()) || !currentArtifacts.get(p.getArtifactName()).getArtifactChecksum().equals(p.getArtifactChecksum())); + List<Artifact> artifactsToClone = sourceVfcmt.getArtifacts().stream().filter(predicate).collect(Collectors.toList()); + debugLogger.log(LogLevel.DEBUG,this.getClass().getName(), "submitted MC version artifacts to clone or overwrite on latest MC: {}", artifactsToClone.stream().map(Artifact::getArtifactName).collect(Collectors.toList())); + // clone source artifacts to target + if(!artifactsToClone.isEmpty()) { + checkVfcmtType(targetVfcmt); + checkUserIfResourceCheckedOut(userId, targetVfcmt); + if (isNeedToCheckOut(targetVfcmt.getLifecycleState())) { + targetVfcmt = sdcRestClient.changeResourceLifecycleState(userId, revertedUuid, LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT before clone", requestId); + } + for (Artifact artifactToClone : artifactsToClone) { + String payload = sdcRestClient.getResourceArtifact(vfcmtUuid, artifactToClone.getArtifactUUID(), requestId); + cloneArtifactToTarget(userId, revertedUuid, payload, artifactToClone, currentArtifacts.get(artifactToClone.getArtifactName()), requestId); + } + } + // delete any target artifacts that do not match source artifacts + List<String> artifactsNames = sourceVfcmt.getArtifacts().stream().map(Artifact::getArtifactName).collect(Collectors.toList()); + targetVfcmt.getArtifacts().stream().filter(p -> !artifactsNames.contains(p.getArtifactName())).forEach(a -> + sdcRestClient.deleteResourceArtifact(userId, revertedUuid, a.getArtifactUUID(), requestId) + ); + } + + private void cloneArtifactToTarget(String userId, String targetId, String payload, Artifact artifactToClone, Artifact artifactToOverride, String requestId) throws JsonProcessingException { if (null != artifactToOverride) { artifactToOverride.setDescription(artifactToOverride.getArtifactDescription()); artifactToOverride.setPayloadData(Base64Utils.encodeToString(payload.getBytes())); diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionBusinessLogic.java index a3c68f6..43674fe 100644 --- a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionBusinessLogic.java +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/CompositionBusinessLogic.java @@ -22,8 +22,10 @@ import org.springframework.util.Base64Utils; import org.springframework.util.CollectionUtils; import java.io.IOException; -import java.util.Collections; -import java.util.List; +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; @Component public class CompositionBusinessLogic extends BaseBusinessLogic { @@ -80,6 +82,17 @@ public class CompositionBusinessLogic extends BaseBusinessLogic { } } + // 1810 US436244 Update MC table version representations and actions + public ResponseEntity overwriteRevertedMC(String userId, String vfcmtUuid, String revertedUuid, String updatedPayload, String requestId) { + try { + cloneArtifactsToRevertedMC(userId, vfcmtUuid, revertedUuid, requestId, false); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "clone action failed: {}", e); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.SAVE_CDUMP); + } + return saveComposition(userId, revertedUuid, updatedPayload, requestId, false); + } + Artifact submitComposition(String userId, String context, VfcmtData vfcmtData, String resultBlueprintCreation, String requestId) throws JsonProcessingException { // get service / find vfi 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 d970778..0847a50 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 @@ -39,7 +39,7 @@ public class CompositionCatalogBusinessLogic extends BaseBusinessLogic { public ResponseEntity getModelById(String requestId, String theItemId) { try { - ResourceDetailed resourceDetailed = fetchAndExtractTemplateAndSchema(theItemId, requestId); + ResourceDetailed resourceDetailed = catalogController.getCatalog().hasCachedItem(theItemId) ? fetchCachedArtifactsMetadata(theItemId, requestId) : 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()) { @@ -56,9 +56,15 @@ public class CompositionCatalogBusinessLogic extends BaseBusinessLogic { } - public ResponseEntity getTypeInfo(String theItemId, String theTypeName) { + public ResponseEntity getTypeInfo(String theItemId, String theTypeName, String requestId) { try { + // temporary patch - precede with caching verification // + if(!catalogController.getCatalog().hasCachedItem(theItemId)) { + ResourceDetailed resourceDetailed = fetchAndExtractTemplateAndSchema(theItemId, requestId); + catalogController.getCatalog().template(resourceDetailed).execute(); + } + // // // // // // Future<Catalog.Type> theTypeInfoFuture = catalogController.getCatalog().type(theItemId, theTypeName).withHierarchy().withCapabilities().withRequirements().execute(); if(theTypeInfoFuture.succeeded()) { CatalogResponse response = new CatalogResponse(ElementRequest.EMPTY_REQUEST); @@ -85,14 +91,16 @@ public class CompositionCatalogBusinessLogic extends BaseBusinessLogic { 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; - } + String toscaModelPath = toscaModelPath(uuid); + ResourceDetailed resourceDetailed = new ResourceDetailed(); + resourceDetailed.setUuid(uuid); + resourceDetailed.setToscaModelURL(toscaModelPath); + resourceDetailed.setArtifacts(extractToscaArtifactsFromCsar(sdcRestClient.getResourceToscaModel(uuid, requestId), toscaModelPath)); + return resourceDetailed; + } + + private ResourceDetailed fetchCachedArtifactsMetadata(String uuid, String requestId) throws IOException { + String toscaModelPath = toscaModelPath(uuid); ResourceDetailed cachedVf = sdcRestClient.getResource(uuid, requestId); cachedVf.getArtifacts().forEach(a -> a.setArtifactURL(toscaModelPath.concat(a.getArtifactName()))); return cachedVf; @@ -115,5 +123,9 @@ public class CompositionCatalogBusinessLogic extends BaseBusinessLogic { } } + private String toscaModelPath(String uuid) { + return "/sdc/v1/catalog/resources/".concat(uuid).concat("/toscaModel/"); + } + } 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 224fc24..522b866 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 @@ -18,6 +18,8 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import static org.springframework.util.CollectionUtils.isEmpty; @@ -52,25 +54,31 @@ public class ReferenceBusinessLogic extends BaseBusinessLogic { debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished to delete vfcmt reference. serviceUuid {}, vfcmtUuid {}", serviceUuid, vfcmtUuid); } + // 1810 US436244 MC table functionality + public void deleteVfcmtReference(String userId, String context, String serviceUuid, String vfiName, String vfcmtUuid, String revertedUuid, String requestId) { + deleteVfcmtReference(userId, context, serviceUuid, vfiName, vfcmtUuid, requestId); + deleteVfcmtReference(userId, context, serviceUuid, vfiName, revertedUuid.concat(REVERTED_REF), requestId); + } + // 1806 US381853 Return a list of monitoring components by external reference id. Support partial success - public Map<String, List<MonitoringComponent>> fetchMonitoringComponents(ExternalReferencesMap mcRefs, String requestId) { + // 1810 US436244 Return a list of monitoring components by external reference id - group latest version (x.y) with submitted version (x.0) + public Map<String, Collection<MonitoringComponent>> fetchMonitoringComponents(ExternalReferencesMap mcRefs, String requestId) { debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to fetch monitoring components metadata for vfis {}", mcRefs.keySet()); - Map<String, List<MonitoringComponent>> result = new LinkedHashMap<>(); + Map<String, Collection<MonitoringComponent>> result = new LinkedHashMap<>(); List<MonitoringComponent> monitoringComponents = Collections.synchronizedList(new ArrayList<>()); List<MonitoringComponent> unavailable = Collections.synchronizedList(new ArrayList<>()); mcRefs.entrySet().parallelStream().forEach(entry -> entry.getValue().parallelStream().forEach(id -> { try{ - monitoringComponents.add(new MonitoringComponent(getSdcRestClient().getResource(id, requestId), entry.getKey())); + monitoringComponents.add(new MonitoringComponent(getSdcRestClient().getResource(id.replace(REVERTED_REF, ""), requestId), entry.getKey())); } catch (Exception e) { debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Failed to fetch monitoring component with uuid {}. message: {} ", id, e); unavailable.add(new MonitoringComponent(id, entry.getKey(), "unavailable")); } - }) ); - result.put("monitoringComponents", monitoringComponents); + result.put("monitoringComponents", groupMonitoringComponentsForRepresentation(mcRefs.values().stream().flatMap(List::stream).collect(Collectors.toList()), monitoringComponents)); if(!isEmpty(unavailable)) { result.put("unavailable", unavailable); } @@ -100,4 +108,49 @@ public class ReferenceBusinessLogic extends BaseBusinessLogic { } } + public ResponseEntity checkoutAndUndoRevertMC(String userId, String contextType, String serviceUuid, String vfiName, String vfcmtUuid, String revertedUuid, String requestId) { + try { + cloneArtifactsToRevertedMC(userId, vfcmtUuid, revertedUuid, requestId, true); + ResourceDetailed vfcmt = sdcRestClient.getResource(revertedUuid, requestId); + undoRevert(userId, contextType, serviceUuid, vfiName, revertedUuid, requestId); + return new ResponseEntity<>(new VfcmtData(vfcmt), HttpStatus.OK); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "clone action failed: {}", e); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.CLONE_VFCMT); + } + } + + public MonitoringComponent revertToSubmittedMC(String userId, String contextType, String serviceUuid, String vfiName, String vfcmtUuid, String submittedUuid, String requestId) { + //TODO validations + MonitoringComponent res = new MonitoringComponent(sdcRestClient.getResource(submittedUuid, requestId), vfiName); + // this should always be the case + if (!submittedUuid.equals(vfcmtUuid)) { + sdcRestClient.updateExternalMonitoringReference(userId, contextType, serviceUuid, vfiName, vfcmtUuid, new ReferenceUUID(vfcmtUuid.concat(REVERTED_REF)), requestId); + res.setUuid(submittedUuid.concat("/").concat(vfcmtUuid)); + } + return res; + } + + + private Collection<MonitoringComponent> groupMonitoringComponentsForRepresentation(List<String> mcRefs, List<MonitoringComponent> components) { + return components.stream().collect(Collectors.toMap(MonitoringComponent::getInvariantUUID, Function.identity(), + (mc1, mc2) -> mergeMcInfo(mc1, mc2, !mcRefs.contains(mc1.getUuid()) || !mcRefs.contains(mc2.getUuid())))).values(); + } + + private MonitoringComponent mergeMcInfo(MonitoringComponent mc1, MonitoringComponent mc2, boolean reverted) { + MonitoringComponent submittedVersion = mc1; + MonitoringComponent latestVersion = mc2; + if("Submitted".equals(mc2.getStatus())) { + submittedVersion = mc2; + latestVersion = mc1; + } + if(reverted) { + submittedVersion.setUuid(submittedVersion.getUuid().concat("/").concat(latestVersion.getUuid())); + return submittedVersion; + } + latestVersion.setSubmittedUuid(submittedVersion.getUuid()); + latestVersion.setStatus(submittedVersion.getStatus()); + return latestVersion; + } + } 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 42807ae..cc0fcb6 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 @@ -323,16 +323,18 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { public ResponseEntity translateRules(TranslateRequest request, String requestId) { + // 1810 US436244 MC table + String vfcmtUuid = request.getVfcmtUuid().split("/")[0]; try { if(!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"); } - ResourceDetailed vfcmt = getSdcRestClient().getResource(request.getVfcmtUuid(), requestId); + ResourceDetailed vfcmt = getSdcRestClient().getResource(vfcmtUuid, requestId); checkVfcmtType(vfcmt); if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { - return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "No rules found on VFCMT " + request.getVfcmtUuid()); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "No rules found on VFCMT " + vfcmtUuid); } String artifactLabel = Normalizers.normalizeArtifactLabel(request.getDcaeCompLabel() + request.getNid() + request.getConfigParam()); @@ -340,10 +342,10 @@ public class RuleEditorBusinessLogic extends BaseBusinessLogic { 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 " + request.getVfcmtUuid()); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", artifactLabel + " doesn't exist on VFCMT " + vfcmtUuid); } - String payload = getSdcRestClient().getResourceArtifact(request.getVfcmtUuid(), rulesArtifact.getArtifactUUID(), requestId); + String payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, 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()); 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 index 005b005..8f4dc46 100644 --- 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 @@ -4,6 +4,7 @@ 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 org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; import java.util.LinkedHashMap; import java.util.List; @@ -32,7 +33,8 @@ public class TopoSearchTranslator extends ActionTranslator<TopoSearchAction> { clazz = "TopoSearch"; searchField = action.searchField(); searchValue = action.searchValue(); - if(action.conditionalSearch()) { + // fix - check that the condition is not only declared but also defined + if(action.conditionalSearch() && ValidationUtils.validateNotEmpty(action.searchFilter().getLeft())) { searchFilter = getSimpleConditionTranslation(action.searchFilter()); } if(action.doEnrich()){ 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 index 1abc2d8..90073e5 100644 --- 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 @@ -1,11 +1,13 @@ package org.onap.sdc.dcae.rule.editor.validators; import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Condition; 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 org.springframework.util.CollectionUtils; import java.util.List; @@ -26,7 +28,7 @@ public class TopoSearchValidator extends BaseActionValidator<TopoSearchAction> { public boolean validate(TopoSearchAction action, List<ResponseFormat> errors) { boolean valid = super.validate(action, errors); - if (action.conditionalSearch() && !conditionValidator.validateConditionalAction(action.searchFilter(), errors)) { + if (action.conditionalSearch() && searchFilterHasNoneEmptyFields(action.searchFilter()) && !conditionValidator.validateConditionalAction(action.searchFilter(), errors)) { valid = false; } if (!ValidationUtils.validateNotEmpty(action.searchField())) { @@ -40,6 +42,9 @@ public class TopoSearchValidator extends BaseActionValidator<TopoSearchAction> { return validateEnrichOrUpdates(action, errors) && valid; } + private boolean searchFilterHasNoneEmptyFields(Condition searchFilter) { + return ValidationUtils.validateNotEmpty(searchFilter.getLeft()) || ValidationUtils.validateNotEmpty(searchFilter.getOperator()) || !CollectionUtils.isEmpty(searchFilter.getRight()) && searchFilter.getRight().stream().anyMatch(ValidationUtils::validateNotEmpty); + } private boolean validateEnrichOrUpdates(TopoSearchAction action, List<ResponseFormat> errors) { if (!action.doEnrich()) { |