diff options
Diffstat (limited to 'dcaedt_be/src/main/java/org')
57 files changed, 5187 insertions, 0 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 new file mode 100644 index 0000000..ee8f5c6 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java @@ -0,0 +1,87 @@ +package org.onap.sdc.dcae.composition; + +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Set; + +import javax.annotation.PostConstruct; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +@Component +@PropertySources({ + @PropertySource(value="classpath:application-fe.properties", ignoreResourceNotFound=true), + @PropertySource(value="file:${jetty.base}/config/dcae-be/application.properties", ignoreResourceNotFound=true) +}) + +public class CompositionConfig { + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @Value("${compositionConfig.flowTypes}") + private String flowTypes; + @JsonIgnore + private Map<String, FlowType> flowTypesMap; + @Value("${compositionConfig.isRuleEditorActive}") + private boolean isRuleEditorActive; + + // get flowTypes as the parsed keySet + public Set<String> getFlowTypes() { + return flowTypesMap.keySet(); + } + + @JsonProperty("isRuleEditorActive") + public boolean isRuleEditorActive() { + return isRuleEditorActive; + } + + public Map<String, FlowType> getFlowTypesMap() { + return flowTypesMap; + } + + public static class FlowType { + + private String entryPointPhaseName; + private String lastPhaseName; + + public String getEntryPointPhaseName() { + return entryPointPhaseName; + } + + public void setEntryPointPhaseName(String entryPointPhaseName) { + this.entryPointPhaseName = entryPointPhaseName; + } + + public String getLastPhaseName() { + return lastPhaseName; + } + + public void setLastPhaseName(String lastPhaseName) { + this.lastPhaseName = lastPhaseName; + } + } + + + @PostConstruct + public void init() { + try { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Reading flow type definitions from configuration"); + 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"); + } + } +}
\ No newline at end of file diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionEngine.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionEngine.java new file mode 100644 index 0000000..186f3f6 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionEngine.java @@ -0,0 +1,140 @@ +package org.onap.sdc.dcae.composition; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Properties; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import javax.servlet.ServletContext; + +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.util.SystemProperties; +import org.onap.sdc.dcae.filter.LoggingFilter; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ErrorConfiguration; +import org.onap.sdc.dcae.errormng.ErrorConfigurationLoader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +@EnableScheduling +@SpringBootApplication +@ComponentScan("org.onap.sdc.dcae") +@EnableAutoConfiguration +@PropertySource("file:${jetty.base}/config/dcae-be/application.properties") +public class CompositionEngine extends SpringBootServletInitializer implements CommandLineRunner{ + private static final String SPECIFICATION_VERSION = "Specification-Version"; + @Autowired + ServletContext servletContext; + private static final String MANIFEST_FILE_NAME = "/META-INF/MANIFEST.MF"; + private static String dcaeVersion; + private OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + public static void main(String[] args) { + SpringApplication.run(CompositionEngine.class, args); + } + + /** + * Creates and returns a new instance of a {@link SystemProperties} class. + * + * @return New instance of {@link SystemProperties}. + */ + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(CompositionEngine.class); + } + + + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurerAdapter() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedHeaders("*") + .allowedMethods("GET", "POST", "OPTIONS", "PUT") + .allowCredentials(false) + .maxAge(3600); + + } + }; + } + + @Override + public void run(String... args) throws Exception { + + ErrorConfigurationLoader errorConfigurationLoader = new ErrorConfigurationLoader(System.getProperty("jetty.base")); + ErrConfMgr instance = ErrConfMgr.INSTANCE; + InputStream inputStream = servletContext.getResourceAsStream(MANIFEST_FILE_NAME); + + //setLogbackXmlLocation(); + + String version = null; + try { + Manifest mf = new Manifest(inputStream); + Attributes atts = mf.getMainAttributes(); + version = atts.getValue(SPECIFICATION_VERSION); + if (version == null || version.isEmpty()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "failed to read DCAE version from MANIFEST."); + } else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "DCAE version from MANIFEST is {}", version); + dcaeVersion = version; + } + + } catch (IOException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "failed to read DCAE version from MANIFEST: {}", e.getMessage()); + } + + } + + private void setLogbackXmlLocation() throws Exception { + String jettyBase = System.getProperty("config.home"); + Properties props = System.getProperties(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Current System Properties are: {}", props); + if (jettyBase == null) { + String msg = "Couldn't resolve config.home environmental variable"; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new Exception(msg + ". Failed to configure logback.xml location... aborting."); + } + String logbackXmlLocation = jettyBase+"/dcae-be/logback.xml"; + props.setProperty("logback.configurationFile", logbackXmlLocation); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Successfuly set the logback.xml location to {}", logbackXmlLocation); + } + + @Bean + public FilterRegistrationBean contextLifecycleFilter() { + Collection<String> urlPatterns = new ArrayList<>(); + urlPatterns.add("/*"); + + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new LoggingFilter()); + filterRegistrationBean.setUrlPatterns(urlPatterns); + + return filterRegistrationBean; + } + + public static String getDcaeVersion() { + return dcaeVersion; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BaseController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BaseController.java new file mode 100644 index 0000000..8b590ca --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BaseController.java @@ -0,0 +1,80 @@ +package org.onap.sdc.dcae.composition.controller; + +import javax.servlet.http.HttpServletRequest; + +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.impl.BaseBusinessLogic; +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.composition.util.SystemProperties; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.DcaeException; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ModelAttribute; + +import com.google.gson.Gson; + +public abstract class BaseController { + + protected Gson gson = new Gson(); + + @Autowired + protected SystemProperties systemProperties; + + @Autowired + protected BaseBusinessLogic baseBusinessLogic; + + protected OnapLoggerError errLogger = OnapLoggerError.getInstance(); + protected OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @ModelAttribute("requestId") + public String getRequestId(HttpServletRequest request) { + return request.getAttribute("requestId").toString(); + } + + Asset checkout(String userId, String uuid, AssetType assetType, String requestId) throws Exception { + return baseBusinessLogic.getSdcRestClient().changeAssetLifecycleState(userId, uuid, LifecycleOperationType.CHECKOUT.name(), null, assetType, requestId); + } + + Asset checkin(String userId, String uuid, AssetType assetType, String requestId) throws Exception { + return baseBusinessLogic.getSdcRestClient().changeAssetLifecycleState(userId, uuid, LifecycleOperationType.CHECKIN.name(), "checking in " + assetType.name() + uuid, assetType, requestId); + } + + + boolean isNeedToCheckOut(String lifecycleState) { + return DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT != DcaeBeConstants.LifecycleStateEnum.findState(lifecycleState); + } + + void checkUserIfResourceCheckedOut(String userId, Asset asset) throws DcaeException { + if (DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT == DcaeBeConstants.LifecycleStateEnum.findState(asset.getLifecycleState())) { + String lastUpdaterUserId = asset.getLastUpdaterUserId(); + if (lastUpdaterUserId != null && !lastUpdaterUserId.equals(userId)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "User conflicts. Operation not allowed for user {} on resource checked out by {}", userId, lastUpdaterUserId); + ResponseFormat responseFormat = ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.USER_CONFLICT, null, userId, asset.getName(), lastUpdaterUserId); + throw new DcaeException(HttpStatus.FORBIDDEN, responseFormat.getRequestError()); + } + } + } + + void checkVfcmtType(ResourceDetailed vfcmt) { + if (!"VFCMT".equals(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()); + } + } + + ResponseEntity handleException(Exception e, ApiType apiType, String... variables){ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), e.getMessage()); + return ErrConfMgr.INSTANCE.handleException(e, apiType, variables); + } +} 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 new file mode 100644 index 0000000..a12c6b8 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java @@ -0,0 +1,239 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.apache.commons.lang.StringUtils; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.MessageResponse; +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.composition.restmodels.sdc.*; +import org.onap.sdc.dcae.utils.Normalizers; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.enums.AssetType; +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.onap.sdc.dcae.utils.SdcRestClientUtils; +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.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.PostConstruct; +import java.io.StringReader; +import java.net.URI; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class BlueprintController extends BaseController{ + + @Autowired + private Blueprinter blueprinter; + + @Autowired + private ASDC asdc; + + private static final String CREATE_DESC = "creating new artifact blueprint on the service vfi"; + private static final String UPDATE_DESC = "updating artifact blueprint on the service vfi"; + + + + @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); + } + + /*** + * VFCMT - Resource, blueprint - as an artifact as an service. + * @param userId + * @param vfcmtUuid + * @param serviceUuid + * @param serviceInstanceName + * @param monitoringFlowType + * @return ResponseEntity + */ + @RequestMapping(value = "/createBluePrint/{VFCMTUuid}/{serviceUuid}/{instanceName}/{monitoringFlowType}", method = RequestMethod.POST) + public ResponseEntity createBluePrint(@RequestHeader("USER_ID") String userId, + @PathVariable("VFCMTUuid") String vfcmtUuid, + @PathVariable("serviceUuid") String serviceUuid, + @PathVariable("instanceName") String serviceInstanceName, + @PathVariable("monitoringFlowType") String monitoringFlowType, + @ModelAttribute("requestId") String requestId) { + try { + + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + checkVfcmtType(vfcmt); + Artifact cdumpArtifactData = findCdumpArtifactData(vfcmt); + if (null != cdumpArtifactData) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Found the cdump (composition.yml) on top of VFCMT {}", vfcmtUuid); + String cdump = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, cdumpArtifactData.getArtifactUUID(), requestId); + 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); + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to use python procedure to create a blueprint...."); + String resultBlueprintCreation; + try{ + resultBlueprintCreation = utils.buildBlueprintViaToscaLab(new StringReader(cdump)).waitForResult().waitForResult(); + }catch (Exception e){ + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERATE_BLUEPRINT_ERROR, e.getMessage(), vfcmt.getName()); + } + if (StringUtils.isEmpty(resultBlueprintCreation)) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERATE_BLUEPRINT_ERROR, "", vfcmt.getName()); + } + + // 1806 US374595 flowType in cdump + String flowTypeFromCdump = StringUtils.substringBetween(cdump,"\"flowType\":\"","\""); + if(StringUtils.isNotBlank(flowTypeFromCdump)) { + monitoringFlowType = flowTypeFromCdump; + } + // saving to serviceVfInstance + Artifact savedBluePrint = saveBluePrint(userId, serviceUuid, serviceInstanceName, resultBlueprintCreation, monitoringFlowType, vfcmt.getName(), requestId); + if(savedBluePrint!=null){ + MessageResponse response = new MessageResponse(); + response.setSuccessResponse("Blueprint build complete \n. Blueprint="+savedBluePrint.getArtifactName()); + //1806 US374593 - certify VFCMT after BP generation + certifyVfcmt(vfcmt, requestId); + return new ResponseEntity<>(response, HttpStatus.OK); + } + else{ + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SUBMIT_BLUEPRINT_ERROR); + } + + }else{ + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", vfcmt.getName()); + } + } catch (Exception e) { + return handleException(e, ApiType.SUBMIT_BLUEPRINT); + } + } + + + /********************* private function ********************/ + + /** + * @param userId + * @param serviceUuid + * @param resourceInstanceName + * @param bluePrint + * @param monitoringFlowType + * @param vfcmtName + * @param requestId + * @return + * @throws Exception + */ + private Artifact saveBluePrint(String userId, String serviceUuid, String resourceInstanceName, String bluePrint, String monitoringFlowType, String vfcmtName, String requestId) throws Exception { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "BLUEPRINT:\n{}", bluePrint); + try { + ServiceDetailed service = baseBusinessLogic.getSdcRestClient().getService(serviceUuid, requestId); + //Validations + checkUserIfResourceCheckedOut(userId, service); + ResourceInstance vfi = findVfiOnService(service, resourceInstanceName); + if(null == vfi){ + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VF instance {} not found on service {}", resourceInstanceName, serviceUuid); + return null; + } + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), service.toString()); + + String normalizedArtifactLabel = Normalizers.normalizeArtifactLabel("blueprint-" + monitoringFlowType); + Artifact blueprintArtifact = CollectionUtils.isEmpty(vfi.getArtifacts()) ? null : vfi.getArtifacts().stream() + .filter(p -> normalizedArtifactLabel.equals(Normalizers.normalizeArtifactLabel(p.getArtifactLabel()))) + .findAny() + .orElse(null); + + boolean isNeed2Checkout = isNeedToCheckOut(service.getLifecycleState()); + if (isNeed2Checkout) { + Asset result = checkout(userId, serviceUuid, AssetType.SERVICE, requestId); + if (result != null) { + serviceUuid = result.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New service after checkout is: {}", serviceUuid); + } + } + //update mode + if (null != blueprintArtifact) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Found that service {} already consist of {} ----> updateMode", serviceUuid, normalizedArtifactLabel); + blueprintArtifact.setDescription(UPDATE_DESC); + blueprintArtifact.setPayloadData(Base64Utils.encodeToString(bluePrint.getBytes())); + blueprintArtifact = baseBusinessLogic.getSdcRestClient().updateVfInstanceArtifact(userId, serviceUuid, Normalizers.normalizeComponentInstanceName(resourceInstanceName), blueprintArtifact, requestId); + //create mode + } else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Service {} does not consist {} ----> createMode", serviceUuid, normalizedArtifactLabel); + blueprintArtifact = SdcRestClientUtils.generateDeploymentArtifact(CREATE_DESC, generateBlueprintFileName(monitoringFlowType, vfcmtName), ArtifactType.DCAE_INVENTORY_BLUEPRINT.name(), normalizedArtifactLabel, bluePrint.getBytes()); + blueprintArtifact = baseBusinessLogic.getSdcRestClient().createVfInstanceArtifact(userId, serviceUuid, Normalizers.normalizeComponentInstanceName(resourceInstanceName), blueprintArtifact, requestId); + } + + //No need to check the service in in 1806 +// Asset blueprintAsJson = checkin(user_id, serviceUuid, AssetType.SERVICE); +// debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "service result after check-in: {}", blueprintAsJson.toString()); + + return blueprintArtifact; + + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occurred while trying to save blueprint {}", e.toString()); + throw e; + } + } + + /** + * + * @param monitoringFlowType + * @param vfcmtName + * @return + */ + private String generateBlueprintFileName(String monitoringFlowType, String vfcmtName) { + StringBuffer sb = new StringBuffer(); + sb.append(monitoringFlowType); + sb.append("."); + sb.append(Normalizers.normalizeComponentName(vfcmtName)); + sb.append("."); + sb.append(DcaeBeConstants.Composition.fileNames.EVENT_PROC_BP_YAML); + return sb.toString(); + } + + private ResourceInstance findVfiOnService(ServiceDetailed service, String vfiName) { + return null == service ? null : CollectionUtils.isEmpty(service.getResources()) ? null : service.getResources().stream().filter(p -> vfiName.equals(p.getResourceInstanceName())).findAny().orElse(null); + } + + private Artifact findCdumpArtifactData(ResourceDetailed vfcmt) { + return null == vfcmt ? null : CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream() + .filter(p -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(p.getArtifactName())).findAny().orElse(null); + } + + private void certifyVfcmt(ResourceDetailed vfcmt, String requestId){ + String state = vfcmt.getLifecycleState(); + if(null == state) { + debugLogger.log(LogLevel.ERROR, this.getClass().getName(), "Couldn't read Vfcmt lifecycle state"); + return; + } + DcaeBeConstants.LifecycleStateEnum lifeCycleState = DcaeBeConstants.LifecycleStateEnum.findState(state); + if(null == lifeCycleState) { + debugLogger.log(LogLevel.ERROR, this.getClass().getName(), "Undefined lifecycle state: {}", state); + return; + } + try{ + switch (lifeCycleState){ + case NOT_CERTIFIED_CHECKOUT: + baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(vfcmt.getLastUpdaterUserId(), vfcmt.getUuid(), LifecycleOperationType.CHECKIN.name(), "check in VFCMT after blueprint successful submission", requestId); + case NOT_CERTIFIED_CHECKIN: + baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(vfcmt.getLastUpdaterUserId(), vfcmt.getUuid(), LifecycleOperationType.CERTIFY.name(), "certify VFCMT after blueprint successful submission", requestId); + } + } + catch (Exception e){ + //informative only. no message to user (TBA) + debugLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occurred during vfcmt lifecycle operation: {}", e.toString()); + } + } + +} 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 new file mode 100644 index 0000000..5cba14f --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java @@ -0,0 +1,338 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.json.JSONArray; +import org.json.JSONException; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.MessageResponse; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.catalog.Catalog; +import org.onap.sdc.dcae.catalog.Catalog.*; +import org.onap.sdc.dcae.catalog.engine.*; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.ArtifactType; +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.onap.sdc.dcae.utils.SdcRestClientUtils; +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.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; + +import javax.annotation.PostConstruct; +import java.net.URI; +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 +public class CompositionController extends BaseController{ + + @Autowired + private CatalogController catalogController; + + @PostConstruct + public void init() { + catalogController.setDefaultCatalog(URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_CATALOG_URL))); + } + + @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); + 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()); + checkVfcmtType(vfcmt); + checkUserIfResourceCheckedOut(userId, vfcmt); + boolean isTargetNeed2Checkout = 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 checkout 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) { + + final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout()); + + catalog.rootsByLabel(request.getStartingLabel()) + .setHandler(catalogController.new CatalogHandler<Folders>(request, result) { + public CatalogResponse handleData(Folders theFolders) { + JSONArray ja = new JSONArray(); + if (theFolders != null) { + for (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; + } + }); + return result; + } + + @RequestMapping(value = "/{theItemId}/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") + public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest, @PathVariable String theItemId) { + + final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout()); + + catalog + // .fetchFolderByItemId(theItemId) + .folder(theItemId).withParts().withPartAnnotations().withItems().withItemAnnotations().withItemModels() + .execute().setHandler(catalogController.new CatalogHandler<Folder>(request, result) { + public CatalogResponse handleData(Folder theFolder) { + CatalogResponse response = new CatalogResponse(this.request); + if (theFolder == null) { + return response; + } + + try { + Elements folders = theFolder.elements("parts", Folders.class); + if (folders != null) { + for (Object folder : folders) { + catalogController.patchData(catalog, ((Element) folder).data()); + // lots of ephemere proxies created here .. + Elements annotations = ((Element) folder).elements("annotations", + Annotations.class); + if (annotations != null) { + for (Object a : annotations) { + catalogController.patchData(catalog, ((Annotation) a).data()); + } + } + } + } + Elements items = theFolder.elements("items", Items.class); + if (items != null) { + for (Object i : items) { + catalogController.patchData(catalog, ((Element) i).data()); + // lots of ephemere proxies created here .. + Elements annotations = ((Element) i).elements("annotations", Annotations.class); + if (annotations != null) { + for (Object a : annotations) { + catalogController.patchData(catalog, ((Annotation) a).data()); + } + } + } + } + } 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; + } + }); + + return result; + } + + @RequestMapping(value = "/{theItemId}/model", method = { RequestMethod.POST,RequestMethod.GET }, produces = "application/json") + public DeferredResult model(@RequestBody(required = false) ElementRequest theRequest, + @PathVariable String theItemId) { + final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout()); + + catalog + .item(theItemId).withModels().execute() + .setHandler(catalogController.new CatalogHandler<Item>(request, result) { + public CatalogResponse handleData(Item theItem) { + if (theItem == null) { + return new CatalogError(this.request, "No such item"); + } + Templates models = null; + try { + models = (Templates) theItem.elements("models", Templates.class); + 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 !?"); + } + catalog.template(models.get(0).id()).withInputs().withOutputs().withNodes() + .withNodeProperties().withNodePropertiesAssignments().withNodeRequirements() + .withNodeCapabilities().withNodeCapabilityProperties() + .withNodeCapabilityPropertyAssignments().withPolicies().withPolicyProperties() + .withPolicyPropertiesAssignments().execute().setHandler( + catalogController.new CatalogHandler<Template>(this.request, this.result) { + public CatalogResponse handleData(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); + } + } + return response; + } + }); + } catch (Exception e) { + handleException(e, ApiType.GET_MODEL, models.get(0).name()); + } + return null; + } + }); + + return result; + } + + @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) { + final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout()); + + catalog.type(theItemId, theTypeName).withHierarchy().withCapabilities().withRequirements().execute() + .setHandler(catalogController.new CatalogHandler<Type>(request, result) { + public CatalogResponse handleData(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; + } + }); + + return result; + } + + @RequestMapping(value = { "/getComposition/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getComposition(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) { + MessageResponse response = new MessageResponse(); + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + checkVfcmtType(vfcmt); + + Artifact compositionArtifact = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(a.getArtifactName())).findAny().orElse(null); + + if(null == compositionArtifact){ + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Couldn't find {} in VFCMT artifacts", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + response.setErrorResponse("No Artifacts"); + return new ResponseEntity<>(response, HttpStatus.NO_CONTENT); + } + + String artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, compositionArtifact.getArtifactUUID(), requestId); + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ARTIFACT: {}", artifact); + response.setSuccessResponse(artifact); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_CDUMP); + } + } + + @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) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ARTIFACT CDUMP: {}", theCdump); + + try { + + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT: {}", vfcmt); + + checkVfcmtType(vfcmt); + checkUserIfResourceCheckedOut(userId, vfcmt); + boolean isNeed2Checkout = isNeedToCheckOut(vfcmt.getLifecycleState()); + Artifact compositionArtifact = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(a.getArtifactName())).findAny().orElse(null); + String resourceUuid = vfcmtUuid; // by default the resource is the original vfcmtId unless a checkout will be done + if (isNeed2Checkout) { + vfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, resourceUuid, LifecycleOperationType.CHECKOUT.name(), null, requestId); + if (vfcmt != null) { + resourceUuid = vfcmt.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New resource after checkout is: {}", resourceUuid); + } + } + boolean isUpdateMode = null != compositionArtifact; + if (isUpdateMode) { + compositionArtifact.setDescription("updating composition file"); + compositionArtifact.setPayloadData(Base64Utils.encodeToString(theCdump.getBytes())); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT {} does consist {} ----> updateMode", resourceUuid, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + baseBusinessLogic.getSdcRestClient().updateResourceArtifact(userId, resourceUuid, compositionArtifact, requestId); + + } else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT {} does not consist {} ----> createMode", resourceUuid, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + compositionArtifact = SdcRestClientUtils.generateDeploymentArtifact("creating composition file", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML, ArtifactType.DCAE_TOSCA.name(), "composition", theCdump.getBytes()); + baseBusinessLogic.getSdcRestClient().createResourceArtifact(userId, resourceUuid, compositionArtifact, requestId); + } + Asset result = checkin(userId, resourceUuid, org.onap.sdc.dcae.enums.AssetType.RESOURCE, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "vfcmt check-in result: {}", result); + + return new ResponseEntity<>(result, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.SAVE_CDUMP); + } + } +} 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 new file mode 100644 index 0000000..4f083ca --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java @@ -0,0 +1,63 @@ +package org.onap.sdc.dcae.composition.controller; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.CompositionConfig; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.ves.VesStructureLoader; +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 io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +@RequestMapping("/conf") +public class ConfigurationController extends BaseController{ + + @Autowired + private CompositionConfig compositionConfig; + + @ApiOperation(value = "Get a list of available flow types", response = CompositionConfig.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successfully retrieved available flow types list"), + @ApiResponse(code = 500, message = "Flow types couldn't be fetched due to internal error")}) + @RequestMapping(value = "/composition", method = RequestMethod.GET) + public ResponseEntity getCompositionConfig() { + try { + return new ResponseEntity<>(compositionConfig, HttpStatus.OK); + }catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Exception:{}",e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.FLOW_TYPES_CONFIGURATION_ERROR); + } + } + + @RequestMapping(value = "/ves/schemaversions", method = RequestMethod.GET) + public ResponseEntity getCommonEventFormatVersion() { + try { + Set<String> availableVersionsSet = VesStructureLoader.getAvailableVersionsList(); + List<String> availableVersionsList = new ArrayList<>(availableVersionsSet.size()); + availableVersionsList.addAll(availableVersionsSet); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got a request to return available ves schema versions: {}", availableVersionsSet); + return new ResponseEntity<>(availableVersionsList, HttpStatus.OK); + }catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Exception:{}",e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.VES_SCHEMA_NOT_FOUND); + } + } + + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/LifecycleController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/LifecycleController.java new file mode 100644 index 0000000..3007335 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/LifecycleController.java @@ -0,0 +1,84 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class LifecycleController extends BaseController { + + private static final String VFCMT = "vfcmt"; + + @RequestMapping(value={"/checkin/{assetType}/{uuid}"}, method={RequestMethod.PUT}, produces={"application/json"}) + public ResponseEntity putCheckin( + @PathVariable("assetType") String assetType, + @PathVariable("uuid") UUID uuid, + @RequestHeader("USER_ID") String user_id, + @ModelAttribute("requestId") String requestId) { + + try { + switch (assetType) { + case VFCMT: + Asset res_checkin = checkin(user_id, uuid.toString(), AssetType.RESOURCE, requestId); + return new ResponseEntity<>(res_checkin, HttpStatus.OK); + + default: + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.CHECK_IN_RESOURCE); + } + } + + @RequestMapping(value={"/checkout/{assetType}/{uuid}"}, method={RequestMethod.PUT}, produces={"application/json"}) + public ResponseEntity putCheckout( + @PathVariable("assetType") String assetType, + @PathVariable("uuid") UUID uuid, + @RequestHeader("USER_ID") String user_id, + @ModelAttribute("requestId") String requestId) { + + try { + switch (assetType) { + case VFCMT: + Asset asset = checkout(user_id, uuid.toString(), AssetType.RESOURCE, requestId); + return new ResponseEntity<>(asset, HttpStatus.OK); + + default: + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.CHECK_OUT_RESOURCE); + } + } + + @RequestMapping(value={"/certify/{assetType}/{uuid}"}, method={RequestMethod.PUT}, produces={"application/json"}) + public ResponseEntity putCertify( + @PathVariable("assetType") String assetType, + @PathVariable("uuid") String uuid, + @RequestHeader("USER_ID") String user_id, + @ModelAttribute("requestId") String requestId) { + + try { + switch (assetType) { + case VFCMT: + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(user_id, uuid, LifecycleOperationType.CERTIFY.name(), "certifying VFCMT", requestId); + return new ResponseEntity<>(vfcmt, HttpStatus.OK); + + default: + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.CHECK_OUT_RESOURCE); + } + } +} 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 new file mode 100644 index 0000000..3f5ff1a --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java @@ -0,0 +1,453 @@ +package org.onap.sdc.dcae.composition.controller; + +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.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.composition.CompositionConfig; +import org.onap.sdc.dcae.utils.Normalizers; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.ArtifactType; +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.errormng.ErrConfMgr.ApiType; +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.utils.SdcRestClientUtils; +import org.onap.sdc.dcae.ves.VesDataItemsDefinition; +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.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +@RequestMapping("/rule-editor") +public class RuleEditorController extends BaseController { + + private static final String EXCEPTION = "Exception {}"; + @Autowired + private CompositionConfig compositionConfig; + + @Autowired + private RulesBusinessLogic rulesBusinessLogic; + + @RequestMapping(value = "/list-events-by-versions", method = RequestMethod.GET) + public ResponseEntity getEventsByVersion() { + try { + + Map<String, Set<String>> eventsByVersions = VesStructureLoader.getAvailableVersionsAndEventTypes(); + + List<EventTypesByVersionUI> resBody = eventsByVersions.entrySet().stream().map(entry -> { + Set<String> events = entry.getValue().stream().filter(event -> !EventTypesByVersionUI.DEFAULT_EVENTS.contains(event)).collect(Collectors.toSet()); + return new EventTypesByVersionUI(entry.getKey(), events); + }).collect(Collectors.toList()); + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got a request to return all ves event types by versions {}", eventsByVersions); + return new ResponseEntity<>(resBody, HttpStatus.OK); + + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), EXCEPTION, e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.VES_SCHEMA_NOT_FOUND); + } + } + + @RequestMapping(value = { "/definition/{version:.*}/{eventType}" }, method = { RequestMethod.GET }, produces = { "application/json" }) + public ResponseEntity getDefinition(@PathVariable("version") String version, + @PathVariable("eventType") String eventType) { + + try { + List<EventTypeDefinitionUI> result = getEventTypeDefinitionUIs(version, eventType); + + return new ResponseEntity<>(result, HttpStatus.OK); + + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), EXCEPTION, e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.VES_SCHEMA_NOT_FOUND); + } + } + + /** + * This endpoint functions as a 'create/update' service for the rule editor UI + * + * @param json - json representing the saved rule + * @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 + * @return json representing the rule editor UI + * 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/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}", method = { RequestMethod.POST }, produces = "application/json") + public ResponseEntity saveRule(@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) { + try { + Rule rule = RulesPayloadUtils.parsePayloadToRule(json); + if (null == rule) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT); + } + + List<ServiceException> errors = rulesBusinessLogic.validateRule(rule); + if(!errors.isEmpty()){ + return ErrConfMgr.INSTANCE.buildErrorArrayResponse(errors); + } + + ResourceDetailed vfcmt = baseBusinessLogic.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); + + // exception thrown if vfcmt is checked out and current user is not its owner + // performs vfcmt checkout 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); + } + 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); + + } 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 handleException(e, ErrConfMgr.ApiType.SAVE_RULE_ARTIFACT); + } + + } + + + /** + * This endpoint functions as a 'fetch' 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 + * @return json representing the rule editor UI + */ + @RequestMapping(value = "/rule/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}", method = { RequestMethod.GET }, produces = "application/json") + public ResponseEntity getRules( + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam, + @ModelAttribute("requestId") String requestId) { + + try { + ResourceDetailed vfcmt = baseBusinessLogic.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 = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactListed.getArtifactUUID(), requestId); + + // 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); + List<EventTypeDefinitionUI> schema = null == schemainfo? new ArrayList<>() : getEventTypeDefinitionUIs(schemainfo.getVersion(), schemainfo.getEventType()); + return new ResponseEntity<>(RulesPayloadUtils.buildSchemaAndRulesResponse(ruleFile, schema), HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_RULE_ARTIFACT); + } + + } + + /** + * 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 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 ruleUid - the unique id of the rule to delete + * @return operation result + */ + @RequestMapping(value = "/rule/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}/{ruleUid}", method = { RequestMethod.DELETE }, produces = "application/json") + public ResponseEntity deleteRule( + @RequestHeader("USER_ID") String userId, + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam, + @PathVariable("ruleUid") String ruleUid, + @ModelAttribute("requestId") String requestId){ + + try { + ResourceDetailed vfcmt = baseBusinessLogic.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 vfcmtId = assertOwnershipOfVfcmtId(userId, vfcmt, requestId); + String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtId, mappingRuleFile.getArtifactUUID(), requestId); + MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); + Rule removedRule = rulesBusinessLogic.deleteRule(rules, ruleUid); + if(null == removedRule){ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Rule {} not found.", ruleUid); + 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 + baseBusinessLogic.getSdcRestClient().deleteResourceArtifact(userId, vfcmtId, mappingRuleFile.getArtifactUUID(), requestId); + } else { + updateRulesArtifact(vfcmtId, userId, mappingRuleFile, rules, requestId); + } + return checkInAndReturnSaveArtifactResult(removedRule, vfcmtId, userId, requestId); + } catch (Exception e) { + return handleException(e, ApiType.SAVE_RULE_ARTIFACT); + } + + } + + /** + * 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) + * @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 + * @throws Exception + */ + @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) throws Exception { + + 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"); + } + + // 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 = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + checkVfcmtType(vfcmt); + + if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "No rules found on VFCMT " + vfcmtUuid); + } + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // 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); + } + + String payload = baseBusinessLogic.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); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished parsing rules, calling validator..."); + List<ServiceException> errors = rulesBusinessLogic.validateRules(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()); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Translation completed successfully"); + return new ResponseEntity<>(translateJson, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.SAVE_RULE_ARTIFACT); + } + } + + + ///////////////////PRIVATE METHODS//////////////////////////////////////////////////////////////////////// + + private String assertOwnershipOfVfcmtId(String userId, ResourceDetailed vfcmt, String requestId) throws Exception { + checkUserIfResourceCheckedOut(userId, vfcmt); + String newVfcmtId = vfcmt.getUuid(); // may change after checking out a certified vfcmt + if (isNeedToCheckOut(vfcmt.getLifecycleState())) { + Asset result = checkout(userId, newVfcmtId, AssetType.RESOURCE, requestId); + if (result != null) { + newVfcmtId = result.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New resource after checkout 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() + .filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equalsIgnoreCase(a.getArtifactName())) + .findAny().orElse(null); + if (null == cdump || null == cdump.getArtifactUUID()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "No {} found on vfcmt {}", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML, vfcmt.getUuid()); + return false; + } + try { + String artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmt.getUuid(), cdump.getArtifactUUID(), requestId); + if (!artifact.contains("\"nid\":\""+nid)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "{} doesn't contain nid {}. Cannot save mapping rule file", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML, nid); + return false; + } + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), EXCEPTION, e); + return false; + } + return true; + } + + private ResponseEntity<String> saveNewRulesArtifact(Rule rule, String vfcmtUuid, String artifactFileName, String artifactLabel, String userId, String requestId) throws Exception { + MappingRules body = new MappingRules(rule); + Artifact artifact = SdcRestClientUtils.generateDeploymentArtifact(body.describe(), artifactFileName, ArtifactType.OTHER.name(), artifactLabel, body.convertToPayload()); + baseBusinessLogic.getSdcRestClient().createResourceArtifact(userId, vfcmtUuid, artifact, requestId); + return checkInAndReturnSaveArtifactResult(rule, vfcmtUuid, userId, requestId); + } + + private ResponseEntity addOrEditRuleInArtifact(Rule rule, String vfcmtUuid, String userId, Artifact rulesArtifact, String requestId) throws Exception { + String payload = baseBusinessLogic.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)) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SAVE_RULE_FAILED); + } + updateRulesArtifact(vfcmtUuid, userId, rulesArtifact, rules, requestId); + return checkInAndReturnSaveArtifactResult(rule, vfcmtUuid, userId, requestId); + } + + // regardless of check in result, return save artifact success + private ResponseEntity<String> checkInAndReturnSaveArtifactResult(Rule rule, String vfcmtUuid, String userId, String requestId) { + try { + checkin(userId, vfcmtUuid, AssetType.RESOURCE, 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); + } + + private void updateRulesArtifact(String vfcmtUuid, String userId, Artifact artifactInfo, MappingRules rules, String requestId) throws Exception { + artifactInfo.setPayloadData(Base64Utils.encodeToString(rules.convertToPayload())); + // POST must contain 'description' while GET returns 'artifactDescription' + artifactInfo.setDescription(artifactInfo.getArtifactDescription()); + baseBusinessLogic.getSdcRestClient().updateResourceArtifact(userId, vfcmtUuid, artifactInfo, requestId); + } + + + /** + * @param eventMapStream + * @param parent + * @param path + * @return + */ + private List<EventTypeDefinitionUI> convertToEventTypeDefinition(Stream<Entry<String, VesDataTypeDefinition>> eventMapStream, VesDataTypeDefinition parent, String path) { + + return eventMapStream.map(entry -> { + Map<String, VesDataTypeDefinition> properties = entry.getValue().getProperties(); + VesDataItemsDefinition items = entry.getValue().getItems(); + String newPath = path + "." + entry.getKey(); + List<EventTypeDefinitionUI> children = (properties == null) ? null : convertToEventTypeDefinition(properties.entrySet().stream(), entry.getValue(), newPath); + if(VesSimpleTypesEnum.ARRAY.getType().equals(entry.getValue().getType())) { + newPath += "[]"; + if(innerTypeIsComplex(items)) { + children = convertComplexArrayType(items, newPath); + } else if(innerTypeIsArray(items)) { + newPath += "[]"; + } + } + + boolean isRequired = (parent != null) ? parent.getRequired().contains(entry.getKey()) : false; + return new EventTypeDefinitionUI(entry.getKey(), children, isRequired, newPath); + }).collect(Collectors.toList()); + } + + private boolean innerTypeIsComplex(VesDataItemsDefinition items){ + return items != null && items.stream().anyMatch(p -> p.getProperties() != null); + } + + private boolean innerTypeIsArray(VesDataItemsDefinition items){ + return items != null && items.stream().anyMatch(p -> p.getItems() != null); + } + + private List<EventTypeDefinitionUI> convertComplexArrayType(VesDataItemsDefinition items, String path){ + return items.stream().map(item -> item.getProperties() != null ? convertToEventTypeDefinition(item.getProperties().entrySet().stream(), item, path) : new ArrayList<EventTypeDefinitionUI>()) + .flatMap(List::stream).collect(Collectors.toList()); + } + + + private String generateMappingRulesFileName(String dcaeCompLabel, String nid, String configParam) { + return dcaeCompLabel + "_" + nid + "_" + configParam + DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX; + } + + 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); + Stream<Entry<String, VesDataTypeDefinition>> filteredEvents = eventDefs.entrySet().stream().filter(entry -> eventNamesToReturn.contains(entry.getKey())); + + return convertToEventTypeDefinition(filteredEvents, null, "event"); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ServicesController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ServicesController.java new file mode 100644 index 0000000..257d1a9 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ServicesController.java @@ -0,0 +1,230 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.AttachVFCMTServiceRequest; +import org.onap.sdc.dcae.composition.restmodels.DcaeMinimizedService; +import org.onap.sdc.dcae.composition.restmodels.MessageResponse; +import org.onap.sdc.dcae.composition.restmodels.sdc.*; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants.LifecycleStateEnum; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.DcaeException; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class ServicesController extends BaseController { + + /*** + * GET services list by VFCMT + * @param userId + * @param vfcmtUuid + * @return ResponseEntity + */ + @RequestMapping(value = { "/services/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity services(@RequestHeader("USER_ID") String userId, @PathVariable String vfcmtUuid, @ModelAttribute("requestId") String requestId) { + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "GET ({}) Vfcmt form SDC: {}", vfcmtUuid, vfcmt); + checkVfcmtType(vfcmt); + checkUserIfResourceCheckedOut(userId, vfcmt); + + List<Service> services = baseBusinessLogic.getSdcRestClient().getServices(requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "GET services data from SDC: {}", services); + List<Service> uuids = filterServicesByUser(services, userId); + return new ResponseEntity<>(uuids, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.GET_SERVICE); + } + } + + /*** + * GET a single service + * @param theServiceId + * @return ResponseEntity + */ + @RequestMapping(value = { "/service/{theServiceId}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity service(@PathVariable String theServiceId, @ModelAttribute("requestId") String requestId) { + try { + ServiceDetailed service = baseBusinessLogic.getSdcRestClient().getService(theServiceId, requestId); + if (service != null) { + if(service.getResources()!=null){ + List<ResourceInstance> vfResourcesOnly = service.getResources().stream().filter(vfi -> vfi.getResoucreType().equals("VF")).collect(Collectors.toList()); + service.setResources(vfResourcesOnly); + }else{ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Service {} doesn't have any resources (e.g VFi's)", theServiceId); + } + } else { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Couldn't fetch service with uuid {} from SDC", theServiceId); + } + return new ResponseEntity<>(service, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.GET_SERVICE); + } + } + + + /*** + * Attach service and service instance to VFCMT + * @param userId + * @param request + * @return ResponseEntity + */ + @RequestMapping(value = "/{vfcmtUuid}/attachment", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity attachService( + @PathVariable("vfcmtUuid") String vfcmtUuid, + @RequestHeader("USER_ID") String userId, + @RequestBody AttachVFCMTServiceRequest request, + @ModelAttribute("requestId") String requestId) { + + String serviceUuid = request.getServiceUuid(); + String vfiName = request.getInstanceName(); + String resourceUuid = vfcmtUuid; + MessageResponse response = new MessageResponse(); + + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + + checkVfcmtType(vfcmt); + verifyVfiExists(serviceUuid, vfiName, requestId); + + boolean isUpdateMode = false; + Artifact artifactObj = null; + + String reference = serviceUuid + "/resources/" + vfiName; + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "*****************************************"); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Reference between service and vfi {}", reference); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "*****************************************"); + + if(!CollectionUtils.isEmpty(vfcmt.getArtifacts())){ + artifactObj = vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.SVC_REF.equals(a.getArtifactName())).findAny().orElse(null); + isUpdateMode = null != artifactObj; + } + + if (isNeedToCheckOut(vfcmt.getLifecycleState())) { + vfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, vfcmtUuid, LifecycleOperationType.CHECKOUT.name(), null, requestId); + if (vfcmt != null) { + resourceUuid = vfcmt.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New vfcmt uuid after checkout is: {}", resourceUuid); + } + } + + if(isUpdateMode){ + updateReferenceArtifact(userId, resourceUuid, artifactObj, reference, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Artifact {} updated with content: {}", reference, DcaeBeConstants.Composition.fileNames.SVC_REF, reference); + }else{ + Artifact artifact = SdcRestClientUtils.generateDeploymentArtifact("createReferenceArtifact", DcaeBeConstants.Composition.fileNames.SVC_REF, ArtifactType.DCAE_TOSCA.name(), "servicereference", reference.getBytes()); + baseBusinessLogic.getSdcRestClient().createResourceArtifact(userId, resourceUuid, artifact, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Artifact {} created with content: {}", DcaeBeConstants.Composition.fileNames.SVC_REF, reference); + } + checkin(userId, resourceUuid, org.onap.sdc.dcae.enums.AssetType.RESOURCE, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Attachment of reference={} in VFCMT {} has finished successfully", reference, resourceUuid); + + response.setSuccessResponse("Artifact updated"); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.ATTACH_TO_SERVICE); + } + } + + @RequestMapping(value = { "/{vfcmtUuid}/attachment" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getAttachedService(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) { + + MessageResponse response = new MessageResponse(); + + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + checkVfcmtType(vfcmt); + String artifact = "No Artifacts"; + + if (!CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + Artifact artifactObj = vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.SVC_REF.equals(a.getArtifactName())).findAny().orElse(null); + if (null != artifactObj) + artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactObj.getArtifactUUID(), requestId); + } + response.setSuccessResponse(artifact); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.GET_VFCMT); + } + } + + /**** PRIVATE METHODS ****/ + + private void updateReferenceArtifact(String userId, String VFCMTUuid, Artifact artifactObj, String reference, String requestId) throws Exception { + artifactObj.setDescription("updateReferenceArtifact"); + artifactObj.setPayloadData(Base64Utils.encodeToString(reference.getBytes())); + baseBusinessLogic.getSdcRestClient().updateResourceArtifact(userId, VFCMTUuid, artifactObj, requestId); + } + + + /** + * + * @param lastUpdaterUserId + * @param services + * @param userId + * @return + */ + + //TODO move method to ci tests + public List<DcaeMinimizedService> parseAndFilterServicesByUser(String lastUpdaterUserId, List<LinkedHashMap<String, String>> services, String userId) { + List<DcaeMinimizedService> uuids = null; + if (services != null) { + //services.stream().filter(predicate) + uuids = services.stream() + .map(x -> new DcaeMinimizedService(x.get("uuid"), x.get("name"), x.get("lastUpdaterUserId"), x.get("lifecycleState"), x.get("version"), x.get("invariantUUID"))) + .collect(Collectors.groupingBy(DcaeMinimizedService::getInvariantUUID)).values().stream() + .map(p -> p.stream() + .sorted(Comparator.comparing(DcaeMinimizedService::getVersionAsFloat).reversed())).map(p -> p.collect(Collectors.toList())).map(p -> p.get(0)) + .filter(x -> (!(!x.getLastUpdaterUserId().equals(userId) && x.getLifeCycleState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())))) + .sorted(Comparator.comparing(DcaeMinimizedService::getName)).collect(Collectors.toList()); + } + return uuids; + } + + private List<Service> filterServicesByUser(List<Service> services, String userId) { + return CollectionUtils.isEmpty(services) ? new ArrayList<>() : services.stream() + .collect(Collectors.groupingBy(Service::getInvariantUUID)).values().stream() + .map(p -> p.stream() + .sorted(Comparator.comparing(Service::versionAsFloat).reversed())).map(p -> p.collect(Collectors.toList())).map(p -> p.get(0)) + .filter(x -> (!(!x.getLastUpdaterUserId().equals(userId) && x.getLifecycleState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())))) + .sorted(Comparator.comparing(Service::getName)).collect(Collectors.toList()); + } + + /** + * + * @param serviceUuid + * @param vfiName + * @param requestId + * @throws Exception + */ + private void verifyVfiExists(String serviceUuid, String vfiName, String requestId) throws Exception { + ServiceDetailed service = baseBusinessLogic.getSdcRestClient().getService(serviceUuid, requestId); + boolean isServiceContainsVfi = null != service && !CollectionUtils.isEmpty(service.getResources()) && service.getResources().stream() + .filter(vfi -> "VF".equals(vfi.getResoucreType())) + .anyMatch(vfi -> vfiName.equals(vfi.getResourceInstanceName())); + if (!isServiceContainsVfi) { + ResponseFormat responseFormat = ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.VFI_FETCH_ERROR, null, serviceUuid, vfiName); + throw new DcaeException(HttpStatus.NOT_FOUND, responseFormat.getRequestError()); + } + } +} 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 new file mode 100644 index 0000000..0e1b209 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java @@ -0,0 +1,183 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.impl.ReferenceBusinessLogic; +import org.onap.sdc.dcae.composition.impl.VfcmtBusinessLogic; +import org.onap.sdc.dcae.composition.restmodels.CreateVFCMTRequest; +import org.onap.sdc.dcae.composition.restmodels.ImportVFCMTRequest; +import org.onap.sdc.dcae.composition.restmodels.sdc.ExternalReferencesMap; +import org.onap.sdc.dcae.composition.restmodels.sdc.Resource; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +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.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class VfcmtController extends BaseController{ + + + @Autowired + private VfcmtBusinessLogic vfcmtBusinessLogic; + @Autowired + private ReferenceBusinessLogic referenceBusinessLogic; + + private static final String VFCMT = "VFCMT"; + private static final String TEMPLATE = "Template"; + private static final String BASE_MONITORING_TEMPLATE = "Base Monitoring Template"; + + + + /*** + * Get one resource information + * @param theResourceId retrieved resource id + * @return ResponseEntity + */ + @RequestMapping(value = { "/resource/{theResourceId}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity resource(@PathVariable String theResourceId, @ModelAttribute("requestId") String requestId) { + try { + ResourceDetailed resource = baseBusinessLogic.getSdcRestClient().getResource(theResourceId, requestId); + return new ResponseEntity<>(resource, HttpStatus.OK); + }catch (Exception e) { + return handleException(e, ApiType.GET_VFCMT); + } + } + + /*** + * Get All resources + * @return ResponseEntity + */ + @RequestMapping(value = { "/getResourcesByCategory" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getResourcesByCategory(@ModelAttribute("requestId") String requestId) { + try { + List<Resource> resources = baseBusinessLogic.getSdcRestClient().getResources(VFCMT, null, null, requestId); + return new ResponseEntity<>(resources, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_ALL_VFCMTS); + } + } + + /*** + * Get All resources by Service + * @return ResponseEntity + */ + + @RequestMapping(value = { "/{contextType}/{uuid}/{version}/getVfcmtsForMigration" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getVfcmtsForMigration(@RequestHeader("USER_ID") String userId, + @PathVariable String contextType, + @PathVariable String uuid, + @PathVariable String version, + @ModelAttribute("requestId") String requestId){ + + return vfcmtBusinessLogic.getVfcmtsForMigration(userId, contextType, uuid, version, requestId); + } + + /*** + * Get All resources by Monitoring Template Category + * @return ResponseEntity + */ + @RequestMapping(value = { "/getResourcesByMonitoringTemplateCategory" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getResourcesByMonitoringTemplateCategory(@ModelAttribute("requestId") String requestId) { + try { + List<Resource> resources = baseBusinessLogic.getSdcRestClient().getResources(VFCMT, TEMPLATE, BASE_MONITORING_TEMPLATE, requestId); + return new ResponseEntity<>(resources, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_ALL_VFCMTS); + } + } + + /*** + * Create new Vfcmt + * @param userId retrieved user ID + * @param request retrieved request + * @return ResponseEntity + */ + @RequestMapping(value = "/createVFCMT", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity createVFCMT(@RequestHeader("USER_ID") String userId, @RequestBody CreateVFCMTRequest request, @ModelAttribute("requestId") String requestId) { + vfcmtBusinessLogic.addSdcMandatoryFields(request, userId); + try { + ResourceDetailed response = baseBusinessLogic.getSdcRestClient().createResource(userId, request, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "createVFCMT after post: {}", response); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.CREATE_NEW_VFCMT); + } + } + + /*** + * Create new Vfcmt from general screen + * @param userId retrieved user ID + * @param request retrieved request + * @return ResponseEntity + */ + @RequestMapping(value = "/createMC", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity createMC(@RequestHeader("USER_ID") String userId, @RequestBody CreateVFCMTRequest request, @ModelAttribute("requestId") String requestId) { + return vfcmtBusinessLogic.createMcFromTemplate(userId, request, requestId); + } + + + /*** + * Clone or import existing VFCMT and attach to selected service/resource + * @param userId + * @param request + * @return ResponseEntity + */ + @RequestMapping(value = "/importMC", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity importMC(@RequestHeader("USER_ID") String userId, @RequestBody ImportVFCMTRequest request, @ModelAttribute("requestId") String requestId) { + return vfcmtBusinessLogic.importMC(userId, request, requestId); + } + + /*** + * GET a list of Monitoring Components of a service by uuid and version + * @param context the context type of this request + * @param uuid the uuid of the type requested + * @param version the version of the entity requested + * @return ResponseEntity + */ + @RequestMapping(value = { "/{context}/{uuid}/{version}/monitoringComponents" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getMonitoringComponents(@PathVariable String context, @PathVariable String uuid, @PathVariable String version, @ModelAttribute("requestId") String requestId) { + try { + ExternalReferencesMap mcRefs = baseBusinessLogic.getSdcRestClient().getMonitoringReferences(context, uuid, version, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got monitoring references map from SDC: {}", mcRefs.values()); + return new ResponseEntity<>(referenceBusinessLogic.fetchMonitoringComponents(mcRefs, requestId), HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_SERVICE); + } + } + + @RequestMapping(value = { "/{context}/{serviceUuid}/{vfiName}/{vfcmtUuid}/deleteVfcmtReference" }, method = { RequestMethod.DELETE }, produces = {"application/json" }) + public ResponseEntity deleteVfcmtReference(@RequestHeader("USER_ID") String userId, @PathVariable String context, @PathVariable String serviceUuid, @PathVariable String vfiName, @PathVariable String vfcmtUuid, @ModelAttribute String requestId) { + try { + referenceBusinessLogic.deleteVfcmtReference(userId, context, serviceUuid, vfiName, vfcmtUuid, requestId); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.DELETE_VFCMT_REFERENCE); + } + } + + @RequestMapping(value = { "/{context}/{monitoringComponentName}/{serviceUuid}/{vfiName}/{vfcmtUuid}/deleteVfcmtReference" }, method = { RequestMethod.DELETE }, produces = {"application/json" }) + public ResponseEntity deleteVfcmtReferenceWithBlueprint(@RequestHeader("USER_ID") String userId, @PathVariable String context, @PathVariable String monitoringComponentName, @PathVariable String serviceUuid, @PathVariable String vfiName, @PathVariable String vfcmtUuid, @ModelAttribute String requestId) { + try { + referenceBusinessLogic.deleteVfcmtReference(userId, context, serviceUuid, vfiName, vfcmtUuid, requestId); + } catch (Exception e) { + return handleException(e, ApiType.DELETE_VFCMT_REFERENCE); + } + return referenceBusinessLogic.deleteVfcmtReferenceBlueprint(userId, context, monitoringComponentName, serviceUuid, vfiName, vfcmtUuid, requestId); + } + + @RequestMapping(value = { "/getVfcmtReferenceData/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getVfcmtReferenceData(@PathVariable String vfcmtUuid, @ModelAttribute String requestId) { + try { + return vfcmtBusinessLogic.getVfcmtReferenceData(vfcmtUuid, requestId); + } catch (Exception e) { + return handleException(e, ApiType.GET_VFCMT); + } + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthController.java new file mode 100644 index 0000000..eaad1b0 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthController.java @@ -0,0 +1,77 @@ +package org.onap.sdc.dcae.composition.controller.health; + +import java.util.ArrayList; +import java.util.List; + +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.composition.restmodels.health.HealthResponse; +import org.onap.sdc.dcae.composition.CompositionEngine; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +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 com.google.gson.Gson; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class HealthController { + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + Gson gson = new Gson(); + + @Autowired + ToscaLabHealthState toscaLabHealthState; + + @RequestMapping(value = "/healthCheck", method = RequestMethod.GET) + public ResponseEntity<String> healthCheck() { + HttpStatus httpSts = HttpStatus.OK; + try{ + HealthResponse healthResponse = new HealthResponse(); + healthResponse.setHealthCheckComponent(DcaeBeConstants.Health.APP_NAME); + healthResponse.setHealthCheckStatus(DcaeBeConstants.Health.UP); + healthResponse.setSdcVersion(CompositionEngine.getDcaeVersion()); + healthResponse.setDescription(DcaeBeConstants.Health.OK); + + List<ComponentsInfo> componentsInfoList = new ArrayList<ComponentsInfo>(); + ComponentsInfo componentsInfo = new ComponentsInfo(); + componentsInfo.setHealthCheckComponent(DcaeBeConstants.Health.BE); + componentsInfo.setHealthCheckStatus(DcaeBeConstants.Health.UP); + componentsInfo.setVersion(CompositionEngine.getDcaeVersion()); + componentsInfo.setDescription(DcaeBeConstants.Health.OK); + componentsInfoList.add(componentsInfo); + + ComponentsInfo toscaLab = new ComponentsInfo(); + ComponentsInfo toscaLabHealthRes = toscaLabHealthState.getToscaLabHealthResponse(); + if(toscaLabHealthRes.getHealthCheckStatus().equals(DcaeBeConstants.Health.DOWN)){ + healthResponse.setHealthCheckStatus(DcaeBeConstants.Health.DOWN); + healthResponse.setDescription(toscaLabHealthRes.getHealthCheckComponent()+" is down"); + httpSts = HttpStatus.INTERNAL_SERVER_ERROR; + } + toscaLab.setHealthCheckComponent(toscaLabHealthRes.getHealthCheckComponent()); + toscaLab.setHealthCheckStatus(toscaLabHealthRes.getHealthCheckStatus()); + toscaLab.setVersion(toscaLabHealthRes.getVersion()); + toscaLab.setDescription(toscaLabHealthRes.getDescription()); + componentsInfoList.add(toscaLab); + + healthResponse.setComponentsInfo(componentsInfoList); + String json = gson.toJson(healthResponse, HealthResponse.class); + + return new ResponseEntity<String>(json, httpSts); + } + catch(Exception e){ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occured while performing HealthCheck: {}", e.getLocalizedMessage()); + return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + +}
\ No newline at end of file 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 new file mode 100644 index 0000000..609480d --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java @@ -0,0 +1,97 @@ +package org.onap.sdc.dcae.composition.controller.health; + +import java.net.URI; +import java.util.Collections; + +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.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.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import com.google.gson.Gson; + +@Configuration +@EnableAsync +@EnableScheduling +@ConfigurationProperties(prefix="blueprinter") +public class HealthPoller { + private URI hcuri; + private String hcretrynum; + private Gson gson; + + private OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @Autowired + private ToscaLabHealthState toscaLabHealthState; + + public HealthPoller() { + super(); + gson = new Gson(); + } + + @Scheduled(fixedDelayString="${healthpoller.fixedDelay}") + public void pollToscaLabHealth() { + ComponentsInfo toscaLabHealthRes = null; + ResponseEntity<String> healthRes = null; + try { + 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(); + toscaLabHealthRes = gson.fromJson(result, ComponentsInfo.class); + break; + } + } + } catch (Exception e) { + toscaLabHealthRes = getNegativeHealth(e.getMessage()); + } + if(toscaLabHealthRes == null){ + toscaLabHealthRes = getNegativeHealth(healthRes.getBody() + "-" + healthRes.getStatusCode()); + } + toscaLabHealthState.setToscaLabHealthResponse(toscaLabHealthRes); + } + + private ComponentsInfo getNegativeHealth(String msg) { + ComponentsInfo toscaLabHealthRes = new ComponentsInfo(); + String description = "DCAE-D BE failed while trying to fetch Tosca_Lab healthcheck. Exception: " +msg; + toscaLabHealthRes.setDescription(description); + toscaLabHealthRes.setHealthCheckComponent(DcaeBeConstants.Health.TOSCA_LAB); + toscaLabHealthRes.setHealthCheckStatus(DcaeBeConstants.Health.DOWN); + errLogger.log(LogLevel.ERROR, this.getClass().getName(), description); + return toscaLabHealthRes; + } + + public ResponseEntity<String> sendHealthCheck() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + HttpEntity<String> entity = new HttpEntity<String>(headers); + return Http.exchangeSync(hcuri.toString(), HttpMethod.GET, entity, String.class, 5000); + } + + public void setHcuri(URI hcuri) { + this.hcuri = hcuri; + } + + public void setHcretrynum(String hcretrynum) { + this.hcretrynum = hcretrynum; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/ToscaLabHealthState.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/ToscaLabHealthState.java new file mode 100644 index 0000000..6fe469f --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/ToscaLabHealthState.java @@ -0,0 +1,29 @@ +package org.onap.sdc.dcae.composition.controller.health; + +import org.onap.sdc.dcae.composition.restmodels.health.ComponentsInfo; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Scope(value = "singleton") +@Component +public class ToscaLabHealthState { + private ComponentsInfo toscaLabHealthResponse; + + public ToscaLabHealthState() { + super(); + toscaLabHealthResponse = new ComponentsInfo(); + toscaLabHealthResponse.setDescription("Not up yet"); + toscaLabHealthResponse.setHealthCheckComponent(DcaeBeConstants.Health.TOSCA_LAB); + toscaLabHealthResponse.setHealthCheckStatus(DcaeBeConstants.Health.DOWN); + } + + public ComponentsInfo getToscaLabHealthResponse() { + return toscaLabHealthResponse; + } + + public void setToscaLabHealthResponse(ComponentsInfo toscaLabHealthResponse) { + this.toscaLabHealthResponse = toscaLabHealthResponse; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/swagger/SwaggerConfig.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/swagger/SwaggerConfig.java new file mode 100644 index 0000000..48c7153 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/swagger/SwaggerConfig.java @@ -0,0 +1,23 @@ +package org.onap.sdc.dcae.composition.controller.swagger; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket productApi() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("org.onap.sdc.dcae.composition.controller")) + .paths(PathSelectors.regex("/*.*")) + .build(); + } +} 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 new file mode 100644 index 0000000..f26c885 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java @@ -0,0 +1,49 @@ +package org.onap.sdc.dcae.composition.impl; + +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.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; + +@Component +public class BaseBusinessLogic { + @Autowired + protected ISdcClient sdcRestClient; + + protected static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + protected static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + public ISdcClient getSdcRestClient() { + return sdcRestClient; + } + + void setSdcRestClient(ISdcClient sdcRestClient) { + this.sdcRestClient = sdcRestClient; + } + + Artifact cloneArtifactToTarget(String userId, String targetId, String payload, Artifact artifactToClone, String requestId) throws Exception { + Artifact cloned = SdcRestClientUtils.generateDeploymentArtifact(artifactToClone.getArtifactDescription(), artifactToClone.getArtifactName(), artifactToClone.getArtifactType(), artifactToClone.getArtifactLabel(), payload.getBytes()); + return sdcRestClient.createResourceArtifact(userId, targetId, cloned, requestId); + } + + public void cloneArtifactToTarget(String userId, String targetId, String payload, Artifact artifactToClone, Artifact artifactToOverride, String requestId) throws Exception{ + if (null != artifactToOverride) { + artifactToOverride.setDescription(artifactToOverride.getArtifactDescription()); + artifactToOverride.setPayloadData(Base64Utils.encodeToString(payload.getBytes())); + sdcRestClient.updateResourceArtifact(userId, targetId, artifactToOverride, requestId); + } else { + cloneArtifactToTarget(userId, targetId, payload, artifactToClone, requestId); + } + } + + Artifact findArtifactDataByArtifactName(ResourceDetailed vfcmt, String artifactName) { + return null == vfcmt ? null : CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream() + .filter(p -> artifactName.equals(p.getArtifactName())).findAny().orElse(null); + } +} 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 new file mode 100644 index 0000000..d229b67 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java @@ -0,0 +1,74 @@ +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.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.ExternalReferencesMap; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceInstance; +import org.onap.sdc.dcae.composition.restmodels.sdc.ServiceDetailed; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.utils.Normalizers; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.util.*; + +import static org.springframework.util.CollectionUtils.isEmpty; + +@Component +public class ReferenceBusinessLogic extends BaseBusinessLogic { + + public ResponseEntity deleteVfcmtReferenceBlueprint(String userId, String context, String monitoringComponentName, String serviceUuid, String vfiName, String vfcmtUuid, String requestId) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to delete blueprint, monitoringComponentName = {}, vfiName = {}", monitoringComponentName, vfiName); + try { + String normalizedVfiName = Normalizers.normalizeComponentInstanceName(vfiName); + ServiceDetailed serviceDetailed = sdcRestClient.getService(serviceUuid, requestId); + Optional<ResourceInstance> resourceInstance = serviceDetailed.getResources().stream().filter(item -> item.getResourceInstanceName().equalsIgnoreCase(vfiName)).findAny(); + if (resourceInstance.isPresent() && resourceInstance.get().getArtifacts() != null) { + Optional<Artifact> artifact = resourceInstance.get().getArtifacts().stream().filter(item -> item.getArtifactName().contains(monitoringComponentName)).findAny(); + artifact.ifPresent(artifact1 -> sdcRestClient.deleteInstanceResourceArtifact(userId, context, serviceUuid, normalizedVfiName, artifact1.getArtifactUUID(), requestId)); + } + } catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Failed to delete blueprint with serviceUuid {}, vfcmtUuid . message: {} ", serviceUuid, vfcmtUuid, e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_BLUEPRINT_FAILED); + } + return new ResponseEntity<>(HttpStatus.OK); + } + + public void deleteVfcmtReference(String userId, String context, String serviceUuid, String vfiName, String vfcmtUuid, String requestId) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to delete vfcmt reference, vfiName = {}", vfiName); + String normalizedVfiName = Normalizers.normalizeComponentInstanceName(vfiName); + sdcRestClient.deleteExternalMonitoringReference(userId, context, serviceUuid, normalizedVfiName, vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished to delete vfcmt reference. serviceUuid {}, vfcmtUuid {}", serviceUuid, vfcmtUuid); + } + + // 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) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to fetch monitoring components metadata for vfis {}", mcRefs.keySet()); + Map<String, List<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())); + } 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); + if(!isEmpty(unavailable)) { + result.put("unavailable", unavailable); + } + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished fetching monitoring components metadata for vfis {}", mcRefs.keySet()); + return result; + } + + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/VfcmtBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/VfcmtBusinessLogic.java new file mode 100644 index 0000000..e68a8ee --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/VfcmtBusinessLogic.java @@ -0,0 +1,283 @@ +package org.onap.sdc.dcae.composition.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang.StringUtils; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.*; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.ExternalReferencesMap; +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.ArtifactType; +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.utils.SdcRestClientUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.onap.sdc.dcae.composition.util.DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT; +import static org.onap.sdc.dcae.composition.util.DcaeBeConstants.LifecycleStateEnum.findState; + +@Component +public class VfcmtBusinessLogic extends BaseBusinessLogic { + + private static final String VFCMT = "VFCMT"; + private static final String TEMPLATE = "Template"; + private static final String MONITORING_TEMPLATE = "Monitoring Template"; + private static final String DEFAULTICON = "defaulticon"; + private static final String VENDOR_NAME = "vendorName"; + private static final String VENDOR_RELEASE = "vendorRelease"; + + public ResponseEntity createMcFromTemplate(String userId, CreateVFCMTRequest request, String requestId) { + if(!validateMCRequestFields(request)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Missing information"); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_CONTENT); + } + return cloneMcAndAddServiceReference(userId, request, requestId); + } + + //1806 US388513 collect existing VFCMT data - flowType from cdump artifact and external reference from svc_reference artifact. If cdump not found - return error + + public ResponseEntity getVfcmtReferenceData(String vfcmtUuid, String requestId) throws Exception { + ResourceDetailed vfcmt = sdcRestClient.getResource(vfcmtUuid, requestId); + Artifact artifactData = findCdumpArtifactData(vfcmt); + if(null == artifactData) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"No composition found on vfcmt {}", vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", vfcmt.getName()); + } + VfcmtData vfcmtData = new VfcmtData(vfcmt); + //fetch cdump payload + String payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactData.getArtifactUUID(), requestId); + //extract and set flowType from cdump payload + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Looking for flowType definition in cdump"); + vfcmtData.setFlowType(StringUtils.substringBetween(payload,"\"flowType\":\"","\"")); + //find svc_reference + artifactData = findArtifactDataByArtifactName(vfcmt, DcaeBeConstants.Composition.fileNames.SVC_REF); + if(null != artifactData) { + //fetch svc_reference payload + payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactData.getArtifactUUID(), requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Looking for attached service and vfi info in svc_reference"); + //extract and set serviceUuid from svc_reference payload + vfcmtData.setServiceUuid(StringUtils.substringBefore(payload, "/")); + //extract and set vfiName from svc_reference payload + vfcmtData.setVfiName(StringUtils.substringAfterLast(payload, "/")); + } + return new ResponseEntity<>(vfcmtData, HttpStatus.OK); + } + + + //1806 US388525 import or clone VFCMT - always pass the flowType - update will only take place if missing from cdump + public ResponseEntity importMC(String userId, ImportVFCMTRequest request, String requestId) { + if(!validateMCRequestFields(request)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Missing information"); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_CONTENT); + } + // option 1 - clone + if(request.isCloneVFCMT()) { + return cloneMcAndAddServiceReference(userId, request, requestId); + } + + ResourceDetailed vfcmt = null; + boolean undoCheckoutOnFailure = false; + // fetch vfcmt and cdump + try { + vfcmt = sdcRestClient.getResource(request.getTemplateUuid(), requestId); + Artifact cdumpArtifactData = fetchCdumpAndSetFlowType(vfcmt, request.getFlowType(), requestId); + if (null == cdumpArtifactData) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "No cdump found for monitoring component {}", vfcmt.getUuid()); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", vfcmt.getName()); + } + String cdumpPayload = cdumpArtifactData.getPayloadData(); + + // option 2 - edit original cdump - requires check out + if(request.isUpdateFlowType()) { + if(DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT != DcaeBeConstants.LifecycleStateEnum.findState(vfcmt.getLifecycleState())) { + vfcmt = sdcRestClient.changeResourceLifecycleState(userId, vfcmt.getUuid(), LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT", requestId); + undoCheckoutOnFailure = true; + } + cdumpArtifactData.setDescription("updating flowType on cdump"); + cdumpArtifactData.setPayloadData(Base64Utils.encodeToString(cdumpPayload.getBytes())); + sdcRestClient.updateResourceArtifact(userId, vfcmt.getUuid(), cdumpArtifactData, requestId); + } + // option 3 - update service reference only + updateReferenceToService(userId, request, vfcmt.getUuid(), requestId); + if(DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT == DcaeBeConstants.LifecycleStateEnum.findState(vfcmt.getLifecycleState())) { + // this will not throw an exception + checkinVfcmtAfterClone(userId, vfcmt, requestId); + } + return new ResponseEntity<>(buildVfcmtAndCdumpResponse(vfcmt, request.getVfiName(), request.getFlowType(), cdumpPayload), HttpStatus.OK); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed updating Monitoring Component:{}", e.getMessage()); + if(undoCheckoutOnFailure) { + rollBack(userId, vfcmt, requestId); + } + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.CREATE_NEW_VFCMT); + } + + } + + private boolean validateMCRequestFields(CreateVFCMTRequest request) { + return Stream.of(request.getFlowType(), request.getTemplateUuid(), request.getName(), request.getDescription(), request.getContextType(), request.getServiceUuid(), request.getVfiName()) + .allMatch(StringUtils::isNotBlank); + } + + private void updateReferenceToService(String userId, CreateVFCMTRequest request, String newVfcmtUuid, String requestId) { + String serviceUuid = request.getServiceUuid(); + String vfiName = request.getVfiName(); + + debugLogger.log(LogLevel.INFO, this.getClass().getName(),"About to update service {}/{} to monitoring component {} ", serviceUuid, vfiName, request.getName()); + + sdcRestClient.addExternalMonitoringReference(userId, request, new ReferenceUUID(newVfcmtUuid), requestId); + + } + + private void rollBack(String userId, ResourceDetailed newVfcmt, String requestId) { + if (null != newVfcmt) { + try { + getSdcRestClient().changeResourceLifecycleState(userId, newVfcmt.getUuid(), LifecycleOperationType.UNDO_CHECKOUT.getValue(), "DCAE rollback", requestId); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed rolling back Monitoring Component. ID:{}", newVfcmt.getUuid()); + debugLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed rolling back Monitoring Component:{}", e); + } + } + } + + private ResponseEntity cloneMcAndAddServiceReference(String userId, CreateVFCMTRequest request, String requestId) { + addSdcMandatoryFields(request, userId); + ResourceDetailed newVfcmt = null; + try { + // Retrieve the Template VFCMT from SDC - use the template UUID provided from UI + ResourceDetailed templateMC = sdcRestClient.getResource(request.getTemplateUuid(), requestId); + // Download the CDUMP file from the template VFCMT + Artifact cdumpArtifactData = fetchCdumpAndSetFlowType(templateMC, request.getFlowType(), requestId); + if (null == cdumpArtifactData) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"No cdump found for template {} while creating monitoring component", templateMC.getUuid()); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", templateMC.getName()); + } + newVfcmt = sdcRestClient.createResource(userId, request, requestId); + // The cdump has the original template id. we need to replace it with the new vfcmt id + String newVfcmtUuid = newVfcmt.getUuid(); + String cdumpPayload = cdumpArtifactData.getPayloadData().replaceAll(templateMC.getUuid(), newVfcmtUuid); + + // Upload it to newly created VFCMT + cloneArtifactToTarget(userId, newVfcmtUuid, cdumpPayload, cdumpArtifactData, requestId); + cloneRuleArtifacts(userId, templateMC, newVfcmtUuid, requestId); + createReferenceArtifact(userId, request, newVfcmtUuid, requestId); + updateReferenceToService(userId, request, newVfcmtUuid, requestId); + + // this will not throw an exception + checkinVfcmtAfterClone(userId, newVfcmt, requestId); + return new ResponseEntity<>(buildVfcmtAndCdumpResponse(newVfcmt, request.getVfiName(), request.getFlowType(), cdumpPayload), HttpStatus.OK); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed creating Monitoring Component:{}", e.getMessage()); + rollBack(userId, newVfcmt, requestId); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.CREATE_NEW_VFCMT); + } + } + + private CreateMcResponse buildVfcmtAndCdumpResponse(ResourceDetailed vfcmt, String vfiName, String flowType, String cdumpPayload) throws IOException { + return new CreateMcResponse(new VfcmtData(vfcmt, vfiName, flowType), new ObjectMapper().readValue(cdumpPayload, Object.class)); + } + + private void checkinVfcmtAfterClone(String userId, ResourceDetailed vfcmt, String requestId) { + try { + vfcmt = sdcRestClient.changeResourceLifecycleState(userId, vfcmt.getUuid(), LifecycleOperationType.CHECKIN.getValue(), "check in after clone", requestId); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed to check in Monitoring Component: {}. message: {}", vfcmt.getUuid(), e); + } + } + + + private Artifact findCdumpArtifactData(ResourceDetailed vfcmt) { + return findArtifactDataByArtifactName(vfcmt, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + } + + private void cloneRuleArtifacts(String userId, ResourceDetailed templateMC, String newVfcmtUuid, String requestId) throws Exception { + // handle rule artifacts using java 7 for-loop - exception propagation to calling method + for(Artifact artifact : templateMC.getArtifacts()) { + if(artifact.getArtifactName().endsWith(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX)) { + cloneArtifactToTarget(userId, newVfcmtUuid, sdcRestClient.getResourceArtifact(templateMC.getUuid(), artifact.getArtifactUUID(), requestId), artifact, requestId); + } + } + } + + // fetch the vfcmt cdump artifact payload and insert the flowType. Return the artifact with updated payload or null (artifact doesn't exist) + private Artifact fetchCdumpAndSetFlowType(ResourceDetailed vfcmt, String flowType, String requestId) throws Exception { + Artifact cdumpArtifactData = findCdumpArtifactData(vfcmt); + if (null != cdumpArtifactData) { + String cdumpPayload = sdcRestClient.getResourceArtifact(vfcmt.getUuid(), cdumpArtifactData.getArtifactUUID(), requestId); + // Add flowType data to cdump if provided + if(!cdumpPayload.contains("\"flowType\":\"") && StringUtils.isNotBlank(flowType)) { + cdumpPayload = cdumpPayload.replaceFirst("\\{", "{\"flowType\":\"" + flowType + "\","); + } + cdumpArtifactData.setPayloadData(cdumpPayload); + } + return cdumpArtifactData; + } + + // backward compatibility (very backward) + private void createReferenceArtifact(String userId, CreateVFCMTRequest request, String newVfcmtUuid, String requestId) throws Exception { + String referencePayload = request.getServiceUuid() + "/resources/" + request.getVfiName(); + Artifact refArtifact = SdcRestClientUtils.generateDeploymentArtifact("createReferenceArtifact", DcaeBeConstants.Composition.fileNames.SVC_REF, ArtifactType.DCAE_TOSCA.name(), "servicereference", referencePayload.getBytes()); + sdcRestClient.createResourceArtifact(userId, newVfcmtUuid, refArtifact, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Artifact {} created with content: {}", DcaeBeConstants.Composition.fileNames.SVC_REF, referencePayload); + } + + public ResponseEntity getVfcmtsForMigration(String userId, String contextType, String uuid, String version, + String requestId) { + List<Resource> resources; + ExternalReferencesMap connectedVfcmts; + try { + connectedVfcmts = getSdcRestClient().getMonitoringReferences(contextType, uuid, version, requestId); + resources = getSdcRestClient().getResources(VFCMT, TEMPLATE, MONITORING_TEMPLATE, requestId); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Exception getVfcmtsForMigration {}", e); + debugLogger.log(LogLevel.DEBUG,this.getClass().getName(),"Exception getVfcmtsForMigration {}", e); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.GET_ALL_VFCMTS); + } + + List<Resource> vfcmts = resources.stream() + .filter(resource -> notCheckedOutOrMine(userId, resource)) + .filter(resource -> !connected(resource, connectedVfcmts)) + .collect(Collectors.toList()); + return new ResponseEntity<>(vfcmts, HttpStatus.OK); + } + + private boolean connected(Resource resource, ExternalReferencesMap connectedVfcmts){ + return connectedVfcmts.values().stream().anyMatch(p -> p.contains(resource.getUuid())); + } + + private boolean notCheckedOutOrMine(String userId, Resource resource) { + // if the resource belongs to this user then it is kosher + // or if it doesn't belong to the user check the lifecycle state is checked out + + return resource.getLastUpdaterUserId().equalsIgnoreCase(userId) || + NOT_CERTIFIED_CHECKOUT != findState(resource.getLifecycleState()); + } + + + public void addSdcMandatoryFields(CreateVFCMTRequest createRequest, String user) { + createRequest.setContactId(user); + createRequest.setIcon(DEFAULTICON); + createRequest.setResourceType(VFCMT); + createRequest.setVendorName(VENDOR_NAME); + createRequest.setVendorRelease(VENDOR_RELEASE); + if (StringUtils.isBlank(createRequest.getCategory())) { + createRequest.setCategory(TEMPLATE); + } + if (StringUtils.isBlank(createRequest.getSubcategory())) { + createRequest.setSubcategory(MONITORING_TEMPLATE); + } + createRequest.setTags(new String[]{createRequest.getName()}); + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ActionStatus.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ActionStatus.java new file mode 100644 index 0000000..cac92f5 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ActionStatus.java @@ -0,0 +1,48 @@ +package org.onap.sdc.dcae.errormng; + +public enum ActionStatus { + + OK, + CREATED, + NO_CONTENT, + NOT_ALLOWED, + GENERAL_ERROR, + INVALID_CONTENT, + NOT_FOUND, + CONFIGURATION_ERROR, + VES_SCHEMA_NOT_FOUND, + VES_SCHEMA_INVALID, + FLOW_TYPES_CONFIGURATION_ERROR, + CLONE_FAILED, + EMPTY_SERVICE_LIST, + MONITORING_TEMPLATE_ATTACHMENT_ERROR, + MISSING_TOSCA_FILE, + VALIDATE_TOSCA_ERROR, + SUBMIT_BLUEPRINT_ERROR, + GENERATE_BLUEPRINT_ERROR, + INVALID_RULE_FORMAT, + SAVE_RULE_FAILED, + RESOURCE_NOT_VFCMT_ERROR, + VFI_FETCH_ERROR, + USER_CONFLICT, + MISSING_RULE_DESCRIPTION, + MISSING_ACTION, + MISSING_ACTION_FIELD, + MISSING_CONCAT_VALUE, + INVALID_GROUP_CONDITION, + MISSING_CONDITION_ITEM, + MISSING_OPERAND, + INVALID_OPERATOR, + MISSING_ENTRY, + MISSING_DEFAULT_VALUE, + DUPLICATE_KEY, + ACTION_DEPENDENCY, + RULE_DEPENDENCY, + NODE_NOT_FOUND, + DELETE_RULE_FAILED, + TRANSLATE_FAILED, + CATALOG_NOT_AVAILABLE, + AUTH_ERROR, + DELETE_BLUEPRINT_FAILED, + AS_IS +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/BasicConfiguration.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/BasicConfiguration.java new file mode 100644 index 0000000..001109e --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/BasicConfiguration.java @@ -0,0 +1,5 @@ +package org.onap.sdc.dcae.errormng; + +public class BasicConfiguration { + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/DcaeException.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/DcaeException.java new file mode 100644 index 0000000..60b8e0e --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/DcaeException.java @@ -0,0 +1,15 @@ +package org.onap.sdc.dcae.errormng; + +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpClientErrorException; + +public class DcaeException extends BaseException { + +// public DcaeException(HttpClientErrorException theError) { +// super(theError); +// } + + public DcaeException(HttpStatus status, RequestError re){ + super(status, re); + } +} 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 new file mode 100644 index 0000000..de1d06b --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrConfMgr.java @@ -0,0 +1,306 @@ +package org.onap.sdc.dcae.errormng; + +import org.onap.sdc.dcae.catalog.asdc.ASDCException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.util.*; + +public enum ErrConfMgr { + INSTANCE; + + private static EnumMap<ApiType, Map<String, String>> sdcDcaeMsgIdMap; + public static final String AS_IS = "AS_IS"; + private ResponseFormatManager responseFormatManager; + + ErrConfMgr() { + responseFormatManager = ResponseFormatManager.getInstance(); + populateSdcDcaeMsgIdMap(); + } + + private void setSdcCatalogPolicyMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("POL5000", AS_IS); + map.put("POL5001", "POL5500"); + map.put("POL5002", "POL5501"); + sdcDcaeMsgIdMap.put(ApiType.ALL_SDC_CATALOG, map); + } + + private void setGetVfcmtMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", AS_IS); + map.put("SVC4505", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.GET_VFCMT, map); + } + + private void setCreateNewVfcmtMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4050", AS_IS); + map.put("SVC4126", AS_IS); + map.put("SVC4500", AS_IS); + map.put("SVC4062", AS_IS); + map.put("SVC4064", AS_IS); + map.put("SVC4065", AS_IS); + map.put("SVC4066", AS_IS); + map.put("SVC4067", AS_IS); + map.put("SVC4068", AS_IS); + map.put("SVC4069", AS_IS); + map.put("SVC4070", AS_IS); + map.put("SVC4071", AS_IS); + map.put("SVC4072", AS_IS); + map.put("SVC4073", AS_IS); + map.put("SVC4053", AS_IS); + map.put("POL5003", AS_IS); + // adding service referencing error handling to create scenario + map.put("SVC4063", AS_IS); + map.put("SVC4122", AS_IS); + map.put("SVC4124", AS_IS); + map.put("SVC4128", AS_IS); + map.put("SVC4125", AS_IS); + map.put("SVC4127", AS_IS); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.CREATE_NEW_VFCMT, map); + } + + private void setCloneVfcmtMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", AS_IS); + map.put("SVC4505", AS_IS); + map.put("SVC4085", AS_IS); + map.put("SVC4080", AS_IS); + map.put("SVC4122", "SVC6010"); + map.put("SVC4124", "SVC6010"); + map.put("SVC4128", "SVC6010"); + map.put("SVC4125", AS_IS); + map.put("SVC4127", "SVC6010"); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + map.put("SVC4086", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.CLONE_VFCMT, map); + } + + + private void setGetServiceMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4503", AS_IS); + map.put("SVC4642", "200"); + sdcDcaeMsgIdMap.put(ApiType.GET_SERVICE, map); + } + + private void setAttachToServiceMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", "SVC6021"); + map.put("SVC4122", "SVC6021"); + map.put("SVC4124", "SVC6021"); + map.put("SVC4128", "SVC6021"); + map.put("SVC4125", AS_IS); + map.put("SVC4127", "SVC6021"); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + map.put("SVC4503", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.ATTACH_TO_SERVICE, map); + } + + private void setGetCdumpMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", AS_IS); + map.put("SVC4505", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.GET_CDUMP, map); + } + + private void setGetModelMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", AS_IS); + map.put("SVC4505", "SVC6031"); + sdcDcaeMsgIdMap.put(ApiType.GET_MODEL, map); + } + + private void setCheckoutResourceMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", "SVC6021"); + map.put("SVC4085", AS_IS); + map.put("SVC4080", AS_IS); + map.put("SVC4002", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.CHECK_OUT_RESOURCE, map); + } + + private void setCheckinResourceMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", "SVC6021"); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + map.put("SVC4084", AS_IS); + map.put("SVC4085", AS_IS); + map.put("SVC4002", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.CHECK_IN_RESOURCE, map); + } + + private void setSaveCdumpMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", "SVC6021"); + map.put("SVC4122", "SVC6021"); + map.put("SVC4124", "SVC6021"); + map.put("SVC4128", "SVC6021"); + map.put("SVC4125", AS_IS); + map.put("SVC4127", "SVC6021"); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.SAVE_CDUMP, map); + } + + private void setSubmitBlueprintMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", AS_IS); + map.put("SVC4505", "SVC6031"); + map.put("SVC4503", AS_IS); + map.put("SVC4085", AS_IS); + map.put("SVC4080", AS_IS); + map.put("SVC4122", "SVC6033"); + map.put("SVC4124", "SVC6033"); + map.put("SVC4128", "SVC6033"); + map.put("SVC4125", AS_IS); + map.put("SVC4127", "SVC6033"); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.SUBMIT_BLUEPRINT, map); + } + + private void setGetRuleMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.GET_RULE_ARTIFACT, map); + } + + private void setSaveRuleMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4063", "SVC6036"); + map.put("SVC4122", "SVC6036"); + map.put("SVC4124", "SVC6036"); + map.put("SVC4128", "SVC6036"); + map.put("SVC4125", AS_IS); + map.put("SVC4127", "SVC6036"); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + map.put("SVC4000", "SVC6036"); + sdcDcaeMsgIdMap.put(ApiType.SAVE_RULE_ARTIFACT, map); + } + + private void setGetAllVfcmtMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("SVC4642", "200"); + sdcDcaeMsgIdMap.put(ApiType.GET_ALL_VFCMTS, map); + } + + + private void setDeleteReferenceMapping(){ + Map<String, String> map = new HashMap<>(); + map.put("POL5003", AS_IS); + map.put("SVC4063", AS_IS); + map.put("POL4050", AS_IS); + map.put("SVC4086", AS_IS); + map.put("SVC4301", AS_IS); + map.put("SVC4687", AS_IS); + sdcDcaeMsgIdMap.put(ApiType.DELETE_VFCMT_REFERENCE, map); + } + + private void populateSdcDcaeMsgIdMap() { + sdcDcaeMsgIdMap = new EnumMap<>(ApiType.class); + setAttachToServiceMapping(); + setCheckinResourceMapping(); + setCheckoutResourceMapping(); + setCloneVfcmtMapping(); + setGetAllVfcmtMapping(); + setGetRuleMapping(); + setCreateNewVfcmtMapping(); + setGetCdumpMapping(); + setGetModelMapping(); + setSaveCdumpMapping(); + setSaveRuleMapping(); + setSubmitBlueprintMapping(); + setGetServiceMapping(); + setGetVfcmtMapping(); + setSdcCatalogPolicyMapping(); + setDeleteReferenceMapping(); + } + + public enum ApiType { + CREATE_NEW_VFCMT, + GET_ALL_VFCMTS, + CLONE_VFCMT, + GET_VFCMT, + GET_SERVICE, + ATTACH_TO_SERVICE, + GET_CDUMP, + GET_MODEL, + CHECK_OUT_RESOURCE, + CHECK_IN_RESOURCE, + SAVE_CDUMP, + SUBMIT_BLUEPRINT, + GET_RULE_ARTIFACT, + SAVE_RULE_ARTIFACT, + ALL_SDC_CATALOG, + DELETE_VFCMT_REFERENCE + } + + public ResponseFormat getResponseFormat(ActionStatus actionStatus, String notes, String... variables) { + return responseFormatManager.getResponseFormat(actionStatus, notes, variables); + } + + public ResponseEntity buildErrorResponse(ActionStatus actionStatus, String notes, String... variables) { + ResponseFormat response = responseFormatManager.getResponseFormat(actionStatus, notes, variables); + return new ResponseEntity<>(response, HttpStatus.valueOf(response.getStatus())); + } + + public ResponseEntity buildErrorResponse(ActionStatus actionStatus) { + ResponseFormat response = responseFormatManager.getResponseFormat(actionStatus, ""); + return new ResponseEntity<>(response, HttpStatus.valueOf(response.getStatus())); + } + + public ResponseEntity buildErrorResponse(BaseException baseException) { + ResponseFormat response = responseFormatManager.getResponseFormat(baseException); + return new ResponseEntity<>(response, HttpStatus.valueOf(response.getStatus())); + } + + public ResponseEntity buildErrorArrayResponse(List<ServiceException> errors) { + ResponseFormat response = responseFormatManager.getResponseFormat(errors); + return new ResponseEntity<>(response, HttpStatus.valueOf(response.getStatus())); + } + + // ActionStatus determined by sdc to dcae mapping + public ActionStatus convertToDcaeActionStatus(String messageId, ApiType apiType) { + // try the apiType's specific mapping from SDC messageId to dcaeMessageId + String dcaeMessageId = sdcDcaeMsgIdMap.get(apiType).get(messageId); + // if no specific mapping found try the general mapping + if(null == dcaeMessageId) + dcaeMessageId = sdcDcaeMsgIdMap.get(ApiType.ALL_SDC_CATALOG).get(messageId); + // if no mapping found return general error + if(null == dcaeMessageId) + return ActionStatus.GENERAL_ERROR; + // if mapped to 'AS_IS' return 'AS_IS' + if(AS_IS.equals(dcaeMessageId)) + return ActionStatus.AS_IS; + // for any other valid mapping fetch the ActionStatus by corresponding dcaeMessageId + return responseFormatManager.getMsgIdToActionStatusMap().get(dcaeMessageId); + } + + public ResponseEntity handleException(Exception e, ApiType apiType, String... variables){ + if (e instanceof ASDCException){ + ASDCException se = (ASDCException)e; + ActionStatus status = convertToDcaeActionStatus(se.getMessageId(), apiType); + switch (status) { + case AS_IS: + return buildErrorResponse(se); + case OK: + return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK); + default: + return buildErrorResponse(status, se.getMessage(), variables); + } + } + //TODO refactor - don't throw DcaeException + if (e instanceof DcaeException){ + return buildErrorResponse((DcaeException)e); + } + return buildErrorResponse(ActionStatus.GENERAL_ERROR, e.getMessage()); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorConfiguration.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorConfiguration.java new file mode 100644 index 0000000..8f6f5af --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorConfiguration.java @@ -0,0 +1,46 @@ +package org.onap.sdc.dcae.errormng; + +import java.util.Map; + +/** + * Example: + * VES_SCHEMA_INVALID: { + code: 500, + message: "Error – Failed to parse VES Schema file '%1'. [%2]", + messageId: "SVC6007" + } + + key will be "VES_SCHEMA_INVALID" + value is the json object containing code, message, messageId + */ + +import org.onap.sdc.dcae.errormng.BasicConfiguration; + +public class ErrorConfiguration extends BasicConfiguration { + + private Map<String, ErrorInfo> errors; + + public Map<String, ErrorInfo> getErrors() { + return errors; + } + + public void setErrors(Map<String, ErrorInfo> errors) { + this.errors = errors; + } + + public ErrorInfo getErrorInfo(String key) { + ErrorInfo clone = null; + ErrorInfo other = errors.get(key); + if (other != null) { + clone = new ErrorInfo(); + clone.cloneData(other); + } + return clone; + } + + @Override + public String toString() { + return "ErrorConfiguration [errors=" + errors + "]"; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorConfigurationLoader.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorConfigurationLoader.java new file mode 100644 index 0000000..8b7ab44 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorConfigurationLoader.java @@ -0,0 +1,121 @@ +package org.onap.sdc.dcae.errormng; + +import org.apache.commons.lang.ArrayUtils; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; + +public class ErrorConfigurationLoader { + + private static ErrorConfigurationLoader instance; + private String jettyBase; + private ErrorConfiguration errorConfiguration = new ErrorConfiguration(); + private OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + public ErrorConfigurationLoader(String sourcePath) { + jettyBase = sourcePath; + loadErrorConfiguration(); + instance = this; + } + + private void loadErrorConfiguration(){ + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ErrorConfigurationLoader: Trying to load error configuration"); + if (jettyBase == null) { + String msg = "Couldn't resolve jetty.base environmental variable"; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new ExceptionInInitializerError (msg + ". Failed to load error configuration files... aborting"); + } + + String path = jettyBase + "/config/dcae-be"; + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "jetty.base={}", jettyBase); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Configuration Path={}", path); + + File dir = new File(path); + File[] files = dir.listFiles(new FilenameFilter() { + @Override public boolean accept(File dir, String name) { + return name.equals("error-configuration.yaml"); + } + }); + + if (ArrayUtils.isEmpty(files)) { + String msg = "No error configuration files found"; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new ExceptionInInitializerError (msg); + }else if (files.length>1){ + String msg = "Multiple configuration files found. Make sure only one file exists. Path: "+ path; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new ExceptionInInitializerError (msg); + } + else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Loading error configuration file: {}", files[0].getName()); + try { + errorConfiguration = parseErrConfFileAndSaveToMap(files[0].getCanonicalPath()); +// convertToUsefulMaps(errorConfiguration); + } catch (IOException e) { + String msg = "Exception thrown while trying to read the error configuration file path. File="+files[0].getName(); + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new ExceptionInInitializerError (msg); + } + if(errorConfiguration == null){ + String msg = "Error configuration file couldn't be parsed"; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new ExceptionInInitializerError (msg); + } + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Error Configuration: {}", errorConfiguration.toString()); + } + } + + + private ErrorConfiguration parseErrConfFileAndSaveToMap(String fullFileName) { + + Yaml yaml = new Yaml(); + + InputStream in = null; + ErrorConfiguration errorConfiguration = null; + try { + + File f = new File(fullFileName); + if (false == f.exists()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "The file {} cannot be found. Ignore reading configuration.", fullFileName); + return null; + } + in = Files.newInputStream(Paths.get(fullFileName)); + + errorConfiguration = yaml.loadAs(in, ErrorConfiguration.class); + + } catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Failed to convert yaml file {} to object. {}", fullFileName, e); + return null; + } + finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Failed to close input stream {}", e.getMessage()); + } + } + } + + return errorConfiguration; + } + + ErrorConfiguration getErrorConfiguration() { + return errorConfiguration; + } + + public static ErrorConfigurationLoader getErrorConfigurationLoader() { + return instance; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorInfo.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorInfo.java new file mode 100644 index 0000000..3ec3cef --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ErrorInfo.java @@ -0,0 +1,99 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.dcae.errormng; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; + +public class ErrorInfo { + + private Integer code; + private String message; + private String messageId; + private ErrorInfoType errorInfoType; + + private static final String SVC_PREFIX = "SVC"; + private static final String POL_PREFIX = "POL"; + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + + public ErrorInfo() { + this.errorInfoType = ErrorInfoType.OK; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + // Determining the type of error + if (messageId == null || "200".equals(messageId) || "201".equals(messageId) || "204".equals(messageId)) { + this.errorInfoType = ErrorInfoType.OK; + } else if (messageId.startsWith(SVC_PREFIX)) { + this.errorInfoType = ErrorInfoType.SERVICE_EXCEPTION; + } else if (messageId.startsWith(POL_PREFIX)) { + this.errorInfoType = ErrorInfoType.POLICY_EXCEPTION; + } else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Error: unexpected error message ID {}, should start with {} or {}", messageId, SVC_PREFIX, POL_PREFIX); + } + this.messageId = messageId; + } + + public ErrorInfoType getErrorInfoType() { + return this.errorInfoType; + } + + public void cloneData(ErrorInfo other) { + this.code = other.getCode(); + this.message = other.getMessage(); + this.messageId = other.getMessageId(); + this.errorInfoType = other.errorInfoType; + } + + @Override + public String toString() { + return "ErrorInfo [code=" + code + ", messageId=" + messageId + ", message=" + message + "]"; + } + + public enum ErrorInfoType { + OK, POLICY_EXCEPTION, SERVICE_EXCEPTION + } + +} 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 new file mode 100644 index 0000000..ada790f --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormatManager.java @@ -0,0 +1,103 @@ +package org.onap.sdc.dcae.errormng; + +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.errormng.ErrorInfo.ErrorInfoType; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ResponseFormatManager { + + private volatile static ResponseFormatManager instance; + private static ErrorConfiguration errorConfiguration; + private static Map<String, ActionStatus> msgIdToActionStatusMap = new HashMap<>(); + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + + public static ResponseFormatManager getInstance() { + if (instance == null) { + instance = init(); + } + return instance; + } + + private static synchronized ResponseFormatManager init() { + if (instance == null) { + instance = new ResponseFormatManager(); + errorConfiguration = ErrorConfigurationLoader.getErrorConfigurationLoader().getErrorConfiguration(); + convertToActionMap(); + } + return instance; + } + + ResponseFormat getResponseFormat(ActionStatus actionStatus, String notes, String... variables) { + ErrorInfo errorInfo = errorConfiguration.getErrorInfo(actionStatus.name()); + if (errorInfo == null) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "failed to locate {} in error configuration", actionStatus.name()); + errorInfo = errorConfiguration.getErrorInfo(ActionStatus.GENERAL_ERROR.name()); + } + + ResponseFormat responseFormat = new ResponseFormat(errorInfo.getCode()); + String errorMessage = errorInfo.getMessage(); + String errorMessageId = errorInfo.getMessageId(); + ErrorInfoType errorInfoType = errorInfo.getErrorInfoType(); + responseFormat.setNotes(notes); + + if (errorInfoType==ErrorInfoType.SERVICE_EXCEPTION) { + responseFormat.setServiceException(new ServiceException(errorMessageId, errorMessage, variables)); + } + else if (errorInfoType==ErrorInfoType.POLICY_EXCEPTION) { + responseFormat.setPolicyException(new PolicyException(errorMessageId, errorMessage, variables)); + } + else if (errorInfoType==ErrorInfoType.OK) { + responseFormat.setOkResponseInfo(new OkResponseInfo(errorMessageId, errorMessage, variables)); + } + return responseFormat; + } + + ResponseFormat getResponseFormat(BaseException baseException) { + + ResponseFormat responseFormat = new ResponseFormat(baseException.getRawStatusCode()); + AbstractSdncException e = baseException.getRequestError().getError(); + + if (e instanceof ServiceException) { + responseFormat.setServiceException((ServiceException)e); + } + else if (e instanceof PolicyException) { + responseFormat.setPolicyException((PolicyException)e); + } + else { + responseFormat.setOkResponseInfo((OkResponseInfo)e); + } + return responseFormat; + } + + ResponseFormat getResponseFormat(List<ServiceException> errors) { + ResponseFormat responseFormat = new ResponseFormat(400); + responseFormat.setServiceExceptions(errors); + return responseFormat; + } + + public Map<String, ActionStatus> getMsgIdToActionStatusMap() { + return msgIdToActionStatusMap; + } + + private static void convertToActionMap() { + Map<String, ErrorInfo> errors = errorConfiguration.getErrors(); + + if(errors!=null){ + errors.forEach((k, v) -> { + debugLogger.log(LogLevel.DEBUG, ResponseFormatManager.class.getName(), "{}, {}", v.getMessageId(), k); + msgIdToActionStatusMap.put(v.getMessageId(), ActionStatus.valueOf(k)); + }); + } + } + + public ResponseFormatManager(){ + + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/filter/LoggingFilter.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/filter/LoggingFilter.java new file mode 100644 index 0000000..919d244 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/filter/LoggingFilter.java @@ -0,0 +1,247 @@ +package org.onap.sdc.dcae.filter; + +import static java.net.HttpURLConnection.HTTP_BAD_METHOD; +import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; +import static java.net.HttpURLConnection.HTTP_CLIENT_TIMEOUT; +import static java.net.HttpURLConnection.HTTP_CONFLICT; +import static java.net.HttpURLConnection.HTTP_ENTITY_TOO_LARGE; +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; +import static java.net.HttpURLConnection.HTTP_GONE; +import static java.net.HttpURLConnection.HTTP_LENGTH_REQUIRED; +import static java.net.HttpURLConnection.HTTP_NOT_ACCEPTABLE; +import static java.net.HttpURLConnection.HTTP_NOT_FOUND; +import static java.net.HttpURLConnection.HTTP_PAYMENT_REQUIRED; +import static java.net.HttpURLConnection.HTTP_PRECON_FAILED; +import static java.net.HttpURLConnection.HTTP_PROXY_AUTH; +import static java.net.HttpURLConnection.HTTP_REQ_TOO_LONG; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; +import static java.net.HttpURLConnection.HTTP_UNSUPPORTED_TYPE; + +import java.io.IOException; +import java.util.Locale; +import java.util.UUID; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.impl.EnglishReasonPhraseCatalog; +import org.onap.sdc.common.onaplog.OnapLoggerAudit; +import org.onap.sdc.common.onaplog.OnapMDCWrapper; +import org.onap.sdc.common.onaplog.Enums.OnapLoggerErrorCode; +import org.onap.sdc.common.onaplog.Enums.LogLevel; + +public class LoggingFilter implements Filter { + + private static final String serviceName = "DCAE-D-BE"; + + private OnapMDCWrapper commonLoggerArgs = OnapMDCWrapper.getInstance(); + private OnapLoggerAudit auditLogger = OnapLoggerAudit.getInstance(); + + public LoggingFilter() { + super(); + } + + + @Override + public void destroy() {} + + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + + boolean shouldLogRequest = true; + + try { + if (request instanceof HttpServletRequest) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + if (httpRequest.getServletPath().equals("/healthCheck")) { + shouldLogRequest = false; + } + + if (shouldLogRequest) { + beforeHandle(httpRequest); + } + } + } catch (Exception e) { + // TODO: log problem with extracting parameters or writing to log + } + + filterChain.doFilter(request, response); // handle request + + try { + if (response instanceof HttpServletResponse && shouldLogRequest) { + afterHandle((HttpServletResponse) response); + } + } catch (Exception e) { + // TODO: log problem with extracting parameters or writing to log + } + } + + + private void beforeHandle(HttpServletRequest request) { + + String requestId = getRequestId(request); + request.setAttribute("requestId", requestId); // making requestId available for the API controllers + commonLoggerArgs + .clear() + .startTimer() + .setRemoteHost(request.getRemoteAddr()) + .setServiceName(serviceName) + .setPartnerName(getPartnerName(request.getHeader("USER_ID"), request.getHeader("user-agent"))) + .setKeyRequestId(requestId) + .setAutoServerIPAddress(request.getLocalAddr()) + .setOptCustomField1(request.getProtocol()) + .setOptCustomField2(request.getMethod()) + .setOptCustomField3(request.getServletPath()); + + } + + + private static String getRequestId(HttpServletRequest request) { + String requestId = request.getHeader("X-ECOMP-RequestID"); + return isNullOrEmpty(requestId) + ? UUID.randomUUID().toString() + : requestId; + } + + + private void afterHandle(HttpServletResponse response) { + String responseDesc = EnglishReasonPhraseCatalog.INSTANCE.getReason(response.getStatus(), Locale.ENGLISH); + commonLoggerArgs + .stopTimer() + .setResponseCode(getLoggingErrorCode(response.getStatus()).getErrorCode()) + .setResponseDesc(responseDesc) + .setOptCustomField4(Integer.toString(response.getStatus())); + + auditLogger + .setStatusCode(Integer.toString(response.getStatus())) + .log(LogLevel.INFO, this.getClass().getName(), responseDesc); + } + + + private OnapLoggerErrorCode getLoggingErrorCode(int httpResponseCode) { + if (isSuccessError(httpResponseCode)) { + return OnapLoggerErrorCode.SUCCESS; + } + else if (isSchemaError(httpResponseCode)) { + return OnapLoggerErrorCode.SCHEMA_ERROR; + } + else if (isDataError(httpResponseCode)) { + return OnapLoggerErrorCode.DATA_ERROR; + } + else if (isPermissionsError(httpResponseCode)) { + return OnapLoggerErrorCode.PERMISSION_ERROR; + } + else if (isTimeoutOrAvailabilityError(httpResponseCode)) { + return OnapLoggerErrorCode.AVAILABILITY_TIMEOUTS_ERROR; + } + else if (isBusinessProcessError(httpResponseCode)) { + return OnapLoggerErrorCode.BUSINESS_PROCESS_ERROR; + } + else { + return OnapLoggerErrorCode.UNKNOWN_ERROR; + } + } + + + private boolean isTimeoutOrAvailabilityError(int httpResponseCode) { + + switch (httpResponseCode) { + case HTTP_BAD_REQUEST: + case HTTP_UNAUTHORIZED: + case HTTP_NOT_FOUND: + case HTTP_CLIENT_TIMEOUT: + case HTTP_GONE: + return true; + } + + return false; + } + + private boolean isPermissionsError(int httpResponseCode) { + + switch (httpResponseCode) { + case HTTP_PAYMENT_REQUIRED: + case HTTP_FORBIDDEN: + case HTTP_BAD_METHOD: + case HTTP_PROXY_AUTH: + return true; + } + + return false; + } + + private boolean isDataError(int httpResponseCode) { + + switch (httpResponseCode) { + case HTTP_NOT_ACCEPTABLE: + case HTTP_LENGTH_REQUIRED: + case HTTP_PRECON_FAILED: + case HTTP_REQ_TOO_LONG: + case HTTP_ENTITY_TOO_LARGE: + case HTTP_UNSUPPORTED_TYPE: + return true; + } + + return false; + } + + private boolean isSchemaError(int httpResponseCode) { + + switch (httpResponseCode) { + case HTTP_CONFLICT: + return true; + } + + return false; + } + + private boolean isSuccessError(int httpResponseCode) { + return httpResponseCode < 399; + } + + private boolean isBusinessProcessError(int httpResponseCode) { + return httpResponseCode > 499; + } + + private String getPartnerName(String userId, String userAgent) { + return (isNullOrEmpty(userId)) + ? getClientApplication(userAgent) + : userId; + } + + private String getClientApplication(String userAgent) { + if (userAgent != null && userAgent.length() > 0) { + if (userAgent.toLowerCase().contains("firefox")) { + return "fireFox_FE"; + } + + if (userAgent.toLowerCase().contains("msie")) { + return "explorer_FE"; + } + + if (userAgent.toLowerCase().contains("chrome")) { + return "chrome_FE"; + } + + return userAgent; + } + return ""; + } + + + private static boolean isNullOrEmpty(String str) { + return (str == null || str.isEmpty()); + } + + + @Override + public void init(FilterConfig config) throws ServletException {} +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/ConditionTypeEnum.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/ConditionTypeEnum.java new file mode 100644 index 0000000..e4921e2 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/ConditionTypeEnum.java @@ -0,0 +1,22 @@ +package org.onap.sdc.dcae.rule.editor.enums; + +import java.util.Arrays; + +public enum ConditionTypeEnum { + ALL("And"), ANY("Or"); + + public String getFilterClass() { + return filterClass; + } + + private String filterClass; + + ConditionTypeEnum(String filterClass) { + + this.filterClass = filterClass; + } + + public static ConditionTypeEnum getTypeByName(String name) { + return Arrays.stream(ConditionTypeEnum.values()).filter(type -> name.equalsIgnoreCase(type.name())).findAny().orElse(null); + } +} 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 new file mode 100644 index 0000000..2cd03a7 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/OperatorTypeEnum.java @@ -0,0 +1,32 @@ +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); + + private String type; + private String modifiedType; + + OperatorTypeEnum(String type, String modifiedType) { + this.type = type; + this.modifiedType = modifiedType; + } + + public String getType() { + return type; + } + + public String getModifiedType() { + return modifiedType; + } + + public static OperatorTypeEnum getTypeByName(String name) { + return Arrays.stream(OperatorTypeEnum.values()).filter(type -> name.replaceAll(" ", "").equalsIgnoreCase(type.getType())).findAny().orElse(null); + } + +} 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 new file mode 100644 index 0000000..0bec7d8 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/enums/RuleEditorElementType.java @@ -0,0 +1,58 @@ +package org.onap.sdc.dcae.rule.editor.enums; + +import java.util.Arrays; + +import org.onap.sdc.dcae.rule.editor.translators.ConditionGroupTranslator; +import org.onap.sdc.dcae.rule.editor.translators.ConditionTranslator; +import org.onap.sdc.dcae.rule.editor.translators.CopyActionTranslator; +import org.onap.sdc.dcae.rule.editor.translators.DateFormatterTranslator; +import org.onap.sdc.dcae.rule.editor.translators.FieldConditionTranslator; +import org.onap.sdc.dcae.rule.editor.translators.IRuleElementTranslator; +import org.onap.sdc.dcae.rule.editor.translators.MapActionTranslator; +import org.onap.sdc.dcae.rule.editor.translators.MappingRulesTranslator; +import org.onap.sdc.dcae.rule.editor.translators.RegexActionTranslator; +import org.onap.sdc.dcae.rule.editor.translators.RuleTranslator; +import org.onap.sdc.dcae.rule.editor.validators.ActionValidator; +import org.onap.sdc.dcae.rule.editor.validators.ConcatActionValidator; +import org.onap.sdc.dcae.rule.editor.validators.ConditionGroupValidator; +import org.onap.sdc.dcae.rule.editor.validators.ConditionValidator; +import org.onap.sdc.dcae.rule.editor.validators.DateFormatterValidator; +import org.onap.sdc.dcae.rule.editor.validators.IRuleElementValidator; +import org.onap.sdc.dcae.rule.editor.validators.MapActionValidator; +import org.onap.sdc.dcae.rule.editor.validators.RuleValidator; + +public enum RuleEditorElementType { + COPY("Copy", ActionValidator.getInstance(), CopyActionTranslator.getInstance()), + CONCAT("Concat", ConcatActionValidator.getInstance(), CopyActionTranslator.getInstance()), + MAP("Map", MapActionValidator.getInstance(), MapActionTranslator.getInstance()), + REGEX("Regex", ActionValidator.getInstance(), RegexActionTranslator.getInstance()), + DATE_FORMATTER("DateFormatter", DateFormatterValidator.getInstance(), DateFormatterTranslator.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()); + + private String elementType; + private IRuleElementValidator validator; + private IRuleElementTranslator translator; + + public IRuleElementValidator getValidator() { + return validator; + } + + public IRuleElementTranslator getTranslator() { + return translator; + } + + RuleEditorElementType(String elementType, IRuleElementValidator validator, IRuleElementTranslator translator) { + this.elementType = elementType; + this.validator = validator; + this.translator = translator; + } + + public static RuleEditorElementType getElementTypeByName(String name) { + return Arrays.stream(RuleEditorElementType.values()).filter(p -> p.elementType.equalsIgnoreCase(name)) + .findAny().orElse(null); + } +} 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 new file mode 100644 index 0000000..849ad42 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/impl/RulesBusinessLogic.java @@ -0,0 +1,149 @@ +package org.onap.sdc.dcae.rule.editor.impl; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.apache.commons.lang3.StringUtils; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; +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.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.validators.RuleValidator; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Component +public class RulesBusinessLogic { + + protected OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + private RuleValidator ruleValidator = RuleValidator.getInstance(); + private MappingRulesTranslator mappingRulesTranslator = MappingRulesTranslator.getInstance(); + private static Gson gsonTranslator = new GsonBuilder().registerTypeAdapter(String.class, new EmptyStringTranslationSerializer()).enableComplexMapKeySerialization().create(); + + public List<ServiceException> validateRule(Rule rule) { + List<ResponseFormat> errors = new ArrayList<>(); + if(ruleValidator.validate(rule, errors)) + detectAndResolveActionDependencies(rule, errors); + return errors.stream().map(r -> r.getRequestError().getServiceException()).collect(Collectors.toList()); + } + + public List<ServiceException> validateRules(MappingRules rules) { + List<ResponseFormat> errors = new ArrayList<>(); + 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) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Start translating mapping rules"); + return gsonTranslator.toJson(mappingRulesTranslator.translateToHpJson(rules, entryPointPhase, lastPhase, runPhase)); + } + + public boolean addOrEditRule(MappingRules rules, Rule rule) { + // 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; + rules.addOrReplaceRule(rule); + return true; + } + + public Rule deleteRule(MappingRules rules, String ruleUid) { + return rules.removeRule(ruleUid); + } + + 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()); + } + + // if all dependencies are resolvable returns empty list + // else returns list of non resolvable items (circular dependent items) + // iterate through all dependentItems removing resolvable items each iteration. + + private <T> List<T> detectCircularDependenciesByDependencyDefinition(List<T> dependentItems, BiFunction<T, Collection<T>, Boolean> dependencyDetector) { + while(!CollectionUtils.isEmpty(dependentItems)) { + List<T> resolvable = dependentItems.stream() + .filter(i -> !dependencyDetector.apply(i, dependentItems)) + .collect(Collectors.toList()); + if(CollectionUtils.isEmpty(resolvable)) + break; + dependentItems.removeAll(resolvable); + } + return dependentItems; + } + + private <T> List<T> reorderItemsByDependencyDefinition(Collection<T> allItems, BiFunction<T, T, Boolean> dependencyDetector) { + List<T> ordered = new ArrayList<>(allItems); + allItems.forEach(i -> { + List<T> dependencies = allItems.stream().filter(o -> dependencyDetector.apply(i, o)).collect(Collectors.toList()); + dependencies.forEach(d -> { + if(ordered.indexOf(d) > ordered.indexOf(i)) { + ordered.remove(d); + ordered.add(ordered.indexOf(i), d); + } + }); + }); + return ordered; + } + + private void detectAndResolveActionDependencies(Rule rule, List<ResponseFormat> errors) { + List<BaseAction> dependentActions = detectDependentItemsByDependencyDefinition(rule.getActions(), BaseAction::hasDependencies); + if(!CollectionUtils.isEmpty(dependentActions)) { + List<BaseAction> nonResolvable = detectCircularDependenciesByDependencyDefinition(dependentActions, BaseAction::hasDependencies); + if (!CollectionUtils.isEmpty(nonResolvable)) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.ACTION_DEPENDENCY, null, nonResolvable.stream().map(BaseAction::getTarget).collect(Collectors.joining(", ")))); + return; + } + List<BaseAction> actions = reorderItemsByDependencyDefinition(rule.getActions(), BaseAction::referencesTarget); + rule.setActions(actions); + } + } + + // first identify dependent rules + // if no dependencies found return true + // if non resolvable dependencies found return false + // else reorder and return true + + private void detectAndResolveRuleDependencies(MappingRules rules, List<ResponseFormat> errors) { + List<Rule> dependentRules = detectDependentItemsByDependencyDefinition(rules.getRules().values(), Rule::referencesOtherRules); + if(!CollectionUtils.isEmpty(dependentRules)) { + List<Rule> nonResolvable = detectCircularDependenciesByDependencyDefinition(dependentRules, Rule::referencesOtherRules); + if (!CollectionUtils.isEmpty(nonResolvable)) { + String nonResolvableRuleIds = nonResolvable.stream().map(Rule::getUid).collect(Collectors.joining(", ")); + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.RULE_DEPENDENCY, null, nonResolvableRuleIds, extractDependentActionTargetsFromRules(nonResolvable))); + return; + } + reorderRulesByDependency(rules); + } + } + + 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 + List<BaseAction> nonResolvable = detectCircularDependenciesByDependencyDefinition(allActions, BaseAction::hasDependencies); + if(CollectionUtils.isEmpty(nonResolvable)) + // option 2: circular dependency between rules - collect dependent actions and condition dependencies + nonResolvable = dependentRules.stream() + .map(r -> r.findDependencies(dependentRules)) + .flatMap(List::stream) + .collect(Collectors.toList()); + return nonResolvable.stream() + .map(BaseAction::getTarget) + .collect(Collectors.joining(", ")); + } + + private void reorderRulesByDependency(MappingRules rules) { + List<Rule> ordered = reorderItemsByDependencyDefinition(rules.getRules().values(), Rule::referencesOtherRule); + Map<String, Rule> rulesMap = ordered.stream().collect(Collectors.toMap(Rule::getUid, Function.identity(), (u, v) -> { + throw new IllegalStateException(String.format("Duplicate key %s", u)); + }, LinkedHashMap::new)); + rules.setRules(rulesMap); + } +} 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 new file mode 100644 index 0000000..093c239 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionGroupTranslator.java @@ -0,0 +1,47 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; +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 java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class ConditionGroupTranslator implements IRuleElementTranslator<ConditionGroup> { + + private static ConditionGroupTranslator conditionGroupTranslator = new ConditionGroupTranslator(); + + public static ConditionGroupTranslator getInstance() { + return conditionGroupTranslator; + } + + private ConditionGroupTranslator(){} + + public Translation translateToHpJson(ConditionGroup conditionGroup) { + String clazz = ConditionTypeEnum.getTypeByName(conditionGroup.getType()).getFilterClass(); + FiltersTranslation translation = new FiltersTranslation(clazz, conditionGroup.getChildren().stream() + .map(this::getTranslation) + .collect(Collectors.toList())); + flattenNestedFilters(translation, clazz); + return translation; + } + + + private IRuleElementTranslator getConditionTranslator(BaseCondition condition){ + return condition instanceof ConditionGroup ? ConditionGroupTranslator.getInstance() : + ValidationUtils.validateNotEmpty(OperatorTypeEnum.getTypeByName(((Condition)condition).getOperator()).getModifiedType()) ? FieldConditionTranslator.getInstance() : ConditionTranslator.getInstance(); + } + + private Translation getTranslation(BaseCondition condition) { + return getConditionTranslator(condition).translateToHpJson(condition); + } + + private void flattenNestedFilters(FiltersTranslation filtersTranslation, String clazz) { + Map<Boolean, List<Translation>> partitioned = filtersTranslation.filters.stream().collect(Collectors.partitioningBy(f -> clazz.equals(((ProcessorTranslation) f).clazz))); + filtersTranslation.filters.removeAll(partitioned.get(Boolean.TRUE)); + filtersTranslation.filters.addAll(partitioned.get(Boolean.TRUE).stream().map(f -> ((FiltersTranslation) f).filters).flatMap(List::stream).collect(Collectors.toList())); + } + +} 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 new file mode 100644 index 0000000..f93101b --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/ConditionTranslator.java @@ -0,0 +1,40 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Condition; +import org.onap.sdc.dcae.rule.editor.enums.ConditionTypeEnum; +import org.onap.sdc.dcae.rule.editor.enums.OperatorTypeEnum; + +import java.util.stream.Collectors; + +public class ConditionTranslator implements IRuleElementTranslator<Condition> { + + private static ConditionTranslator conditionTranslator = new ConditionTranslator(); + + public static ConditionTranslator getInstance() { + return conditionTranslator; + } + + private ConditionTranslator(){} + + private class StringFilterTranslation extends ProcessorTranslation { + private String string; + private String value; + + private StringFilterTranslation(Condition condition, String value){ + this.clazz = OperatorTypeEnum.getTypeByName(condition.getOperator()).getType(); + this.string = condition.getLeft(); + this.value = value; + } + + private StringFilterTranslation(Condition condition){ + this(condition, condition.getRight().get(0)); + } + } + + public Translation translateToHpJson(Condition condition) { + return 1 == condition.getRight().size() ? new StringFilterTranslation(condition) : new FiltersTranslation(ConditionTypeEnum.ANY.getFilterClass(), condition.getRight().stream() + .map(r -> new StringFilterTranslation(condition, r)).collect(Collectors.toList())); + } + + +} 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 new file mode 100644 index 0000000..9d02c8e --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/CopyActionTranslator.java @@ -0,0 +1,47 @@ +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; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseAction; + +public class CopyActionTranslator<A extends BaseAction> implements IRuleElementTranslator<A>{ + + private static CopyActionTranslator copyActionTranslator = new CopyActionTranslator(); + + public static CopyActionTranslator getInstance() { + return copyActionTranslator; + } + + CopyActionTranslator(){} + + public Translation translateToHpJson(A action) { + return new CopyActionSetTranslation(action.getTarget(), action.getFromValue()); + } + + void addToHpJsonProcessors(A action, List<Translation> processors) { + processors.add(translateToHpJson(action)); + } + + public boolean addToHpJsonProcessors(A action, List<Translation> processors, boolean asNewProcessor) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Translating {} action. New Processor: {}", action.getActionType(), asNewProcessor); + if(asNewProcessor) + addToHpJsonProcessors(action, processors); + else + ((CopyActionSetTranslation) processors.get(processors.size()-1)).updates.put(action.getTarget(), action.getFromValue()); + 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 new file mode 100644 index 0000000..89f0def --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/DateFormatterTranslator.java @@ -0,0 +1,49 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import java.util.List; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.DateFormatterAction; + +public class DateFormatterTranslator extends CopyActionTranslator<DateFormatterAction> { + + private static DateFormatterTranslator dateFormatterTranslator = new DateFormatterTranslator(); + + public static DateFormatterTranslator getInstance() { + return dateFormatterTranslator; + } + + private DateFormatterTranslator(){} + + private class DateFormatterTranslation extends ProcessorTranslation { + private String fromFormat; + private String fromTz; + private String toField; + private String toFormat; + private String toTz; + private String value; + + private DateFormatterTranslation(DateFormatterAction action){ + clazz = "DateFormatter"; + fromFormat = action.getFromFormat(); + fromTz = action.getFromTz(); + toField = action.getTarget(); + toFormat = action.getToFormat(); + toTz = action.getToTz(); + value = action.getFromValue(); + } + } + + @Override + public boolean addToHpJsonProcessors(DateFormatterAction action, List<Translation> processors, boolean asNewProcessor) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Translating date formatter action"); + addToHpJsonProcessors(action, processors); + return true; + } + + @Override + public Translation translateToHpJson(DateFormatterAction action){ + return new DateFormatterTranslation(action); + } + +} 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 new file mode 100644 index 0000000..ef2949e --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/FieldConditionTranslator.java @@ -0,0 +1,43 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Condition; +import org.onap.sdc.dcae.rule.editor.enums.OperatorTypeEnum; + +import java.util.List; + +public class FieldConditionTranslator implements IRuleElementTranslator<Condition> { + + private static FieldConditionTranslator fieldConditionTranslator = new FieldConditionTranslator(); + + public static FieldConditionTranslator getInstance() { + return fieldConditionTranslator; + } + + private FieldConditionTranslator(){} + + private class FieldFilterTranslation extends ProcessorTranslation { + private String field; + private String value; + + private FieldFilterTranslation(Condition condition) { + clazz = OperatorTypeEnum.getTypeByName(condition.getOperator()).getType(); + field = condition.getLeft(); + value = condition.getRight().get(0); + } + } + + private class MultiFieldFilterTranslation extends ProcessorTranslation { + private String field; + private List<String> values; + + private MultiFieldFilterTranslation(Condition condition) { + field = condition.getLeft(); + values = condition.getRight(); + clazz = OperatorTypeEnum.getTypeByName(condition.getOperator()).getModifiedType(); + } + } + + public Translation translateToHpJson(Condition condition) { + return 1 == condition.getRight().size() ? new FieldFilterTranslation(condition) : new MultiFieldFilterTranslation(condition); + } +} 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 new file mode 100644 index 0000000..dac818d --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/IRuleElementTranslator.java @@ -0,0 +1,50 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import com.google.gson.annotations.SerializedName; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; + +import java.util.ArrayList; +import java.util.List; + +public interface IRuleElementTranslator<T> { + + OnapLoggerError errLogger = OnapLoggerError.getInstance(); + OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + Translation translateToHpJson(T element); + + abstract class Translation { + } + + class ProcessorTranslation extends Translation { + @SerializedName("class") + protected String clazz; + } + + + class FiltersTranslation extends ProcessorTranslation { + protected List<Translation> filters; + + protected FiltersTranslation(String clazz, List<Translation> filters) { + this.clazz = clazz; + this.filters = filters; + } + } + + class RuleTranslation extends Translation { + protected String phase; + protected Translation filter; + protected List<Translation> processors = new ArrayList<>(); + } + + class RunPhaseProcessorsTranslation extends ProcessorTranslation { + protected String phase; + + protected RunPhaseProcessorsTranslation(String runPhase){ + clazz ="RunPhase"; + phase = runPhase; + } + } + +} 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 new file mode 100644 index 0000000..922312e --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MapActionTranslator.java @@ -0,0 +1,50 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import com.google.gson.annotations.SerializedName; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; + +import java.util.List; +import java.util.Map; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.MapAction; + +public class MapActionTranslator extends CopyActionTranslator<MapAction> { + + private static MapActionTranslator mapActionTranslator = new MapActionTranslator(); + + public static MapActionTranslator getInstance() { + return mapActionTranslator; + } + + private MapActionTranslator(){} + + private class MapActionTranslation extends ProcessorTranslation { + + private Map<String, String> map; + private String field; + private String toField; + @SerializedName("default") + private String Default; + + private MapActionTranslation(MapAction action) { + clazz = "MapAlarmValues"; + Default = action.getMapDefaultValue(); + field = action.getFromValue(); + toField = action.getTarget(); + map = action.transformToMap(); + } + } + + @Override + public Translation translateToHpJson(MapAction action) { + return new MapActionTranslation(action); + } + + @Override + public boolean addToHpJsonProcessors(MapAction action, List<Translation> processors, boolean asNewProcessor) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Translating map action"); + addToHpJsonProcessors(action, processors); + return true; + } +} 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 new file mode 100644 index 0000000..0164446 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/MappingRulesTranslator.java @@ -0,0 +1,69 @@ +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; + +public class MappingRulesTranslator implements IRuleElementTranslator<MappingRules> { + + private static MappingRulesTranslator mappingRulesTranslator = new MappingRulesTranslator(); + + public static MappingRulesTranslator getInstance() { + return mappingRulesTranslator; + } + + private MappingRulesTranslator() { + } + + private RuleTranslator ruleTranslator = RuleTranslator.getInstance(); + + public Translation translateToHpJson(MappingRules mappingRules) { + return new MappingRulesTranslation(mappingRules); + } + + public Translation 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 class MappingRulesTranslation extends Translation { + + private List<Translation> 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)); + } + } + + private class RunPhaseRuleTranslation extends RuleTranslation { + + private RunPhaseRuleTranslation(String phaseName, String runPhase) { + phase = phaseName; + if ("snmp_map".equals(phaseName)) + processors.add(new SnmpConvertor()); + processors.add(new RunPhaseProcessorsTranslation(runPhase)); + } + } + + // hardcoded SNMP processor + private class SnmpConvertor extends ProcessorTranslation { + private String array = "varbinds"; + private String datacolumn = "varbind_value"; + private String keycolumn = "varbind_oid"; + + private SnmpConvertor() { + clazz = "SnmpConvertor"; + } + } + +} 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 new file mode 100644 index 0000000..c49a04e --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RegexActionTranslator.java @@ -0,0 +1,44 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import java.util.List; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseAction; + +public class RegexActionTranslator extends CopyActionTranslator<BaseAction> { + + private static RegexActionTranslator regexActionTranslator = new RegexActionTranslator(); + + public static RegexActionTranslator getInstance() { + return regexActionTranslator; + } + + private RegexActionTranslator(){} + + private class RegexCopyActionTranslation extends ProcessorTranslation { + + private String regex; + private String field; + private String value; + + private RegexCopyActionTranslation(BaseAction action) { + clazz = "ExtractText"; + regex = action.getRegexValue(); + field = action.getTarget(); + value = action.getFromValue(); + } + } + + @Override + public boolean addToHpJsonProcessors(BaseAction action, List<Translation> processors, boolean asNewProcessor) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Translating copy action as regex action"); + addToHpJsonProcessors(action, processors); + return true; + } + + @Override + public Translation translateToHpJson(BaseAction action) { + return new RegexCopyActionTranslation(action); + } + +} 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 new file mode 100644 index 0000000..f7dea47 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/translators/RuleTranslator.java @@ -0,0 +1,51 @@ +package org.onap.sdc.dcae.rule.editor.translators; + +import com.google.gson.Gson; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; +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; + +public class RuleTranslator implements IRuleElementTranslator<Rule> { + + private static RuleTranslator ruleTranslator = new RuleTranslator(); + + public static RuleTranslator getInstance() { + return ruleTranslator; + } + + private RuleTranslator() { + } + + private class ActionRuleTranslation extends RuleTranslation { + private ActionRuleTranslation(Rule rule) { + phase = rule.getPhase(); + filter = rule.isConditionalRule() ? getConditionTranslator(rule.getCondition()).translateToHpJson(rule.getCondition()) : null; + boolean asNewProcessor = true; + for (BaseAction action : rule.getActions()) { + // consecutive copy actions are aggregated into a single processor + asNewProcessor = getActionTranslator(action).addToHpJsonProcessors(action, processors, asNewProcessor); + } + } + } + + public Translation translateToHpJson(Rule rule) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Start translating rule {}", rule.getUid()); + Translation translation = new ActionRuleTranslation(rule); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished translation for rule {}. Result: {}", rule.getUid(), new Gson().toJson(translation)); + return translation; + } + + private IRuleElementTranslator getConditionTranslator(BaseCondition condition){ + return condition instanceof ConditionGroup ? ConditionGroupTranslator.getInstance() : + ValidationUtils.validateNotEmpty(OperatorTypeEnum.getTypeByName(((Condition)condition).getOperator()).getModifiedType()) ? FieldConditionTranslator.getInstance() : ConditionTranslator.getInstance(); + } + + private CopyActionTranslator getActionTranslator(BaseAction action) { + ActionTypeEnum type = ActionTypeEnum.getTypeByName(action.getActionType()); + if(ActionTypeEnum.COPY == type && ValidationUtils.validateNotEmpty(action.getRegexValue())) + return RegexActionTranslator.getInstance(); + return (CopyActionTranslator)RuleEditorElementType.getElementTypeByName(type.getType()).getTranslator(); + } +}
\ No newline at end of file diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/EmptyStringTranslationSerializer.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/EmptyStringTranslationSerializer.java new file mode 100644 index 0000000..c65076f --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/EmptyStringTranslationSerializer.java @@ -0,0 +1,14 @@ +package org.onap.sdc.dcae.rule.editor.utils; + +import com.google.gson.*; + +import java.lang.reflect.Type; + +public class EmptyStringTranslationSerializer implements JsonSerializer<String> { + + public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { + if("\"\"".equals(src)) + return new JsonPrimitive(""); + return new JsonPrimitive(src); + } +} 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 new file mode 100644 index 0000000..33f9e92 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/RulesPayloadUtils.java @@ -0,0 +1,38 @@ +package org.onap.sdc.dcae.rule.editor.utils; + +import java.util.List; + +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; + +import com.google.gson.Gson; +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); + } + + public static MappingRules parseMappingRulesArtifactPayload(String payload) throws JsonParseException { + return gson.fromJson(payload, MappingRules.class); + } + + public static SchemaInfo extractInfoFromDescription(Artifact rulesArtifact) { + try { + return gson.fromJson(rulesArtifact.getArtifactDescription(), SchemaInfo.class); + }catch (JsonParseException 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 new file mode 100644 index 0000000..7a3b206 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/utils/ValidationUtils.java @@ -0,0 +1,20 @@ +package org.onap.sdc.dcae.rule.editor.utils; + +import org.apache.commons.lang3.StringUtils; + + +public class ValidationUtils { + + private static final String EXPLICIT_EMPTY = "\"\""; + + public static boolean validateNotEmpty(String value){ + return StringUtils.isNoneBlank(value); + } + + 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/ActionValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ActionValidator.java new file mode 100644 index 0000000..3eb0eb5 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ActionValidator.java @@ -0,0 +1,40 @@ +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 class ActionValidator<A extends BaseAction> implements IRuleElementValidator<A> { + + private static ActionValidator actionValidator = new ActionValidator(); + + public static ActionValidator getInstance() { + return actionValidator; + } + + ActionValidator(){} + + public boolean validate(A action, List<ResponseFormat> errors) { + + // validate from is populated + boolean valid = validateFromValue(action, errors); + //validate target is populated + if (!ValidationUtils.validateTargetField(action.getTarget())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "target", action.getActionType(), action.getTarget())); + } + return valid; + } + + protected boolean validateFromValue(A action, List<ResponseFormat> errors) { + if(!ValidationUtils.validateNotEmpty(action.getFromValue())) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from", action.getActionType(), action.getTarget())); + return false; + } + return true; + } +} 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 new file mode 100644 index 0000000..965c898 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConcatActionValidator.java @@ -0,0 +1,29 @@ +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 class ConcatActionValidator extends ActionValidator<BaseAction> { + + private static ConcatActionValidator concatActionValidator = new ConcatActionValidator(); + + public static ConcatActionValidator getInstance() { + return concatActionValidator; + } + + private ConcatActionValidator(){} + + @Override + protected boolean validateFromValue(BaseAction action, List<ResponseFormat> errors) { + if(!ValidationUtils.validateNotEmpty(action.getFromValue()) || 2 > action.getFromValues().size()) { + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_CONCAT_VALUE, null, action.getTarget())); + return false; + } + return true; + } +} 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 new file mode 100644 index 0000000..995a817 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionGroupValidator.java @@ -0,0 +1,40 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.ConditionGroup; +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.enums.ConditionTypeEnum; +import org.onap.sdc.dcae.rule.editor.enums.RuleEditorElementType; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +public class ConditionGroupValidator implements IRuleElementValidator<ConditionGroup> { + + private static ConditionGroupValidator conditionGroupValidator = new ConditionGroupValidator(); + + public static ConditionGroupValidator getInstance() { + return conditionGroupValidator; + } + + private ConditionGroupValidator(){} + + public boolean validate(ConditionGroup condition, List<ResponseFormat> errors) { + boolean valid = true; + if(!ValidationUtils.validateNotEmpty(condition.getType()) || null == ConditionTypeEnum.getTypeByName(condition.getType())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_GROUP_CONDITION, null, condition.getType())); + } + if(CollectionUtils.isEmpty(condition.getChildren()) || 2 > condition.getChildren().size()) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_CONDITION_ITEM, null, null)); + } else { + valid = condition.getChildren().stream() + .map(c -> RuleEditorElementType.getElementTypeByName(c.getClass().getSimpleName()).getValidator().validate(c, errors)) + .reduce(true, (x,y) -> x && y) && valid; + } + return valid; + } +} 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 new file mode 100644 index 0000000..1b4ae94 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/ConditionValidator.java @@ -0,0 +1,40 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.Condition; +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.enums.OperatorTypeEnum; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +public class ConditionValidator implements IRuleElementValidator<Condition> { + + private static ConditionValidator conditionValidator = new ConditionValidator(); + + public static ConditionValidator getInstance() { + return conditionValidator; + } + + private ConditionValidator(){} + + public boolean validate(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())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_OPERAND, null, "right")); + } + if(!ValidationUtils.validateNotEmpty(condition.getOperator()) || null == OperatorTypeEnum.getTypeByName(condition.getOperator())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.INVALID_OPERATOR, null, condition.getOperator())); + } + return valid; + } + +} 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 new file mode 100644 index 0000000..d5ec0fc --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/DateFormatterValidator.java @@ -0,0 +1,41 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.DateFormatterAction; +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 DateFormatterValidator extends ActionValidator<DateFormatterAction> { + private static DateFormatterValidator dateFormatterValidator = new DateFormatterValidator(); + + public static DateFormatterValidator getInstance() { + return dateFormatterValidator; + } + + private DateFormatterValidator(){} + + @Override + public boolean validate(DateFormatterAction action, List<ResponseFormat> errors) { + boolean valid = super.validate(action, errors); + if(!ValidationUtils.validateNotEmpty(action.getFromFormat())){ + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from format", action.getActionType(), action.getTarget())); + } + if(!ValidationUtils.validateNotEmpty(action.getFromTz())){ + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "from timezone", action.getActionType(), action.getTarget())); + } + if(!ValidationUtils.validateNotEmpty(action.getToFormat())){ + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "to format", action.getActionType(), action.getTarget())); + } + if(!ValidationUtils.validateNotEmpty(action.getToTz())){ + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION_FIELD, null, "to timezone", action.getActionType(), action.getTarget())); + } + return valid; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/IRuleElementValidator.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/IRuleElementValidator.java new file mode 100644 index 0000000..dd1eaf4 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/IRuleElementValidator.java @@ -0,0 +1,9 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.errormng.ResponseFormat; + +import java.util.List; + +public interface IRuleElementValidator <T> { + boolean validate(T element, List<ResponseFormat> 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 new file mode 100644 index 0000000..8cbcaa8 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/MapActionValidator.java @@ -0,0 +1,49 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.MapAction; +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; + +public class MapActionValidator extends ActionValidator<MapAction> { + + private static MapActionValidator mapActionValidator = new MapActionValidator(); + + public static MapActionValidator getInstance() { + return mapActionValidator; + } + + private MapActionValidator(){} + + @Override + public boolean validate(MapAction action, List<ResponseFormat> errors) { + boolean valid = super.validate(action, errors); + if (action.getMap() == null || CollectionUtils.isEmpty(action.getMapValues())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ENTRY, null, action.getTarget())); + } else { + if (action.mapHasDefault() && !ValidationUtils.validateNotEmpty(action.getMapDefaultValue())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_DEFAULT_VALUE, null, action.getTarget())); + } + try { + if (!validateMapValues(action)) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ENTRY, null, action.getTarget())); + } + } catch (IllegalStateException err) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.DUPLICATE_KEY, null)); + } + } + return valid; + } + + private boolean validateMapValues(MapAction action) { + return action.transformToMap().entrySet().stream().noneMatch(p -> !ValidationUtils.validateNotEmpty(p.getKey()) || !ValidationUtils.validateNotEmpty(p.getValue())); + } +} 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 new file mode 100644 index 0000000..371d1e9 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/rule/editor/validators/RuleValidator.java @@ -0,0 +1,56 @@ +package org.onap.sdc.dcae.rule.editor.validators; + +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.ActionTypeEnum; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseAction; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.BaseCondition; +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.errormng.ServiceException; +import org.onap.sdc.dcae.rule.editor.enums.RuleEditorElementType; +import org.onap.sdc.dcae.rule.editor.utils.ValidationUtils; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +public class RuleValidator implements IRuleElementValidator<Rule> { + + private static RuleValidator ruleValidator = new RuleValidator(); + + public static RuleValidator getInstance() { + return ruleValidator; + } + + private RuleValidator(){} + + + public boolean validate(Rule rule, List<ResponseFormat> errors) { + boolean valid = true; + if(rule.isConditionalRule()) + valid = getConditionValidator(rule.getCondition()).validate(rule.getCondition(), errors); + if(!ValidationUtils.validateNotEmpty(rule.getDescription())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_RULE_DESCRIPTION, null, null)); + } + if(CollectionUtils.isEmpty(rule.getActions())) { + valid = false; + errors.add(ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.MISSING_ACTION, null, null)); + } else { + valid = rule.getActions().stream() + .map(a -> getActionValidator(a).validate(a, errors)) + .reduce(true, (x,y) -> x && y) && valid; + } + return valid; + } + + + private IRuleElementValidator getActionValidator(BaseAction action) { + ActionTypeEnum type = ActionTypeEnum.getTypeByName(action.getActionType()); + return RuleEditorElementType.getElementTypeByName(type.getType()).getValidator(); + } + + private IRuleElementValidator getConditionValidator(BaseCondition condition) { + return RuleEditorElementType.getElementTypeByName(condition.getClass().getSimpleName()).getValidator(); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/EventListenerDefinition.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/EventListenerDefinition.java new file mode 100644 index 0000000..cc5bec1 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/EventListenerDefinition.java @@ -0,0 +1,101 @@ +package org.onap.sdc.dcae.ves; + +import com.google.gson.Gson; +import org.apache.commons.lang.StringUtils; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class EventListenerDefinition extends VesDataTypeDefinition { + + public static final String EVENT_ROOT = "event"; + private String $schema; + private Map<String, VesDataTypeDefinition> definitions; + + public String get$schema() { + return $schema; + } + + public void set$schema(String $schema) { + this.$schema = $schema; + } + + public Map<String, VesDataTypeDefinition> getDefinitions() { + return definitions; + } + + public void setDefinitions(Map<String, VesDataTypeDefinition> definitions) { + this.definitions = definitions; + } + + // returns error message detailing unresolvable types - or null (success) + public String resolveRefTypes() { + + Predicate<Map.Entry<String, VesDataTypeDefinition>> isFullyResolved = dt -> !dt.getValue().containsAnyReferenceItem(); + Map<String, VesDataTypeDefinition> resolved = definitions.entrySet().stream() + .filter(isFullyResolved) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + int initialUnresolvedItems = -1; + int remainingUnresolvedItems = 0; + + while (resolved.size() != definitions.size() && initialUnresolvedItems != remainingUnresolvedItems) { + initialUnresolvedItems = definitions.size() - resolved.size(); + definitions.entrySet().forEach(definition -> { + if (!resolved.containsKey(definition.getKey()) && definition.getValue().isResolvable(resolved)) { + definition.getValue().resolveAllReferences(resolved); + resolved.put(definition.getKey(), definition.getValue()); + } + }); + remainingUnresolvedItems = definitions.size() - resolved.size(); + } + + if (resolved.size() != definitions.size()) { + definitions.keySet().removeAll(resolved.keySet()); + return constructErrorMessage(definitions.keySet()); + } + return resolveRootRefTypes(); + + } + + private String constructErrorMessage(Set<String> unresolvable) { + return "the following definitions containing unresolvable references: " + new Gson().toJson(unresolvable); + } + + private String resolveRootRefTypes() { + Set<String> unresolvable = new HashSet<>(); + getProperties().forEach((k, v) -> { + if (isResolvable(definitions)) + resolveAllReferences(definitions); + else + unresolvable.add(k); + }); + return unresolvable.isEmpty() ? null : constructErrorMessage(unresolvable); + + } + + @Override + public String validate() { + String error = getProperties().containsKey(EVENT_ROOT) ? null : "schema not containing property: event"; + if (StringUtils.isBlank(error)) + error = super.validate(); + if (StringUtils.isBlank(error)) + error = validateDefinitions(); + return error; + } + + private String validateDefinitions() { + String error = null; + for (VesDataTypeDefinition def : definitions.values()) { + if (StringUtils.isBlank(error)) + error = def.validate(); + else + break; + } + return error; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesDataItemsDefinition.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesDataItemsDefinition.java new file mode 100644 index 0000000..ad1b2f9 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesDataItemsDefinition.java @@ -0,0 +1,9 @@ +package org.onap.sdc.dcae.ves; + +import java.util.ArrayList; + +// json 'items' value can be either a single object or an array. customized POJO will always be an array +public class VesDataItemsDefinition extends ArrayList<VesDataTypeDefinition> { + + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesDataTypeDefinition.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesDataTypeDefinition.java new file mode 100644 index 0000000..5465d62 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesDataTypeDefinition.java @@ -0,0 +1,270 @@ +package org.onap.sdc.dcae.ves; + +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; + +import java.util.*; + +public class VesDataTypeDefinition { + + private static final String jsonReferencePrefix = "#/definitions/"; + private String type; + private String description; + private String format; + private String title; + private Map<String, VesDataTypeDefinition> properties; + private List<String> required = new ArrayList<>(); + @SerializedName("enum") + private List<String> enums; + @SerializedName("default") + private JsonElement defaultValue; + private VesDataItemsDefinition items; + @SerializedName("$ref") + private String ref; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Map<String, VesDataTypeDefinition> getProperties() { + return properties; + } + + public void setProperties(Map<String, VesDataTypeDefinition> properties) { + this.properties = properties; + } + + public List<String> getRequired() { + return required; + } + + public void setRequired(List<String> required) { + this.required = required; + } + + public List<String> getEnums() { + return enums; + } + + public void setEnums(List<String> enums) { + this.enums = enums; + } + + public JsonElement getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(JsonElement defaultValue) { + this.defaultValue = defaultValue; + } + + public VesDataItemsDefinition getItems() { + return items; + } + + public void setItems(VesDataItemsDefinition items) { + this.items = items; + } + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + protected boolean hasReference() { + return StringUtils.isNotBlank(getRef()); + } + + protected boolean itemsContainReference() { + return CollectionUtils.isNotEmpty(getItems()) && getItems().stream().anyMatch(VesDataTypeDefinition::containsAnyReferenceItem); + } + + protected boolean propertiesContainReference() { + return MapUtils.isNotEmpty(getProperties()) && getProperties().values().stream().anyMatch(VesDataTypeDefinition::containsAnyReferenceItem); + } + + protected boolean containsAnyReferenceItem() { + return hasReference() || itemsContainReference() || propertiesContainReference(); + } + + protected String getJsonRefPointer() { + return getRef().replace(jsonReferencePrefix, ""); + } + + private void addReferenceItem(Set<String> allRefs) { + if (hasReference()) { + allRefs.add(getJsonRefPointer()); + } + } + + private Set<String> extractAllReferenceTokens() { + Set<String> allRefs = new HashSet<>(); + extractReferenceTokens(allRefs); + return allRefs; + } + + private void extractReferenceTokens(Set<String> allRefs) { + + addReferenceItem(allRefs); + if (itemsContainReference()) { + getItems().forEach(item -> item.extractReferenceTokens(allRefs)); + } + if (propertiesContainReference()) { + getProperties().values().forEach(property -> property.extractReferenceTokens(allRefs)); + } + } + + protected boolean isResolvable(Map<String, VesDataTypeDefinition> resolvedTypes) { + return resolvedTypes.keySet().containsAll(extractAllReferenceTokens()); + } + + private void resolveReference(Map<String, VesDataTypeDefinition> resolvedTypes) { + if (hasReference()) { + VesDataTypeDefinition other = resolvedTypes.get(getJsonRefPointer()); + setType(other.getType()); + setRef(other.getRef()); + setDefaultValue(other.getDefaultValue()); + setDescription(other.getDescription()); + setEnums(other.getEnums()); + setProperties(other.getProperties()); + setFormat(other.getFormat()); + setRequired(other.getRequired()); + setItems(other.getItems()); + setTitle(other.getTitle()); + } + } + + private void resolveItemReferences(Map<String, VesDataTypeDefinition> resolvedTypes) { + if (itemsContainReference()) { + for (VesDataTypeDefinition item : getItems()) { + item.resolveAllReferences(resolvedTypes); + } + } + } + + private void resolvePropertyReferences(Map<String, VesDataTypeDefinition> resolvedTypes) { + if (propertiesContainReference()) { + for (VesDataTypeDefinition property : getProperties().values()) { + property.resolveAllReferences(resolvedTypes); + } + } + } + + // the reference resolver is called on each VesDataTypeDefinition after it passes the 'isResolvable' validation, affirming that all its references(direct/properties/items) point to a resolved VesDataTypeDefinition (has no references) + protected void resolveAllReferences(Map<String, VesDataTypeDefinition> resolvedTypes) { + resolveReference(resolvedTypes); + resolveItemReferences(resolvedTypes); + resolvePropertyReferences(resolvedTypes); + } + + private String validateType() { + return null == type? null : VesSimpleTypesEnum.getSimpleTypes().contains(type) ? null : "invalid type declaration: " + type; + } + + private String validateRequired() { + String invalid = null == type? null : !type.equals(VesSimpleTypesEnum.OBJECT.getType()) ? null : required.stream().filter(r -> !properties.keySet().contains(r)).findAny().orElse(null); + return StringUtils.isBlank(invalid) ? invalid : "invalid required entry: " + invalid; + } + + // returns error message detailing invalid 'type' or 'required' fields (null for success) + protected String validate() { + String error = validateType(); + if (StringUtils.isBlank(error)) + error = validateRequired(); + if (StringUtils.isBlank(error) && CollectionUtils.isNotEmpty(items)) + error = validateItems(); + if(StringUtils.isBlank(error) && MapUtils.isNotEmpty(properties)) + error = validateProperties(); + return error; + } + + private String validateItems(){ + String error = null; + for (VesDataTypeDefinition def : items) { + if (StringUtils.isBlank(error)) + error = def.validate(); + else + break; + } + return error; + } + + private String validateProperties(){ + String error = null; + for (VesDataTypeDefinition def : properties.values()) { + if (StringUtils.isBlank(error)) + error = def.validate(); + else + break; + } + return error; + } + + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (null == obj || getClass() != obj.getClass()) + return false; + VesDataTypeDefinition other = (VesDataTypeDefinition) obj; + return Objects.equals(type, other.type) && + Objects.equals(description, other.description) && + Objects.equals(format, other.format) && + Objects.equals(title, other.title) && + Objects.equals(required, other.required) && + Objects.equals(enums, other.enums) && + Objects.equals(defaultValue, other.defaultValue) && + Objects.equals(items, other.items) && + Objects.equals(properties, other.properties) && + Objects.equals(ref, other.ref); + } + + @Override public int hashCode() { + int result = type != null ? type.hashCode() : 0; + result = 31 * result + (description != null ? description.hashCode() : 0); + result = 31 * result + (format != null ? format.hashCode() : 0); + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + (properties != null ? properties.hashCode() : 0); + result = 31 * result + (required != null ? required.hashCode() : 0); + result = 31 * result + (enums != null ? enums.hashCode() : 0); + result = 31 * result + (defaultValue != null ? defaultValue.hashCode() : 0); + result = 31 * result + (items != null ? items.hashCode() : 0); + result = 31 * result + (ref != null ? ref.hashCode() : 0); + return result; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesJsonDeserializer.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesJsonDeserializer.java new file mode 100644 index 0000000..f5cfd2a --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesJsonDeserializer.java @@ -0,0 +1,20 @@ +package org.onap.sdc.dcae.ves; + +import com.google.gson.*; + +import java.lang.reflect.Type; + +// json 'items' value can be either a single object or an array. customized POJO will always be an array +public class VesJsonDeserializer implements JsonDeserializer<VesDataItemsDefinition> { + @Override + public VesDataItemsDefinition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + + if(json instanceof JsonArray){ + return new Gson().fromJson(json, VesDataItemsDefinition.class); + } + + VesDataItemsDefinition items = new VesDataItemsDefinition(); + items.add(new Gson().fromJson(json, VesDataTypeDefinition.class)); + return items; + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesSimpleTypesEnum.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesSimpleTypesEnum.java new file mode 100644 index 0000000..0606a6d --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesSimpleTypesEnum.java @@ -0,0 +1,26 @@ +package org.onap.sdc.dcae.ves; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public enum VesSimpleTypesEnum { + + ARRAY("array"), BOOLEAN("boolean"), INTEGER("integer"), NULL("null"), NUMBER("number"), OBJECT("object"), STRING("string"); + + private String type; + + public String getType() { + return type; + } + + private VesSimpleTypesEnum(String type) { + this.type = type; + } + + public static Set<String> getSimpleTypes() { + return Arrays.stream(VesSimpleTypesEnum.values()).map(t -> t.getType()).collect(Collectors.toSet()); + } + + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesStructureLoader.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesStructureLoader.java new file mode 100644 index 0000000..cb8a16c --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/ves/VesStructureLoader.java @@ -0,0 +1,115 @@ +package org.onap.sdc.dcae.ves; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.io.*; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Service("vesstructureloader") +public class VesStructureLoader { + + + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + private static Map<String, EventListenerDefinition> eventListeners = new HashMap<>(); + private static final Type type = new TypeToken<VesDataItemsDefinition>(){}.getType(); + private static final Gson gson = new GsonBuilder().registerTypeAdapter(type, new VesJsonDeserializer()).create(); + private static final String SCHEMA_NAME_PREFIX = "CommonEventFormat_v"; + private static final String SCHEMA_NAME_SUFFIX = ".json"; + + private VesStructureLoader() { + } + + @PostConstruct public void init() { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VesStructureLoader: Trying to load json schemas"); + String jettyBase = System.getProperty("jetty.base"); + if (jettyBase == null) { + String msg = "Couldn't resolve jetty.base environmental variable"; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new IllegalArgumentException(msg + ". Failed to load VES schema files... aborting"); + } + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "jetty.base={}", jettyBase); + + File dir = new File(jettyBase + "/config/dcae-be/ves-schema"); + File[] files = dir.listFiles((dir1, name) -> name.startsWith(SCHEMA_NAME_PREFIX) && name.endsWith(SCHEMA_NAME_SUFFIX)); + + if (ArrayUtils.isEmpty(files)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error – Failed to find VES Schema definitions."); + } else { + + for (File f : files) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Loading VES schema file: {}", f.getName()); + parseJsonFileAndSaveToMap(f); + } + } + + } + + private void parseJsonFileAndSaveToMap(File file) { + + try { + EventListenerDefinition eventListener = gson.fromJson(new FileReader(file), EventListenerDefinition.class); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), gson.toJson(eventListener)); + String validationError = getValidatorMessage(eventListener); + if (StringUtils.isEmpty(validationError)) { + eventListeners.put(getVersionFromFileName(file.getName()), eventListener); + } else { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error: Failed to parse VES schema file {}. [{}]", file.getName(), validationError); + } + } catch (FileNotFoundException | JsonIOException | JsonSyntaxException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error: Failed to parse VES schema file {}. [{}]", file.getName(), e); + } + } + + public static Map<String, VesDataTypeDefinition> getEventListenerDefinitionByVersion(String version) { + return eventListeners.get(version).getProperties().get(EventListenerDefinition.EVENT_ROOT).getProperties(); + } + + public static Set<String> getAvailableVersionsList() { + return eventListeners.keySet(); + } + + public static Map<String, Set<String>> getAvailableVersionsAndEventTypes() { + return eventListeners.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getEventListenerDefinitionByVersion(e.getKey()).keySet())); + } + + public static Set<String> getEventTypeListByVersion(String version) { + return getEventListenerDefinitionByVersion(version).keySet(); + } + + private String getValidatorMessage(EventListenerDefinition eventListenerDefinition) { + String validationError = eventListenerDefinition.validate(); + if (StringUtils.isBlank(validationError)) { + validationError = eventListenerDefinition.resolveRefTypes(); + } + return validationError; + } + + private String getVersionFromFileName(String fileName) { + return fileName.replace(SCHEMA_NAME_PREFIX, "").replace(SCHEMA_NAME_SUFFIX, ""); + } + + @PreDestroy + public void preDestroy() { + // why is this method empty? + } +} |