From 7b1f813441f94261f43ec4f5bb0944ad2570fbdf Mon Sep 17 00:00:00 2001 From: "Blackwell, Ian (ib733q)" Date: Tue, 3 Apr 2018 17:28:44 +0100 Subject: Revisions made to the Model Loader to use Babel Change the Model Loader to use the Babel micro service. Responsibility for transformation of ASDC TOSCA models, the yaml files, has been moved from ASDC and placed into the Bable microservice. Model Loader will forward any CSAR received from ASDC and delegate transformation to Babel. Babel will return the transformed TOSCA models to Model Loader which will then ingest them into the A&AI Inventory. Issue-ID: AAI-987 Change-Id: I99594770b51b00cb7dcc0f30706060ae27cd94c5 Signed-off-by: Blackwell, Ian (ib733q) --- .../model-loader/v1/conf/modelLoaderBeans.groovy | 23 +- .../model-loader/v1/docs/README.txt | 23 +- .../model-loader_v1/model-loader/v1/lib/README.txt | 23 +- .../model-loader/v1/props/module.props | 35 +- .../model-loader/v1/routes/modelLoader.route | 22 +- src/main/assemble/ajsc_module_assembly.xml | 21 +- src/main/assemble/ajsc_props_assembly.xml | 21 +- src/main/assemble/ajsc_runtime_assembly.xml | 21 +- src/main/bin/start.sh | 24 +- src/main/config/ajsc-jetty.xml | 21 +- src/main/config/ajsc-override-web.xml | 25 +- src/main/config/jul-redirect.properties | 35 +- src/main/config/runner-web.xml | 24 +- .../aai/modelloader/config/ModelLoaderConfig.java | 184 +- .../org/onap/aai/modelloader/entity/Artifact.java | 30 +- .../aai/modelloader/entity/ArtifactHandler.java | 14 +- .../onap/aai/modelloader/entity/ArtifactType.java | 8 +- .../entity/catalog/VnfCatalogArtifact.java | 9 +- .../entity/catalog/VnfCatalogArtifactHandler.java | 262 +-- .../entity/catalog/VnfImageException.java | 58 + .../entity/model/AbstractModelArtifact.java | 104 +- .../entity/model/AbstractModelArtifactParser.java | 293 +++ .../model/BabelArtifactParsingException.java | 49 + .../modelloader/entity/model/IModelArtifact.java | 51 + .../aai/modelloader/entity/model/IModelId.java | 51 + .../aai/modelloader/entity/model/IModelParser.java | 3 +- .../modelloader/entity/model/ModelArtifact.java | 339 +-- .../entity/model/ModelArtifactHandler.java | 74 +- .../entity/model/ModelArtifactParser.java | 331 +-- .../entity/model/ModelParserFactory.java | 85 - .../aai/modelloader/entity/model/ModelSorter.java | 361 +-- .../modelloader/entity/model/ModelV8Artifact.java | 120 - .../entity/model/ModelV8ArtifactParser.java | 133 -- .../entity/model/NamedQueryArtifact.java | 135 +- .../entity/model/NamedQueryArtifactParser.java | 152 +- .../onap/aai/modelloader/entity/model/Pair.java | 54 + .../extraction/ArtifactInfoExtractor.java | 62 + .../extraction/InvalidArchiveException.java | 48 + .../notification/ArtifactDeploymentManager.java | 123 + .../notification/ArtifactDownloadManager.java | 250 ++ .../notification/BabelArtifactConverter.java | 83 + .../notification/CompDoneStatusMessageBuilder.java | 47 + .../notification/CompDoneStatusMsg.java | 69 + .../DistributionStatusMessageBuilder.java | 66 + .../notification/DistributionStatusMsg.java | 84 +- .../notification/DownloadFailureException.java | 38 + .../modelloader/notification/EventCallback.java | 287 +-- .../notification/NotificationPublisher.java | 228 ++ .../ProcessToscaArtifactsException.java | 35 + .../aai/modelloader/restclient/AaiRestClient.java | 573 ++--- .../modelloader/restclient/BabelServiceClient.java | 184 ++ .../aai/modelloader/service/ArtifactInfoImpl.java | 134 ++ .../modelloader/service/ModelLoaderInterface.java | 28 +- .../aai/modelloader/service/ModelLoaderMsgs.java | 170 +- .../modelloader/service/ModelLoaderService.java | 360 +-- .../modelloader/service/NotificationDataImpl.java | 117 + .../aai/modelloader/service/SdcConnectionJob.java | 72 +- .../aai/modelloader/util/JsonXmlConverter.java | 85 +- .../modelloader/service/ModelLoaderMsgs.properties | 84 +- src/main/resources/schema/aai_schema_v8.xsd | 2462 -------------------- src/main/resources/schema/vnfcatalog.xsd | 127 - 61 files changed, 3919 insertions(+), 5115 deletions(-) create mode 100644 src/main/java/org/onap/aai/modelloader/entity/catalog/VnfImageException.java create mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifactParser.java create mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/BabelArtifactParsingException.java create mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/IModelArtifact.java create mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/IModelId.java delete mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/ModelParserFactory.java delete mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/ModelV8Artifact.java delete mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/ModelV8ArtifactParser.java create mode 100644 src/main/java/org/onap/aai/modelloader/entity/model/Pair.java create mode 100644 src/main/java/org/onap/aai/modelloader/extraction/ArtifactInfoExtractor.java create mode 100644 src/main/java/org/onap/aai/modelloader/extraction/InvalidArchiveException.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManager.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/BabelArtifactConverter.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMessageBuilder.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMsg.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMessageBuilder.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/DownloadFailureException.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/NotificationPublisher.java create mode 100644 src/main/java/org/onap/aai/modelloader/notification/ProcessToscaArtifactsException.java create mode 100644 src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClient.java create mode 100644 src/main/java/org/onap/aai/modelloader/service/ArtifactInfoImpl.java create mode 100644 src/main/java/org/onap/aai/modelloader/service/NotificationDataImpl.java delete mode 100644 src/main/resources/schema/aai_schema_v8.xsd delete mode 100644 src/main/resources/schema/vnfcatalog.xsd (limited to 'src/main') diff --git a/src/main/ajsc/model-loader_v1/model-loader/v1/conf/modelLoaderBeans.groovy b/src/main/ajsc/model-loader_v1/model-loader/v1/conf/modelLoaderBeans.groovy index 32379f7..2fadedd 100644 --- a/src/main/ajsc/model-loader_v1/model-loader/v1/conf/modelLoaderBeans.groovy +++ b/src/main/ajsc/model-loader_v1/model-loader/v1/conf/modelLoaderBeans.groovy @@ -1,21 +1,22 @@ -/*- - * ============LICENSE_START======================================================= - * MODEL LOADER SERVICE - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= + * limitations under the License. + * ============LICENSE_END============================================ */ beans{ diff --git a/src/main/ajsc/model-loader_v1/model-loader/v1/docs/README.txt b/src/main/ajsc/model-loader_v1/model-loader/v1/docs/README.txt index 508361d..b642878 100644 --- a/src/main/ajsc/model-loader_v1/model-loader/v1/docs/README.txt +++ b/src/main/ajsc/model-loader_v1/model-loader/v1/docs/README.txt @@ -1,21 +1,22 @@ -/*- - * ============LICENSE_START======================================================= - * MODEL LOADER SERVICE - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= + * limitations under the License. + * ============LICENSE_END============================================ */ Place any docs here that you want to access within the ajsc upon deployment of your service. diff --git a/src/main/ajsc/model-loader_v1/model-loader/v1/lib/README.txt b/src/main/ajsc/model-loader_v1/model-loader/v1/lib/README.txt index f80be9b..002a511 100644 --- a/src/main/ajsc/model-loader_v1/model-loader/v1/lib/README.txt +++ b/src/main/ajsc/model-loader_v1/model-loader/v1/lib/README.txt @@ -1,21 +1,22 @@ -/*- - * ============LICENSE_START======================================================= - * MODEL LOADER SERVICE - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= + * limitations under the License. + * ============LICENSE_END============================================ */ 3rd party JAR's needed by your jars (if any) for a ajsc deployment package go here... diff --git a/src/main/ajsc/model-loader_v1/model-loader/v1/props/module.props b/src/main/ajsc/model-loader_v1/model-loader/v1/props/module.props index aab4afa..acee82b 100644 --- a/src/main/ajsc/model-loader_v1/model-loader/v1/props/module.props +++ b/src/main/ajsc/model-loader_v1/model-loader/v1/props/module.props @@ -1,21 +1,22 @@ ### -# ============LICENSE_START======================================================= -# MODEL LOADER SERVICE -# ================================================================================ -# 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========================================================= +# ============LICENSE_START========================================== +# org.onap.aai +# =================================================================== +# Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. +# Copyright © 2017-2018 Amdocs +# =================================================================== +# 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============================================ ### EXAMPLE.PROPERTY=EXAMLE_VALUE diff --git a/src/main/ajsc/model-loader_v1/model-loader/v1/routes/modelLoader.route b/src/main/ajsc/model-loader_v1/model-loader/v1/routes/modelLoader.route index 170c466..0d9f5eb 100644 --- a/src/main/ajsc/model-loader_v1/model-loader/v1/routes/modelLoader.route +++ b/src/main/ajsc/model-loader_v1/model-loader/v1/routes/modelLoader.route @@ -1,23 +1,25 @@ + diff --git a/src/main/assemble/ajsc_module_assembly.xml b/src/main/assemble/ajsc_module_assembly.xml index 520870f..3237439 100644 --- a/src/main/assemble/ajsc_module_assembly.xml +++ b/src/main/assemble/ajsc_module_assembly.xml @@ -1,21 +1,22 @@ @@ -35,7 +36,7 @@ false - /extJars/httpclient-4.5.jar,/extJars/httpcore-4.4.1.jar,/extJars/json-20131018.jar + /extJars/httpclient-4.5.jar,/extJars/httpcore-4.4.1.jar,/extJars/json-20131018.jar diff --git a/src/main/config/ajsc-override-web.xml b/src/main/config/ajsc-override-web.xml index b0d44f3..f5d7863 100644 --- a/src/main/config/ajsc-override-web.xml +++ b/src/main/config/ajsc-override-web.xml @@ -1,28 +1,25 @@ - - diff --git a/src/main/config/jul-redirect.properties b/src/main/config/jul-redirect.properties index b94397e..d7406e3 100644 --- a/src/main/config/jul-redirect.properties +++ b/src/main/config/jul-redirect.properties @@ -1,21 +1,22 @@ ### -# ============LICENSE_START======================================================= -# MODEL LOADER SERVICE -# ================================================================================ -# 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========================================================= +# ============LICENSE_START========================================== +# org.onap.aai +# =================================================================== +# Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. +# Copyright © 2017-2018 Amdocs +# =================================================================== +# 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============================================ ### # Bridge JUL->slf4j Logging Configuration File diff --git a/src/main/config/runner-web.xml b/src/main/config/runner-web.xml index 99d9191..198e2e9 100644 --- a/src/main/config/runner-web.xml +++ b/src/main/config/runner-web.xml @@ -1,27 +1,25 @@ - diff --git a/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java b/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java index 58e2bad..692f412 100644 --- a/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java +++ b/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java @@ -20,58 +20,66 @@ */ package org.onap.aai.modelloader.config; -import org.eclipse.jetty.util.security.Password; -import org.openecomp.sdc.api.consumer.IConfiguration; - +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import org.eclipse.jetty.util.security.Password; +import org.openecomp.sdc.api.consumer.IConfiguration; +/** + * Properties for the Model Loader + * + */ public class ModelLoaderConfig implements IConfiguration { - + // Configuration file structure public static final String PREFIX_MODEL_LOADER_CONFIG = "ml"; - public static final String PREFIX_DISTRIBUTION_CLIENT = - PREFIX_MODEL_LOADER_CONFIG + ".distribution."; + public static final String PREFIX_DISTRIBUTION_CLIENT = PREFIX_MODEL_LOADER_CONFIG + ".distribution."; public static final String PREFIX_AAI = PREFIX_MODEL_LOADER_CONFIG + ".aai."; + public static final String PREFIX_BABEL = PREFIX_MODEL_LOADER_CONFIG + ".babel."; public static final String PREFIX_DEBUG = PREFIX_MODEL_LOADER_CONFIG + ".debug."; + private static final String SUFFIX_KEYSTORE_FILE = "KEYSTORE_FILE"; + private static final String SUFFIX_KEYSTORE_PASS = "KEYSTORE_PASSWORD"; + // Configuration file properties - protected static final String PROP_ML_DISTRIBUTION_ACTIVE_SERVER_TLS_AUTH = + protected static final String PROP_ML_DISTRIBUTION_ACTIVE_SERVER_TLS_AUTH = PREFIX_DISTRIBUTION_CLIENT + "ACTIVE_SERVER_TLS_AUTH"; - protected static final String PROP_ML_DISTRIBUTION_ASDC_ADDRESS = PREFIX_DISTRIBUTION_CLIENT - + "ASDC_ADDRESS"; - protected static final String PROP_ML_DISTRIBUTION_CONSUMER_GROUP = PREFIX_DISTRIBUTION_CLIENT - + "CONSUMER_GROUP"; - protected static final String PROP_ML_DISTRIBUTION_CONSUMER_ID = PREFIX_DISTRIBUTION_CLIENT - + "CONSUMER_ID"; - protected static final String PROP_ML_DISTRIBUTION_ENVIRONMENT_NAME = PREFIX_DISTRIBUTION_CLIENT - + "ENVIRONMENT_NAME"; - protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_PASSWORD = PREFIX_DISTRIBUTION_CLIENT - + "KEYSTORE_PASSWORD"; - protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_FILE = PREFIX_DISTRIBUTION_CLIENT - + "KEYSTORE_FILE"; - protected static final String PROP_ML_DISTRIBUTION_PASSWORD = PREFIX_DISTRIBUTION_CLIENT - + "PASSWORD"; - protected static final String PROP_ML_DISTRIBUTION_POLLING_INTERVAL = PREFIX_DISTRIBUTION_CLIENT - + "POLLING_INTERVAL"; - protected static final String PROP_ML_DISTRIBUTION_POLLING_TIMEOUT = PREFIX_DISTRIBUTION_CLIENT - + "POLLING_TIMEOUT"; + protected static final String PROP_ML_DISTRIBUTION_ASDC_CONNECTION_DISABLED = PREFIX_DISTRIBUTION_CLIENT + "ASDC_CONNECTION_DISABLE"; + protected static final String PROP_ML_DISTRIBUTION_ASDC_ADDRESS = PREFIX_DISTRIBUTION_CLIENT + "ASDC_ADDRESS"; + protected static final String PROP_ML_DISTRIBUTION_CONSUMER_GROUP = PREFIX_DISTRIBUTION_CLIENT + "CONSUMER_GROUP"; + protected static final String PROP_ML_DISTRIBUTION_CONSUMER_ID = PREFIX_DISTRIBUTION_CLIENT + "CONSUMER_ID"; + protected static final String PROP_ML_DISTRIBUTION_ENVIRONMENT_NAME = + PREFIX_DISTRIBUTION_CLIENT + "ENVIRONMENT_NAME"; + protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_PASSWORD = + PREFIX_DISTRIBUTION_CLIENT + SUFFIX_KEYSTORE_PASS; + protected static final String PROP_ML_DISTRIBUTION_KEYSTORE_FILE = + PREFIX_DISTRIBUTION_CLIENT + SUFFIX_KEYSTORE_FILE; + protected static final String PROP_ML_DISTRIBUTION_PASSWORD = PREFIX_DISTRIBUTION_CLIENT + "PASSWORD"; + protected static final String PROP_ML_DISTRIBUTION_POLLING_INTERVAL = + PREFIX_DISTRIBUTION_CLIENT + "POLLING_INTERVAL"; + protected static final String PROP_ML_DISTRIBUTION_POLLING_TIMEOUT = PREFIX_DISTRIBUTION_CLIENT + "POLLING_TIMEOUT"; protected static final String PROP_ML_DISTRIBUTION_USER = PREFIX_DISTRIBUTION_CLIENT + "USER"; - protected static final String PROP_ML_DISTRIBUTION_ARTIFACT_TYPES = PREFIX_DISTRIBUTION_CLIENT - + "ARTIFACT_TYPES"; + protected static final String PROP_ML_DISTRIBUTION_ARTIFACT_TYPES = PREFIX_DISTRIBUTION_CLIENT + "ARTIFACT_TYPES"; + protected static final String PROP_ML_DISTRIBUTION_MSG_BUS_ADDRESSES = PREFIX_DISTRIBUTION_CLIENT + "MSG_BUS_ADDRESSES"; protected static final String PROP_ML_DISTRIBUTION_HTTPS_WITH_DMAAP = - PREFIX_DISTRIBUTION_CLIENT + "USE_HTTPS_WITH_DMAAP"; + PREFIX_DISTRIBUTION_CLIENT + "USE_HTTPS_WITH_DMAAP"; protected static final String PROP_AAI_BASE_URL = PREFIX_AAI + "BASE_URL"; - protected static final String PROP_AAI_KEYSTORE_FILE = PREFIX_AAI + "KEYSTORE_FILE"; - protected static final String PROP_AAI_KEYSTORE_PASSWORD = PREFIX_AAI + "KEYSTORE_PASSWORD"; + protected static final String PROP_AAI_KEYSTORE_FILE = PREFIX_AAI + SUFFIX_KEYSTORE_FILE; + protected static final String PROP_AAI_KEYSTORE_PASSWORD = PREFIX_AAI + SUFFIX_KEYSTORE_PASS; protected static final String PROP_AAI_MODEL_RESOURCE_URL = PREFIX_AAI + "MODEL_URL"; protected static final String PROP_AAI_NAMED_QUERY_RESOURCE_URL = PREFIX_AAI + "NAMED_QUERY_URL"; protected static final String PROP_AAI_VNF_IMAGE_RESOURCE_URL = PREFIX_AAI + "VNF_IMAGE_URL"; protected static final String PROP_AAI_AUTHENTICATION_USER = PREFIX_AAI + "AUTH_USER"; protected static final String PROP_AAI_AUTHENTICATION_PASSWORD = PREFIX_AAI + "AUTH_PASSWORD"; + protected static final String PROP_BABEL_BASE_URL = PREFIX_BABEL + "BASE_URL"; + protected static final String PROP_BABEL_KEYSTORE_FILE = PREFIX_BABEL + SUFFIX_KEYSTORE_FILE; + protected static final String PROP_BABEL_KEYSTORE_PASSWORD = PREFIX_BABEL + SUFFIX_KEYSTORE_PASS; + protected static final String PROP_BABEL_GENERATE_RESOURCE_URL = PREFIX_BABEL + "GENERATE_ARTIFACTS_URL"; + protected static final String PROP_DEBUG_INGEST_SIMULATOR = PREFIX_DEBUG + "INGEST_SIMULATOR"; private Properties modelLoaderProperties = null; @@ -80,6 +88,11 @@ public class ModelLoaderConfig implements IConfiguration { private List artifactTypes = null; + private List msgBusAddrs = null; + + private String modelVersion = null; + + /** * This is the class constructor. * @@ -91,14 +104,22 @@ public class ModelLoaderConfig implements IConfiguration { this.certLocation = certLocation; // Get list of artifacts - artifactTypes = new ArrayList(); + artifactTypes = new ArrayList<>(); if (modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_ARTIFACT_TYPES) != null) { - String[] artTypeList = modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_ARTIFACT_TYPES) - .split(","); + String[] artTypeList = modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_ARTIFACT_TYPES).split(","); for (String artType : artTypeList) { artifactTypes.add(artType); } } + + // Get list of message bus addresses + msgBusAddrs = new ArrayList<>(); + if (modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_MSG_BUS_ADDRESSES) != null) { + String[] msgBusList = modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_MSG_BUS_ADDRESSES).split(","); + for (String addr : msgBusList) { + msgBusAddrs.add(addr); + } + } } @Override @@ -129,8 +150,7 @@ public class ModelLoaderConfig implements IConfiguration { @Override public String getKeyStorePassword() { - return Password - .deobfuscate(modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_KEYSTORE_PASSWORD)); + return Password.deobfuscate(modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_KEYSTORE_PASSWORD)); } @Override @@ -145,14 +165,12 @@ public class ModelLoaderConfig implements IConfiguration { @Override public int getPollingInterval() { - return Integer - .parseInt(modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_POLLING_INTERVAL)); + return Integer.parseInt(modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_POLLING_INTERVAL)); } @Override public int getPollingTimeout() { - return Integer - .parseInt(modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_POLLING_TIMEOUT)); + return Integer.parseInt(modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_POLLING_TIMEOUT)); } @Override @@ -167,53 +185,81 @@ public class ModelLoaderConfig implements IConfiguration { @Override public boolean isFilterInEmptyResources() { - return false; + return false; } @Override public Boolean isUseHttpsWithDmaap() { - String useHTTPS = modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_HTTPS_WITH_DMAAP); - return useHTTPS == null ? false : Boolean.valueOf(useHTTPS); + String useHTTPS = modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_HTTPS_WITH_DMAAP); + return useHTTPS == null ? false : Boolean.valueOf(useHTTPS); } - + + @Override + public List getMsgBusAddress() { + return msgBusAddrs; + } + public String getAaiKeyStorePath() { - return certLocation + "/" + modelLoaderProperties.getProperty(PROP_AAI_KEYSTORE_FILE); + return certLocation + File.separator + modelLoaderProperties.getProperty(PROP_AAI_KEYSTORE_FILE); + } + + public String getBabelKeyStorePath() { + return certLocation + File.separator + modelLoaderProperties.getProperty(PROP_BABEL_KEYSTORE_FILE); } public String getAaiKeyStorePassword() { return Password.deobfuscate(modelLoaderProperties.getProperty(PROP_AAI_KEYSTORE_PASSWORD)); } + public String getBabelKeyStorePassword() { + return Password.deobfuscate(modelLoaderProperties.getProperty(PROP_BABEL_KEYSTORE_PASSWORD)); + } + public String getAaiBaseUrl() { return modelLoaderProperties.getProperty(PROP_AAI_BASE_URL); } + public String getBabelBaseUrl() { + return modelLoaderProperties.getProperty(PROP_BABEL_BASE_URL); + } + + public String getBabelGenerateArtifactsUrl() { + return modelLoaderProperties.getProperty(PROP_BABEL_GENERATE_RESOURCE_URL); + } + public String getAaiModelUrl(String version) { - return modelLoaderProperties.getProperty(PROP_AAI_MODEL_RESOURCE_URL).replace("v*", version); + setModelVersion(version); + return updatePropertyOXMVersion(modelLoaderProperties, PROP_AAI_MODEL_RESOURCE_URL, version); } public String getAaiNamedQueryUrl(String version) { - return modelLoaderProperties.getProperty(PROP_AAI_NAMED_QUERY_RESOURCE_URL).replace("v*", version); + return updatePropertyOXMVersion(modelLoaderProperties, PROP_AAI_NAMED_QUERY_RESOURCE_URL, version); } public String getAaiVnfImageUrl() { - return modelLoaderProperties.getProperty(PROP_AAI_VNF_IMAGE_RESOURCE_URL); + return updatePropertyOXMVersion(modelLoaderProperties, PROP_AAI_VNF_IMAGE_RESOURCE_URL, getModelVersion()); } public String getAaiAuthenticationUser() { return modelLoaderProperties.getProperty(PROP_AAI_AUTHENTICATION_USER); } + public String getModelVersion() { + return modelVersion; + } + + public void setModelVersion(String modelVersion) { + this.modelVersion = modelVersion; + } + /** - * @return password for AAI authentication that has been reverse-engineered - * from its obfuscated form. + * @return password for AAI authentication that has been reverse-engineered from its obfuscated form. */ public String getAaiAuthenticationPassword() { - String password = Password - .deobfuscate(modelLoaderProperties.getProperty(PROP_AAI_AUTHENTICATION_PASSWORD)); + String password = Password.deobfuscate(modelLoaderProperties.getProperty(PROP_AAI_AUTHENTICATION_PASSWORD)); - if ((password != null) && (password.equals(""))) { - return null; + if (password != null && password.isEmpty()) { + password = null; } return password; @@ -224,16 +270,30 @@ public class ModelLoaderConfig implements IConfiguration { */ public boolean getIngestSimulatorEnabled() { String propValue = modelLoaderProperties.getProperty(PROP_DEBUG_INGEST_SIMULATOR); + return propValue != null && "enabled".equalsIgnoreCase(propValue); + } - if (propValue == null) { - return false; - } - - if (propValue.compareToIgnoreCase("enabled") == 0) { - return true; - } - - return false; + /** + * @return a String value of the defined property with the oxm version + */ + private String updatePropertyOXMVersion(Properties modelLoaderProperties, String propertyName, String version) { + if (version != null) + return modelLoaderProperties.getProperty(propertyName).replace("v*", version); + else + return modelLoaderProperties.getProperty(propertyName); } + + + + /** + * @return a boolean value indicating whether model loader is connected to ASDC. + */ + public boolean getASDCConnectionDisabled(){ + String propValue = modelLoaderProperties.getProperty(PROP_ML_DISTRIBUTION_ASDC_CONNECTION_DISABLED); + return propValue != null && "true".equalsIgnoreCase(propValue); + + } + + } diff --git a/src/main/java/org/onap/aai/modelloader/entity/Artifact.java b/src/main/java/org/onap/aai/modelloader/entity/Artifact.java index 32a13b7..4c0e0f1 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/Artifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/Artifact.java @@ -22,23 +22,23 @@ package org.onap.aai.modelloader.entity; public abstract class Artifact { - private String payload; - private ArtifactType type; + private String payload; + private ArtifactType type; - public Artifact(ArtifactType type) { - this.type = type; - } - - public ArtifactType getType() { - return type; - } + public Artifact(ArtifactType type) { + this.type = type; + } - public String getPayload() { - return payload; - } + public ArtifactType getType() { + return type; + } - public void setPayload(String payload) { - this.payload = payload; - } + public String getPayload() { + return payload; + } + + public void setPayload(String payload) { + this.payload = payload; + } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/ArtifactHandler.java b/src/main/java/org/onap/aai/modelloader/entity/ArtifactHandler.java index 44335b8..9e80e05 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/ArtifactHandler.java +++ b/src/main/java/org/onap/aai/modelloader/entity/ArtifactHandler.java @@ -23,15 +23,19 @@ package org.onap.aai.modelloader.entity; import java.util.List; import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.restclient.AaiRestClient; public abstract class ArtifactHandler { - protected ModelLoaderConfig config; + protected ModelLoaderConfig config; - public ArtifactHandler(ModelLoaderConfig config) { - this.config = config; - } + public ArtifactHandler(ModelLoaderConfig config) { + this.config = config; + } - public abstract boolean pushArtifacts(List artifacts, String distributionId); + public abstract boolean pushArtifacts(List artifacts, String distributionId, List completedArtifacts, + AaiRestClient restClient); + public abstract void rollback(List completedArtifacts, String distributionId, + AaiRestClient aaiClient); } diff --git a/src/main/java/org/onap/aai/modelloader/entity/ArtifactType.java b/src/main/java/org/onap/aai/modelloader/entity/ArtifactType.java index 1a71004..6959936 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/ArtifactType.java +++ b/src/main/java/org/onap/aai/modelloader/entity/ArtifactType.java @@ -21,8 +21,8 @@ package org.onap.aai.modelloader.entity; public enum ArtifactType { - MODEL, - MODEL_V8, - NAMED_QUERY, - VNF_CATALOG; + MODEL, + MODEL_V8, + NAMED_QUERY, + VNF_CATALOG; } diff --git a/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifact.java index c5b6447..3219625 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifact.java @@ -24,8 +24,9 @@ import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.entity.ArtifactType; public class VnfCatalogArtifact extends Artifact { - public VnfCatalogArtifact(String payload) { - super(ArtifactType.VNF_CATALOG); - setPayload(payload); - } + + public VnfCatalogArtifact(String payload) { + super(ArtifactType.VNF_CATALOG); + setPayload(payload); + } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler.java b/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler.java index 9022516..b224407 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler.java +++ b/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfCatalogArtifactHandler.java @@ -20,171 +20,159 @@ */ package org.onap.aai.modelloader.entity.catalog; -import com.sun.jersey.api.client.ClientResponse; - -import generated.VnfCatalog; -import generated.VnfCatalog.PartNumberList; - -import inventory.aai.openecomp.org.v8.VnfImage; - -import org.eclipse.persistence.jaxb.MarshallerProperties; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.apache.commons.text.StringEscapeUtils; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; import org.onap.aai.modelloader.config.ModelLoaderConfig; import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.entity.ArtifactHandler; import org.onap.aai.modelloader.restclient.AaiRestClient; -import org.onap.aai.modelloader.restclient.AaiRestClient.MimeType; import org.onap.aai.modelloader.service.ModelLoaderMsgs; -import org.onap.aai.cl.api.Logger; -import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.restclient.client.OperationResult; import org.springframework.web.util.UriUtils; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; - - +/** + * VNF Catalog specific handling + */ public class VnfCatalogArtifactHandler extends ArtifactHandler { - private static Logger logger = LoggerFactory.getInstance() - .getLogger(VnfCatalogArtifactHandler.class.getName()); - - public VnfCatalogArtifactHandler(ModelLoaderConfig config) { - super(config); - } + private static Logger logger = LoggerFactory.getInstance().getLogger(VnfCatalogArtifactHandler.class.getName()); - @Override - public boolean pushArtifacts(List artifacts, String distributionId) { - for (Artifact art : artifacts) { - VnfCatalogArtifact vnfCatalog = (VnfCatalogArtifact) art; - String artifactPayload = vnfCatalog.getPayload(); + public static final String ATTR_UUID = "uuid"; - AaiRestClient restClient = new AaiRestClient(this.config); - List putImages = new ArrayList(); - - try { - JAXBContext inputContext = JAXBContext.newInstance(VnfCatalog.class); - Unmarshaller unmarshaller = inputContext.createUnmarshaller(); - StringReader reader = new StringReader(artifactPayload); - VnfCatalog cat = (VnfCatalog) unmarshaller.unmarshal(reader); + public VnfCatalogArtifactHandler(ModelLoaderConfig config) { + super(config); + } - int numParts = cat.getPartNumberList().size(); + /* + * (non-Javadoc) + * + * @see org.openecomp.modelloader.entity.ArtifactHandler#pushArtifacts(java.util.List, java.lang.String) + */ + @Override + public boolean pushArtifacts(List artifacts, String distributionId, List completedArtifacts, + AaiRestClient aaiClient) { + for (Artifact artifact : artifacts) { + try { + distributeVnfcData(aaiClient, distributionId, artifact, completedArtifacts); + } catch (VnfImageException e) { + if (e.getResultCode().isPresent()) { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, + "Ingestion failed on vnf-image " + e.getImageId() + " with status " + + e.getResultCode().orElse(0) + ". Rolling back distribution."); + } else { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, + "Ingestion failed on " + e.getImageId() + ". Rolling back distribution."); + } + return false; + } + } - for (int i = 0; i < numParts; i++) { + return true; + } - PartNumberList pnl = cat.getPartNumberList().get(i); + private void distributeVnfcData(AaiRestClient restClient, String distributionId, Artifact vnfcArtifact, + List completedArtifacts) throws VnfImageException { - String application = pnl.getVendorInfo().getVendorModel(); - String applicationVendor = pnl.getVendorInfo().getVendorName(); + List> vnfcData = unmarshallVnfcData(vnfcArtifact); - int numVersions = pnl.getSoftwareVersionList().size(); + for (Map dataItem : vnfcData) { + // If an empty dataItem is supplied, do nothing. + if (dataItem.isEmpty()) { + logger.warn(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Empty image data supplied, skipping ingestion."); + return; + } - for (int j = 0; j < numVersions; j++) { - String applicationVersion = pnl.getSoftwareVersionList().get(j).getSoftwareVersion(); + String urlParams; + StringBuilder imageId = new StringBuilder("vnf image"); - String imageId = "vnf image " + applicationVendor + " " + application + " " - + applicationVersion; + try { + urlParams = buildUrlImgIdStrings(imageId, dataItem); + } catch (UnsupportedEncodingException e) { + throw new VnfImageException(e); + } - String queryURI = "application-vendor=" + applicationVendor + "&application=" + application + "&application-version=" + applicationVersion; - - String getUrl = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "?" + UriUtils.encodePath(queryURI, "UTF-8"); + OperationResult tryGet = + restClient.getResource(config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "?" + urlParams, + distributionId, MediaType.APPLICATION_JSON_TYPE); - ClientResponse tryGet = restClient.getResource(getUrl, distributionId, MimeType.JSON); if (tryGet == null) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Ingestion failed on " + imageId + ". Rolling back distribution."); - failureCleanup(putImages, restClient, distributionId); - return false; + throw new VnfImageException(imageId.toString()); } - if (tryGet.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) { - // this vnf-image not already in the db, need to add - // only do this on 404 bc other error responses could mean there - // are problems that - // you might not want to try to PUT against - - VnfImage image = new VnfImage(); - image.setApplication(application); - image.setApplicationVendor(applicationVendor); - image.setApplicationVersion(applicationVersion); - String uuid = UUID.randomUUID().toString(); - image.setUuid(uuid); // need to create uuid - - System.setProperty("javax.xml.bind.context.factory", - "org.eclipse.persistence.jaxb.JAXBContextFactory"); - JAXBContext jaxbContext = JAXBContext.newInstance(VnfImage.class); - Marshaller marshaller = jaxbContext.createMarshaller(); - marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json"); - marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false); - marshaller.setProperty(MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); - marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false); - StringWriter writer = new StringWriter(); - marshaller.marshal(image, writer); - String payload = writer.toString(); - - String putUrl = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "/vnf-image/" - + uuid; - - ClientResponse putResp = restClient.putResource(putUrl, payload, distributionId, - MimeType.JSON); - if (putResp == null - || putResp.getStatus() != Response.Status.CREATED.getStatusCode()) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Ingestion failed on vnf-image " + imageId + ". Rolling back distribution."); - failureCleanup(putImages, restClient, distributionId); - return false; - } - putImages.add(image); - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, imageId + " successfully ingested."); - } else if (tryGet.getStatus() == Response.Status.OK.getStatusCode()) { - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, - imageId + " already exists. Skipping ingestion."); + + int resultCode = tryGet.getResultCode(); + if (resultCode == Response.Status.NOT_FOUND.getStatusCode()) { + // This vnf-image is missing, so add it + boolean success = putVnfImage(restClient, dataItem, distributionId); + if (!success) { + throw new VnfImageException(imageId.toString()); + } + completedArtifacts.add(vnfcArtifact); + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, imageId + " successfully ingested."); + } else if (resultCode == Response.Status.OK.getStatusCode()) { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, imageId + " already exists. Skipping ingestion."); } else { - // if other than 404 or 200, something went wrong - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Ingestion failed on vnf-image " + imageId + " with status " + tryGet.getStatus() - + ". Rolling back distribution."); - failureCleanup(putImages, restClient, distributionId); - return false; + // if other than 404 or 200, something went wrong + throw new VnfImageException(imageId.toString(), resultCode); } - } } + } - } catch (JAXBException e) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Ingestion failed. " + e.getMessage() + ". Rolling back distribution."); - failureCleanup(putImages, restClient, distributionId); - return false; - } catch (UnsupportedEncodingException e) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed. " + e.getMessage() + ". Rolling back distribution."); - failureCleanup(putImages, restClient, distributionId); - return false; - } + private String buildUrlImgIdStrings(StringBuilder imageId, Map dataItem) + throws UnsupportedEncodingException { + StringBuilder urlParams = new StringBuilder(); + for (Entry entry : dataItem.entrySet()) { + urlParams.append(entry.getKey()).append("=").append(UriUtils.encode(entry.getValue(), "UTF-8")).append("&"); + imageId.append(" ").append(entry.getValue()); + } + return urlParams.deleteCharAt(urlParams.length() - 1).toString(); + } + + private boolean putVnfImage(AaiRestClient restClient, Map dataItem, String distributionId) { + // Generate a new UUID for the image data item + String uuid = UUID.randomUUID().toString(); + dataItem.put(ATTR_UUID, uuid); + + String payload = createVnfImagePayload(dataItem); + String putUrl = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "/vnf-image/" + uuid; + OperationResult putResp = + restClient.putResource(putUrl, payload, distributionId, MediaType.APPLICATION_JSON_TYPE); + return putResp != null && putResp.getResultCode() == Response.Status.CREATED.getStatusCode(); + } + + private String createVnfImagePayload(Map dataItem) { + dataItem.put(ATTR_UUID, UUID.randomUUID().toString()); + return new Gson().toJson(dataItem); + } + + private List> unmarshallVnfcData(Artifact vnfcArtifact) { + // Unmarshall Babel JSON payload into a List of Maps of JSON attribute name/values. + return new Gson().fromJson(StringEscapeUtils.unescapeJson(vnfcArtifact.getPayload()), + new TypeToken>>() {}.getType()); } - return true; - } - - /* - * if something fails in the middle of ingesting the catalog we want to - * rollback any changes to the db - */ - private void failureCleanup(List putImages, AaiRestClient restClient, String transId) { - for (VnfImage image : putImages) { - String url = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "/vnf-image/" - + image.getUuid(); - restClient.getAndDeleteResource(url, transId); // try to delete the image, - // if something goes wrong - // we can't really do - // anything here + /* + * If something fails in the middle of ingesting the catalog we want to roll back any changes to the DB + */ + @Override + public void rollback(List completedArtifacts, String distributionId, AaiRestClient aaiClient) { + for (Artifact completedArtifact : completedArtifacts) { + List> completedImageData = unmarshallVnfcData(completedArtifact); + for (Map data : completedImageData) { + String url = config.getAaiBaseUrl() + config.getAaiVnfImageUrl() + "/vnf-image/" + data.get(ATTR_UUID); + // Try to delete the image. If something goes wrong we can't really do anything here + aaiClient.getAndDeleteResource(url, distributionId); + } + } } - } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfImageException.java b/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfImageException.java new file mode 100644 index 0000000..9459c49 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/entity/catalog/VnfImageException.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.entity.catalog; + +import java.util.Optional; + +/** + * Exception class used by the VnfCatalogArtifactHandler + */ +class VnfImageException extends Exception { + + private static final long serialVersionUID = 1L; + + private final String imageId; + private final transient Optional resultCode; + + public VnfImageException(String imageId) { + this.imageId = imageId; + this.resultCode = Optional.empty(); + } + + public VnfImageException(String imageId, int resultCode) { + this.imageId = imageId; + this.resultCode = Optional.of(resultCode); + } + + public VnfImageException(Exception e) { + this.imageId = e.getMessage(); + this.resultCode = Optional.empty(); + } + + public String getImageId() { + return imageId; + } + + public Optional getResultCode() { + return resultCode; + } + +} \ No newline at end of file diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java index 889db55..3c1152f 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java @@ -29,55 +29,59 @@ import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.entity.ArtifactType; import org.onap.aai.modelloader.restclient.AaiRestClient; -public abstract class AbstractModelArtifact extends Artifact { - - private String modelNamespace; - private String modelNamespaceVersion; - private Set referencedModelIds = new HashSet<>(); - - public AbstractModelArtifact(ArtifactType type) { - super(type); - } - - public Set getDependentModelIds() { - return referencedModelIds; - } - - public void addDependentModelId(String dependentModelId) { - this.referencedModelIds.add(dependentModelId); - } - - public String getModelNamespace() { - return modelNamespace; - } - - public void setModelNamespace(String modelNamespace) { - this.modelNamespace = modelNamespace; - - // Get the version from the namespace (in format 'http://org.openecomp.aai.inventory/v9') - String[] parts = modelNamespace.split("/"); - modelNamespaceVersion = parts[parts.length-1].trim(); - } - - public String getModelNamespaceVersion() { - return modelNamespaceVersion; - } - - public abstract String getUniqueIdentifier(); - - public abstract boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, List addedModels); - - public abstract void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId); +public abstract class AbstractModelArtifact extends Artifact implements IModelArtifact { + + private String modelNamespace; + private String modelNamespaceVersion; + private Set referencedModelIds = new HashSet<>(); + + public AbstractModelArtifact(ArtifactType type) { + super(type); + } + + public Set getDependentModelIds() { + return referencedModelIds; + } + + @Override + public void addDependentModelId(String dependentModelId) { + this.referencedModelIds.add(dependentModelId); + } + + public String getModelNamespace() { + return modelNamespace; + } + + @Override + public void setModelNamespace(String modelNamespace) { + this.modelNamespace = modelNamespace; + + // Get the version from the namespace (in format 'http://org.openecomp.aai.inventory/v9') + String[] parts = modelNamespace.split("/"); + modelNamespaceVersion = parts[parts.length - 1].trim(); + } + + public String getModelNamespaceVersion() { + return modelNamespaceVersion; + } + + public abstract String getUniqueIdentifier(); + + public abstract boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, + List completedArtifacts); + + public abstract void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId); + @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("\nType=" + getType().toString() +"\nId=" + getUniqueIdentifier() +"\nVersion=" + getModelNamespaceVersion() + "\nDependant models: "); - for (String dep : referencedModelIds) { - sb.append(dep + " "); - } - - return sb.toString(); - } - - + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("\nType=" + getType().toString() + "\nId=" + getUniqueIdentifier() + "\nVersion=" + + getModelNamespaceVersion() + "\nDependant models: "); + for (String dep : referencedModelIds) { + sb.append(dep + " "); + } + + return sb.toString(); + } + } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifactParser.java b/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifactParser.java new file mode 100644 index 0000000..fd6af31 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifactParser.java @@ -0,0 +1,293 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.entity.model; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.stream.Collector; +import java.util.stream.IntStream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.service.ModelLoaderMsgs; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +/** + * This class provides common behaviour for implementations of IModelParser. + * + * Some of the common behaviour takes the form of abstract methods that will be implemented in concrete classes. + * + * Some other behaviour will be overridden in concrete classes. + */ +public abstract class AbstractModelArtifactParser implements IModelParser { + private static Logger logger = LoggerFactory.getInstance().getLogger(AbstractModelArtifactParser.class); + + protected static final String RELATIONSHIP_DATA = "relationship-data"; + private static final String RELATIONSHIP_KEY = "relationship-key"; + private static final String RELATIONSHIP_VALUE = "relationship-value"; + + BiConsumer, Node> applyRelationshipValue = (p, n) -> { + if (n.getNodeName().equalsIgnoreCase(RELATIONSHIP_KEY)) { + p.setKey(n.getTextContent().trim()); + } else { + p.setValue(n.getTextContent().trim()); + } + }; + + + /** + * This method is responsible for parsing the payload to produce a list of artifacts. + * + * @param artifactPayload the payload to be parsed + * @param artifactName the name of the artifact to be parsed + * @return List a list of artifacts that have been parsed from the payload. + */ + @Override + public List parse(String artifactPayload, String artifactName) { + List modelList = new ArrayList<>(); + + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource is = new InputSource(new StringReader(artifactPayload)); + Document doc = builder.parse(is); + + IModelArtifact model = parseModel(doc.getDocumentElement(), artifactPayload); + + if (!processParsedModel(modelList, artifactName, model)) { + modelList = null; + } + } catch (Exception ex) { + logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, + buildArtifactParseExceptionMessage(artifactName, ex.getLocalizedMessage())); + } + + return modelList; + } + + private IModelArtifact parseModel(Node modelNode, String payload) { + IModelArtifact model = createModelArtifactInstance(); + model.setPayload(payload); + + Element e = (Element) modelNode; + model.setModelNamespace(e.getAttribute("xmlns")); + + parseNode(modelNode, model); + + return modelIsValid(model) ? model : null; + } + + /** + * This method is responsible for creating a new instance of IModel that represents the model id for a concrete + * implementation of IArtifactParser. + * + * @return IModelArtifact implementation of IModel that represents the model id for a concrete implementation of + * IArtifactParser + */ + abstract IModelArtifact createModelArtifactInstance(); + + /** + * This method is responsible for the actual parsing of a node. + * + * It will do one of three things: + *
    + *
  1. set the version id if the name of the node is the same as the name of the node that is the version Id
  2. + *
  3. if the node is contains data about the relationship it will parse the node accordingly
  4. + *
  5. if it does neither of option 1 or 2 it will parse the children of this node
  6. + *
+ * + * @param node node to be parsed + * @param model the model artifact to be updated with either the versionId or details of dependent node + */ + void parseNode(Node node, IModelArtifact model) { + if (node.getNodeName().equalsIgnoreCase(getVersionIdNodeName())) { + setVersionId(model, node); + } else if (node.getNodeName().equalsIgnoreCase(RELATIONSHIP_DATA)) { + parseRelationshipNode(node, model); + } else { + parseChildNodes(node, model); + } + } + + /** + * This method gets the name of the node that acts as the version Id for the node. + * + * @return String name of the node that acts as the version Id for the node + */ + abstract String getVersionIdNodeName(); + + /** + * This method is responsible for setting the values on the model artifact that represent the version Id. Each + * implementation of a IModelArtifact has its own properties that define the version Id. + * + * @param model the model artifact upon which the version Id will be set + * @param node the source of the data that holds the actual value of the version id to be set on the model artifact + */ + abstract void setVersionId(IModelArtifact model, Node node); + + /** + * @param relationshipNode a node containing child nodes storing relationship data + * @param model artifact whose dependent node id will be update with any relationship data if it exists + */ + void parseRelationshipNode(Node relationshipNode, IModelArtifact model) { + NodeList nodeList = getChildNodes(relationshipNode); + + IModelId modelId = buildModelId(nodeList); + + updateModelsDependentNodeId(model, modelId); + } + + private NodeList getChildNodes(Node relationshipNode) { + Objects.requireNonNull(relationshipNode); + NodeList nodeList = relationshipNode.getChildNodes(); + Objects.requireNonNull(nodeList); + + return nodeList; + } + + /** + * This method is responsible for building an instance of IModelId representing the id of the model. + * + * @param nodeList list of modes used to build the model id. + * @return IModelId instance of IModelId representing the id of the model + */ + IModelId buildModelId(NodeList nodeList) { + Pair relationship = IntStream.range(0, nodeList.getLength()).mapToObj(nodeList::item) // + .filter(this::filterRelationshipNode) + .collect(Collector.of(Pair::new, applyRelationshipValue, (p, n) -> p)); + + IModelId modelId = createModelIdInstance(); + modelId.setRelationship(relationship); + + return modelId; + } + + /** + * This method tests if a node is either one that either represents a relationship key or a relationship value. + * + * @param n the node to to be tested + * @return true if the node is either represents a relationship key or a relationship value + */ + boolean filterRelationshipNode(Node n) { + return n.getNodeName().equalsIgnoreCase(RELATIONSHIP_KEY) + || n.getNodeName().equalsIgnoreCase(RELATIONSHIP_VALUE); + } + + /** + * This method is responsible for creating an instance of {@link AbstractModelArtifactParser.ModelId} + * + * @return IModelId instance of {@link AbstractModelArtifactParser.ModelId} + */ + IModelId createModelIdInstance() { + return new ModelId(); + } + + private void updateModelsDependentNodeId(IModelArtifact model, IModelId modelId) { + if (modelId.defined()) { + model.addDependentModelId(modelId.toString()); + } + } + + /** + * This method is responsible for parsing the children of a given node. + * + * @param node node whose children, if any, should be parsed. + * @param model model to be updated as a result of parsing the node + */ + void parseChildNodes(Node node, IModelArtifact model) { + NodeList nodeList = node.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node childNode = nodeList.item(i); + parseNode(childNode, model); + } + } + + /** + * Validates if the mode is valid or not by examining specific properties of the model. + * + * @param model model to be validated + * @return true if the mode is valid otherwise false + */ + abstract boolean modelIsValid(IModelArtifact model); + + /** + * This method is responsible for building a message used for logging artifact parsing errors. + * + * @param artifactName the name of the artifact + * @param localisedMessage the message associated with the exception that is raised by the error + * @return String a message used for logging artifact parsing errors + */ + abstract String buildArtifactParseExceptionMessage(String artifactName, String localisedMessage); + + /** + * This method is responsible for either adding the model artifact to the list of model artifacts or reporting an + * error. + * + * If the model is not null then it will be added to the list of artifacts otherwise an error will be logged. + * + * @param modelList the list of artifacts to which the model will be added if it is not null + * @param artifactName the name of the artifact + * @param artifactModel the model artifact to be added to the list of model artifacts + * @return true/code> if the model is not null otherwise false + */ + abstract boolean processParsedModel(List modelList, String artifactName, IModelArtifact artifactModel); + + private class ModelId implements IModelId { + private String modelIdValue; + + @Override + public void setRelationship(Pair p) { + if (getModelElementRelationshipKey().equals(p.getKey())) { + modelIdValue = p.getValue(); + } + } + + @Override + public boolean defined() { + return modelIdValue != null; + } + + @Override + public String toString() { + return modelIdValue; + } + } + + /** + * This method gets the name of the key of the element relationship for the model. + * + * @return String name of the key of the element relationship for the model + */ + abstract String getModelElementRelationshipKey(); +} diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/BabelArtifactParsingException.java b/src/main/java/org/onap/aai/modelloader/entity/model/BabelArtifactParsingException.java new file mode 100644 index 0000000..1426e82 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/entity/model/BabelArtifactParsingException.java @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.entity.model; + +/** + * This class represents an exception encountered when parsing an XML model Artifact. + */ +public class BabelArtifactParsingException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructor for an instance of this exception with just a message. + * + * @param message information about the exception + */ + public BabelArtifactParsingException(String message) { + super(message); + } + + /** + * Constructor for an instance of this exception with a message and actual exception encountered. + * + * @param message information about the exception + * @param cause the actual exception that was encountered + */ + public BabelArtifactParsingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/IModelArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/IModelArtifact.java new file mode 100644 index 0000000..5978b99 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/entity/model/IModelArtifact.java @@ -0,0 +1,51 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.entity.model; + +/** + * Defines methods for implementations of a Model Artifact. + */ +public interface IModelArtifact { + + /** + * This method is responsible for adding the id of a dependent node to the model. + * + * The model will have a collection of dependent nodes that may or may not have contents. + * + * @param value id of a dependent node to be added to the model. + */ + void addDependentModelId(String value); + + /** + * This method sets the payload for the model. + * + * @param payload the actual payload for the model + */ + void setPayload(String payload); + + /** + * This methods sets the value of the namespace for the model. + * + * @param xmlns the namespace for the model + */ + void setModelNamespace(String xmlns); +} diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/IModelId.java b/src/main/java/org/onap/aai/modelloader/entity/model/IModelId.java new file mode 100644 index 0000000..9b635bf --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/entity/model/IModelId.java @@ -0,0 +1,51 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.entity.model; + +/** + * Defines methods for c + */ +public interface IModelId { + + /** + * This method is responsible for using the values in the supplied Pair to set the id of the model. + * + * The definition of what the relationship will be is defined by the implementation. Some model ids would have + * single key/value pairs, others would have a composite key. + * + * Where the id of the model is a composite key multiple calls to this method will be required to successfully set + * the relationship in order to meet the rules of {@link #defined} + * + * @param pair object representing a key and its value. + */ + void setRelationship(Pair pair); + + /** + * This method indicates whether the id of the model has been defined according to the rules of the specific model + * implemented. + * + * Usually defined means that all properties that make up the key have been set. + * + * @return boolean true if the id of the model has been defined otherwise false + */ + boolean defined(); +} diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/IModelParser.java b/src/main/java/org/onap/aai/modelloader/entity/model/IModelParser.java index bf2361b..758a882 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/IModelParser.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/IModelParser.java @@ -26,5 +26,6 @@ import org.onap.aai.modelloader.entity.Artifact; @FunctionalInterface public interface IModelParser { - public List parse(byte[] artifactPayload, String artifactName); + + List parse(String artifactPayload, String artifactName); } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java index d15776a..896167a 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java @@ -22,8 +22,9 @@ package org.onap.aai.modelloader.entity.model; import java.io.StringWriter; import java.util.List; - +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.xml.XMLConstants; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; @@ -37,172 +38,222 @@ import org.onap.aai.modelloader.restclient.AaiRestClient; import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; -import org.w3c.dom.Node; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.restclient.client.OperationResult; -import com.sun.jersey.api.client.ClientResponse; +import org.w3c.dom.Node; public class ModelArtifact extends AbstractModelArtifact { - private static final String AAI_MODEL_VER_SUB_URL = "/model-vers/model-ver"; - - private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifact.class.getName()); - - private String modelVerId; - private String modelInvariantId; - private Node modelVer; - private boolean firstVersionOfModel = false; - - public ModelArtifact() { - super(ArtifactType.MODEL); - } - - public String getModelVerId() { - return modelVerId; - } - - public void setModelVerId(String modelVerId) { - this.modelVerId = modelVerId; - } - - public String getModelInvariantId() { - return modelInvariantId; - } - - public void setModelInvariantId(String modelInvariantId) { - this.modelInvariantId = modelInvariantId; - } - - public Node getModelVer() { - return modelVer; - } - - public void setModelVer(Node modelVer) { - this.modelVer = modelVer; - } - - @Override - public String getUniqueIdentifier() { - return getModelInvariantId() + "|" + getModelVerId(); - } - - @Override - public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, List addedModels) { - ClientResponse getResponse = aaiClient.getResource(getModelUrl(config), distId, AaiRestClient.MimeType.XML); - if ( (getResponse == null) || (getResponse.getStatus() != Response.Status.OK.getStatusCode()) ) { - // Only attempt the PUT if the model doesn't already exist - ClientResponse putResponse = aaiClient.putResource(getModelUrl(config), getPayload(), distId, AaiRestClient.MimeType.XML); - if ( (putResponse != null) && (putResponse.getStatus() == Response.Status.CREATED.getStatusCode()) ) { - addedModels.add(this); - - // Flag this as the first version of the model that has been added. - firstVersionOfModel = true; - - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, getType().toString() + " " + getUniqueIdentifier() + " successfully ingested."); - } - else { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed for " + getType().toString() + " " + getUniqueIdentifier() + - ". Rolling back distribution."); - return false; - } - } - else { - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, getType().toString() + " " + getModelInvariantId() + " already exists. Skipping ingestion."); - getResponse = aaiClient.getResource(getModelVerUrl(config), distId, AaiRestClient.MimeType.XML); - if ( (getResponse == null) || (getResponse.getStatus() != Response.Status.OK.getStatusCode()) ) { - // Only attempt the PUT if the model-ver doesn't already exist - ClientResponse putResponse = null; + private static final String AAI_MODEL_VER_SUB_URL = "/model-vers/model-ver"; - try { - putResponse = aaiClient.putResource(getModelVerUrl(config), nodeToString(getModelVer()), distId, AaiRestClient.MimeType.XML); - } catch (TransformerException e) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed for " + getType().toString() + " " + getUniqueIdentifier() - + ": " + e.getMessage() + ". Rolling back distribution."); - return false; + private static final String FAILURE_MSG_PREFIX = "Ingestion failed for "; + private static final String ROLLBACK_MSG_SUFFIX = ". Rolling back distribution."; + + private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifact.class.getName()); + + private String modelVerId; + private String modelInvariantId; + private Node modelVer; + private boolean firstVersionOfModel = false; + + public ModelArtifact() { + super(ArtifactType.MODEL); + } + + public String getModelVerId() { + return modelVerId; + } + + public void setModelVerId(String modelVerId) { + this.modelVerId = modelVerId; + } + + public String getModelInvariantId() { + return modelInvariantId; + } + + public void setModelInvariantId(String modelInvariantId) { + this.modelInvariantId = modelInvariantId; + } + + public Node getModelVer() { + return modelVer; + } + + public void setModelVer(Node modelVer) { + this.modelVer = modelVer; + } + + @Override + public String getUniqueIdentifier() { + return getModelInvariantId() + "|" + getModelVerId(); + } + + + /** + * Test whether the specified resource (URL) can be requested successfully + * + * @param aaiClient + * @param distId + * @param xmlResourceUrl + * @return true if a request to GET this resource as XML media is successful (status OK) + */ + private boolean xmlResourceCanBeFetched(AaiRestClient aaiClient, String distId, String xmlResourceUrl) { + OperationResult getResponse = aaiClient.getResource(xmlResourceUrl, distId, MediaType.APPLICATION_XML_TYPE); + return getResponse != null && getResponse.getResultCode() == Response.Status.OK.getStatusCode(); + } + + /** + * PUT the specified XML resource + * + * @param aaiClient + * @param distId + * @param resourceUrl + * @param payload + * @return true if the resource PUT as XML media was successful (status OK) + */ + private boolean putXmlResource(AaiRestClient aaiClient, String distId, String resourceUrl, String payload) { + OperationResult putResponse = + aaiClient.putResource(resourceUrl, payload, distId, MediaType.APPLICATION_XML_TYPE); + return putResponse != null && putResponse.getResultCode() == Response.Status.CREATED.getStatusCode(); + } + + @Override + public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, + List completedArtifacts) { + boolean success; + + // See whether the model is already present + String resourceUrl = getModelUrl(config); + + if (xmlResourceCanBeFetched(aaiClient, distId, resourceUrl)) { + logInfoMsg(getType().toString() + " " + getModelInvariantId() + " already exists. Skipping ingestion."); + success = pushModelVersion(aaiClient, config, distId, completedArtifacts); + } else { + // Assume that the model does not exist and attempt the PUT + success = putXmlResource(aaiClient, distId, resourceUrl, getPayload()); + if (success) { + completedArtifacts.add(this); + + // Record state to remember that this is the first version of the model (just added). + firstVersionOfModel = true; + + logInfoMsg(getType().toString() + " " + getUniqueIdentifier() + " successfully ingested."); + } else { + logErrorMsg( + FAILURE_MSG_PREFIX + getType().toString() + " " + getUniqueIdentifier() + ROLLBACK_MSG_SUFFIX); + } } - if ( (putResponse != null) && (putResponse.getStatus() == Response.Status.CREATED.getStatusCode()) ) { - addedModels.add(this); - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, getType().toString() + " " + getUniqueIdentifier() + " successfully ingested."); + + return success; + } + + /** + * @param aaiClient + * @param config + * @param distId + * @param completedArtifacts + * @return + */ + private boolean pushModelVersion(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, + List completedArtifacts) { + if (xmlResourceCanBeFetched(aaiClient, distId, getModelVerUrl(config))) { + logInfoMsg(getType().toString() + " " + getUniqueIdentifier() + " already exists. Skipping ingestion."); + return true; } - else { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed for " + getType().toString() + " " - + getUniqueIdentifier() + ". Rolling back distribution."); - return false; + + // Load the model version + boolean success = true; + try { + success = putXmlResource(aaiClient, distId, getModelVerUrl(config), nodeToString(getModelVer())); + if (success) { + completedArtifacts.add(this); + logInfoMsg(getType().toString() + " " + getUniqueIdentifier() + " successfully ingested."); + } else { + logErrorMsg( + FAILURE_MSG_PREFIX + getType().toString() + " " + getUniqueIdentifier() + ROLLBACK_MSG_SUFFIX); + } + } catch (TransformerException e) { + logErrorMsg(FAILURE_MSG_PREFIX + getType().toString() + " " + getUniqueIdentifier() + ": " + e.getMessage() + + ROLLBACK_MSG_SUFFIX); + success = false; } - } - else { - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, getType().toString() + " " + getUniqueIdentifier() + " already exists. Skipping ingestion."); - } - } - - return true; - } - - @Override - public void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId) { - String url = getModelVerUrl(config); - if (firstVersionOfModel) { - // If this was the first version of the model which was added, we want to remove the entire - // model rather than just the version. - url = getModelUrl(config); + + return success; } - - // Best effort to delete. Nothing we can do in the event this fails. - aaiClient.getAndDeleteResource(url, distId); - } - - private String getModelUrl(ModelLoaderConfig config) { - String baseURL = config.getAaiBaseUrl().trim(); - String subURL = null; - String instance = null; - subURL = config.getAaiModelUrl(getModelNamespaceVersion()).trim(); - instance = getModelInvariantId(); - if ( (!baseURL.endsWith("/")) && (!subURL.startsWith("/")) ) { - baseURL = baseURL + "/"; + @Override + public void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId) { + String url = getModelVerUrl(config); + if (firstVersionOfModel) { + // If this was the first version of the model which was added, we want to remove the entire + // model rather than just the version. + url = getModelUrl(config); + } + + // Best effort to delete. Nothing we can do in the event this fails. + aaiClient.getAndDeleteResource(url, distId); } - if ( baseURL.endsWith("/") && subURL.startsWith("/") ) { - baseURL = baseURL.substring(0, baseURL.length()-1); + + private void logInfoMsg(String infoMsg) { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, infoMsg); } - if (!subURL.endsWith("/")) { - subURL = subURL + "/"; + private void logErrorMsg(String errorMsg) { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, errorMsg); } - String url = baseURL + subURL + instance; - return url; - } + private String getModelUrl(ModelLoaderConfig config) { + String baseURL = config.getAaiBaseUrl().trim(); + String subURL = config.getAaiModelUrl(getModelNamespaceVersion()).trim(); + String instance = getModelInvariantId(); - private String getModelVerUrl(ModelLoaderConfig config) { - String baseURL = config.getAaiBaseUrl().trim(); - String subURL = null; - String instance = null; + if ((!baseURL.endsWith("/")) && (!subURL.startsWith("/"))) { + baseURL = baseURL + "/"; + } - subURL = config.getAaiModelUrl(getModelNamespaceVersion()).trim() + getModelInvariantId() + AAI_MODEL_VER_SUB_URL; - instance = getModelVerId(); + if (baseURL.endsWith("/") && subURL.startsWith("/")) { + baseURL = baseURL.substring(0, baseURL.length() - 1); + } - if ( (!baseURL.endsWith("/")) && (!subURL.startsWith("/")) ) { - baseURL = baseURL + "/"; - } + if (!subURL.endsWith("/")) { + subURL = subURL + "/"; + } - if ( baseURL.endsWith("/") && subURL.startsWith("/") ) { - baseURL = baseURL.substring(0, baseURL.length()-1); + return baseURL + subURL + instance; } - if (!subURL.endsWith("/")) { - subURL = subURL + "/"; + private String getModelVerUrl(ModelLoaderConfig config) { + String baseURL = config.getAaiBaseUrl().trim(); + String subURL = config.getAaiModelUrl(getModelNamespaceVersion()).trim() + getModelInvariantId() + + AAI_MODEL_VER_SUB_URL; + String instance = getModelVerId(); + + if ((!baseURL.endsWith("/")) && (!subURL.startsWith("/"))) { + baseURL = baseURL + "/"; + } + + if (baseURL.endsWith("/") && subURL.startsWith("/")) { + baseURL = baseURL.substring(0, baseURL.length() - 1); + } + + if (!subURL.endsWith("/")) { + subURL = subURL + "/"; + } + + return baseURL + subURL + instance; } - String url = baseURL + subURL + instance; - return url; - } - - private String nodeToString(Node node) throws TransformerException { - StringWriter sw = new StringWriter(); - Transformer t = TransformerFactory.newInstance().newTransformer(); - t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - t.transform(new DOMSource(node), new StreamResult(sw)); - return sw.toString(); - } + private String nodeToString(Node node) throws TransformerException { + StringWriter sw = new StringWriter(); + TransformerFactory transFact = TransformerFactory.newInstance(); + transFact.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + Transformer t = transFact.newTransformer(); + t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + t.transform(new DOMSource(node), new StreamResult(sw)); + return sw.toString(); + } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactHandler.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactHandler.java index 570d8fe..157ac8d 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactHandler.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactHandler.java @@ -20,6 +20,8 @@ */ package org.onap.aai.modelloader.entity.model; +import java.util.List; + import org.onap.aai.modelloader.config.ModelLoaderConfig; import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.entity.ArtifactHandler; @@ -28,56 +30,42 @@ import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; -import java.util.ArrayList; -import java.util.List; - - public class ModelArtifactHandler extends ArtifactHandler { - private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifactHandler.class.getName()); - - public ModelArtifactHandler(ModelLoaderConfig config) { - super(config); - } + private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifactHandler.class.getName()); - @Override - public boolean pushArtifacts(List artifacts, String distributionID) { - ModelSorter modelSorter = new ModelSorter(); - List sortedModelArtifacts; - try { - sortedModelArtifacts = modelSorter.sort(artifacts); - } - catch (RuntimeException ex) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Unable to resolve models: " + ex.getMessage()); - return false; + public ModelArtifactHandler(ModelLoaderConfig config) { + super(config); } - - // Push the ordered list of model artifacts to A&AI. If one fails, we need to roll back - // the changes. - List completedModels = new ArrayList<>(); - AaiRestClient aaiClient = new AaiRestClient(config); - for (Artifact art : sortedModelArtifacts) { - AbstractModelArtifact model = (AbstractModelArtifact)art; - if (model.push(aaiClient, config, distributionID, completedModels) != true) { - for (AbstractModelArtifact modelToDelete : completedModels) { - modelToDelete.rollbackModel(aaiClient, config, distributionID); + @Override + public boolean pushArtifacts(List artifacts, String distributionID, List completedArtifacts, + AaiRestClient aaiClient) { + ModelSorter modelSorter = new ModelSorter(); + List sortedModelArtifacts; + try { + sortedModelArtifacts = modelSorter.sort(artifacts); + } catch (RuntimeException ex) { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Unable to resolve models: " + ex.getMessage()); + return false; } - return false; - } - } + // Push the ordered list of model artifacts to A&AI. If one fails, we need to roll back the changes. + for (Artifact art : sortedModelArtifacts) { + AbstractModelArtifact model = (AbstractModelArtifact) art; + if (!model.push(aaiClient, config, distributionID, completedArtifacts)) { + return false; + } + } - return true; - } + return true; + } - // This method is used for the test REST interface to load models without an ASDC - public void loadModelTest(byte[] payload) { - List modelArtifacts = new ArrayList(); - ModelArtifactParser parser = new ModelArtifactParser(); - modelArtifacts.addAll(parser.parse(payload, "Test-Artifact")); - ModelSorter modelSorter = new ModelSorter(); - List sortedModelArtifacts = modelSorter.sort(modelArtifacts); - pushArtifacts(sortedModelArtifacts, "Test-Distribution"); - } + @Override + public void rollback(List completedArtifacts, String distributionId, AaiRestClient aaiClient) { + for (Artifact artifactToDelete : completedArtifacts) { + AbstractModelArtifact model = (AbstractModelArtifact) artifactToDelete; + model.rollbackModel(aaiClient, config, distributionId); + } + } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactParser.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactParser.java index d03c13c..17bdd87 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactParser.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifactParser.java @@ -20,172 +20,183 @@ */ package org.onap.aai.modelloader.entity.model; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collector; +import java.util.stream.IntStream; +import javax.xml.XMLConstants; + import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; -import org.w3c.dom.Document; + import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - - -public class ModelArtifactParser implements IModelParser { - - private static String MODEL_VER = "model-ver"; - private static String MODEL_VERSION_ID = "model-version-id"; - private static String MODEL_INVARIANT_ID = "model-invariant-id"; - private static String RELATIONSHIP = "relationship"; - private static String RELATIONSHIP_DATA = "relationship-data"; - private static String RELATIONSHIP_KEY = "relationship-key"; - private static String RELATIONSHIP_VALUE = "relationship-value"; - private static String MODEL_ELEMENT_RELATIONSHIP_KEY = "model.model-invariant-id"; - private static String MODEL_VER_ELEMENT_RELATIONSHIP_KEY = "model-ver.model-version-id"; - - private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifactParser.class.getName()); - - public List parse(byte[] artifactPayload, String artifactName) { - String payload = new String(artifactPayload); - List modelList = new ArrayList(); - - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(payload)); - Document doc = builder.parse(is); - - ModelArtifact model = parseModel(doc.getDocumentElement(), payload); - - if (model != null) { - logger.info( ModelLoaderMsgs.DISTRIBUTION_EVENT, "Model parsed =====>>>> " - + "Model-invariant-Id: "+ model.getModelInvariantId() - + " Model-Version-Id: "+ model.getModelVerId()); - modelList.add(model); - } - else { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse artifact " + artifactName); - return null; - } - } - catch (Exception ex) { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse artifact " + artifactName + ": " + ex.getLocalizedMessage()); - } - - return modelList; - } - - private ModelArtifact parseModel(Node modelNode, String payload) { - ModelArtifact model = new ModelArtifact(); - model.setPayload(payload); - - Element e = (Element)modelNode; - model.setModelNamespace(e.getAttribute("xmlns")); - - parseNode(modelNode, model); - - if ( (model.getModelInvariantId() == null) || (model.getModelVerId() == null) ){ - return null; - } - - return model; - } - - private void parseNode(Node node, ModelArtifact model) { - if (node.getNodeName().equalsIgnoreCase(MODEL_INVARIANT_ID)) { - model.setModelInvariantId(node.getTextContent().trim()); - } - else if (node.getNodeName().equalsIgnoreCase(MODEL_VERSION_ID)) { - model.setModelVerId(node.getTextContent().trim()); - } - else if (node.getNodeName().equalsIgnoreCase(RELATIONSHIP)) { - String dependentModelKey = parseRelationshipNode(node, model); - if (dependentModelKey != null) { - model.addDependentModelId(dependentModelKey); - } - } - else { - if (node.getNodeName().equalsIgnoreCase(MODEL_VER)) { - model.setModelVer(node); - if ( (model.getModelNamespace() != null) && (!model.getModelNamespace().isEmpty()) ) { - Element e = (Element) node; - e.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns", model.getModelNamespace()); - } - } - - NodeList nodeList = node.getChildNodes(); - - for (int i = 0; i < nodeList.getLength(); i++) { - Node childNode = nodeList.item(i); - parseNode(childNode, model); - } - } - } - - private String parseRelationshipNode(Node node, ModelArtifact model) { - String currentKey = null; - String currentValue = null; - String modelVersionIdValue = null; - String modelInvariantIdValue = null; - - NodeList nodeList = node.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node childNode = nodeList.item(i); - - if (childNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_DATA)) { - NodeList relDataChildList = childNode.getChildNodes(); - - for (int j = 0; j < relDataChildList.getLength(); j++) { - Node relDataChildNode = relDataChildList.item(j); - - if (relDataChildNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_KEY)) { - currentKey = relDataChildNode.getTextContent().trim(); - - if (currentValue != null) { - if (currentKey.equalsIgnoreCase(MODEL_VER_ELEMENT_RELATIONSHIP_KEY)) { - modelVersionIdValue = currentValue; - } - else if (currentKey.equalsIgnoreCase(MODEL_ELEMENT_RELATIONSHIP_KEY)) { - modelInvariantIdValue = currentValue; - } - - currentKey = null; - currentValue = null; - } - } - else if (relDataChildNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_VALUE)) { - currentValue = relDataChildNode.getTextContent().trim(); - - if (currentKey != null) { - if (currentKey.equalsIgnoreCase(MODEL_VER_ELEMENT_RELATIONSHIP_KEY)) { - modelVersionIdValue = currentValue; - } - else if (currentKey.equalsIgnoreCase(MODEL_ELEMENT_RELATIONSHIP_KEY)) { - modelInvariantIdValue = currentValue; - } - - currentKey = null; - currentValue = null; - } - } - } - } - } - - if ( (modelVersionIdValue != null) && (modelInvariantIdValue != null) ) { - return modelInvariantIdValue + "|" + modelVersionIdValue; - } - - return null; - - } +public class ModelArtifactParser extends AbstractModelArtifactParser { + + public static final String MODEL_VER = "model-ver"; + public static final String MODEL_VERSION_ID = "model-version-id"; + public static final String MODEL_INVARIANT_ID = "model-invariant-id"; + private static final String RELATIONSHIP = "relationship"; + private static final String MODEL_ELEMENT_RELATIONSHIP_KEY = "model." + MODEL_INVARIANT_ID; + private static final String MODEL_VER_ELEMENT_RELATIONSHIP_KEY = MODEL_VER + "." + MODEL_VERSION_ID; + + private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifactParser.class.getName()); + + @Override + void parseNode(Node node, IModelArtifact model) { + if (node.getNodeName().equalsIgnoreCase(MODEL_INVARIANT_ID) + || node.getNodeName().equalsIgnoreCase(MODEL_VERSION_ID)) { + setVersionId(model, node); + } else if (node.getNodeName().equalsIgnoreCase(RELATIONSHIP)) { + parseRelationshipNode(node, model); + } else { + if (node.getNodeName().equalsIgnoreCase(MODEL_VER)) { + ((ModelArtifact) model).setModelVer(node); + if ((((ModelArtifact) model).getModelNamespace() != null) + && (!((ModelArtifact) model).getModelNamespace().isEmpty())) { + Element e = (Element) node; + e.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns", + ((ModelArtifact) model).getModelNamespace()); + } + } + + parseChildNodes(node, model); + } + } + + /** + * {@inheritDoc} + */ + @Override + void setVersionId(IModelArtifact model, Node node) { + if (MODEL_INVARIANT_ID.equals(node.getNodeName())) { + ((ModelArtifact) model).setModelInvariantId(node.getTextContent().trim()); + } else if (MODEL_VERSION_ID.equals(node.getNodeName())) { + ((ModelArtifact) model).setModelVerId(node.getTextContent().trim()); + } + } + + /** + * {@inheritDoc} + */ + @Override + ModelId buildModelId(NodeList nodeList) { + return IntStream.range(0, nodeList.getLength()).mapToObj(nodeList::item) + .filter(childNode -> childNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_DATA)) + .map(this::getRelationship) // + .collect(Collector.of(ModelId::new, ModelId::setRelationship, (m, p) -> m)); + } + + /** + * Find a relationship key and value pair from the children of the supplied node. + * + * @param node containing children storing relationship keys and values + * @return a pair containing a relationship key and its value. Note: if multiple relationships are found, existing + * values stored in the pair will be overwritten. + */ + private Pair getRelationship(Node node) { + Objects.requireNonNull(node); + NodeList relDataChildList = node.getChildNodes(); + Objects.requireNonNull(relDataChildList); + + return IntStream.range(0, relDataChildList.getLength()).mapToObj(relDataChildList::item) + .filter(this::filterRelationshipNode) + .collect(Collector.of(Pair::new, applyRelationshipValue, (p, n) -> p)); + } + + /** + * This method is responsible for creating an instance of {@link ModelArtifactParser.ModelId} + * + * @return IModelId instance of {@link ModelArtifactParser.ModelId} + */ + @Override + IModelId createModelIdInstance() { + return new ModelId(); + } + + private class ModelId implements IModelId { + + private String modelInvariantIdValue; + private String modelVersionIdValue; + + @Override + public void setRelationship(Pair p) { + if (p.getKey().equalsIgnoreCase(MODEL_VER_ELEMENT_RELATIONSHIP_KEY)) { + modelVersionIdValue = p.getValue(); + } else if (p.getKey().equalsIgnoreCase(MODEL_ELEMENT_RELATIONSHIP_KEY)) { + modelInvariantIdValue = p.getValue(); + } + } + + @Override + public boolean defined() { + return modelInvariantIdValue != null && modelVersionIdValue != null; + } + + @Override + public String toString() { + return modelInvariantIdValue + "|" + modelVersionIdValue; + } + } + + /** + * {@inheritDoc} + */ + @Override + String buildArtifactParseExceptionMessage(String artifactName, String localisedMessage) { + return "Unable to parse legacy model artifact " + artifactName + ": " + localisedMessage; + } + + /** + * {@inheritDoc} + */ + @Override + IModelArtifact createModelArtifactInstance() { + return new ModelArtifact(); + } + + @Override + boolean modelIsValid(IModelArtifact model) { + return ((ModelArtifact) model).getModelInvariantId() != null && ((ModelArtifact) model).getModelVerId() != null; + } + + /** + * {@inheritDoc} + */ + @Override + boolean processParsedModel(List modelList, String artifactName, IModelArtifact model) { + boolean valid = false; + + if (model != null) { + ModelArtifact modelImpl = (ModelArtifact) model; + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Model parsed =====>>>> " + "Model-invariant-Id: " + + modelImpl.getModelInvariantId() + " Model-Version-Id: " + modelImpl.getModelVerId()); + modelList.add(modelImpl); + valid = true; + } else { + logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse artifact " + artifactName); + } + + return valid; + } + + /** + * {@inheritDoc} + */ + @Override + String getModelElementRelationshipKey() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + String getVersionIdNodeName() { + return null; + } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelParserFactory.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelParserFactory.java deleted file mode 100644 index 3f6bf6e..0000000 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelParserFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * 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.aai.modelloader.entity.model; - -import java.io.StringReader; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.onap.aai.modelloader.service.ModelLoaderMsgs; -import org.onap.aai.cl.api.Logger; -import org.onap.aai.cl.eelf.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; - -public class ModelParserFactory { - private static Logger logger = LoggerFactory.getInstance().getLogger(ModelParserFactory.class.getName()); - - private static String MODEL_ELEMENT = "model"; - private static String NAMED_QUERY_ELEMENT = "named-query"; - - public static IModelParser createModelParser(byte[] artifactPayload, String artifactName) { - Document doc = null; - - try { - String payload = new String(artifactPayload); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder; - builder = factory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(payload)); - doc = builder.parse(is); - } catch (Exception e) { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse artifact " + artifactName); - return null; - } - - if (doc.getDocumentElement().getNodeName().equalsIgnoreCase(NAMED_QUERY_ELEMENT)) { - return new NamedQueryArtifactParser(); - } - - if (!doc.getDocumentElement().getNodeName().equalsIgnoreCase(MODEL_ELEMENT)) { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse artifact " + artifactName - + ": Invalid root element: " + doc.getDocumentElement().getNodeName()); - return null; - } - - Element e = doc.getDocumentElement(); - String ns = e.getAttribute("xmlns"); - String[] parts = ns.split("/"); - - if (parts.length < 1) { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse artifact " + artifactName - + ": Could not parse namespace version"); - return null; - } - - String modelNamespaceVersion = parts[parts.length-1].trim().replace("v", ""); - int version = Integer.parseInt(modelNamespaceVersion); - - if (version > 8) { - return new ModelArtifactParser(); - } - - return new ModelV8ArtifactParser(); - } -} diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelSorter.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelSorter.java index 41c873e..e8fcf3f 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelSorter.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/ModelSorter.java @@ -20,214 +20,223 @@ */ package org.onap.aai.modelloader.entity.model; -import jline.internal.Log; - import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import jline.internal.Log; import org.onap.aai.modelloader.entity.Artifact; /** - * Utility class to sort the given Models according to their dependencies. - * Example: Given a list of Models [A, B, C] where B depends on A, and A depends - * on C, the sorted result will be [C, A, B] + * Utility class to sort the given Models according to their dependencies.
+ * Example: Given a list of Models [A, B, C]
+ * where B depends on A, and A depends on C, the sorted result will be [C, A, B] */ public class ModelSorter { - /** - * Wraps a Model object to form dependencies other Models using Edges. - */ - static class Node { - private final AbstractModelArtifact model; - private final HashSet inEdges; - private final HashSet outEdges; - - public Node(AbstractModelArtifact model) { - this.model = model; - inEdges = new HashSet(); - outEdges = new HashSet(); - } + /** + * Wraps a Model object to form dependencies other Models using Edges. + */ + static class Node { - public Node addEdge(Node node) { - Edge edge = new Edge(this, node); - outEdges.add(edge); - node.inEdges.add(edge); - return this; - } + private final AbstractModelArtifact model; + private final HashSet inEdges; + private final HashSet outEdges; - @Override - public String toString() { - return model.getUniqueIdentifier(); - } + public Node(AbstractModelArtifact model) { + this.model = model; + inEdges = new HashSet<>(); + outEdges = new HashSet<>(); + } - @Override - public boolean equals(Object other) { - AbstractModelArtifact otherModel = ((Node) other).model; - return this.model.getUniqueIdentifier().equals(otherModel.getUniqueIdentifier()); - } + public Node addEdge(Node node) { + Edge edge = new Edge(this, node); + outEdges.add(edge); + node.inEdges.add(edge); + return this; + } - @Override - public int hashCode() { - return this.model.getUniqueIdentifier().hashCode(); - } - } - - /** - * Represents a dependency between two Nodes. - */ - static class Edge { - public final Node from; - public final Node to; - - public Edge(Node from, Node to) { - this.from = from; - this.to = to; - } + @Override + public String toString() { + return model.getUniqueIdentifier(); + } - @Override - public boolean equals(Object obj) { - Edge edge = (Edge) obj; - return edge.from == from && edge.to == to; - } - } - - /** - * Returns the list of models sorted by order of dependency. - * - * @param originalList - * the list that needs to be sorted - * @return a list of sorted models - */ - public List sort(List originalList) { - - if (originalList.size() <= 1) { - return originalList; - } + @Override + public boolean equals(Object other) { + if (other == null || this.getClass() != other.getClass()) { + return false; + } + AbstractModelArtifact otherModel = ((Node) other).model; + return this.model.getUniqueIdentifier().equals(otherModel.getUniqueIdentifier()); + } - Collection nodes = createNodes(originalList); - Collection sortedNodes = sortNodes(nodes); - - List sortedModelsList = new ArrayList(sortedNodes.size()); - for (Node node : sortedNodes) { - sortedModelsList.add(node.model); + @Override + public int hashCode() { + return this.model.getUniqueIdentifier().hashCode(); + } } - return sortedModelsList; - } - - /** - * Create nodes from the list of models and their dependencies. - * - * @param models - * what the nodes creation is based upon - * @return Collection of Node objects - */ - private Collection createNodes(Collection models) { - - // load list of models into a map, so we can later replace referenceIds with - // real Models - HashMap versionIdToModelMap = new HashMap<>(); - for (Artifact art : models) { - AbstractModelArtifact ma = (AbstractModelArtifact) art; - versionIdToModelMap.put(ma.getUniqueIdentifier(), ma); - } + /** + * Represents a dependency between two Nodes. + */ + static class Edge { - HashMap nodes = new HashMap(); - // create a node for each model and its referenced models - for (Artifact art : models) { - - AbstractModelArtifact model = (AbstractModelArtifact) art; - - // node might have been created by another model referencing it - Node node = nodes.get(model.getUniqueIdentifier()); - - if (null == node) { - node = new Node(model); - nodes.put(model.getUniqueIdentifier(), node); - } - - for (String referencedModelId : model.getDependentModelIds()) { - // node might have been created by another model referencing it - Node referencedNode = nodes.get(referencedModelId); - - if (null == referencedNode) { - // create node - AbstractModelArtifact referencedModel = versionIdToModelMap.get(referencedModelId); - if (referencedModel == null) { - Log.debug("ignoring " + referencedModelId); - continue; // referenced model not supplied, no need to sort it - } - referencedNode = new Node(referencedModel); - nodes.put(referencedModelId, referencedNode); - } - referencedNode.addEdge(node); - } - } + public final Node from; + public final Node to; - return nodes.values(); - } - - /** - * Sorts the given Nodes by order of dependency. - * - * @param originalList - * the collection of nodes to be sorted - * @return a sorted collection of the given nodes - */ - private Collection sortNodes(Collection unsortedNodes) { - // L <- Empty list that will contain the sorted elements - ArrayList nodeList = new ArrayList(); - - // S <- Set of all nodes with no incoming edges - HashSet nodeSet = new HashSet(); - for (Node unsortedNode : unsortedNodes) { - if (unsortedNode.inEdges.size() == 0) { - nodeSet.add(unsortedNode); - } + public Edge(Node from, Node to) { + this.from = from; + this.to = to; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + Edge edge = (Edge) obj; + return edge.from == from && edge.to == to; + } + + @Override + public int hashCode() { + return Objects.hash(this.from, this.to); + } } - // while S is non-empty do - while (!nodeSet.isEmpty()) { - // remove a node n from S - Node node = nodeSet.iterator().next(); - nodeSet.remove(node); + /** + * Returns the list of models sorted by order of dependency. + * + * @param originalList the list that needs to be sorted + * @return a list of sorted models + */ + public List sort(List originalList) { - // insert n into L - nodeList.add(node); + if (originalList.size() <= 1) { + return originalList; + } - // for each node m with an edge e from n to m do - for (Iterator it = node.outEdges.iterator(); it.hasNext();) { - // remove edge e from the graph - Edge edge = it.next(); - Node to = edge.to; - it.remove();// Remove edge from n - to.inEdges.remove(edge);// Remove edge from m + Collection nodes = createNodes(originalList); + Collection sortedNodes = sortNodes(nodes); - // if m has no other incoming edges then insert m into S - if (to.inEdges.isEmpty()) { - nodeSet.add(to); + List sortedModelsList = new ArrayList<>(sortedNodes.size()); + for (Node node : sortedNodes) { + sortedModelsList.add(node.model); } - } - } - // Check to see if all edges are removed - boolean cycle = false; - for (Node node : unsortedNodes) { - if (!node.inEdges.isEmpty()) { - cycle = true; - break; - } + + return sortedModelsList; } - if (cycle) { - throw new RuntimeException( - "Circular dependency present between models, topological sort not possible"); + + /** + * Create nodes from the list of models and their dependencies. + * + * @param models what the nodes creation is based upon + * @return Collection of Node objects + */ + private Collection createNodes(Collection models) { + + // load list of models into a map, so we can later replace referenceIds with real Models + Map versionIdToModelMap = new HashMap<>(); + for (Artifact art : models) { + AbstractModelArtifact ma = (AbstractModelArtifact) art; + versionIdToModelMap.put(ma.getUniqueIdentifier(), ma); + } + + Map nodes = new HashMap<>(); + // create a node for each model and its referenced models + for (Artifact art : models) { + + AbstractModelArtifact model = (AbstractModelArtifact) art; + + // node might have been created by another model referencing it + Node node = nodes.get(model.getUniqueIdentifier()); + + if (null == node) { + node = new Node(model); + nodes.put(model.getUniqueIdentifier(), node); + } + + for (String referencedModelId : model.getDependentModelIds()) { + // node might have been created by another model referencing it + Node referencedNode = nodes.get(referencedModelId); + + if (null == referencedNode) { + // create node + AbstractModelArtifact referencedModel = versionIdToModelMap.get(referencedModelId); + if (referencedModel == null) { + Log.debug("ignoring " + referencedModelId); + continue; // referenced model not supplied, no need to sort it + } + referencedNode = new Node(referencedModel); + nodes.put(referencedModelId, referencedNode); + } + referencedNode.addEdge(node); + } + } + + return nodes.values(); } - return nodeList; - } + /** + * Sorts the given Nodes by order of dependency. + * + * @param unsortedNodes the collection of nodes to be sorted + * @return a sorted collection of the given nodes + */ + private Collection sortNodes(Collection unsortedNodes) { + // L <- Empty list that will contain the sorted elements + List nodeList = new ArrayList<>(); + + // S <- Set of all nodes with no incoming edges + Set nodeSet = new HashSet<>(); + for (Node unsortedNode : unsortedNodes) { + if (unsortedNode.inEdges.isEmpty()) { + nodeSet.add(unsortedNode); + } + } + // while S is non-empty do + while (!nodeSet.isEmpty()) { + // remove a node n from S + Node node = nodeSet.iterator().next(); + nodeSet.remove(node); + + // insert n into L + nodeList.add(node); + + // for each node m with an edge e from n to m do + for (Iterator it = node.outEdges.iterator(); it.hasNext();) { + // remove edge e from the graph + Edge edge = it.next(); + Node to = edge.to; + it.remove();// Remove edge from n + to.inEdges.remove(edge);// Remove edge from m + + // if m has no other incoming edges then insert m into S + if (to.inEdges.isEmpty()) { + nodeSet.add(to); + } + } + } + // Check to see if all edges are removed + boolean cycle = false; + for (Node node : unsortedNodes) { + if (!node.inEdges.isEmpty()) { + cycle = true; + break; + } + } + if (cycle) { + throw new RuntimeException("Circular dependency present between models, topological sort not possible"); + } + + return nodeList; + } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelV8Artifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelV8Artifact.java deleted file mode 100644 index cd7afef..0000000 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelV8Artifact.java +++ /dev/null @@ -1,120 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * 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.aai.modelloader.entity.model; - -import java.util.List; - -import javax.ws.rs.core.Response; - -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.Artifact; -import org.onap.aai.modelloader.entity.ArtifactType; -import org.onap.aai.modelloader.restclient.AaiRestClient; -import org.onap.aai.modelloader.service.ModelLoaderMsgs; -import org.onap.aai.cl.api.Logger; -import org.onap.aai.cl.eelf.LoggerFactory; - -import com.sun.jersey.api.client.ClientResponse; - -public class ModelV8Artifact extends AbstractModelArtifact { - private static String AAI_CONVERSION_URL = "/aai/tools/modeltransform"; - - private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifact.class.getName()); - - private String modelNameVersionId; - private ModelArtifact translatedModel; - - public ModelV8Artifact() { - super(ArtifactType.MODEL_V8); - } - - public String getModelNameVersionId() { - return modelNameVersionId; - } - - public void setModelNameVersionId(String modelNameVersionId) { - this.modelNameVersionId = modelNameVersionId; - } - - @Override - public String getUniqueIdentifier() { - return getModelNameVersionId(); - } - - @Override - public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, List addedModels) { - // For a legacy model (version <= v8), we need to call out to an A&AI endpoint to convert to the proper format - ClientResponse response = aaiClient.postResource(getConversionUrl(config), constructTransformPayload(), distId, AaiRestClient.MimeType.XML); - if ( (response == null) || (response.getStatus() != Response.Status.OK.getStatusCode()) ) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed for " + - getType().toString() + " " + getModelNameVersionId() + ". Unable to convert model. Rolling back distribution."); - return false; - } - - String translatedPayload = response.getEntity(String.class); - - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Translated artifact payload:\n" + translatedPayload); - - ModelArtifactParser parser = new ModelArtifactParser(); - - List parsedArtifacts = parser.parse(translatedPayload.getBytes(), "translated-payload"); - if (parsedArtifacts == null || parsedArtifacts.isEmpty()) { - return false; - } - - translatedModel = (ModelArtifact)parsedArtifacts.get(0); - return translatedModel.push(aaiClient, config, distId, addedModels); - } - - @Override - public void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId) { - if (translatedModel != null) { - translatedModel.rollbackModel(aaiClient, config, distId); - } - } - - - private String constructTransformPayload() { - // A&AI requires that to transform a legacy model, we need to use the v8 namespace (even - // if the version < 8) - return getPayload().replaceFirst("aai.inventory/v.", "aai.inventory/v8"); - } - - private String getConversionUrl(ModelLoaderConfig config) { - String baseUrl = config.getAaiBaseUrl().trim(); - String subUrl = AAI_CONVERSION_URL; - - if ( (!baseUrl.endsWith("/")) && (!subUrl.startsWith("/")) ) { - baseUrl = baseUrl + "/"; - } - - if ( baseUrl.endsWith("/") && subUrl.startsWith("/") ) { - baseUrl = baseUrl.substring(0, baseUrl.length()-1); - } - - if (!subUrl.endsWith("/")) { - subUrl = subUrl + "/"; - } - - String url = baseUrl + subUrl; - return url; - } -} diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelV8ArtifactParser.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelV8ArtifactParser.java deleted file mode 100644 index 0e0c88b..0000000 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelV8ArtifactParser.java +++ /dev/null @@ -1,133 +0,0 @@ -/** - * ============LICENSE_START========================================== - * org.onap.aai - * =================================================================== - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * =================================================================== - * 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.aai.modelloader.entity.model; - -import org.onap.aai.modelloader.entity.Artifact; -import org.onap.aai.modelloader.service.ModelLoaderMsgs; -import org.onap.aai.cl.api.Logger; -import org.onap.aai.cl.eelf.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - - -public class ModelV8ArtifactParser implements IModelParser { - - private static String MODEL_NAME_VERSION_ID = "model-name-version-id"; - private static String RELATIONSHIP_DATA = "relationship-data"; - private static String RELATIONSHIP_KEY = "relationship-key"; - private static String RELATIONSHIP_VALUE = "relationship-value"; - private static String MODEL_ELEMENT_RELATIONSHIP_KEY = "model.model-name-version-id"; - - - private static Logger logger = LoggerFactory.getInstance().getLogger(ModelV8ArtifactParser.class.getName()); - @Override - public List parse(byte[] artifactPayload, String artifactName) { - String payload = new String(artifactPayload); - List modelList = new ArrayList<>(); - - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(payload)); - Document doc = builder.parse(is); - - ModelV8Artifact model = parseModel(doc.getDocumentElement(), payload); - - if (model != null) { - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Model parsed =====>>>> " + "Model-Named-Version-Id: "+ model.getModelNameVersionId()); - modelList.add(model); - } - else { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse legacy model artifact " + artifactName); - return null; - } - } - catch (Exception ex) { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse legacy model artifact " + artifactName + ": " + ex.getLocalizedMessage()); - } - - return modelList; - } - - private ModelV8Artifact parseModel(Node modelNode, String payload) { - ModelV8Artifact model = new ModelV8Artifact(); - model.setPayload(payload); - - Element e = (Element)modelNode; - model.setModelNamespace(e.getAttribute("xmlns")); - - parseNode(modelNode, model); - - if (model.getModelNameVersionId() == null) { - return null; - } - - return model; - } - - private void parseNode(Node node, ModelV8Artifact model) { - if (node.getNodeName().equalsIgnoreCase(MODEL_NAME_VERSION_ID)) { - model.setModelNameVersionId(node.getTextContent().trim()); - } - else if (node.getNodeName().equalsIgnoreCase(RELATIONSHIP_DATA)) { - parseRelationshipNode(node, model); - } - else { - NodeList nodeList = node.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node childNode = nodeList.item(i); - parseNode(childNode, model); - } - } - } - - private void parseRelationshipNode(Node node, ModelV8Artifact model) { - String key = null; - String value = null; - - NodeList nodeList = node.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node childNode = nodeList.item(i); - if (childNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_KEY)) { - key = childNode.getTextContent().trim(); - } - else if (childNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_VALUE)) { - value = childNode.getTextContent().trim(); - } - } - - if ( (key != null) && (key.equalsIgnoreCase(MODEL_ELEMENT_RELATIONSHIP_KEY )) && (value != null) ) { - - model.addDependentModelId(value); - - } - } -} diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java index 1e1f3a2..668a751 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java @@ -21,7 +21,7 @@ package org.onap.aai.modelloader.entity.model; import java.util.List; - +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.onap.aai.modelloader.config.ModelLoaderConfig; @@ -31,81 +31,80 @@ import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; -import com.sun.jersey.api.client.ClientResponse; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.restclient.client.OperationResult; public class NamedQueryArtifact extends AbstractModelArtifact { - - private Logger logger = LoggerFactory.getInstance().getLogger(NamedQueryArtifact.class.getName()); - - private String namedQueryUuid; - - public NamedQueryArtifact() { - super(ArtifactType.NAMED_QUERY); - } - - public String getNamedQueryUuid() { - return namedQueryUuid; - } - - public void setNamedQueryUuid(String namedQueryUuid) { - this.namedQueryUuid = namedQueryUuid; - } - - @Override - public String getUniqueIdentifier() { - return getNamedQueryUuid(); - } - - @Override - public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, List addedModels) { - ClientResponse getResponse = aaiClient.getResource(getNamedQueryUrl(config), distId, AaiRestClient.MimeType.XML); - if ( (getResponse == null) || (getResponse.getStatus() != Response.Status.OK.getStatusCode()) ) { - // Only attempt the PUT if the model doesn't already exist - ClientResponse putResponse = aaiClient.putResource(getNamedQueryUrl(config), getPayload(), distId, AaiRestClient.MimeType.XML); - if ( (putResponse != null) && (putResponse.getStatus() == Response.Status.CREATED.getStatusCode()) ) { - addedModels.add(this); - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, getType().toString() + " " + getUniqueIdentifier() + " successfully ingested."); - } - else { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed for " + getType().toString() + " " + getUniqueIdentifier() + - ". Rolling back distribution."); - return false; - } + + private Logger logger = LoggerFactory.getInstance().getLogger(NamedQueryArtifact.class.getName()); + + private String namedQueryUuid; + + public NamedQueryArtifact() { + super(ArtifactType.NAMED_QUERY); } - else { - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, getType().toString() + " " + getUniqueIdentifier() + " already exists. Skipping ingestion."); + + public String getNamedQueryUuid() { + return namedQueryUuid; + } + + public void setNamedQueryUuid(String namedQueryUuid) { + this.namedQueryUuid = namedQueryUuid; } - - return true; - } - - @Override - public void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId) { - // Best effort to delete. Nothing we can do in the event this fails. - aaiClient.getAndDeleteResource(getNamedQueryUrl(config), distId); - } - - private String getNamedQueryUrl(ModelLoaderConfig config) { - String baseURL = config.getAaiBaseUrl().trim(); - String subURL = null; - String instance = null; - - subURL = config.getAaiNamedQueryUrl(getModelNamespaceVersion()).trim(); - instance = this.getNamedQueryUuid(); - - if ( (!baseURL.endsWith("/")) && (!subURL.startsWith("/")) ) { - baseURL = baseURL + "/"; + + @Override + public String getUniqueIdentifier() { + return getNamedQueryUuid(); } - if ( baseURL.endsWith("/") && subURL.startsWith("/") ) { - baseURL = baseURL.substring(0, baseURL.length()-1); + @Override + public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, List completedArtifacts) { + OperationResult getResponse = + aaiClient.getResource(getNamedQueryUrl(config), distId, MediaType.APPLICATION_XML_TYPE); + if ((getResponse == null) || (getResponse.getResultCode() != Response.Status.OK.getStatusCode())) { + // Only attempt the PUT if the model doesn't already exist + OperationResult putResponse = aaiClient.putResource(getNamedQueryUrl(config), getPayload(), distId, + MediaType.APPLICATION_XML_TYPE); + if ((putResponse != null) && (putResponse.getResultCode() == Response.Status.CREATED.getStatusCode())) { + completedArtifacts.add(this); + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, + getType().toString() + " " + getUniqueIdentifier() + " successfully ingested."); + } else { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed for " + getType().toString() + + " " + getUniqueIdentifier() + ". Rolling back distribution."); + return false; + } + } else { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, + getType().toString() + " " + getUniqueIdentifier() + " already exists. Skipping ingestion."); + } + + return true; } - if (!subURL.endsWith("/")) { - subURL = subURL + "/"; + @Override + public void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId) { + // Best effort to delete. Nothing we can do in the event this fails. + aaiClient.getAndDeleteResource(getNamedQueryUrl(config), distId); } - String url = baseURL + subURL + instance; - return url; - } + private String getNamedQueryUrl(ModelLoaderConfig config) { + String baseURL = config.getAaiBaseUrl().trim(); + String subURL = config.getAaiNamedQueryUrl(getModelNamespaceVersion()).trim(); + String instance = this.getNamedQueryUuid(); + + if ((!baseURL.endsWith("/")) && (!subURL.startsWith("/"))) { + baseURL = baseURL + "/"; + } + + if (baseURL.endsWith("/") && subURL.startsWith("/")) { + baseURL = baseURL.substring(0, baseURL.length() - 1); + } + + if (!subURL.endsWith("/")) { + subURL = subURL + "/"; + } + + return baseURL + subURL + instance; + } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifactParser.java b/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifactParser.java index 8188b28..5b9488e 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifactParser.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifactParser.java @@ -20,114 +20,86 @@ */ package org.onap.aai.modelloader.entity.model; +import java.util.List; + import org.onap.aai.modelloader.entity.Artifact; import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Node; -public class NamedQueryArtifactParser implements IModelParser { +public class NamedQueryArtifactParser extends AbstractModelArtifactParser { - private static String NAMED_QUERY_VERSION_ID = "named-query-uuid"; - private static String RELATIONSHIP_DATA = "relationship-data"; - private static String RELATIONSHIP_KEY = "relationship-key"; - private static String RELATIONSHIP_VALUE = "relationship-value"; - private static String MODEL_ELEMENT_RELATIONSHIP_KEY = "model.model-invariant-id"; + private static final String NAMED_QUERY_VERSION_ID = "named-query-uuid"; + private static final String MODEL_ELEMENT_RELATIONSHIP_KEY = "model.model-invariant-id"; - - private static Logger logger = LoggerFactory.getInstance().getLogger(NamedQueryArtifactParser.class.getName()); - - public List parse(byte[] artifactPayload, String artifactName) { - String payload = new String(artifactPayload); - List modelList = new ArrayList(); + private static Logger logger = LoggerFactory.getInstance().getLogger(NamedQueryArtifactParser.class.getName()); - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(payload)); - Document doc = builder.parse(is); + /** + * {@inheritDoc} + */ + @Override + boolean processParsedModel(List modelList, String artifactName, IModelArtifact model) { + boolean valid = false; - NamedQueryArtifact model = parseModel(doc.getDocumentElement(), payload); + if (model != null) { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, + "Named-Query parsed =====>>>> " + "Named-Query-UUID: " + ((NamedQueryArtifact) model) + .getNamedQueryUuid()); + modelList.add((NamedQueryArtifact) model); - if (model != null) { - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Named-Query parsed =====>>>> " + "Named-Query-UUID: "+ model.getNamedQueryUuid()); - modelList.add(model); - } - else { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse named-query artifact " + artifactName); - return null; - } - } - catch (Exception ex) { - logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, "Unable to parse named-query artifact " + artifactName + ": " + ex.getLocalizedMessage()); - } + valid = true; + } else { + logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, + "Unable to parse named-query artifact " + artifactName); + } - return modelList; - } + return valid; + } - private NamedQueryArtifact parseModel(Node modelNode, String payload) { - NamedQueryArtifact model = new NamedQueryArtifact(); - model.setPayload(payload); + /** + * {@inheritDoc} + */ + @Override + String buildArtifactParseExceptionMessage(String artifactName, String localisedMessage) { + return "Unable to parse named-query artifact " + artifactName + ": " + localisedMessage; + } - Element e = (Element)modelNode; - model.setModelNamespace(e.getAttribute("xmlns")); + @Override + String getModelElementRelationshipKey() { + return MODEL_ELEMENT_RELATIONSHIP_KEY; + } - parseNode(modelNode, model); + /** + * {@inheritDoc} + */ + @Override + String getVersionIdNodeName() { + return NAMED_QUERY_VERSION_ID; + } - if (model.getNamedQueryUuid() == null) { - return null; + /** + * {@inheritDoc} + */ + @Override + void setVersionId(IModelArtifact model, Node node) { + ((NamedQueryArtifact) model).setNamedQueryUuid(node.getTextContent().trim()); } - return model; - } - - private void parseNode(Node node, NamedQueryArtifact model) { - if (node.getNodeName().equalsIgnoreCase(NAMED_QUERY_VERSION_ID)) { - model.setNamedQueryUuid(node.getTextContent().trim()); - } - else if (node.getNodeName().equalsIgnoreCase(RELATIONSHIP_DATA)) { - parseRelationshipNode(node, model); - } - else { - NodeList nodeList = node.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node childNode = nodeList.item(i); - parseNode(childNode, model); - } - } - } - - private void parseRelationshipNode(Node node, NamedQueryArtifact model) { - String key = null; - String value = null; - - NodeList nodeList = node.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node childNode = nodeList.item(i); - if (childNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_KEY)) { - key = childNode.getTextContent().trim(); - } - else if (childNode.getNodeName().equalsIgnoreCase(RELATIONSHIP_VALUE)) { - value = childNode.getTextContent().trim(); - } + /** + * {@inheritDoc} + */ + @Override + IModelArtifact createModelArtifactInstance() { + return new NamedQueryArtifact(); } - - if ( (key != null) && (key.equalsIgnoreCase(MODEL_ELEMENT_RELATIONSHIP_KEY )) ) { - if (value != null) { - model.addDependentModelId(value); - } + + /** + * {@inheritDoc} + */ + @Override + boolean modelIsValid(IModelArtifact model) { + return ((NamedQueryArtifact) model).getNamedQueryUuid() != null; } - } } diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/Pair.java b/src/main/java/org/onap/aai/modelloader/entity/model/Pair.java new file mode 100644 index 0000000..ede60eb --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/entity/model/Pair.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.entity.model; + +/** + * Utility class to pair a key and value + * + * @param key + * @param value + */ +class Pair { + private K key; + private V value; + + public void setKey(K key) { + this.key = key; + } + + public K getKey() { + return key; + } + + public void setValue(V value) { + this.value = value; + } + + public V getValue() { + return value; + } + + @Override + public String toString() { + return key + "=" + value; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/extraction/ArtifactInfoExtractor.java b/src/main/java/org/onap/aai/modelloader/extraction/ArtifactInfoExtractor.java new file mode 100644 index 0000000..7dbc34f --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/extraction/ArtifactInfoExtractor.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.extraction; + +import java.util.ArrayList; +import java.util.List; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.api.notification.IResourceInstance; + +/** + * This class is responsible for extracting implementations of IArtifactInto from an implementation of + * INotificationData. + */ +public class ArtifactInfoExtractor { + + /** + * This method is responsible for extracting a collection of IArtifactInfo objects from a given instance of + * INotificationData. + *

+ * + * @param data an object that may contain instances of IArtifactInfo + * @return List instances of IArtifactInfo extracted from the given data + */ + public List extract(INotificationData data) { + List artifacts = new ArrayList<>(); + + if (data != null) { + if (data.getServiceArtifacts() != null) { + artifacts.addAll(data.getServiceArtifacts()); + } + + if (data.getResources() != null) { + for (IResourceInstance resource : data.getResources()) { + if (resource.getArtifacts() != null) { + artifacts.addAll(resource.getArtifacts()); + } + } + } + } + + return artifacts; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/extraction/InvalidArchiveException.java b/src/main/java/org/onap/aai/modelloader/extraction/InvalidArchiveException.java new file mode 100644 index 0000000..5e6353f --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/extraction/InvalidArchiveException.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.extraction; + +/** + * This class represents an exception encountered when processing an archive in memory. + */ +public class InvalidArchiveException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructor for an instance of this exception with just a message. + * + * @param message information about the exception + */ + public InvalidArchiveException(String message) { + super(message); + } + + /** + * Constructor for an instance of this exception with a message and actual exception encountered. + * + * @param message information about the exception + * @param cause the actual exception that was encountered + */ + InvalidArchiveException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManager.java b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManager.java new file mode 100644 index 0000000..6d75306 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDeploymentManager.java @@ -0,0 +1,123 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +import java.util.ArrayList; +import java.util.List; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifactHandler; +import org.onap.aai.modelloader.entity.model.ModelArtifactHandler; +import org.onap.aai.modelloader.restclient.AaiRestClient; +import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; + +/** + * This class is responsible for deploying model and catalog artifacts. + */ +public class ArtifactDeploymentManager { + + private IDistributionClient client; + private ModelLoaderConfig config; + private ModelArtifactHandler modelArtifactHandler; + private VnfCatalogArtifactHandler vnfCatalogArtifactHandler; + private NotificationPublisher notificationPublisher; + + public ArtifactDeploymentManager(IDistributionClient client, ModelLoaderConfig config) { + this.client = client; + this.config = config; + } + + /** + * Deploys model and catalog artifacts to A&AI + * + * @param data data about the notification that is being processed + * @param artifacts the specific artifacts found in the data. + * @param modelArtifacts collection of artifacts that represent yml files found in a TOSCA_CSAR file that have been + * converted to XML and also those for model query specs + * @param catalogArtifacts collection of artifacts that represent vnf catalog files + * @return boolean true if all deployments were successful otherwise false + */ + public boolean deploy(final INotificationData data, final List artifacts, + final List modelArtifacts, final List catalogArtifacts) { + + AaiRestClient aaiClient = new AaiRestClient(config); + String distributionId = data.getDistributionID(); + + List completedArtifacts = new ArrayList<>(); + boolean deploySuccess = + getModelArtifactHandler().pushArtifacts(modelArtifacts, distributionId, completedArtifacts, aaiClient); + + if (!deploySuccess) { + getModelArtifactHandler().rollback(completedArtifacts, distributionId, aaiClient); + } else { + List completedImageData = new ArrayList<>(); + deploySuccess = getVnfCatalogArtifactHandler().pushArtifacts(catalogArtifacts, distributionId, + completedImageData, aaiClient); + if (!deploySuccess) { + getModelArtifactHandler().rollback(completedArtifacts, distributionId, aaiClient); + getVnfCatalogArtifactHandler().rollback(completedImageData, distributionId, aaiClient); + } + } + + publishNotifications(data, "TOSCA_CSAR", artifacts, deploySuccess); + + return deploySuccess; + } + + private void publishNotifications(INotificationData data, String filterType, List artifacts, + boolean deploymentSuccess) { + if (deploymentSuccess) { + artifacts.stream().filter(a -> filterType.equalsIgnoreCase(a.getArtifactType())) + .forEach(a -> getNotificationPublisher().publishDeploySuccess(client, data, a)); + getNotificationPublisher().publishComponentSuccess(client, data); + } else { + artifacts.stream().filter(a -> filterType.equalsIgnoreCase(a.getArtifactType())) + .forEach(a -> getNotificationPublisher().publishDeployFailure(client, data, a)); + getNotificationPublisher().publishComponentFailure(client, data, "deploy failure"); + } + } + + private ModelArtifactHandler getModelArtifactHandler() { + if (modelArtifactHandler == null) { + modelArtifactHandler = new ModelArtifactHandler(config); + } + + return modelArtifactHandler; + } + + private NotificationPublisher getNotificationPublisher() { + if (notificationPublisher == null) { + notificationPublisher = new NotificationPublisher(); + } + + return notificationPublisher; + } + + private VnfCatalogArtifactHandler getVnfCatalogArtifactHandler() { + if (vnfCatalogArtifactHandler == null) { + this.vnfCatalogArtifactHandler = new VnfCatalogArtifactHandler(config); + } + + return vnfCatalogArtifactHandler; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java new file mode 100644 index 0000000..bdd101e --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java @@ -0,0 +1,250 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Base64; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.onap.aai.babel.service.data.BabelArtifact; +import org.onap.aai.babel.service.data.BabelArtifact.ArtifactType; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.cl.mdc.MdcOverride; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; +import org.onap.aai.modelloader.entity.model.IModelParser; +import org.onap.aai.modelloader.entity.model.NamedQueryArtifactParser; +import org.onap.aai.modelloader.extraction.InvalidArchiveException; +import org.onap.aai.modelloader.restclient.BabelServiceClient; +import org.onap.aai.modelloader.service.ModelLoaderMsgs; +import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.api.results.IDistributionClientDownloadResult; +import org.openecomp.sdc.utils.ArtifactTypeEnum; +import org.openecomp.sdc.utils.DistributionActionResultEnum; + +/** + * This class is responsible for downloading the artifacts from the ASDC. + * + * The downloads can be TOSCA_CSAR files or VNF_CATALOG files. + * + * The status of the download is published. The status of the extraction of yml files from a TOSCA_CSAR file is also + * published as a deployment event. + * + * TOSCA_CSAR file artifacts will be converted into XML and returned as model artifacts. + */ +public class ArtifactDownloadManager { + + private static Logger logger = LoggerFactory.getInstance().getLogger(ArtifactDownloadManager.class); + + private IDistributionClient client; + private NotificationPublisher notificationPublisher; + private BabelArtifactConverter babelArtifactConverter; + private ModelLoaderConfig config; + + public ArtifactDownloadManager(IDistributionClient client, ModelLoaderConfig config) { + this.client = client; + this.config = config; + } + + /** + * This method downloads the artifacts from the ASDC. + * + * @param data data about the notification that is being processed + * @param artifacts the specific artifacts found in the data. + * @param modelArtifacts collection of artifacts for model query specs + * @param catalogArtifacts collection of artifacts that represent vnf catalog files + * @return boolean true if the download process was successful otherwise false + */ + boolean downloadArtifacts(INotificationData data, List artifacts, List modelArtifacts, + List catalogArtifacts) { + boolean success = true; + + for (IArtifactInfo artifact : artifacts) { + try { + IDistributionClientDownloadResult downloadResult = downloadIndividualArtifacts(data, artifact); + processDownloadedArtifacts(modelArtifacts, catalogArtifacts, artifact, downloadResult, data); + } catch (DownloadFailureException e) { + getNotificationPublisher().publishDownloadFailure(client, data, artifact, e.getMessage()); + success = false; + } catch (Exception e) { + getNotificationPublisher().publishDeployFailure(client, data, artifact); + success = false; + } + + if (!success) { + break; + } + } + + return success; + } + + private IDistributionClientDownloadResult downloadIndividualArtifacts(INotificationData data, + IArtifactInfo artifact) throws DownloadFailureException { + // Grab the current time so we can measure the download time for the metrics log + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + MdcOverride override = new MdcOverride(); + override.addAttribute(MdcContext.MDC_START_TIME, ZonedDateTime.now().format(formatter)); + + IDistributionClientDownloadResult downloadResult = client.download(artifact); + + logger.info(ModelLoaderMsgs.DOWNLOAD_COMPLETE, downloadResult.getDistributionActionResult().toString(), + downloadResult.getArtifactPayload() == null ? "null" + : Base64.getEncoder().encodeToString(downloadResult.getArtifactPayload())); + + if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Downloaded artifact: " + artifact.getArtifactName()); + getNotificationPublisher().publishDownloadSuccess(client, data, artifact); + } else { + throw new DownloadFailureException(downloadResult.getDistributionMessageResult()); + } + + return downloadResult; + } + + private void processDownloadedArtifacts(List modelArtifacts, List catalogArtifacts, + IArtifactInfo artifactInfo, IDistributionClientDownloadResult downloadResult, INotificationData data) + throws ProcessToscaArtifactsException, InvalidArchiveException, BabelArtifactParsingException { + if ("TOSCA_CSAR".equalsIgnoreCase(artifactInfo.getArtifactType())) { + processToscaArtifacts(modelArtifacts, catalogArtifacts, downloadResult.getArtifactPayload(), artifactInfo, + data.getDistributionID(), data.getServiceVersion()); + } else if (ArtifactTypeEnum.MODEL_QUERY_SPEC.toString().equalsIgnoreCase(artifactInfo.getArtifactType())) { + processModelQuerySpecArtifact(modelArtifacts, downloadResult); + } else { + logger.info(ModelLoaderMsgs.UNSUPPORTED_ARTIFACT_TYPE, artifactInfo.getArtifactName(), + artifactInfo.getArtifactType()); + throw new InvalidArchiveException("Unsupported artifact type: " + artifactInfo.getArtifactType()); + } + } + + public void processToscaArtifacts(List modelArtifacts, List catalogArtifacts, byte[] payload, + IArtifactInfo artifactInfo, String distributionId, String serviceVersion) + throws ProcessToscaArtifactsException { + try { + BabelServiceClient babelClient = createBabelServiceClient(artifactInfo, serviceVersion); + + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, + "Posting artifact: " + artifactInfo.getArtifactName() + ", version: " + serviceVersion); + + List babelArtifacts = + babelClient.postArtifact(payload, artifactInfo.getArtifactName(), serviceVersion, distributionId); + + // Sort Babel artifacts based on type + Map> artifactMap = + babelArtifacts.stream().collect(Collectors.groupingBy(BabelArtifact::getType)); + + if (artifactMap.containsKey(BabelArtifact.ArtifactType.MODEL)) { + modelArtifacts.addAll( + getBabelArtifactConverter().convertToModel(artifactMap.get(BabelArtifact.ArtifactType.MODEL))); + artifactMap.remove(BabelArtifact.ArtifactType.MODEL); + } + + if (artifactMap.containsKey(BabelArtifact.ArtifactType.VNFCATALOG)) { + catalogArtifacts.addAll(getBabelArtifactConverter() + .convertToCatalog(artifactMap.get(BabelArtifact.ArtifactType.VNFCATALOG))); + artifactMap.remove(BabelArtifact.ArtifactType.VNFCATALOG); + } + + // Log unexpected artifact types + if (!artifactMap.isEmpty()) { + logger.warn(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, + artifactInfo.getArtifactName() + " " + serviceVersion + + ". Unexpected artifact types returned by the babel service: " + + artifactMap.keySet().toString()); + } + + } catch (BabelArtifactParsingException e) { + logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, + "Error for artifact " + artifactInfo.getArtifactName() + " " + serviceVersion + e); + throw new ProcessToscaArtifactsException( + "An error occurred while trying to parse the Babel artifacts: " + e.getLocalizedMessage()); + } catch (Exception e) { + logger.error(ModelLoaderMsgs.BABEL_REST_REQUEST_ERROR, e, "POST", config.getBabelBaseUrl(), + "Error posting artifact " + artifactInfo.getArtifactName() + " " + serviceVersion + " to Babel: " + + e.getLocalizedMessage()); + throw new ProcessToscaArtifactsException( + "An error occurred while calling the Babel service: " + e.getLocalizedMessage()); + } + } + + private BabelServiceClient createBabelServiceClient(IArtifactInfo artifact, String serviceVersion) + throws ProcessToscaArtifactsException { + BabelServiceClient babelClient; + try { + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Creating Babel client"); + babelClient = new BabelServiceClient(config); + } catch (Exception e) { + logger.error(ModelLoaderMsgs.BABEL_REST_REQUEST_ERROR, e, "POST", config.getBabelBaseUrl(), + "Error posting artifact " + artifact.getArtifactName() + " " + serviceVersion + " to Babel: " + + e.getLocalizedMessage()); + throw new ProcessToscaArtifactsException( + "An error occurred tyring to convert the tosca artifacts to xml artifacts: " + + e.getLocalizedMessage()); + } + + return babelClient; + } + + private void processModelQuerySpecArtifact(List modelArtifacts, + IDistributionClientDownloadResult downloadResult) throws BabelArtifactParsingException { + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Processing named query artifact."); + + IModelParser parser = new NamedQueryArtifactParser(); + + List parsedArtifacts = + parser.parse(new String(downloadResult.getArtifactPayload()), downloadResult.getArtifactFilename()); + + if (parsedArtifactsExist(parsedArtifacts)) { + modelArtifacts.addAll(parsedArtifacts); + } else { + throw new BabelArtifactParsingException( + "Could not parse generated XML: " + new String(downloadResult.getArtifactPayload())); + } + } + + private boolean parsedArtifactsExist(List parsedArtifacts) { + return parsedArtifacts != null && !parsedArtifacts.isEmpty(); + } + + private NotificationPublisher getNotificationPublisher() { + if (notificationPublisher == null) { + notificationPublisher = new NotificationPublisher(); + } + + return notificationPublisher; + } + + private BabelArtifactConverter getBabelArtifactConverter() { + if (babelArtifactConverter == null) { + babelArtifactConverter = new BabelArtifactConverter(); + } + + return babelArtifactConverter; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/BabelArtifactConverter.java b/src/main/java/org/onap/aai/modelloader/notification/BabelArtifactConverter.java new file mode 100644 index 0000000..7eb562a --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/BabelArtifactConverter.java @@ -0,0 +1,83 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import org.onap.aai.babel.service.data.BabelArtifact; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifact; +import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; +import org.onap.aai.modelloader.entity.model.ModelArtifact; +import org.onap.aai.modelloader.entity.model.ModelArtifactParser; + +/** + * This class is responsible for converting TOSCA artifacts into instances of {@link ModelArtifact} ready for pushing + * the converted artifacts . + */ +class BabelArtifactConverter { + + /** + * This method converts BabelArtifacts into instances of {@link ModelArtifact}. + * + * @param xmlArtifacts xml artifacts to be parsed + * @return List list of converted model artifacts + * @throws BabelArtifactParsingException if an error occurs trying to parse the generated XML files that were + * converted from tosca artifacts + */ + List convertToModel(List xmlArtifacts) throws BabelArtifactParsingException { + Objects.requireNonNull(xmlArtifacts); + List modelArtifacts = new ArrayList<>(); + ModelArtifactParser modelArtParser = new ModelArtifactParser(); + + // Parse TOSCA payloads + for (BabelArtifact xmlArtifact : xmlArtifacts) { + + List parsedArtifacts = modelArtParser.parse(xmlArtifact.getPayload(), xmlArtifact.getName()); + + if (parsedArtifacts == null || parsedArtifacts.isEmpty()) { + throw new BabelArtifactParsingException("Could not parse generated XML: " + xmlArtifact.getPayload()); + } + + modelArtifacts.addAll(parsedArtifacts); + } + + return modelArtifacts; + } + + /** + * This method converts BabelArtifacts into instances of {@link VnfCatalogArtifact}. + * + * @param xmlArtifacts xml artifacts to be parsed + * @return List list of converted catalog artifacts + */ + List convertToCatalog(List xmlArtifacts) { + Objects.requireNonNull(xmlArtifacts); + List catalogArtifacts = new ArrayList<>(); + + for (BabelArtifact xmlArtifact : xmlArtifacts) { + catalogArtifacts.add(new VnfCatalogArtifact(xmlArtifact.getPayload())); + } + + return catalogArtifacts; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMessageBuilder.java b/src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMessageBuilder.java new file mode 100644 index 0000000..5660ad0 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMessageBuilder.java @@ -0,0 +1,47 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.consumer.IComponentDoneStatusMessage; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.utils.DistributionStatusEnum; + +/** + * This class is responsible for building an instance of {@link DistributionStatusMsg}. + */ +public class CompDoneStatusMessageBuilder { + + private CompDoneStatusMessageBuilder() {} + + /** + * Builds an instance of {@link CompDoneStatusMsg} from the given parameters about the status of the + * distribution of the given artifact. + * + * @param client the distribution client this message pertains to + * @param data data about the notification that resulted in this message being created + * @param status the status of the distribution of the artifact to be reported + * @return IComponentDoneStatusMessage implementation of IComponentDoneStatusMessage from the given parameters + */ + public static IComponentDoneStatusMessage build(IDistributionClient client, INotificationData data, DistributionStatusEnum status) { + return new CompDoneStatusMsg(status, data.getDistributionID(), client.getConfiguration().getConsumerID()); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMsg.java b/src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMsg.java new file mode 100644 index 0000000..db358f3 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/CompDoneStatusMsg.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +import org.openecomp.sdc.api.consumer.IComponentDoneStatusMessage; +import org.openecomp.sdc.utils.DistributionStatusEnum; + +public class CompDoneStatusMsg implements IComponentDoneStatusMessage { + + private DistributionStatusEnum status; + private String distributionId; + private String consumerId; + + /** + * Creates a new DistributionStatusMsg instance. + * + * @param status - The distribution status to be reported. + * @param distributionId - The identifier of the distribution who's status is being rported on. + * @param consumerId - Identifier of the consumer associated with the distribution. + */ + public CompDoneStatusMsg(DistributionStatusEnum status, String distributionId, String consumerId) { + this.status = status; + this.distributionId = distributionId; + this.consumerId = consumerId; + } + + @Override + public long getTimestamp() { + return System.currentTimeMillis(); + } + + @Override + public DistributionStatusEnum getStatus() { + return status; + } + + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public String getConsumerID() { + return consumerId; + } + + @Override + public String getComponentName() { + return "AAI"; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMessageBuilder.java b/src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMessageBuilder.java new file mode 100644 index 0000000..fcfd81c --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMessageBuilder.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.consumer.IDistributionStatusMessage; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.utils.DistributionStatusEnum; + +/** + * This class is responsible for building an instance of {@link DistributionStatusMsg}. + */ +public class DistributionStatusMessageBuilder { + + private DistributionStatusMessageBuilder() {} + + /** + * Builds an instance of {@link DistributionStatusMsg} from the given parameters about the status of the + * distribution of the given artifact. + * + * @param client the distribution client this message pertains to + * @param data data about the notification that resulted in this message being created + * @param artifact the specific artifact to have its distribution status reported on + * @param status the status of the distribution of the artifact to be reported + * @return IDistributionStatusMessage implementation of IDistributionStatusMsg from the given parameters + */ + public static IDistributionStatusMessage build(IDistributionClient client, INotificationData data, + IArtifactInfo artifact, DistributionStatusEnum status) { + return new DistributionStatusMsg(status, data.getDistributionID(), client.getConfiguration().getConsumerID(), + artifact.getArtifactURL()); + } + + /** + * Builds an instance of {@link DistributionStatusMsg} from the given parameters about the status of the + * distribution of the given artifact. + * + * @param client the distribution client this message pertains to + * @param data data about the notification that resulted in this message being created + * @param status the status of the distribution of the artifact to be reported + * @return IDistributionStatusMessage implementation of IDistributionStatusMsg from the given parameters + */ + public static IDistributionStatusMessage build(IDistributionClient client, + INotificationData data, DistributionStatusEnum status) { + return new DistributionStatusMsg(status, data.getDistributionID(), + client.getConfiguration().getConsumerID(), ""); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMsg.java b/src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMsg.java index b4f12a5..cc9fb0b 100644 --- a/src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMsg.java +++ b/src/main/java/org/onap/aai/modelloader/notification/DistributionStatusMsg.java @@ -24,52 +24,50 @@ import org.openecomp.sdc.api.consumer.IDistributionStatusMessage; import org.openecomp.sdc.utils.DistributionStatusEnum; public class DistributionStatusMsg implements IDistributionStatusMessage { - private DistributionStatusEnum status; - private String distributionId; - private String consumerId; - private String artifactUrl; - /** - * Creates a new DistributionStatusMsg instance. - * - * @param status - The distribution status to be reported. - * @param distributionId - The identifier of the distribution who's status is being rported on. - * @param consumerId - Identifier of the consumer associated with the distribution. - * @param artifactUrl - Resource identifier for the artifact. - */ - public DistributionStatusMsg(DistributionStatusEnum status, - String distributionId, - String consumerId, - String artifactUrl) { - this.status = status; - this.distributionId = distributionId; - this.consumerId = consumerId; - this.artifactUrl = artifactUrl; - } + private DistributionStatusEnum status; + private String distributionId; + private String consumerId; + private String artifactUrl; - @Override - public long getTimestamp() { - long currentTimeMillis = System.currentTimeMillis(); - return currentTimeMillis; - } + /** + * Creates a new DistributionStatusMsg instance. + * + * @param status - The distribution status to be reported. + * @param distributionId - The identifier of the distribution who's status is being rported on. + * @param consumerId - Identifier of the consumer associated with the distribution. + * @param artifactUrl - Resource identifier for the artifact. + */ + public DistributionStatusMsg(DistributionStatusEnum status, String distributionId, String consumerId, + String artifactUrl) { + this.status = status; + this.distributionId = distributionId; + this.consumerId = consumerId; + this.artifactUrl = artifactUrl; + } - @Override - public DistributionStatusEnum getStatus() { - return status; - } + @Override + public long getTimestamp() { + return System.currentTimeMillis(); + } - @Override - public String getDistributionID() { - return distributionId; - } + @Override + public DistributionStatusEnum getStatus() { + return status; + } - @Override - public String getConsumerID() { - return consumerId; - } - - @Override - public String getArtifactURL() { - return artifactUrl; - } + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public String getConsumerID() { + return consumerId; + } + + @Override + public String getArtifactURL() { + return artifactUrl; + } } diff --git a/src/main/java/org/onap/aai/modelloader/notification/DownloadFailureException.java b/src/main/java/org/onap/aai/modelloader/notification/DownloadFailureException.java new file mode 100644 index 0000000..73a191a --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/DownloadFailureException.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +/** + * Failure to download a distribution. + */ +class DownloadFailureException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructor for an instance of this exception with just a message. + * + * @param message information about the exception + */ + DownloadFailureException(String message) { + super(message); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java b/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java index fde4826..827ff81 100644 --- a/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java +++ b/src/main/java/org/onap/aai/modelloader/notification/EventCallback.java @@ -20,271 +20,70 @@ */ package org.onap.aai.modelloader.notification; +import java.util.ArrayList; +import java.util.List; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.extraction.ArtifactInfoExtractor; +import org.onap.aai.modelloader.service.ModelLoaderMsgs; import org.openecomp.sdc.api.IDistributionClient; -import org.openecomp.sdc.api.consumer.IDistributionStatusMessage; import org.openecomp.sdc.api.consumer.INotificationCallback; import org.openecomp.sdc.api.notification.IArtifactInfo; import org.openecomp.sdc.api.notification.INotificationData; -import org.openecomp.sdc.api.notification.IResourceInstance; -import org.openecomp.sdc.api.results.IDistributionClientDownloadResult; -import org.openecomp.sdc.api.results.IDistributionClientResult; -import org.openecomp.sdc.utils.ArtifactTypeEnum; -import org.openecomp.sdc.utils.DistributionActionResultEnum; -import org.openecomp.sdc.utils.DistributionStatusEnum; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.Artifact; -import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifact; -import org.onap.aai.modelloader.entity.catalog.VnfCatalogArtifactHandler; -import org.onap.aai.modelloader.entity.model.IModelParser; -import org.onap.aai.modelloader.entity.model.ModelArtifactHandler; -import org.onap.aai.modelloader.entity.model.ModelParserFactory; -import org.onap.aai.modelloader.service.ModelLoaderMsgs; -import org.onap.aai.cl.api.Logger; -import org.onap.aai.cl.eelf.LoggerFactory; -import org.onap.aai.cl.mdc.MdcContext; -import org.onap.aai.cl.mdc.MdcOverride; import org.slf4j.MDC; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; - public class EventCallback implements INotificationCallback { + private static Logger logger = LoggerFactory.getInstance().getLogger(EventCallback.class.getName()); + private static Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(EventCallback.class.getName()); - private IDistributionClient client; - private ModelLoaderConfig config; - private static Logger logger = LoggerFactory.getInstance() - .getLogger(EventCallback.class.getName()); - private static Logger auditLogger = LoggerFactory.getInstance() - .getAuditLogger(EventCallback.class.getName()); - private static Logger metricsLogger = LoggerFactory.getInstance() - .getMetricsLogger(EventCallback.class.getName()); - - private static SimpleDateFormat dateFormatter = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); - - public EventCallback(IDistributionClient client, ModelLoaderConfig config) { - this.client = client; - this.config = config; - } - - @Override - public void activateCallback(INotificationData data) { - // Init MDC - MdcContext.initialize(data.getDistributionID(), "ModelLoader", "", "Event-Bus", ""); - - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, - "Received distribution " + data.getDistributionID()); - - boolean success = true; - List artifacts = getArtifacts(data); - List modelArtifacts = new ArrayList(); - List catalogArtifacts = new ArrayList(); - - for (IArtifactInfo artifact : artifacts) { - // Grab the current time so we can measure the download time for the - // metrics log - long startTimeInMs = System.currentTimeMillis(); - MdcOverride override = new MdcOverride(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - // Download Artifact - IDistributionClientDownloadResult downloadResult = client.download(artifact); - - // Generate metrics log - metricsLogger.info(ModelLoaderMsgs.DOWNLOAD_COMPLETE, null, override, - artifact.getArtifactName(), downloadResult.getDistributionActionResult().toString()); - - if (downloadResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - publishDownloadFailure(data, artifact, downloadResult.getDistributionMessageResult()); - success = false; - break; - } + private ArtifactDeploymentManager artifactDeploymentManager; + private ArtifactDownloadManager artifactDownloadManager; + private IDistributionClient client; + private ModelLoaderConfig config; - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, - "Downloaded artifact: " + artifact.getArtifactName() + " Payload:\n" + new String(downloadResult.getArtifactPayload())); - - publishDownloadSuccess(data, artifact, downloadResult); - - if ((artifact.getArtifactType().compareToIgnoreCase(ArtifactTypeEnum.MODEL_INVENTORY_PROFILE.toString()) == 0) - || (artifact.getArtifactType().compareToIgnoreCase(ArtifactTypeEnum.MODEL_QUERY_SPEC.toString()) == 0)) { - IModelParser parser = ModelParserFactory.createModelParser(downloadResult.getArtifactPayload(), downloadResult.getArtifactName()); - List parsedArtifacts = parser.parse(downloadResult.getArtifactPayload(), downloadResult.getArtifactName()); - if (parsedArtifacts != null && !parsedArtifacts.isEmpty()) { - modelArtifacts.addAll(parsedArtifacts); - } else { - success = false; - publishDeployFailure(data, artifact); - break; - } - } else if (artifact.getArtifactType() - .compareToIgnoreCase(ArtifactTypeEnum.VNF_CATALOG.toString()) == 0) { - catalogArtifacts - .add(new VnfCatalogArtifact(new String(downloadResult.getArtifactPayload()))); - } + public EventCallback(IDistributionClient client, ModelLoaderConfig config) { + this.client = client; + this.config = config; } - String statusString = "SUCCESS"; - if (success) { - ModelArtifactHandler modelHandler = new ModelArtifactHandler(config); - boolean modelDeploySuccess = modelHandler.pushArtifacts(modelArtifacts, - data.getDistributionID()); + @Override + public void activateCallback(INotificationData data) { + MdcContext.initialize(data.getDistributionID(), "ModelLoader", "", "Event-Bus", ""); + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Received distribution " + data.getDistributionID()); - VnfCatalogArtifactHandler catalogHandler = new VnfCatalogArtifactHandler(config); - boolean catalogDeploySuccess = catalogHandler.pushArtifacts(catalogArtifacts, - data.getDistributionID()); + List artifacts = new ArtifactInfoExtractor().extract(data); + List catalogArtifacts = new ArrayList<>(); + List modelArtifacts = new ArrayList<>(); - for (IArtifactInfo artifact : artifacts) { - if ((artifact.getArtifactType() - .compareToIgnoreCase(ArtifactTypeEnum.MODEL_INVENTORY_PROFILE.toString()) == 0) - || (artifact.getArtifactType() - .compareToIgnoreCase(ArtifactTypeEnum.MODEL_QUERY_SPEC.toString()) == 0)) { - if (modelDeploySuccess) { - publishDeploySuccess(data, artifact); - } else { - publishDeployFailure(data, artifact); - statusString = "FAILURE"; - } - } else if (artifact.getArtifactType() - .compareToIgnoreCase(ArtifactTypeEnum.VNF_CATALOG.toString()) == 0) { - if (catalogDeploySuccess) { - publishDeploySuccess(data, artifact); - } else { - publishDeployFailure(data, artifact); - statusString = "FAILURE"; - } - } - } - } else { - statusString = "FAILURE"; - } + boolean success = getArtifactDownloadManager() + .downloadArtifacts(data, artifacts, modelArtifacts, catalogArtifacts); - auditLogger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, - "Processed distribution " + data.getDistributionID() + " (" + statusString + ")"); - MDC.clear(); - } - - private List getArtifacts(INotificationData data) { - List artifacts = new ArrayList(); - List resources = data.getResources(); - - if (data.getServiceArtifacts() != null) { - artifacts.addAll(data.getServiceArtifacts()); - } - - if (resources != null) { - for (IResourceInstance resource : resources) { - if (resource.getArtifacts() != null) { - artifacts.addAll(resource.getArtifacts()); + if (success) { + success = getArtifactDeploymentManager().deploy(data, artifacts, modelArtifacts, catalogArtifacts); } - } - } - - return artifacts; - } - - private void publishDownloadFailure(INotificationData data, IArtifactInfo artifact, - String errorMessage) { - // Grab the current time so we can measure the download time for the metrics - // log - long startTimeInMs = System.currentTimeMillis(); - MdcOverride override = new MdcOverride(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - IDistributionClientResult sendDownloadStatus = client.sendDownloadStatus( - buildStatusMessage(client, data, artifact, DistributionStatusEnum.DOWNLOAD_ERROR)); - metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "download failure", - artifact.getArtifactName(), sendDownloadStatus.getDistributionActionResult().toString()); - - if (sendDownloadStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Failed to publish download failure status: " - + sendDownloadStatus.getDistributionMessageResult()); - } - - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Failed to download artifact " + artifact.getArtifactName() + ": " + errorMessage); - } - - private void publishDownloadSuccess(INotificationData data, IArtifactInfo artifact, - IDistributionClientDownloadResult downloadResult) { - // Grab the current time so we can measure the download time for the metrics - // log - long startTimeInMs = System.currentTimeMillis(); - MdcOverride override = new MdcOverride(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - IDistributionClientResult sendDownloadStatus = client.sendDownloadStatus( - buildStatusMessage(client, data, artifact, DistributionStatusEnum.DOWNLOAD_OK)); - metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "download success", - artifact.getArtifactName(), sendDownloadStatus.getDistributionActionResult().toString()); - if (sendDownloadStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Failed to publish download success status: " - + sendDownloadStatus.getDistributionMessageResult()); + String statusString = success ? "SUCCESS" : "FAILURE"; + auditLogger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, + "Processed distribution " + data.getDistributionID() + " (" + statusString + ")"); + MDC.clear(); } - if (logger.isDebugEnabled()) { - StringBuilder sb = new StringBuilder(); - sb.append("Downloaded artifact:\n"); - sb.append("ArtInfo_Art_Name: " + artifact.getArtifactName()); - sb.append("\nArtInfo_Art_description: " + artifact.getArtifactDescription()); - sb.append("\nArtInfo_Art_CheckSum: " + artifact.getArtifactChecksum()); - sb.append("\nArtInfo_Art_Url: " + artifact.getArtifactURL()); - sb.append("\nArtInfo_Art_Type: " + artifact.getArtifactType()); - sb.append("\nArtInfo_Serv_description: " + data.getServiceDescription()); - sb.append("\nArtInfo_Serv_Name: " + data.getServiceName()); - sb.append("\nGet_serviceVersion: " + data.getServiceVersion()); - sb.append("\nGet_Service_UUID: " + data.getServiceUUID()); - sb.append("\nArtInfo_DistributionId: " + data.getDistributionID()); - logger.debug(sb.toString()); - } - } - - private void publishDeployFailure(INotificationData data, IArtifactInfo artifact) { - // Grab the current time so we can measure the download time for the metrics - // log - long startTimeInMs = System.currentTimeMillis(); - MdcOverride override = new MdcOverride(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - IDistributionClientResult sendStatus = client.sendDeploymentStatus( - buildStatusMessage(client, data, artifact, DistributionStatusEnum.DEPLOY_ERROR)); - metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "deploy failure", - artifact.getArtifactName(), sendStatus.getDistributionActionResult().toString()); + private ArtifactDeploymentManager getArtifactDeploymentManager() { + if (artifactDeploymentManager == null) { + artifactDeploymentManager = new ArtifactDeploymentManager(client, config); + } - if (sendStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Failed to publish deploy failure status: " + sendStatus.getDistributionMessageResult()); + return artifactDeploymentManager; } - } - - private void publishDeploySuccess(INotificationData data, IArtifactInfo artifact) { - // Grab the current time so we can measure the download time for the metrics - // log - long startTimeInMs = System.currentTimeMillis(); - MdcOverride override = new MdcOverride(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - IDistributionClientResult sendStatus = client.sendDownloadStatus( - buildStatusMessage(client, data, artifact, DistributionStatusEnum.DEPLOY_OK)); - metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "deploy success", - artifact.getArtifactName(), sendStatus.getDistributionActionResult().toString()); + private ArtifactDownloadManager getArtifactDownloadManager() { + if (artifactDownloadManager == null) { + artifactDownloadManager = new ArtifactDownloadManager(client, config); + } - if (sendStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, - "Failed to publish deploy success status: " + sendStatus.getDistributionMessageResult()); + return artifactDownloadManager; } - } - - private IDistributionStatusMessage buildStatusMessage(IDistributionClient client, - INotificationData data, IArtifactInfo artifact, DistributionStatusEnum status) { - IDistributionStatusMessage statusMessage = new DistributionStatusMsg(status, - data.getDistributionID(), client.getConfiguration().getConsumerID(), - artifact.getArtifactURL()); - - return statusMessage; - } - } diff --git a/src/main/java/org/onap/aai/modelloader/notification/NotificationPublisher.java b/src/main/java/org/onap/aai/modelloader/notification/NotificationPublisher.java new file mode 100644 index 0000000..447e817 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/NotificationPublisher.java @@ -0,0 +1,228 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +import java.io.FileInputStream; +import java.io.IOException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Properties; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.cl.mdc.MdcOverride; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.service.ModelLoaderMsgs; +import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.api.results.IDistributionClientResult; +import org.openecomp.sdc.utils.DistributionActionResultEnum; +import org.openecomp.sdc.utils.DistributionStatusEnum; + +/** + * This class is responsible for publishing the status of actions performed working with artifacts. + */ +class NotificationPublisher { + + private static Logger logger = LoggerFactory.getInstance().getLogger(NotificationPublisher.class); + private static Logger metricsLogger = LoggerFactory.getInstance().getMetricsLogger(NotificationPublisher.class); + + protected static final String FILESEP = + (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator"); + protected static final String CONFIG_DIR = System.getProperty("CONFIG_HOME") + FILESEP; + protected static final String CONFIG_AUTH_LOCATION = CONFIG_DIR + "auth" + FILESEP; + protected static final String CONFIG_FILE = CONFIG_DIR + "model-loader.properties"; + + private boolean publishingEnabled; + + public NotificationPublisher() { + Properties configProperties = new Properties(); + try { + configProperties.load(new FileInputStream(CONFIG_FILE)); + } catch (IOException e) { + String errorMsg = "Failed to load configuration: " + e.getMessage(); + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, e, errorMsg); + } + + ModelLoaderConfig config = new ModelLoaderConfig(configProperties, CONFIG_AUTH_LOCATION); + + publishingEnabled = !config.getASDCConnectionDisabled(); + } + + /** + * This method is responsible for publishing notification that the download of an artifact failed. + * + * @param client The distribution client this notification relates to + * @param data data about the notification that resulted in this message being created + * @param artifact the specific artifact to have its distribution status reported on + * @param errorMessage the error message that is to be reported + */ + void publishDownloadFailure(IDistributionClient client, INotificationData data, IArtifactInfo artifact, + String errorMessage) { + publishDownloadStatus(DistributionStatusEnum.DOWNLOAD_ERROR, client, data, artifact, "failure"); + + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, + "Failed to download artifact " + artifact.getArtifactName() + ": " + errorMessage); + } + + private void publishDownloadStatus(DistributionStatusEnum distributionStatusEnum, IDistributionClient client, + INotificationData data, IArtifactInfo artifact, String result) { + if (publishingEnabled) { + MdcOverride override = initMDCStartTime(); + + IDistributionClientResult sendDownloadStatus = client.sendDownloadStatus( + DistributionStatusMessageBuilder.build(client, data, artifact, distributionStatusEnum)); + metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "download " + result, + artifact.getArtifactName(), sendDownloadStatus.getDistributionActionResult().toString()); + + if (sendDownloadStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Failed to publish download " + result + + " status: " + sendDownloadStatus.getDistributionMessageResult()); + } + } else { + logPublishingDisabled(distributionStatusEnum.toString(), result); + } + } + + private MdcOverride initMDCStartTime() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + MdcOverride override = new MdcOverride(); + + override.addAttribute(MdcContext.MDC_START_TIME, ZonedDateTime.now().format(formatter)); + + return override; + } + + /** + * This method is responsible for publishing notification that the download of an artifact was successful. + * + * @param client The distribution client this notification relates to + * @param data data about the notification that resulted in this message being created + * @param artifact the specific artifact to have its distribution status reported on + */ + void publishDownloadSuccess(IDistributionClient client, INotificationData data, IArtifactInfo artifact) { + publishDownloadStatus(DistributionStatusEnum.DOWNLOAD_OK, client, data, artifact, "success"); + + if (logger.isDebugEnabled()) { + // @formatter:off + String msg = "Downloaded artifact:\n" + + "ArtInfo_Art_Name: " + artifact.getArtifactName() + + "\nArtInfo_Art_description: " + artifact.getArtifactDescription() + + "\nArtInfo_Art_CheckSum: " + artifact.getArtifactChecksum() + + "\nArtInfo_Art_Url: " + artifact.getArtifactURL() + + "\nArtInfo_Art_Type: " + artifact.getArtifactType() + + "\nArtInfo_Serv_description: " + data.getServiceDescription() + + "\nArtInfo_Serv_Name: " + data.getServiceName() + + "\nGet_serviceVersion: " + data.getServiceVersion() + + "\nGet_Service_UUID: " + data.getServiceUUID() + + "\nArtInfo_DistributionId: " + data.getDistributionID(); + logger.debug(msg); + // @formatter:on + } + } + + /** + * This method is responsible for publishing notification that the deployment of an artifact failed. + * + * @param client The distribution client this notification relates to + * @param data data about the notification that resulted in this message being created + * @param artifact the specific artifact to have its deployment status reported on + */ + void publishDeployFailure(IDistributionClient client, INotificationData data, IArtifactInfo artifact) { + publishDeployStatus(client, data, artifact, DistributionStatusEnum.DEPLOY_ERROR, "failure"); + } + + private void publishDeployStatus(IDistributionClient client, INotificationData data, IArtifactInfo artifact, + DistributionStatusEnum distributionStatusEnum, String result) { + if (publishingEnabled) { + MdcOverride override = initMDCStartTime(); + + IDistributionClientResult sendStatus = client.sendDeploymentStatus( + DistributionStatusMessageBuilder.build(client, data, artifact, distributionStatusEnum)); + metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "deploy " + result, + artifact.getArtifactName(), sendStatus.getDistributionActionResult().toString()); + + if (sendStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, + "Failed to publish deploy " + result + " status: " + sendStatus.getDistributionMessageResult()); + } + } else { + logPublishingDisabled(distributionStatusEnum.toString(), result); + } + } + + /** + * This method is responsible for publishing notification that the deployment of an artifact was succesful. + * + * @param client The distribution client this notification relates to + * @param data data about the notification that resulted in this message being created + * @param artifact the specific artifact to have its deployment status reported on + */ + void publishDeploySuccess(IDistributionClient client, INotificationData data, IArtifactInfo artifact) { + publishDeployStatus(client, data, artifact, DistributionStatusEnum.DEPLOY_OK, "success"); + } + + void publishComponentSuccess(IDistributionClient client, INotificationData data) { + if (publishingEnabled) { + MdcOverride override = initMDCStartTime(); + + IDistributionClientResult sendStatus = client.sendComponentDoneStatus( + CompDoneStatusMessageBuilder.build(client, data, DistributionStatusEnum.COMPONENT_DONE_OK)); + + metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "component done ok", "all", + sendStatus.getDistributionActionResult().toString()); + + if (sendStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, + "Failed to publish component done ok: " + sendStatus.getDistributionMessageResult()); + } + } else { + logPublishingDisabled(DistributionStatusEnum.COMPONENT_DONE_OK.toString(), null); + } + } + + void publishComponentFailure(IDistributionClient client, INotificationData data, String errorReason) { + if (publishingEnabled) { + MdcOverride override = initMDCStartTime(); + + IDistributionClientResult sendStatus = client.sendComponentDoneStatus( + CompDoneStatusMessageBuilder.build(client, data, DistributionStatusEnum.COMPONENT_DONE_ERROR), + errorReason); + + metricsLogger.info(ModelLoaderMsgs.EVENT_PUBLISHED, null, override, "component done error", "all", + sendStatus.getDistributionActionResult().toString()); + + if (sendStatus.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, + "Failed to publish component done error: " + sendStatus.getDistributionMessageResult()); + } + } else { + logPublishingDisabled(DistributionStatusEnum.COMPONENT_DONE_ERROR.toString(), errorReason); + } + } + + private void logPublishingDisabled(String statusType, String message) { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, + "Notification publishing is disabled, skipping publishing of the following status: " + statusType + + " with message: " + message); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/notification/ProcessToscaArtifactsException.java b/src/main/java/org/onap/aai/modelloader/notification/ProcessToscaArtifactsException.java new file mode 100644 index 0000000..6678af6 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/ProcessToscaArtifactsException.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.notification; + +public class ProcessToscaArtifactsException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructor for an instance of this exception with just a message. + * + * @param message information about the exception + */ + public ProcessToscaArtifactsException(String message) { + super(message); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java b/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java index 08d1417..7d2ab09 100644 --- a/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java +++ b/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java @@ -20,461 +20,192 @@ */ package org.onap.aai.modelloader.restclient; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.config.ClientConfig; -import com.sun.jersey.api.client.config.DefaultClientConfig; -import com.sun.jersey.api.client.filter.LoggingFilter; -import com.sun.jersey.client.urlconnection.HTTPSProperties; - -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.restclient.AaiRestClient; -import org.onap.aai.modelloader.service.ModelLoaderMsgs; -import org.onap.aai.cl.api.LogFields; -import org.onap.aai.cl.api.LogLine; +import com.sun.jersey.core.util.MultivaluedMapImpl; // NOSONAR +// import edu.emory.mathcs.backport.java.util.Collections; +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; -import org.onap.aai.cl.mdc.MdcContext; -import org.onap.aai.cl.mdc.MdcOverride; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.service.ModelLoaderMsgs; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.restclient.client.RestClient; +import org.onap.aai.restclient.enums.RestAuthenticationMode; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.io.StringReader; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.cert.X509Certificate; -import java.text.SimpleDateFormat; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; -import javax.ws.rs.core.Response; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - +/** + * Wrapper around the standard A&AI Rest Client interface. This currently uses Jersey client 1.x + * + */ public class AaiRestClient { - public enum MimeType { - XML("application/xml"), JSON("application/json"); - - private String httpType; - - MimeType(String httpType) { - this.httpType = httpType; - } - - String getHttpHeaderType() { - return httpType; - } - } - - private static String HEADER_TRANS_ID = "X-TransactionId"; - private static String HEADER_FROM_APP_ID = "X-FromAppId"; - private static String HEADER_AUTHORIZATION = "Authorization"; - private static String ML_APP_NAME = "ModelLoader"; - private static String RESOURCE_VERSION_PARAM = "resource-version"; - - private static SimpleDateFormat dateFormatter = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); - - private static Logger logger = LoggerFactory.getInstance() - .getLogger(AaiRestClient.class.getName()); - private static Logger metricsLogger = LoggerFactory.getInstance() - .getMetricsLogger(AaiRestClient.class.getName()); - - private ModelLoaderConfig config = null; - - public AaiRestClient(ModelLoaderConfig config) { - this.config = config; - } - /** - * Send a PUT request to the A&AI. - * - * @param url - * - the url - * @param transId - * - transaction ID - * @param payload - * - the XML or JSON payload for the request - * @param mimeType - * - the content type (XML or JSON) - * @return ClientResponse - */ - public ClientResponse putResource(String url, String payload, String transId, MimeType mimeType) { - ClientResponse result = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - long startTimeInMs = 0; - MdcOverride override = new MdcOverride(); + public static final String HEADER_TRANS_ID = "X-TransactionId"; + public static final String HEADER_FROM_APP_ID = "X-FromAppId"; + public static final String ML_APP_NAME = "ModelLoader"; + private static final String RESOURCE_VERSION_PARAM = "resource-version"; - try { - Client client = setupClient(); + private static Logger logger = LoggerFactory.getInstance().getLogger(AaiRestClient.class.getName()); - baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - if (logger.isDebugEnabled()) { - client.addFilter(new LoggingFilter(ps)); - } + private ModelLoaderConfig config = null; - // Grab the current time so that we can use it for metrics purposes later. - startTimeInMs = System.currentTimeMillis(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - if (useBasicAuth()) { - result = client.resource(url).header(HEADER_TRANS_ID, transId) - .header(HEADER_FROM_APP_ID, ML_APP_NAME) - .header(HEADER_AUTHORIZATION, getAuthenticationCredentials()) - .type(mimeType.getHttpHeaderType()).put(ClientResponse.class, payload); - } else { - result = client.resource(url).header(HEADER_TRANS_ID, transId) - .header(HEADER_FROM_APP_ID, ML_APP_NAME).type(mimeType.getHttpHeaderType()) - .put(ClientResponse.class, payload); - } - } catch (Exception ex) { - logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "PUT", url, ex.getLocalizedMessage()); - return null; - } finally { - if (logger.isDebugEnabled()) { - logger.debug(baos.toString()); - } - } - - if ((result != null) && ((result.getStatus() == Response.Status.CREATED.getStatusCode()) - || (result.getStatus() == Response.Status.OK.getStatusCode()))) { - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "PUT", url, - Integer.toString(result.getStatus())); - metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, - new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()) - .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, - result.getResponseStatus().toString()), - override, "PUT", url, Integer.toString(result.getStatus())); - } else { - // If response is not 200 OK, then additionally log the reason - String respMsg = result.getEntity(String.class); - if (respMsg == null) { - respMsg = result.getStatusInfo().getReasonPhrase(); - } - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, "PUT", url, - Integer.toString(result.getStatus()), respMsg); - metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, - new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()) - .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, - result.getResponseStatus().toString()), - override, "PUT", url, Integer.toString(result.getStatus()), respMsg); + public AaiRestClient(ModelLoaderConfig config) { + this.config = config; } - return result; - } - - /** - * Send a DELETE request to the A&AI. - * - * @param url - * - the url - * @param resourceVersion - * - the resource-version of the model to delete - * @param transId - * - transaction ID - * @return ClientResponse - */ - public ClientResponse deleteResource(String url, String resourceVersion, String transId) { - ClientResponse result = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - long startTimeInMs = 0; - MdcOverride override = new MdcOverride(); - try { - Client client = setupClient(); - - baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - if (logger.isDebugEnabled()) { - client.addFilter(new LoggingFilter(ps)); - } - - // Grab the current time so that we can use it for metrics purposes later. - startTimeInMs = System.currentTimeMillis(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - if (useBasicAuth()) { - result = client.resource(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion) - .header(HEADER_TRANS_ID, transId).header(HEADER_FROM_APP_ID, ML_APP_NAME) - .header(HEADER_AUTHORIZATION, getAuthenticationCredentials()) - .delete(ClientResponse.class); - } else { - result = client.resource(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion) - .header(HEADER_TRANS_ID, transId).header(HEADER_FROM_APP_ID, ML_APP_NAME) - .delete(ClientResponse.class); - } - } catch (Exception ex) { - logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "DELETE", url, ex.getLocalizedMessage()); - return null; - } finally { - if (logger.isDebugEnabled()) { - logger.debug(baos.toString()); - } + /** + * Send a GET request to the A&AI for a resource. + * + * @param url + * @param transId + * @param mediaType + * @return + */ + public OperationResult getResource(String url, String transId, MediaType mediaType) { + return setupClient().get(url, buildHeaders(transId), mediaType); } - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "DELETE", url, - Integer.toString(result.getStatus())); - metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, - new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()).setField( - LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResponseStatus().toString()), - override, "DELETE", url, Integer.toString(result.getStatus())); - - return result; - } - - /** - * Send a GET request to the A&AI for a resource. - * - * @param url - * - the url to use - * @param transId - * - transaction ID - * @return ClientResponse - */ - public ClientResponse getResource(String url, String transId, MimeType mimeType) { - ClientResponse result = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - long startTimeInMs = 0; - MdcOverride override = new MdcOverride(); - - try { - Client client = setupClient(); - - baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - if (logger.isDebugEnabled()) { - client.addFilter(new LoggingFilter(ps)); - } - - // Grab the current time so that we can use it for metrics purposes later. - startTimeInMs = System.currentTimeMillis(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - if (useBasicAuth()) { - result = client.resource(url).header(HEADER_TRANS_ID, transId) - .header(HEADER_FROM_APP_ID, ML_APP_NAME).accept(mimeType.getHttpHeaderType()) - .header(HEADER_AUTHORIZATION, getAuthenticationCredentials()).get(ClientResponse.class); - } else { - result = client.resource(url).header(HEADER_TRANS_ID, transId) - .header(HEADER_FROM_APP_ID, ML_APP_NAME).accept(mimeType.getHttpHeaderType()) - .get(ClientResponse.class); - - } - } catch (Exception ex) { - logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, ex.getLocalizedMessage()); - return null; - } finally { - if (logger.isDebugEnabled()) { - logger.debug(baos.toString()); - } + /** + * Send a PUT request to the A&AI. + * + * @param url - the url + * @param payload - the XML or JSON payload for the request + * @param transId - transaction ID + * @param mediaType - the content type (XML or JSON) + * @return operation result + */ + public OperationResult putResource(String url, String payload, String transId, MediaType mediaType) { + logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload); + return setupClient().put(url, payload, buildHeaders(transId), mediaType, mediaType); } - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "GET", url, - Integer.toString(result.getStatus())); - metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, - new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()).setField( - LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResponseStatus().toString()), - override, "GET", url, Integer.toString(result.getStatus())); - - return result; - } - - /** - * Send a POST request to the A&AI. - * - * @param url - * - the url - * @param transId - * - transaction ID - * @param payload - * - the XML or JSON payload for the request - * @param mimeType - * - the content type (XML or JSON) - * @return ClientResponse - */ - public ClientResponse postResource(String url, String payload, String transId, MimeType mimeType) { - ClientResponse result = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - long startTimeInMs = 0; - MdcOverride override = new MdcOverride(); - try { - Client client = setupClient(); - - baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - if (logger.isDebugEnabled()) { - client.addFilter(new LoggingFilter(ps)); - } - - // Grab the current time so that we can use it for metrics purposes later. - startTimeInMs = System.currentTimeMillis(); - override.addAttribute(MdcContext.MDC_START_TIME, dateFormatter.format(startTimeInMs)); - - if (useBasicAuth()) { - result = client.resource(url).header(HEADER_TRANS_ID, transId) - .header(HEADER_FROM_APP_ID, ML_APP_NAME) - .header(HEADER_AUTHORIZATION, getAuthenticationCredentials()) - .type(mimeType.getHttpHeaderType()).post(ClientResponse.class, payload); - } else { - result = client.resource(url).header(HEADER_TRANS_ID, transId) - .header(HEADER_FROM_APP_ID, ML_APP_NAME).type(mimeType.getHttpHeaderType()) - .post(ClientResponse.class, payload); - } - } catch (Exception ex) { - logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "POST", url, ex.getLocalizedMessage()); - return null; - } finally { - if (logger.isDebugEnabled()) { - logger.debug(baos.toString()); - } + /** + * Send a POST request to the A&AI. + * + * @param url - the url + * @param transId - transaction ID + * @param payload - the XML or JSON payload for the request + * @param mimeType - the content type (XML or JSON) + * @return ClientResponse + */ + public OperationResult postResource(String url, String payload, String transId, MediaType mediaType) { + logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_PAYLOAD, payload); + return setupClient().post(url, payload, buildHeaders(transId), mediaType, mediaType); } - if ((result != null) && ((result.getStatus() == Response.Status.CREATED.getStatusCode()) - || (result.getStatus() == Response.Status.OK.getStatusCode()))) { - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, "POST", url, - Integer.toString(result.getStatus())); - metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_SUCCESS, - new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()) - .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, - result.getResponseStatus().toString()), - override, "POST", url, Integer.toString(result.getStatus())); - } else { - // If response is not 200 OK, then additionally log the reason - String respMsg = result.getEntity(String.class); - if (respMsg == null) { - respMsg = result.getStatusInfo().getReasonPhrase(); - } - logger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, "POST", url, - Integer.toString(result.getStatus()), respMsg); - metricsLogger.info(ModelLoaderMsgs.AAI_REST_REQUEST_UNSUCCESSFUL, - new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getStatus()) - .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, - result.getResponseStatus().toString()), - override, "POST", url, Integer.toString(result.getStatus()), respMsg); - } - return result; - } - - /** - * Does a GET on a resource to retrieve the resource version, and then DELETE - * that version. - * - * @param url - * - the url - * @param transId - * - transaction ID - * @return ClientResponse - */ - public ClientResponse getAndDeleteResource(String url, String transId) { - // First, GET the model - ClientResponse getResponse = getResource(url, transId, MimeType.XML); - if ((getResponse == null) || (getResponse.getStatus() != Response.Status.OK.getStatusCode())) { - return getResponse; + /** + * Send a DELETE request to the A&AI. + * + * @param url - the url + * @param resourceVersion - the resource-version of the model to delete + * @param transId - transaction ID + * @return ClientResponse + */ + public OperationResult deleteResource(String url, String resourceVersion, String transId) { + URI uri = UriBuilder.fromUri(url).queryParam(RESOURCE_VERSION_PARAM, resourceVersion).build(); + return setupClient().delete(uri.toString(), buildHeaders(transId), null); } - // Delete the model using the resource version in the response - String resVersion = null; - try { - resVersion = getResourceVersion(getResponse); - } catch (Exception e) { - logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, e.getLocalizedMessage()); - return null; + /** + * Does a GET on a resource to retrieve the resource version, and then DELETE that version. + * + * @param url - the url + * @param transId - transaction ID + * @return ClientResponse + */ + public OperationResult getAndDeleteResource(String url, String transId) { + // First, GET the model + OperationResult getResponse = getResource(url, transId, MediaType.APPLICATION_XML_TYPE); + if ((getResponse == null) || (getResponse.getResultCode() != Response.Status.OK.getStatusCode())) { + return getResponse; + } + + // Delete the model using the resource version in the response + String resVersion = null; + try { + resVersion = getResourceVersion(getResponse); + } catch (Exception e) { + logger.error(ModelLoaderMsgs.AAI_REST_REQUEST_ERROR, "GET", url, e.getLocalizedMessage()); + return null; + } + + return deleteResource(url, resVersion, transId); } - return deleteResource(url, resVersion, transId); - } - - private Client setupClient() throws IOException, GeneralSecurityException { - ClientConfig clientConfig = new DefaultClientConfig(); - - HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { - @Override - public boolean verify(String string, SSLSession ssls) { - return true; - } - }); - - // Create a trust manager that does not validate certificate chains - TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - @Override - public void checkClientTrusted(X509Certificate[] certs, String authType) {} - @Override - public void checkServerTrusted(X509Certificate[] certs, String authType) {} - } }; - - SSLContext ctx = SSLContext.getInstance("TLS"); - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - FileInputStream fin = new FileInputStream(config.getAaiKeyStorePath()); - KeyStore ks = KeyStore.getInstance("PKCS12"); - char[] pwd = config.getAaiKeyStorePassword().toCharArray(); - ks.load(fin, pwd); - kmf.init(ks, pwd); - - ctx.init(kmf.getKeyManagers(), trustAllCerts, null); - clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, - new HTTPSProperties(new HostnameVerifier() { - @Override - public boolean verify(String theString, SSLSession sslSession) { - return true; - } - }, ctx)); - - Client client = Client.create(clientConfig); + public boolean useBasicAuth() { + return (config.getAaiAuthenticationUser() != null) && (config.getAaiAuthenticationPassword() != null); + } - return client; - } + private RestClient setupClient() { + RestClient restClient = new RestClient(); - private String getResourceVersion(ClientResponse response) - throws ParserConfigurationException, SAXException, IOException { - String respData = response.getEntity(String.class); + // @formatter:off + restClient.validateServerHostname(false) + .validateServerCertChain(false) + .clientCertFile(config.getAaiKeyStorePath()) + .clientCertPassword(config.getAaiKeyStorePassword()); + // @formatter:on - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(respData)); - Document doc = builder.parse(is); + if (useBasicAuth()) { + restClient.authenticationMode(RestAuthenticationMode.SSL_BASIC); + restClient.basicAuthUsername(config.getAaiAuthenticationUser()); + restClient.basicAuthPassword(config.getAaiAuthenticationPassword()); + } - NodeList nodeList = doc.getDocumentElement().getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node currentNode = nodeList.item(i); - if (currentNode.getNodeName().equals(RESOURCE_VERSION_PARAM)) { - return currentNode.getTextContent(); - } + return restClient; } - return null; - } - - private String getAuthenticationCredentials() { - - String usernameAndPassword = config.getAaiAuthenticationUser() + ":" - + config.getAaiAuthenticationPassword(); - return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes()); - } + /** + * Create the HTTP headers required for an A&AI operation (GET/POST/PUT/DELETE) + * + * @param transId + * @return map of headers + */ + @SuppressWarnings("unchecked") + private Map> buildHeaders(String transId) { + MultivaluedMap headers = new MultivaluedMapImpl(); + headers.put(HEADER_TRANS_ID, Collections.singletonList(transId)); + headers.put(HEADER_FROM_APP_ID, Collections.singletonList(ML_APP_NAME)); + return headers; + } - public boolean useBasicAuth() { - return (config.getAaiAuthenticationUser() != null) - && (config.getAaiAuthenticationPassword() != null); - } + private String getResourceVersion(OperationResult getResponse) + throws ParserConfigurationException, SAXException, IOException { + String respData = getResponse.getResult(); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource is = new InputSource(new StringReader(respData)); + Document doc = builder.parse(is); + + NodeList nodesList = doc.getDocumentElement().getChildNodes(); + + // @formatter:off + return IntStream.range(0, nodesList.getLength()).mapToObj(nodesList::item) + .filter(childNode -> childNode.getNodeName().equals(RESOURCE_VERSION_PARAM)) + .findFirst() + .map(Node::getTextContent) + .orElse(null); + // @formatter:on + } } diff --git a/src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClient.java b/src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClient.java new file mode 100644 index 0000000..a861580 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/restclient/BabelServiceClient.java @@ -0,0 +1,184 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.restclient; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.json.JsonSanitizer; +import com.sun.jersey.api.client.Client; // NOSONAR +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.ws.rs.core.Response; +import org.json.JSONObject; +import org.onap.aai.babel.service.data.BabelArtifact; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.service.ModelLoaderMsgs; + +/** + * Initial version for testing End to End scenarios + * + */ +public class BabelServiceClient { + + private static Logger logger = LoggerFactory.getInstance().getLogger(BabelServiceClient.class); + + private static final String SSL_PROTOCOL = "TLS"; + private static final String KEYSTORE_ALGORITHM = "SunX509"; + private static final String KEYSTORE_TYPE = "PKCS12"; + + private ModelLoaderConfig config; + private Client client; + + private TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; // NOSONAR + } + + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) { + // Do nothing + } + + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) { + // Do nothing + } + }}; + + public class BabelServiceException extends Exception { + + /** + * Babel Service error response + */ + private static final long serialVersionUID = 1L; + + public BabelServiceException(String message) { + super(message); + } + + } + + /** + * @param config + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws CertificateException + * @throws IOException + * @throws UnrecoverableKeyException + * @throws KeyManagementException + */ + public BabelServiceClient(ModelLoaderConfig config) throws NoSuchAlgorithmException, KeyStoreException, + CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { + this.config = config; + + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Creating Babel Service client"); + + SSLContext ctx = SSLContext.getInstance(SSL_PROTOCOL); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYSTORE_ALGORITHM); + KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE); + + String clientCertPassword = config.getBabelKeyStorePassword(); + + char[] pwd = null; + if (clientCertPassword != null) { + pwd = clientCertPassword.toCharArray(); + } + + String clientCertFileName = config.getBabelKeyStorePath(); + if (clientCertFileName != null) { + FileInputStream fin = new FileInputStream(clientCertFileName); + ks.load(fin, pwd); + kmf.init(ks, pwd); + ctx.init(kmf.getKeyManagers(), trustAllCerts, null); + } else { + ctx.init(null, trustAllCerts, null); + } + + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Initialised context"); + + HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory()); + HttpsURLConnection.setDefaultHostnameVerifier((host, session) -> true); + + client = Client.create(new DefaultClientConfig()); + + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Jersey client created"); + } + + /** + * @param artifactPayload + * @param artifactName + * @param artifactVersion + * @param transactionId + * @return + * @throws BabelServiceException + */ + public List postArtifact(byte[] artifactPayload, String artifactName, String artifactVersion, + String transactionId) throws BabelServiceException { + Objects.requireNonNull(artifactPayload); + + String encodedPayload = Base64.getEncoder().encodeToString(artifactPayload); + + JSONObject obj = new JSONObject(); + obj.put("csar", encodedPayload); + obj.put("artifactVersion", artifactVersion); + obj.put("artifactName", artifactName); + + logger.info(ModelLoaderMsgs.BABEL_REST_REQUEST_PAYLOAD, " Artifact Name: " + artifactName + + " Artifact version: " + artifactVersion + " Artifact payload: " + encodedPayload); + + WebResource webResource = client.resource(config.getBabelBaseUrl() + config.getBabelGenerateArtifactsUrl()); + ClientResponse response = webResource.type("application/json") + .header(AaiRestClient.HEADER_TRANS_ID, Collections.singletonList(transactionId)) + .header(AaiRestClient.HEADER_FROM_APP_ID, Collections.singletonList(AaiRestClient.ML_APP_NAME)) + .post(ClientResponse.class, obj.toString()); + String sanitizedJson = JsonSanitizer.sanitize(response.getEntity(String.class)); + + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Babel response " + response.getStatus() + " " + sanitizedJson); + + if (response.getStatus() != Response.Status.OK.getStatusCode()) { + throw new BabelServiceException(sanitizedJson); + } + + return new Gson().fromJson(sanitizedJson, new TypeToken>() {}.getType()); + } +} diff --git a/src/main/java/org/onap/aai/modelloader/service/ArtifactInfoImpl.java b/src/main/java/org/onap/aai/modelloader/service/ArtifactInfoImpl.java new file mode 100644 index 0000000..e32d92c --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/service/ArtifactInfoImpl.java @@ -0,0 +1,134 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.service; + +import java.util.Collections; +import org.openecomp.sdc.api.notification.IArtifactInfo; + +/** + * This class is an implementation of IArtifactInfo for test purposes. + */ +public class ArtifactInfoImpl implements IArtifactInfo { + + private java.lang.String artifactName; + private java.lang.String artifactType; + private java.lang.String artifactDescription; + private java.lang.String artifactVersion; + + @Override + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(String artifactName) { + this.artifactName = artifactName; + } + + @Override + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + @Override + public String getArtifactURL() { + return null; + } + + @Override + public String getArtifactChecksum() { + return null; + } + + @Override + public String getArtifactDescription() { + return artifactDescription; + } + + public void setArtifactDescription(String artifactDescription) { + this.artifactDescription = artifactDescription; + } + + @Override + public Integer getArtifactTimeout() { + return null; + } + + @Override + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + @Override + public String getArtifactUUID() { + return null; + } + + @Override + public IArtifactInfo getGeneratedArtifact() { + return null; + } + + @Override + public java.util.List getRelatedArtifacts() { + return Collections.emptyList(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ArtifactInfoImpl that = (ArtifactInfoImpl) o; + + if (artifactName != null ? !artifactName.equals(that.artifactName) : that.artifactName != null) { + return false; + } + if (artifactType != null ? !artifactType.equals(that.artifactType) : that.artifactType != null) { + return false; + } + if (artifactDescription != null ? !artifactDescription.equals(that.artifactDescription) + : that.artifactDescription != null) { + return false; + } + return artifactVersion != null ? artifactVersion.equals(that.artifactVersion) : that.artifactVersion == null; + } + + @Override + public int hashCode() { + int result = artifactName != null ? artifactName.hashCode() : 0; + result = 31 * result + (artifactType != null ? artifactType.hashCode() : 0); + result = 31 * result + (artifactDescription != null ? artifactDescription.hashCode() : 0); + result = 31 * result + (artifactVersion != null ? artifactVersion.hashCode() : 0); + return result; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderInterface.java b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderInterface.java index 56ffe63..1b466c8 100644 --- a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderInterface.java +++ b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderInterface.java @@ -21,8 +21,6 @@ package org.onap.aai.modelloader.service; import java.io.IOException; - -import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -30,24 +28,22 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; public interface ModelLoaderInterface { - @GET - @Path("/loadModel/{modelid}") - public Response loadModel(@PathParam("modelid") String modelid); + @GET + @Path("/loadModel/{modelid}") + public Response loadModel(@PathParam("modelid") String modelid); - @PUT - @Path("/saveModel/{modelid}/{modelname}") - public Response saveModel(@PathParam("modelid") String modelid, - @PathParam("modelname") String modelname); + @PUT + @Path("/saveModel/{modelid}/{modelname}") + public Response saveModel(@PathParam("modelid") String modelid, @PathParam("modelname") String modelname); - @POST - @Consumes("application/xml") - @Produces("application/xml") - @Path("/ingestModel/{modelid}") - public Response ingestModel(@PathParam("modelid") String modelid, @Context HttpServletRequest req, - String payload) throws IOException; + @POST + @Consumes("text/plain") + @Produces("application/xml") + @Path("/ingestModel/{modelName}/{modelVersion}") + public Response ingestModel(@PathParam("modelName") String modelid, @PathParam("modelVersion") String modelVersion, + String payload) throws IOException; } diff --git a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderMsgs.java b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderMsgs.java index f8f04fa..ad17a43 100644 --- a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderMsgs.java +++ b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderMsgs.java @@ -21,88 +21,100 @@ package org.onap.aai.modelloader.service; import com.att.eelf.i18n.EELFResourceManager; - import org.onap.aai.cl.eelf.LogMessageEnum; public enum ModelLoaderMsgs implements LogMessageEnum { - /** - * Arguments: None. - */ - LOADING_CONFIGURATION, - - /** - * Arguments: None. - */ - STOPPING_CLIENT, - - /** - * Arguments: {0} = message. - */ - INITIALIZING, - - /** - * Arguments: {0} = reason. - */ - ASDC_CONNECTION_ERROR, - - /** - * Arguments: {0} = message. - */ - DISTRIBUTION_EVENT, - - /** - * Arguments: {0} = error message. - */ - DISTRIBUTION_EVENT_ERROR, - - /** - * Arguments: {0} = request type. - * {1} = endpoint. - * {2} = result code. - */ - AAI_REST_REQUEST_SUCCESS, - - /** - * Arguments: {0} = request type. - * {1} = endpoint. - * {2} = result code. - * {3} = result. - * message - */ - AAI_REST_REQUEST_UNSUCCESSFUL, - - /** - * Arguments: {0} = request type. - * {1} = endpoint. - * {2} = error message. - */ - AAI_REST_REQUEST_ERROR, - - /** - * Arguments: - * {0} = artifact name - */ - ARTIFACT_PARSE_ERROR, - - /** - * Arguments: {0} = artifact name. - * {1} = result. - */ - DOWNLOAD_COMPLETE, - - /** - * Arguments: {0} = event. - * {1} = artifact name. - * {2} = result. - */ - EVENT_PUBLISHED; - - /** - * Load message bundle (ModelLoaderMsgs.properties file) - */ - static { - EELFResourceManager.loadMessageBundle("org/openecomp/modelloader/service/ModelLoaderMsgs"); - } + /** + * Arguments: None. + */ + LOADING_CONFIGURATION, + + /** + * Arguments: None. + */ + STOPPING_CLIENT, + + /** + * Arguments: {0} = message. + */ + INITIALIZING, + + /** + * Arguments: {0} = reason. + */ + ASDC_CONNECTION_ERROR, + + /** + * Arguments: {0} = message. + */ + DISTRIBUTION_EVENT, + + /** + * Arguments: {0} = error message. + */ + DISTRIBUTION_EVENT_ERROR, + + /** + * Arguments: {0} = request type. {1} = endpoint. {2} = result code. + */ + AAI_REST_REQUEST_SUCCESS, + + /** + * Arguments: {0} = request type. {1} = endpoint. {2} = result code. {3} = result. message + */ + AAI_REST_REQUEST_UNSUCCESSFUL, + + /** + * Arguments: {0} = request type. {1} = endpoint. {2} = error message. + */ + AAI_REST_REQUEST_ERROR, + + /** + * Arguments: {0} = request type. {1} = endpoint. {2} = error message. + */ + BABEL_REST_REQUEST_ERROR, + + /** + * Arguments: {0} = info request payload. + **/ + AAI_REST_REQUEST_PAYLOAD, + + /** + * Arguments: {0} = artifact name + */ + ARTIFACT_PARSE_ERROR, + + /** + * Arguments: {0} = info request payload. + **/ + BABEL_REST_REQUEST_PAYLOAD, + + /** + * Arguments: {0} = info Babel response payload. + **/ + BABEL_RESPONSE_PAYLOAD, + + /** + * Arguments: {0} = artifact name. {1} = payload. + */ + DOWNLOAD_COMPLETE, + + /** + * Arguments: {0} = event. {1} = artifact name. {2} = result. + */ + EVENT_PUBLISHED, + + /** + * Arguments: {0} = artifact name. {1} = artifact type. + */ + UNSUPPORTED_ARTIFACT_TYPE; + + /** + * Load message bundle (ModelLoaderMsgs.properties file) + */ + static { + EELFResourceManager.loadMessageBundle("org/onap.aai/modelloader/service/ModelLoaderMsgs"); + } } diff --git a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java index edab788..aa3481c 100644 --- a/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java +++ b/src/main/java/org/onap/aai/modelloader/service/ModelLoaderService.java @@ -20,182 +20,210 @@ */ package org.onap.aai.modelloader.service; -import org.openecomp.sdc.api.IDistributionClient; -import org.openecomp.sdc.api.results.IDistributionClientResult; -import org.openecomp.sdc.impl.DistributionClientFactory; -import org.openecomp.sdc.utils.DistributionActionResultEnum; -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.entity.model.ModelArtifactHandler; -import org.onap.aai.modelloader.notification.EventCallback; -import org.onap.aai.cl.api.Logger; -import org.onap.aai.cl.eelf.LoggerFactory; - import java.io.FileInputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.Base64; import java.util.Date; +import java.util.List; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; -import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.notification.ArtifactDeploymentManager; +import org.onap.aai.modelloader.notification.ArtifactDownloadManager; +import org.onap.aai.modelloader.notification.EventCallback; +import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.api.results.IDistributionClientResult; +import org.openecomp.sdc.impl.DistributionClientFactory; +import org.openecomp.sdc.utils.DistributionActionResultEnum; + /** - * Service class in charge of managing the negotiating model loading - * capabilities between AAI and an ASDC. + * Service class in charge of managing the negotiating model loading capabilities between AAI and an ASDC. */ public class ModelLoaderService implements ModelLoaderInterface { - - protected static final String FILESEP = (System.getProperty("file.separator") == null) ? "/" - : System.getProperty("file.separator"); - - protected static final String CONFIG_DIR = System.getProperty("CONFIG_HOME") + FILESEP; - protected static final String CONFIG_AUTH_LOCATION = CONFIG_DIR + "auth" + FILESEP; - protected static final String CONFIG_FILE = CONFIG_DIR + "model-loader.properties"; - - private IDistributionClient client; - private ModelLoaderConfig config; - private Timer timer = null; - - static Logger logger = LoggerFactory.getInstance().getLogger(ModelLoaderService.class.getName()); - - /** - * Responsible for loading configuration files and calling initialization. - */ - public ModelLoaderService() { - start(); - } - - protected void start() { - // Load model loader system configuration - logger.info(ModelLoaderMsgs.LOADING_CONFIGURATION); - Properties configProperties = new Properties(); - try { - configProperties.load(new FileInputStream(CONFIG_FILE)); - } catch (IOException e) { - String errorMsg = "Failed to load configuration: " + e.getMessage(); - logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); - shutdown(); - } - - config = new ModelLoaderConfig(configProperties, CONFIG_AUTH_LOCATION); - init(); - - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(){ - public void run() { - preShutdownOperations(); - } - })); - } - - /** - * Responsible for stopping the connection to the distribution client before - * the resource is destroyed. - */ - protected void preShutdownOperations() { - logger.info(ModelLoaderMsgs.STOPPING_CLIENT); - if (client != null) { - client.stop(); - } - } - - /** - * Responsible for loading configuration files, initializing model - * distribution clients, and starting them. - */ - protected void init() { - // Initialize distribution client - logger.debug(ModelLoaderMsgs.INITIALIZING, "Initializing distribution client..."); - client = DistributionClientFactory.createDistributionClient(); - EventCallback callback = new EventCallback(client, config); - - IDistributionClientResult initResult = client.init(config, callback); - - if (initResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - String errorMsg = "Failed to initialize distribution client: " - + initResult.getDistributionMessageResult(); - logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); - - // Kick off a timer to retry the SDC connection - timer = new Timer(); - TimerTask task = new SdcConnectionJob(client, config, callback, timer); - timer.schedule(task, new Date(), 60000); - } - else { - // Start distribution client - logger.debug(ModelLoaderMsgs.INITIALIZING, "Starting distribution client..."); - IDistributionClientResult startResult = client.start(); - if (startResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - String errorMsg = "Failed to start distribution client: " - + startResult.getDistributionMessageResult(); - logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); - - // Kick off a timer to retry the SDC connection - timer = new Timer(); - TimerTask task = new SdcConnectionJob(client, config, callback, timer); - timer.schedule(task, new Date(), 60000); - } - else { - logger.info(ModelLoaderMsgs.INITIALIZING, "Connection to SDC established"); - } - } - } - - /** - * Shut down the process. - */ - private void shutdown() { - preShutdownOperations(); - - // TODO: Find a better way to shut down the model loader. - try { - // Give logs time to write to file - Thread.sleep(2000); - } catch (InterruptedException e) { - // Nothing we can do at this point - } - - Runtime.getRuntime().halt(1); - } - - /** (non-Javadoc) - * @see org.onap.aai.modelloader.service.ModelLoaderInterface#loadModel(java.lang.String) - */ - @Override - public Response loadModel(String modelid) { - Response response = Response.ok("{\"model_loaded\":\"" + modelid + "\"}").build(); - - return response; - } - - /** (non-Javadoc) - * @see org.onap.aai.modelloader.service.ModelLoaderInterface#saveModel(java.lang.String, java.lang.String) - */ - @Override - public Response saveModel(String modelid, String modelname) { - Response response = Response.ok("{\"model_saved\":\"" + modelid + "-" + modelname + "\"}") - .build(); - - return response; - } - - @Override - public Response ingestModel(String modelid, HttpServletRequest req, String payload) - throws IOException { - Response response; - - if (config.getIngestSimulatorEnabled()) { - logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Received test artifact"); - - ModelArtifactHandler handler = new ModelArtifactHandler(config); - handler.loadModelTest(payload.getBytes()); - - response = Response.ok().build(); - } else { - logger.debug("Simulation interface disabled"); - response = Response.serverError().build(); - } - - return response; - } + + protected static final String FILESEP = + (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator"); + + protected static final String CONFIG_DIR = System.getProperty("CONFIG_HOME") + FILESEP; + protected static final String CONFIG_AUTH_LOCATION = CONFIG_DIR + "auth" + FILESEP; + protected static final String CONFIG_FILE = CONFIG_DIR + "model-loader.properties"; + + private IDistributionClient client; + private ModelLoaderConfig config; + + static Logger logger = LoggerFactory.getInstance().getLogger(ModelLoaderService.class.getName()); + + /** + * Responsible for loading configuration files and calling initialization. + */ + public ModelLoaderService() { + start(); + } + + protected void start() { + // Load model loader system configuration + logger.info(ModelLoaderMsgs.LOADING_CONFIGURATION); + Properties configProperties = new Properties(); + try { + configProperties.load(new FileInputStream(CONFIG_FILE)); + } catch (IOException e) { + String errorMsg = "Failed to load configuration: " + e.getMessage(); + logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); + shutdown(); + } + + config = new ModelLoaderConfig(configProperties, CONFIG_AUTH_LOCATION); + init(); + + Runtime.getRuntime().addShutdownHook(new Thread(this::preShutdownOperations)); + } + + /** + * Responsible for stopping the connection to the distribution client before the resource is destroyed. + */ + protected void preShutdownOperations() { + logger.info(ModelLoaderMsgs.STOPPING_CLIENT); + if (client != null) { + client.stop(); + } + } + + /** + * Responsible for loading configuration files, initializing model distribution clients, and starting them. + */ + protected void init() { + if (!config.getASDCConnectionDisabled()) { + // Initialize distribution client + logger.debug(ModelLoaderMsgs.INITIALIZING, "Initializing distribution client..."); + client = DistributionClientFactory.createDistributionClient(); + EventCallback callback = new EventCallback(client, config); + + IDistributionClientResult initResult = client.init(config, callback); + + if (initResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + String errorMsg = + "Failed to initialize distribution client: " + initResult.getDistributionMessageResult(); + logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); + + // Kick off a timer to retry the SDC connection + Timer timer = new Timer(); + TimerTask task = new SdcConnectionJob(client, config, callback, timer); + timer.schedule(task, new Date(), 60000); + } else { + // Start distribution client + logger.debug(ModelLoaderMsgs.INITIALIZING, "Starting distribution client..."); + IDistributionClientResult startResult = client.start(); + if (startResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + String errorMsg = + "Failed to start distribution client: " + startResult.getDistributionMessageResult(); + logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); + + // Kick off a timer to retry the SDC connection + Timer timer = new Timer(); + TimerTask task = new SdcConnectionJob(client, config, callback, timer); + timer.schedule(task, new Date(), 60000); + } else { + logger.info(ModelLoaderMsgs.INITIALIZING, "Connection to SDC established"); + } + } + } + } + + /** + * Shut down the process. + */ + private void shutdown() { + preShutdownOperations(); + + // TODO: Find a better way to shut down the model loader. + try { + // Give logs time to write to file + Thread.sleep(2000); + } catch (InterruptedException e) { // NOSONAR + // Nothing we can do at this point + logger.debug(e.getMessage()); + } + + Runtime.getRuntime().halt(1); + } + + /** + * (non-Javadoc) + * + * @see org.onap.aai.modelloader.service.ModelLoaderInterface#loadModel(java.lang.String) + */ + @Override + public Response loadModel(String modelid) { + return Response.ok("{\"model_loaded\":\"" + modelid + "\"}").build(); + } + + /** + * (non-Javadoc) + * + * @see org.onap.aai.modelloader.service.ModelLoaderInterface#saveModel(java.lang.String, java.lang.String) + */ + @Override + public Response saveModel(String modelid, String modelname) { + return Response.ok("{\"model_saved\":\"" + modelid + "-" + modelname + "\"}").build(); + } + + @Override + public Response ingestModel(String modelName, String modelVersion, String payload) throws IOException { + boolean success; + + if (config.getIngestSimulatorEnabled()) { + try { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Received test artifact"); + + List catalogArtifacts = new ArrayList<>(); + List modelArtifacts = new ArrayList<>(); + + IArtifactInfo artifactInfo = new ArtifactInfoImpl(); + ((ArtifactInfoImpl) artifactInfo).setArtifactName(modelName); + ((ArtifactInfoImpl) artifactInfo).setArtifactVersion(modelVersion); + + byte[] csarFile = Base64.getDecoder().decode(payload); + + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Generating xml models from test artifact"); + + new ArtifactDownloadManager(client, config).processToscaArtifacts(modelArtifacts, catalogArtifacts, + csarFile, artifactInfo, "test-transaction-id", modelVersion); + + List artifacts = new ArrayList<>(); + artifacts.add(artifactInfo); + INotificationData notificationData = new NotificationDataImpl(); + ((NotificationDataImpl) notificationData).setDistributionID("TestDistributionID"); + + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Loading xml models from test artifact"); + + success = new ArtifactDeploymentManager(client, config).deploy(notificationData, artifacts, + modelArtifacts, catalogArtifacts); + + } catch (Exception e) { + return Response.serverError().entity(e).build(); + } + } else { + logger.debug("Simulation interface disabled"); + success = false; + } + + Response response; + if (success) { + response = Response.ok().build(); + } else { + response = Response.serverError().build(); + } + + return response; + } } diff --git a/src/main/java/org/onap/aai/modelloader/service/NotificationDataImpl.java b/src/main/java/org/onap/aai/modelloader/service/NotificationDataImpl.java new file mode 100644 index 0000000..28611ff --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/service/NotificationDataImpl.java @@ -0,0 +1,117 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * 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.aai.modelloader.service; + +import java.util.Collections; +import java.util.List; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.api.notification.IResourceInstance; + +public class NotificationDataImpl implements INotificationData { + + private String distributionID; + + @Override + public IArtifactInfo getArtifactMetadataByUUID(String arg0) { + return null; + } + + @Override + public String getDistributionID() { + return distributionID; + } + + public void setDistributionID(String distributionID) { + this.distributionID = distributionID; + } + + @Override + public List getResources() { + return Collections.emptyList(); + } + + @Override + public List getServiceArtifacts() { + return Collections.emptyList(); + } + + @Override + public String getServiceDescription() { + return null; + } + + @Override + public String getServiceInvariantUUID() { + return null; + } + + @Override + public String getServiceName() { + return null; + } + + @Override + public String getServiceUUID() { + return null; + } + + @Override + public String getServiceVersion() { + return null; + } + + @Override + public String getWorkloadContext() { + return null; + } + + @Override + public void setWorkloadContext(String arg0) { + // Unsupported method - not expected to be called + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((distributionID == null) ? 0 : distributionID.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + NotificationDataImpl other = (NotificationDataImpl) obj; + if (distributionID == null) { + if (other.distributionID != null) + return false; + } else if (!distributionID.equals(other.distributionID)) + return false; + return true; + } + +} diff --git a/src/main/java/org/onap/aai/modelloader/service/SdcConnectionJob.java b/src/main/java/org/onap/aai/modelloader/service/SdcConnectionJob.java index 19a6f4e..d30e6dd 100644 --- a/src/main/java/org/onap/aai/modelloader/service/SdcConnectionJob.java +++ b/src/main/java/org/onap/aai/modelloader/service/SdcConnectionJob.java @@ -20,58 +20,54 @@ */ package org.onap.aai.modelloader.service; -import java.util.Date; import java.util.Timer; import java.util.TimerTask; - -import org.onap.aai.modelloader.config.ModelLoaderConfig; -import org.onap.aai.modelloader.notification.EventCallback; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.notification.EventCallback; import org.openecomp.sdc.api.IDistributionClient; import org.openecomp.sdc.api.results.IDistributionClientResult; import org.openecomp.sdc.utils.DistributionActionResultEnum; public class SdcConnectionJob extends TimerTask { - static Logger logger = LoggerFactory.getInstance().getLogger(SdcConnectionJob.class.getName()); + static Logger logger = LoggerFactory.getInstance().getLogger(SdcConnectionJob.class.getName()); - private IDistributionClient client; - private ModelLoaderConfig config; - private EventCallback callback; - private Timer timer; + private IDistributionClient client; + private ModelLoaderConfig config; + private EventCallback callback; + private Timer timer; - public SdcConnectionJob(IDistributionClient client, - ModelLoaderConfig config, - EventCallback callback, - Timer timer) { - this.client = client; - this.timer = timer; - this.callback = callback; - this.config = config; - } + public SdcConnectionJob(IDistributionClient client, ModelLoaderConfig config, EventCallback callback, Timer timer) { + this.client = client; + this.timer = timer; + this.callback = callback; + this.config = config; + } - @Override - public void run() { + @Override + public void run() { + if (!config.getASDCConnectionDisabled()) { - IDistributionClientResult initResult = client.init(config, callback); + IDistributionClientResult initResult = client.init(config, callback); - if (initResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - String errorMsg = "Failed to initialize distribution client: " - + initResult.getDistributionMessageResult(); - logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); - return; - } + if (initResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + String errorMsg = + "Failed to initialize distribution client: " + initResult.getDistributionMessageResult(); + logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); + return; + } - IDistributionClientResult startResult = client.start(); - if (startResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { - String errorMsg = "Failed to start distribution client: " - + startResult.getDistributionMessageResult(); - logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); - return; - } + IDistributionClientResult startResult = client.start(); + if (startResult.getDistributionActionResult() != DistributionActionResultEnum.SUCCESS) { + String errorMsg = "Failed to start distribution client: " + startResult.getDistributionMessageResult(); + logger.error(ModelLoaderMsgs.ASDC_CONNECTION_ERROR, errorMsg); + return; + } - // Success. Cancel the timer job - timer.cancel(); - logger.info(ModelLoaderMsgs.INITIALIZING, "Connection to SDC established"); - } + // Success. Cancel the timer job + timer.cancel(); + logger.info(ModelLoaderMsgs.INITIALIZING, "Connection to SDC established"); + } + } } diff --git a/src/main/java/org/onap/aai/modelloader/util/JsonXmlConverter.java b/src/main/java/org/onap/aai/modelloader/util/JsonXmlConverter.java index 29a4409..a5a7bc5 100644 --- a/src/main/java/org/onap/aai/modelloader/util/JsonXmlConverter.java +++ b/src/main/java/org/onap/aai/modelloader/util/JsonXmlConverter.java @@ -27,53 +27,48 @@ import org.json.XML; public class JsonXmlConverter { - /** - * Determines whether or not the supplied text string represents a valid - * JSON structure or not. - * - * @param text - The text to be evaluated. - * - * @return - true if the string represents a valid JSON object, - * false, otherwise. - */ - public static boolean isValidJson(String text) { - try { - new JSONObject(text); - } catch (JSONException ex) { - try { - new JSONArray(text); - } catch (JSONException ex1) { - return false; - } + private JsonXmlConverter() { + throw new AssertionError("Instantiating utility class."); } - return true; - } + /** + * Determines whether or not the supplied text string represents a valid JSON structure or not. + * + * @param text The text to be evaluated. + * @return - true if the string represents a valid JSON object, false, otherwise. + */ + public static boolean isValidJson(String text) { + try { + new JSONObject(text); + } catch (JSONException ex) { + try { + new JSONArray(text); + } catch (JSONException ex1) { + return false; + } + } - /** - * Takes a text string representing a valid JSON structure and converts it to - * an equivalent XML string. - * - * @param jsonText - The JSON string to convert to XML. - * - * @return - An XML string representation of the supplied JSON string. - */ - public static String convertJsonToXml(String jsonText) { - JSONObject jsonObj = new JSONObject(jsonText); - String xmlText = XML.toString(jsonObj); - return xmlText; - } + return true; + } + + /** + * Takes a text string representing a valid JSON structure and converts it to an equivalent XML string. + * + * @param jsonText The JSON string to convert to XML. + * @return an XML string representation of the supplied JSON string. + */ + public static String convertJsonToXml(String jsonText) { + return XML.toString(new JSONObject(jsonText)); + } - /** - * Takes a text string representing a valid XML structure and converts it to - * an equivalent JSON string. - * - * @param xmlText - The XML string to convert to JSON. - * - * @return - A JSON string representation of the supplied XML string. - */ - public static String convertXmlToJson(String xmlText) { - JSONObject jsonObj = XML.toJSONObject(xmlText); - return jsonObj.toString(); - } + /** + * Takes a text string representing a valid XML structure and converts it to an equivalent JSON string. + * + * @param xmlText The XML string to convert to JSON. + * @return a JSON string representation of the supplied XML string. + */ + public static String convertXmlToJson(String xmlText) { + JSONObject jsonObj = XML.toJSONObject(xmlText); + return jsonObj.toString(); + } } diff --git a/src/main/resources/org/openecomp/modelloader/service/ModelLoaderMsgs.properties b/src/main/resources/org/openecomp/modelloader/service/ModelLoaderMsgs.properties index 8e2d043..112b48c 100644 --- a/src/main/resources/org/openecomp/modelloader/service/ModelLoaderMsgs.properties +++ b/src/main/resources/org/openecomp/modelloader/service/ModelLoaderMsgs.properties @@ -1,21 +1,22 @@ ### -# ============LICENSE_START======================================================= -# MODEL LOADER SERVICE -# ================================================================================ -# 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========================================================= +# ============LICENSE_START========================================== +# org.onap.aai +# =================================================================== +# Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. +# Copyright © 2017-2018 Amdocs +# =================================================================== +# 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============================================ ### #Resource key=Error Code|Message text|Resolution text |Description text @@ -45,74 +46,95 @@ LOADING_CONFIGURATION=\ MDLSVC0001I|\ Loading configuration |\ None. Attempting to load configuration|\ - Attempting to load Model Loader Service configuration + Attempting to load Model Loader Service configuration.|\ STOPPING_CLIENT=\ MDLSVC0002I|\ Stopping distribution client|\ None. Stopping service|\ - Stopping the Model Service distribution client + Stopping the Model Service distribution client.|\ DISTRIBUTION_EVENT=\ MDLSVC0003I|\ Distribution event: {0}|\ None. Processing distribution.|\ - A distribution event was received from the ASDC + A distribution event was received from the ASDC.|\ AAI_REST_REQUEST_SUCCESS=\ MDLSVC0004I|\ Sent {0} request to {1}. Response: {2}|\ None. Successfully sent REST request to AAI.|\ - The given request was sent to the specified endpoint. + The given request was sent to the specified endpoint.|\ AAI_REST_REQUEST_UNSUCCESSFUL=\ MDLSVC0005I|\ Sent {0} request to {1}. Response code: {2}, Response message: {3}|\ REST request to AAI unsuccessful. Check response code, and message. |\ - The given request was unsuccessful. + The given request was unsuccessful.|\ DOWNLOAD_COMPLETE=\ MDLSVC0006I|\ - Download of artifact {0} from ASDC complete. Result: {1}|\ - None.|\ - An artifact was downloaded from the ASDC + Download of artifact {0} from ASDC complete. An artifact was downloaded from the ASDC. Payload: {1}|\ EVENT_PUBLISHED=\ MDLSVC0007I|\ Published {0} event for artifact {1}. Result: {2}|\ None.|\ - An event was published to the event bus + An event was published to the event bus|\ + + +BABEL_REST_REQUEST_PAYLOAD=\ + MDLSVC0008I|\ + Sending request to Babel. {0}|\ + +BABEL_RESPONSE_PAYLOAD=\ + MDLSVC0009I|\ + Received response from Babel. {0}|\ + +AAI_REST_REQUEST_PAYLOAD=\ + MDLSVC0010I|\ + A&AI request payload: {0}|\ + +UNSUPPORTED_ARTIFACT_TYPE=\ + MDLSVC0011I|\ + The downloaded artifact: {0} has an unsupported type of: {1}|\ # ERROR Level Logs ASDC_CONNECTION_ERROR=\ MDLSVC2001E|\ Unable to register with ASDC: {0}|\ Check configuration. Check network connection to ASDC|\ - During initialization, was not able to register with the configured ASDC instance + During initialization, was not able to register with the configured ASDC instance|\ DISTRIBUTION_EVENT_ERROR=\ MDLSVC2002E|\ Distribution event error: {0}|\ Check configuration. Check network connection to ASDC and UEB|\ - A failure occurred processing a distribution event + A failure occurred processing a distribution event|\ AAI_REST_REQUEST_ERROR=\ MDLSVC2003E|\ Failed to send {0} request to {1}: {2}|\ Check configuration. Check network connection to AAI.|\ - A failure occurred attempting to send a request to the AAI + A failure occurred attempting to send a request to the AAI|\ ARTIFACT_PARSE_ERROR=\ MDLSVC2004E|\ Failed to parse artifact: {0}|\ Check artifact. |\ - A failure occurred attempting to parse artifact from SDC + A failure occurred attempting to parse artifact from SDC|\ + +BABEL_REST_REQUEST_ERROR=\ + MDLSVC2005E|\ + Failed to send {0} request to {1}: {2}|\ + Check configuration. Check network connection to Babel.|\ + A failure occurred attempting to send a request to the Babel|\ # DEBUG Level Logs INITIALIZING=\ MDLSVC0001D|\ init(): {0}|\ None. Initializing service|\ - Debug information during model loader initialization + Debug information during model loader initialization|\ diff --git a/src/main/resources/schema/aai_schema_v8.xsd b/src/main/resources/schema/aai_schema_v8.xsd deleted file mode 100644 index 14f2610..0000000 --- a/src/main/resources/schema/aai_schema_v8.xsd +++ /dev/null @@ -1,2462 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/schema/vnfcatalog.xsd b/src/main/resources/schema/vnfcatalog.xsd deleted file mode 100644 index 1b18ef1..0000000 --- a/src/main/resources/schema/vnfcatalog.xsd +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit 1.2.3-korg