diff options
Diffstat (limited to 'src/main')
20 files changed, 1455 insertions, 0 deletions
diff --git a/src/main/java/org/onap/ves/openapi/manager/Main.java b/src/main/java/org/onap/ves/openapi/manager/Main.java new file mode 100644 index 0000000..209c05b --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/Main.java @@ -0,0 +1,93 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.http.HttpAsdcClient; +import org.onap.sdc.http.HttpClientFactory; +import org.onap.sdc.http.HttpRequestFactory; +import org.onap.sdc.http.SdcConnectorClient; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.service.ArtifactsCollector; +import org.onap.ves.openapi.manager.service.ClientCallback; +import org.onap.ves.openapi.manager.service.notification.ArtifactsCollectorStatusSender; +import org.onap.ves.openapi.manager.service.notification.FinalStatusSender; +import org.onap.ves.openapi.manager.service.notification.ValidationStatusSender; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +@Log4j2 +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } + + /** + * Creates bean of SdcConnectorClient + * @param clientConfig DistributionClientConfig object with configuration properties + * @return SdcConnectorClient + */ + @Bean + public SdcConnectorClient getSdcConnectorClient(DistributionClientConfig clientConfig) { + HttpRequestFactory requestFactory = new HttpRequestFactory(clientConfig.getUser(), clientConfig.getPassword()); + HttpClientFactory clientFactory = new HttpClientFactory(clientConfig); + return new SdcConnectorClient(clientConfig, new HttpAsdcClient(clientConfig.getAsdcAddress(), clientFactory, requestFactory)); + } + + /** + * Creates bean of DistributionClientImpl + * @param clientConfig DistributionClientConfig object with configuration properties + * @param validators List of objects implementing ArtifactValidator interface + * @param artifactsCollector ArtifactsCollector object which downloads artifacts contents + * @return DistributionClientImpl + */ + @Bean + public DistributionClientImpl getDistributionClientImpl(DistributionClientConfig clientConfig, + List<ArtifactsValidator> validators, + ArtifactsCollector artifactsCollector) { + DistributionClientImpl client = new DistributionClientImpl(); + ClientCallback callback = new ClientCallback(validators, artifactsCollector, + new ArtifactsCollectorStatusSender(client), new ValidationStatusSender(client), + new FinalStatusSender(client)); + + log.info(ClientCallback.SEPARATOR); + IDistributionClientResult initResult = client.init(clientConfig, callback); + log.info(initResult.getDistributionMessageResult()); + log.info(ClientCallback.SEPARATOR); + + log.info(ClientCallback.SEPARATOR); + IDistributionClientResult startResult = client.start(); + log.info(startResult.getDistributionMessageResult()); + log.info(ClientCallback.SEPARATOR); + + return client; + } + +} diff --git a/src/main/java/org/onap/ves/openapi/manager/config/DistributionClientConfig.java b/src/main/java/org/onap/ves/openapi/manager/config/DistributionClientConfig.java new file mode 100644 index 0000000..188cced --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/config/DistributionClientConfig.java @@ -0,0 +1,130 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.config; + +import lombok.Getter; +import lombok.Setter; +import org.onap.sdc.api.consumer.IConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.Collections; +import java.util.List; + +/** + * DistributionClientConfig - properties required by DistributionClientImpl, values mapped from application.yml + */ +@Configuration +@ConfigurationProperties(prefix = "vesopenapimanager.distribution") +@Getter +@Setter +public class DistributionClientConfig implements IConfiguration { + + public static final String VES_EVENTS_ARTIFACT_TYPE = "VES_EVENTS"; + + private String asdcAddress; + private String msgBusAddress; + private String user; + private String password; + private Integer pollingInterval; + private Integer pollingTimeout; + private String consumerGroup; + private String environmentName; + private String consumerID; + private Boolean activateServerTLSAuth; + private Boolean isFilterInEmptyResources; + private Boolean isUseHttpsWithDmaap; + + @Override + public String getAsdcAddress() { + return asdcAddress; + } + + @Override + public List<String> getMsgBusAddress() { + return Collections.singletonList(msgBusAddress); + } + + @Override + public String getUser() { + return user; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public int getPollingInterval() { + return pollingInterval; + } + + @Override + public int getPollingTimeout() { + return pollingTimeout; + } + + @Override + public List<String> getRelevantArtifactTypes() { + return Collections.singletonList(VES_EVENTS_ARTIFACT_TYPE); + } + + @Override + public String getConsumerGroup() { + return consumerGroup; + } + + @Override + public String getEnvironmentName() { + return environmentName; + } + + @Override + public String getConsumerID() { + return consumerID; + } + + @Override + public String getKeyStorePath() { + return null; + } + + @Override + public String getKeyStorePassword() { + return null; + } + + @Override + public boolean activateServerTLSAuth() { + return activateServerTLSAuth; + } + + @Override + public boolean isFilterInEmptyResources() { + return isFilterInEmptyResources; + } + + @Override + public Boolean isUseHttpsWithDmaap() { + return isUseHttpsWithDmaap; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/config/ValidatorProperties.java b/src/main/java/org/onap/ves/openapi/manager/config/ValidatorProperties.java new file mode 100644 index 0000000..11beb22 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/config/ValidatorProperties.java @@ -0,0 +1,39 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * ValidatorProperties - properties required by SchemaReferenceValidator, values mapped from application.yml + */ +@Configuration +@ConfigurationProperties(prefix = "vesopenapimanager.validation") +@Getter +@Setter +public class ValidatorProperties { + private String schemaMapPath; + private String eventDomainPath; + private String eventSchemaReferencePath; +} diff --git a/src/main/java/org/onap/ves/openapi/manager/exceptions/ArtifactException.java b/src/main/java/org/onap/ves/openapi/manager/exceptions/ArtifactException.java new file mode 100644 index 0000000..c51face --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/exceptions/ArtifactException.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.exceptions; + +import lombok.NoArgsConstructor; + +@NoArgsConstructor +public class ArtifactException extends RuntimeException { } diff --git a/src/main/java/org/onap/ves/openapi/manager/model/Artifact.java b/src/main/java/org/onap/ves/openapi/manager/model/Artifact.java new file mode 100644 index 0000000..8cc54ac --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/Artifact.java @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.onap.sdc.api.notification.IArtifactInfo; + +/** + * Artifact - model class that contains description and content of artifact + */ +@AllArgsConstructor +@Getter +@EqualsAndHashCode +public class Artifact { + private final IArtifactInfo description; + private final byte[] content; +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/ArtifactValidationResult.java b/src/main/java/org/onap/ves/openapi/manager/model/ArtifactValidationResult.java new file mode 100644 index 0000000..f672bb5 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/ArtifactValidationResult.java @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; + +/** + * ArtifactValidationResult - model class for result of artifact validation + */ +@AllArgsConstructor +@Getter +@EqualsAndHashCode +public class ArtifactValidationResult { + private final IArtifactInfo artifact; + private final boolean isValid; + private final String message; + private final ArtifactsValidator validator; +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/DistributionStatusMessage.java b/src/main/java/org/onap/ves/openapi/manager/model/DistributionStatusMessage.java new file mode 100644 index 0000000..f25e6e0 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/DistributionStatusMessage.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import org.onap.sdc.api.consumer.IDistributionStatusMessage; +import org.onap.sdc.utils.DistributionStatusEnum; + +/** + * DistributionStatusMessage - model class for operation status sent to SDC + */ +@AllArgsConstructor +public class DistributionStatusMessage implements IDistributionStatusMessage { + + private final String artifactUrl; + private final String distributionId; + private final String consumerId; + private final long timestamp; + private final DistributionStatusEnum status; + + @Override + public String getArtifactURL() { + return artifactUrl; + } + + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public String getConsumerID() { + return consumerId; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public DistributionStatusEnum getStatus() { + return status; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/FinalDistributionStatusMessage.java b/src/main/java/org/onap/ves/openapi/manager/model/FinalDistributionStatusMessage.java new file mode 100644 index 0000000..de8836d --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/FinalDistributionStatusMessage.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import org.onap.sdc.api.consumer.IFinalDistrStatusMessage; +import org.onap.sdc.utils.DistributionStatusEnum; + + +/** + * FinalDistributionStatusMessage - model class for final ves-openapi-manager's validation message sent to SDC + */ +@AllArgsConstructor +public class FinalDistributionStatusMessage implements IFinalDistrStatusMessage { + + private final String distributionId; + private final long timestamp; + private final DistributionStatusEnum status; + private final String consumerId; + + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public DistributionStatusEnum getStatus() { + return status; + } + + @Override + public String getConsumerID() { + return consumerId; + } + +} diff --git a/src/main/java/org/onap/ves/openapi/manager/model/SchemaMap.java b/src/main/java/org/onap/ves/openapi/manager/model/SchemaMap.java new file mode 100644 index 0000000..b275e7f --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/model/SchemaMap.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * SchemaMap - model class with list of mappings of publicly stored OpenApi schemas to schemas stored locally in VES. + */ +@AllArgsConstructor +@Getter +public class SchemaMap { + private final List<Mapping> mappings; + + /** + * Single schemas mapping, + * publicURL contains URL to externally located schema, + * localURL contains URL located in VES container + */ + @NoArgsConstructor + @Getter + public static class Mapping { + private String publicURL; + private String localURL; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/ArtifactsCollector.java b/src/main/java/org/onap/ves/openapi/manager/service/ArtifactsCollector.java new file mode 100644 index 0000000..52f1b0e --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/ArtifactsCollector.java @@ -0,0 +1,99 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.http.SdcConnectorClient; +import org.onap.sdc.impl.DistributionClientDownloadResultImpl; +import org.onap.ves.openapi.manager.config.DistributionClientConfig; +import org.onap.ves.openapi.manager.exceptions.ArtifactException; +import org.onap.ves.openapi.manager.model.Artifact; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * ArtifactsCollector - Collector of artifact contents from distributed service, + * downloads artifacts contents basing on artifacts descriptions + */ +@Log4j2 +@Component +public class ArtifactsCollector { + + private static final String QUOTATION_MARK = "\""; + private static final int ARTIFACT_NAME_INDEX_NO_QUOTATION = 0; + private static final int ARTIFACT_NAME_INDEX_WITH_QUOTATION = 1; + private static final int NAME_WITH_QUOTATION_LENGTH = 2; + + private final SdcConnectorClient sdcConnectorClient; + + /** + * Constructor of ArtifactsCollector + * @param sdcConnectorClient SdcConnectorClient object + */ + @Autowired + public ArtifactsCollector(SdcConnectorClient sdcConnectorClient) { + this.sdcConnectorClient = sdcConnectorClient; + } + + /** + * @param artifacts List of IArtifactInfo objects, which are descriptions of artifacts + * @return List of Artifacts, each object contains description and content of artifact + */ + public List<Artifact> pullArtifacts(List<IArtifactInfo> artifacts) { + log.info("Downloading artifacts"); + List<IArtifactInfo> artifactDescriptions = filterVesEventsArtifacts(artifacts); + return artifactDescriptions.stream() + .map(sdcConnectorClient::downloadArtifact) + .map(downloadResult -> mapDownloadResultToArtifactContent(downloadResult, artifactDescriptions)) + .collect(Collectors.toList()); + } + + private List<IArtifactInfo> filterVesEventsArtifacts(List<IArtifactInfo> artifacts) { + return artifacts.stream() + .filter(artifactInfo -> + artifactInfo.getArtifactType().equals(DistributionClientConfig.VES_EVENTS_ARTIFACT_TYPE)) + .collect(Collectors.toList()); + } + + private Artifact mapDownloadResultToArtifactContent(DistributionClientDownloadResultImpl downloadResult, + List<IArtifactInfo> artifactDescriptions) { + String artifactName = parseArtifactName(downloadResult); + Optional<IArtifactInfo> artifact = findArtifactDescription(artifactDescriptions, artifactName); + return artifact.map(artifactInfo -> + new Artifact(artifactInfo, downloadResult.getArtifactPayload())) + .orElseThrow(ArtifactException::new); + } + + private String parseArtifactName(DistributionClientDownloadResultImpl artifact) { + String[] name = artifact.getArtifactName().split(QUOTATION_MARK); + boolean doesContainQuotationMark = name.length >= NAME_WITH_QUOTATION_LENGTH; + return doesContainQuotationMark ? name[ARTIFACT_NAME_INDEX_WITH_QUOTATION] : name[ARTIFACT_NAME_INDEX_NO_QUOTATION]; + } + + private Optional<IArtifactInfo> findArtifactDescription(List<IArtifactInfo> artifacts, String artifactName) { + return artifacts.stream().filter(a -> a.getArtifactName().equals(artifactName)).findFirst(); + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/ClientCallback.java b/src/main/java/org/onap/ves/openapi/manager/service/ClientCallback.java new file mode 100644 index 0000000..720ab8c --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/ClientCallback.java @@ -0,0 +1,143 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.consumer.INotificationCallback; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.notification.IResourceInstance; +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.service.notification.ArtifactsCollectorStatusSender; +import org.onap.ves.openapi.manager.service.notification.FinalStatusSender; +import org.onap.ves.openapi.manager.service.notification.ValidationStatusSender; +import org.onap.ves.openapi.manager.service.validation.ArtifactsValidator; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Log4j2 +public class ClientCallback implements INotificationCallback { + + public static final String SEPARATOR = "==================================="; + private final List<ArtifactsValidator> validators; + private final ValidationStatusSender validationStatusSender; + private final ArtifactsCollectorStatusSender artifactsCollectorStatusSender; + private final ArtifactsCollector artifactsCollector; + private final FinalStatusSender finalStatusSender; + + /** + * Constructor of ClientCallback + * @param validators List of objects implementing ArtifactValidator interface + * @param artifactsCollector ArtifactsCollector object which downloads artifacts contents + * @param artifactsCollectorStatusSender ArtifactsCollectorStatusSender which sends download results back to SDC + * @param validationStatusSender ValidationStatusSender which sends validation results to SDC + * @param finalStatusSender FinalStatusSender which sends final status of VES OpenApi Manager workflow + */ + public ClientCallback(List<ArtifactsValidator> validators, ArtifactsCollector artifactsCollector, + ArtifactsCollectorStatusSender artifactsCollectorStatusSender, + ValidationStatusSender validationStatusSender, FinalStatusSender finalStatusSender) { + this.validators = validators; + this.validationStatusSender = validationStatusSender; + this.artifactsCollectorStatusSender = artifactsCollectorStatusSender; + this.artifactsCollector = artifactsCollector; + this.finalStatusSender = finalStatusSender; + } + + /** + * Callback method of distribution listener. Each time a service distribution takes place it's executed. + * @param service Distributed service information. + */ + @Override + public void activateCallback(INotificationData service) { + logServiceInfo(service); + String distributionID = service.getDistributionID(); + + List<Artifact> artifacts = downloadArtifacts(service); + List<ArtifactValidationResult> validationResults = validate(distributionID, artifacts); + sendFinalStatus(distributionID, validationResults); + } + + private void logServiceInfo(INotificationData service) { + log.info(SEPARATOR); + log.info("Distributed service information"); + log.info("Service UUID: {}", service.getServiceUUID()); + log.info("Service name: {}", service.getServiceName()); + List<IResourceInstance> resources = service.getResources(); + log.info("Service resources:"); + resources.forEach(resource -> { + log.info(" - Resource: {}", resource.getResourceName()); + log.info(" Artifacts:"); + resource.getArtifacts().forEach(artifact -> log.info(" - Name: {}", artifact.getArtifactName())); + }); + log.info(SEPARATOR); + } + + private List<Artifact> downloadArtifacts(INotificationData service) { + List<IArtifactInfo> artifactInfos = getArtifactInfos(service); + List<Artifact> artifacts = artifactsCollector.pullArtifacts(artifactInfos); + sendDownloadStatuses(service, artifactInfos, artifacts); + return artifacts; + } + + private void sendDownloadStatuses(INotificationData service, List<IArtifactInfo> artifactInfos, List<Artifact> artifacts) { + Map<Boolean, List<Artifact>> artifactsDownloadResults = artifacts.stream() + .collect(Collectors.partitioningBy(this::isContentDownloaded)); + artifactsDownloadResults.get(Boolean.TRUE).forEach(artifact -> + artifactsCollectorStatusSender.sendDownloadOk(service.getDistributionID(), artifactInfos)); + artifactsDownloadResults.get(Boolean.FALSE).forEach(artifact -> + artifactsCollectorStatusSender.sendDownloadError(service.getDistributionID(), artifactInfos)); + } + + private boolean isContentDownloaded(Artifact artifact) { + return artifact.getContent() != null && artifact.getContent().length > 0; + } + + private List<IArtifactInfo> getArtifactInfos(INotificationData service) { + return service.getResources().stream() + .map(IResourceInstance::getArtifacts) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List<ArtifactValidationResult> validate(String distributionID, List<Artifact> artifacts) { + return validators.stream() + .map(validator -> { + List<ArtifactValidationResult> validationResults = validator.validate(artifacts); + validationStatusSender.send(distributionID, validationResults); + return validationResults; + }) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private void sendFinalStatus(String distributionID, List<ArtifactValidationResult> validationResults) { + boolean areAllArtifactsValid = validationResults.stream().allMatch(ArtifactValidationResult::isValid); + if (areAllArtifactsValid) { + finalStatusSender.sendFinalStatusOk(distributionID); + } else { + finalStatusSender.sendFinalStatusError(distributionID); + } + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSender.java b/src/main/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSender.java new file mode 100644 index 0000000..0829855 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/notification/ArtifactsCollectorStatusSender.java @@ -0,0 +1,93 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service.notification; + + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.ves.openapi.manager.model.DistributionStatusMessage; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.stream.Collectors; + +/** + * ArtifactsCollectorStatusSender - sender of DistributionStatusMessage with artifacts download status to SDC + */ +@Log4j2 +public class ArtifactsCollectorStatusSender { + + private static final String DOWNLOAD_ERROR_MESSAGE = "Couldn't download artifact"; + private final DistributionClientImpl distributionClient; + + /** + * Constructor of ArtifactsCollectorStatusSender + * @param distributionClient DistributionClientImpl object + */ + public ArtifactsCollectorStatusSender(DistributionClientImpl distributionClient) { + this.distributionClient = distributionClient; + } + + /** + * Sends DOWNLOAD_OK status to SDC + * @param distributionId Service distribution ID + * @param downloadedArtifacts Artifacts which are successfully downloaded + * @return List of IDistributionClientResult, results of sending status + */ + public List<IDistributionClientResult> sendDownloadOk(String distributionId, List<IArtifactInfo> downloadedArtifacts) { + return downloadedArtifacts.stream() + .map(artifact -> { + DistributionStatusMessage distributionMessage = getDownloadMessage(distributionId, + artifact.getArtifactURL(), DistributionStatusEnum.DOWNLOAD_OK); + return distributionClient.sendDownloadStatus(distributionMessage); + }) + .collect(Collectors.toList()); + } + + /** + * Sends DOWNLOAD_ERROR status to SDC + * @param distributionId Service distribution ID + * @param downloadedArtifacts Artifacts which could not be downloaded + * @return List of IDistributionClientResult, results of sending status + */ + public List<IDistributionClientResult> sendDownloadError(String distributionId, List<IArtifactInfo> downloadedArtifacts) { + return downloadedArtifacts.stream() + .map(artifact -> { + DistributionStatusMessage distributionMessage = getDownloadMessage(distributionId, + artifact.getArtifactURL(), DistributionStatusEnum.DOWNLOAD_ERROR); + return distributionClient.sendDownloadStatus(distributionMessage, DOWNLOAD_ERROR_MESSAGE); + }) + .collect(Collectors.toList()); + } + + private DistributionStatusMessage getDownloadMessage(String distributionId, String artifactURL, DistributionStatusEnum downloadStatus) { + return new DistributionStatusMessage( + artifactURL, + distributionId, + distributionClient.getConfiguration().getConsumerID(), + LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), + downloadStatus); + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/notification/FinalStatusSender.java b/src/main/java/org/onap/ves/openapi/manager/service/notification/FinalStatusSender.java new file mode 100644 index 0000000..e21ab70 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/notification/FinalStatusSender.java @@ -0,0 +1,85 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service.notification; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.ves.openapi.manager.model.FinalDistributionStatusMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +/** + * FinalStatusSender - sender of FinalDistributionStatusMessage with final status to SDC + */ +@Log4j2 +@Service +public class FinalStatusSender { + + private static final String INVALID_ARTIFACTS_MESSAGE = "At least one VES_EVENT artifact is invalid"; + private final DistributionClientImpl distributionClient; + + /** + * Constructor of FinalStatusSender + * @param distributionClient DistributionClientImpl object + */ + @Autowired + public FinalStatusSender(DistributionClientImpl distributionClient) { + this.distributionClient = distributionClient; + } + + /** + * Sends final message COMPONENT_DONE_OK to SDC + * @param distributionId Service distribution ID + * @return IDistributionClientResult, result of sending status + */ + public IDistributionClientResult sendFinalStatusOk(String distributionId) { + DistributionStatusEnum okStatus = DistributionStatusEnum.COMPONENT_DONE_OK; + FinalDistributionStatusMessage message = getMessage(distributionId, okStatus); + log.info("All VES_EVENT artifacts are valid, sending final status {}", okStatus.name()); + return distributionClient.sendFinalDistrStatus(message); + } + + /** + * Sends final message COMPONENT_DONE_ERROR to SDC + * @param distributionId Service distribution ID + * @return IDistributionClientResult, result of sending status + */ + public IDistributionClientResult sendFinalStatusError(String distributionId) { + DistributionStatusEnum errorStatus = DistributionStatusEnum.COMPONENT_DONE_ERROR; + FinalDistributionStatusMessage message = getMessage(distributionId, errorStatus); + log.info("At least one VES_EVENT artifact is invalid, sending final status {}", errorStatus.name()); + return distributionClient.sendFinalDistrStatus(message, INVALID_ARTIFACTS_MESSAGE); + } + + private FinalDistributionStatusMessage getMessage(String distributionId, DistributionStatusEnum distributionStatus) { + return new FinalDistributionStatusMessage( + distributionId, + LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), + distributionStatus, + distributionClient.getConfiguration().getConsumerID()); + } + +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSender.java b/src/main/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSender.java new file mode 100644 index 0000000..ae11791 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/notification/ValidationStatusSender.java @@ -0,0 +1,89 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service.notification; + +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientImpl; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.model.DistributionStatusMessage; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.stream.Collectors; + +/** + * ValidationStatusSender - sender of DistributionStatusMessage with validation status to SDC + */ +@Log4j2 +public class ValidationStatusSender { + + private final DistributionClientImpl distributionClient; + + /** + * Constructor of ValidationStatusSender + * @param distributionClient DistributionClientImpl object + */ + public ValidationStatusSender(DistributionClientImpl distributionClient) { + this.distributionClient = distributionClient; + } + + /** + * Sends validation result status to SDC + * @param distributionId Service distribution ID + * @param validationResults Validation results + * @return List of IDistributionClientResult, results of sending status + */ + public List<IDistributionClientResult> send(String distributionId, List<ArtifactValidationResult> validationResults) { + return validationResults.stream() + .map(validationResult -> sendValidationResult(distributionId, validationResult)) + .collect(Collectors.toList()); + } + + private IDistributionClientResult sendValidationResult(String distributionId, ArtifactValidationResult validationResult) { + DistributionStatusMessage distributionMessage = getDistributionMessage(distributionId, validationResult); + String artifactName = validationResult.getArtifact().getArtifactName(); + + if (validationResult.isValid()) { + log.warn("Artifact {} is valid", artifactName); + return distributionClient.sendDeploymentStatus(distributionMessage); + } else { + String message = validationResult.getMessage(); + log.warn("Artifact {} is invalid", artifactName); + log.warn("Validation message: {}", message); + return distributionClient.sendDeploymentStatus(distributionMessage, message); + } + } + + private DistributionStatusMessage getDistributionMessage(String distributionId, ArtifactValidationResult validationResult) { + String artifactURL = validationResult.getArtifact().getArtifactURL(); + DistributionStatusEnum status = getErrorStatus(validationResult); + return new DistributionStatusMessage(artifactURL, distributionId, + distributionClient.getConfiguration().getConsumerID(), + LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), status); + } + + private DistributionStatusEnum getErrorStatus(ArtifactValidationResult validationResult) { + return validationResult.isValid() ? DistributionStatusEnum.DEPLOY_OK : DistributionStatusEnum.DEPLOY_ERROR; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializer.java b/src/main/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializer.java new file mode 100644 index 0000000..8ea434e --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/serialization/SchemaMapDeserializer.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service.serialization; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.log4j.Log4j2; +import org.onap.ves.openapi.manager.model.SchemaMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * SchemaMapDeserializer - Deserializer of JSON file contents to SchemaMap objects + */ +@Log4j2 +@Service +public class SchemaMapDeserializer { + + private static final String COULD_NOT_READ_SCHEMA_MAP_MESSAGE = "Couldn't read schema map from path: "; + private final ObjectMapper objectMapper; + + /** + * Constructor of SchemaMapDeserializer + * @param objectMapper ObjectMapper for YAML parsing + */ + @Autowired + public SchemaMapDeserializer(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Deserializes file content to SchemaMap object + * @param schemaMapPath Path to file containing JSON formatted SchemaMap + * @return SchemaMap + */ + public SchemaMap getSchemaMapFromFile(String schemaMapPath) { + SchemaMap schemaMap; + try { + File file = new File(schemaMapPath); + List<SchemaMap.Mapping> mappings = Arrays.asList(objectMapper.readValue(file, SchemaMap.Mapping[].class)); + schemaMap = new SchemaMap(mappings); + } catch (IOException e) { + schemaMap = new SchemaMap(Collections.emptyList()); + log.error(COULD_NOT_READ_SCHEMA_MAP_MESSAGE + schemaMapPath, e); + } + return schemaMap; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializer.java b/src/main/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializer.java new file mode 100644 index 0000000..4bd6761 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/serialization/VesEventsArtifactDeserializer.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service.serialization; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLParser; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +/** + * VesEventsArtifactDeserializer - Deserializer of byte array of MultiDocument YAML to ObjectNodes + */ +@Log4j2 +@Service +public class VesEventsArtifactDeserializer { + + private static final String COULD_NOT_READ_ARTIFACT_CONTENT_MESSAGE = "Couldn't read artifact content"; + private final ObjectMapper objectMapper; + + /** + * Constructor of VesEventsArtifactDeserializer + * @param objectMapper ObjectMapper for YAML parsing + */ + @Autowired + public VesEventsArtifactDeserializer(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Deserializes MultiDocument YAML given as byte array + * @param data MultiDocument YAML as byte array + * @return List of ObjectNodes, each Document is separate ObjectNode + */ + public List<ObjectNode> deserializeMultiDocumentYaml(byte[] data) { + List<ObjectNode> events = Collections.emptyList(); + try { + YAMLParser yamlParser = new YAMLFactory().createParser(data); + events = objectMapper.readValues(yamlParser, ObjectNode.class).readAll(); + } catch (IOException e) { + log.error(COULD_NOT_READ_ARTIFACT_CONTENT_MESSAGE, e); + } + return events; + } +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/validation/ArtifactsValidator.java b/src/main/java/org/onap/ves/openapi/manager/service/validation/ArtifactsValidator.java new file mode 100644 index 0000000..5963c6b --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/validation/ArtifactsValidator.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service.validation; + +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; + +import java.util.List; + +public interface ArtifactsValidator { + /** + * Validates given VES_EVENT type artifacts + * @param artifacts List of artifacts: descriptions and contents + * @return List of ArtifactValidationResult, validation results + */ + List<ArtifactValidationResult> validate(List<Artifact> artifacts); +} diff --git a/src/main/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidator.java b/src/main/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidator.java new file mode 100644 index 0000000..dd97b09 --- /dev/null +++ b/src/main/java/org/onap/ves/openapi/manager/service/validation/SchemaReferenceValidator.java @@ -0,0 +1,158 @@ +/* + * ============LICENSE_START======================================================= + * VES-OPENAPI-MANAGER + * ================================================================================ + * Copyright (C) 2021 Nokia. 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.ves.openapi.manager.service.validation; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.log4j.Log4j2; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.ves.openapi.manager.config.ValidatorProperties; +import org.onap.ves.openapi.manager.model.Artifact; +import org.onap.ves.openapi.manager.model.ArtifactValidationResult; +import org.onap.ves.openapi.manager.model.SchemaMap; +import org.onap.ves.openapi.manager.service.serialization.SchemaMapDeserializer; +import org.onap.ves.openapi.manager.service.serialization.VesEventsArtifactDeserializer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * SchemaReferenceValidator - validator of schemaReference field in VES_EVENTS artifacts + */ +@Log4j2 +@Service +public class SchemaReferenceValidator implements ArtifactsValidator { + + private static final String HASH_KEY = "#"; + private static final String NEW_LINE = "\n"; + static final String STND_DEFINED_DOMAIN = "stndDefined"; + static final String SCHEMA_REFERENCE_ERROR_MESSAGE = "Schema reference is not present in VES schema map."; + + private final VesEventsArtifactDeserializer vesEventsArtifactDeserializer; + private final SchemaMapDeserializer schemaMapDeserializer; + private final ValidatorProperties validatorProperties; + + /** + * Constructor of SchemaReferenceValidator + * @param vesEventsArtifactDeserializer Deserializer of VES_EVENT type artifact + * @param schemaMapDeserializer Deserializer of Schema Map + * @param validatorProperties Properties required by validator + */ + @Autowired + public SchemaReferenceValidator(VesEventsArtifactDeserializer vesEventsArtifactDeserializer, + SchemaMapDeserializer schemaMapDeserializer, + ValidatorProperties validatorProperties) { + this.vesEventsArtifactDeserializer = vesEventsArtifactDeserializer; + this.schemaMapDeserializer = schemaMapDeserializer; + this.validatorProperties = validatorProperties; + } + + /** + * Validates given VES_EVENT type artifacts + * @param artifacts List of artifacts: descriptions and contents + * @return List of ArtifactValidationResult, validation results + */ + @Override + public List<ArtifactValidationResult> validate(List<Artifact> artifacts) { + return artifacts.stream() + .map(this::getArtifactValidationResult) + .collect(Collectors.toList()); + } + + private ArtifactValidationResult getArtifactValidationResult(Artifact artifact) { + List<JsonNode> stndDefinedEvents = getStndDefinedEvents(artifact.getContent()); + List<String> publicUrls = getPublicUrls(); + + Set<String> invalidSchemaReferences = stndDefinedEvents.stream() + .map(event -> getInvalidReferences(event, publicUrls)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + return getValidationResult(artifact.getDescription(), invalidSchemaReferences); + } + + private ArtifactValidationResult getValidationResult(IArtifactInfo artifact, Set<String> invalidReferences) { + boolean isValid = invalidReferences.isEmpty(); + String message = getMessage(invalidReferences); + return new ArtifactValidationResult(artifact, isValid, message, this); + } + + private String getMessage(Set<String> invalidSchemaReferences) { + final String emptyMessage = ""; + return invalidSchemaReferences.isEmpty() ? emptyMessage : generateMessage(invalidSchemaReferences); + } + + private String generateMessage(Set<String> invalidSchemaReferences) { + return SCHEMA_REFERENCE_ERROR_MESSAGE + ":" + NEW_LINE + String.join(NEW_LINE, invalidSchemaReferences); + } + + private List<JsonNode> getStndDefinedEvents(byte[] artifactData) { + List<ObjectNode> events = vesEventsArtifactDeserializer.deserializeMultiDocumentYaml(artifactData); + return events.stream() + .filter(this::isStndDefinedEvent) + .collect(Collectors.toList()); + } + + private boolean isStndDefinedEvent(ObjectNode event) { + String actualDomain = event.at(validatorProperties.getEventDomainPath()).asText(); + return actualDomain.equals(STND_DEFINED_DOMAIN); + } + + private List<String> getPublicUrls() { + String schemaMapPath = validatorProperties.getSchemaMapPath(); + List<SchemaMap.Mapping> mappings = schemaMapDeserializer.getSchemaMapFromFile(schemaMapPath).getMappings(); + return mappings.stream() + .map(SchemaMap.Mapping::getPublicURL) + .collect(Collectors.toList()); + } + + private List<String> getInvalidReferences(JsonNode event, List<String> publicUrls) { + String schemaReferencePath = validatorProperties.getEventSchemaReferencePath(); + JsonNode schemaReference = event.at(schemaReferencePath); + Stream<JsonNode> schemaReferenceStream = Stream.empty(); + + if (schemaReference.isArray()) { + schemaReferenceStream = StreamSupport.stream(schemaReference.spliterator(), false); + } else if (schemaReference.isValueNode()) { + schemaReferenceStream = Stream.of(schemaReference); + } + + return getInvalidSchemaReferences(schemaReferenceStream, publicUrls); + } + + private List<String> getInvalidSchemaReferences(Stream<JsonNode> schemaReferencesStream, List<String> publicUrls) { + return schemaReferencesStream + .map(this::fetchUrlFromSchemaReference) + .filter(reference -> !publicUrls.contains(reference)) + .collect(Collectors.toList()); + } + + private String fetchUrlFromSchemaReference(JsonNode schemaReference) { + final int urlPartIndex = 0; + return schemaReference.asText().split(HASH_KEY)[urlPartIndex]; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..f179544 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,20 @@ +vesopenapimanager: + validation: + schemaMapPath: ${SCHEMA_MAP_PATH:./src/main/resources/schema-map.json} + eventDomainPath: /event/structure/commonEventHeader/structure/domain/value + eventSchemaReferencePath: /event/structure/stndDefinedFields/structure/schemaReference/value + distribution: + asdcAddress: ${ASDC_ADDRESS:sdc-be.onap:30204} + msgBusAddress: message-router.onap + user: dcae + password: Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U + pollingInterval: 20 + pollingTimeout: 20 + consumerGroup: ves-openapi-manager + environmentName: AUTO + consumerID: ves-openapi-manager + activateServerTLSAuth: false + isFilterInEmptyResources: false + isUseHttpsWithDmaap: false + + diff --git a/src/main/resources/schema-map.json b/src/main/resources/schema-map.json new file mode 100644 index 0000000..359014c --- /dev/null +++ b/src/main/resources/schema-map.json @@ -0,0 +1,58 @@ +[ + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/blob/SA88-Rel16/OpenAPI/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/5gcNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/invalid.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerDataFileReportMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerMeasJobCtlMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerThresMonMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/PerfDataStreamingMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/comDefs.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/comDefs.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/coslaNrm.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/coslaNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/faultMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/blob/SA88-Rel16/OpenAPI/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/genericNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/faultMnS_dcae.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/heartbeatNtf.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/faultMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/nrNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/provMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/provMnS.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/sliceNrm.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/sliceNrm.yaml" + }, + { + "publicURL": "https://forge.3gpp.org/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/streamingDataMnS.yaml", + "localURL": "3gpp/rep/sa5/MnS/tree/SA88-Rel16/OpenAPI/streamingDataMnS.yaml" + } +]
\ No newline at end of file |