Fix CSAR generation default imports file conflict 70/123770/3
authorandre.schmid <andre.schmid@est.tech>
Wed, 1 Sep 2021 16:37:19 +0000 (17:37 +0100)
committerMichael Morris <michael.morris@est.tech>
Fri, 3 Sep 2021 14:14:19 +0000 (14:14 +0000)
When generating a CSAR for a resource that is associated with a
derived model, the default imports for the derived and parent model
can conflict in path, therefore causing an issue during the CSAR
zip generation which can't stand two entries with the same path.

The fix adds a logic to rename a file when conflicting, by adding
the model id as the file prefix.

Change-Id: Ife7168f1c69f90be9c2cfd8ba75efad316c477f6
Issue-ID: SDC-3710
Signed-off-by: andre.schmid <andre.schmid@est.tech>
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaDefaultImportHelper.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaDefaultImportHelperTest.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java

index 73906de..1f17a6f 100644 (file)
@@ -32,6 +32,7 @@ import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -820,9 +821,18 @@ public class CsarUtils {
     private void addSchemaFilesByModel(final ZipOutputStream zipOutputStream, final String modelName) {
         try {
             final List<ToscaImportByModel> modelDefaultImportList = modelOperation.findAllModelImports(modelName, true);
+            final Set<Path> writtenEntryPathList = new HashSet<>();
+            final var definitionsPath = Path.of(DEFINITIONS_PATH);
             for (final ToscaImportByModel toscaImportByModel : modelDefaultImportList) {
-                final var zipEntry = new ZipEntry(DEFINITIONS_PATH + toscaImportByModel.getFullPath());
+                var importPath = Path.of(toscaImportByModel.getFullPath());
+                if (writtenEntryPathList.contains(definitionsPath.resolve(importPath))) {
+                    importPath =
+                        ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId());
+                }
+                final Path entryPath = definitionsPath.resolve(importPath);
+                final var zipEntry = new ZipEntry(entryPath.toString());
                 zipOutputStream.putNextEntry(zipEntry);
+                writtenEntryPathList.add(entryPath);
                 final byte[] content = toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8);
                 zipOutputStream.write(content, 0, content.length);
                 zipOutputStream.closeEntry();
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaDefaultImportHelper.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaDefaultImportHelper.java
new file mode 100644 (file)
index 0000000..969692e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.tosca;
+
+import java.nio.file.Path;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Helper class for TOSCA default imports.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ToscaDefaultImportHelper {
+
+    /**
+     * Add the model as a file prefix in the given path, e.g.: "path/to/entry.yaml -> path/to/modelId-entry.yaml".
+     *
+     * @param originalPath the entry original path
+     * @param modelId      the model id to add as prefix
+     * @return the modified file path with a model prefix.
+     */
+    public static Path addModelAsFilePrefix(final Path originalPath, final String modelId) {
+        if (StringUtils.isEmpty(modelId)) {
+            return originalPath;
+        }
+        final var fileName = originalPath.getFileName().toString();
+        final var newFileName = String.format("%s-%s", modelId, fileName);
+        if (originalPath.getParent() == null) {
+            return Path.of(newFileName);
+        }
+        return originalPath.getParent().resolve(newFileName);
+    }
+
+}
index 6a1ba4e..3c44c4f 100644 (file)
@@ -28,11 +28,13 @@ import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_INPUT;
 import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_PROPERTY;
 
 import fj.data.Either;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -307,9 +309,15 @@ public class ToscaExportHandler {
         
         final List<ToscaImportByModel> allModelImports = modelOperation.findAllModelImports(modelId, true);
         final List<Map<String, Map<String, String>>> importList = new ArrayList<>();
-        for(final ToscaImportByModel toscaImportByModel: allModelImports) {
-            final String fileName = FilenameUtils.getBaseName(toscaImportByModel.getFullPath());
-            importList.add(Map.of(fileName, Map.of("file", toscaImportByModel.getFullPath())));
+        final Set<Path> addedPathList = new HashSet<>();
+        for (final ToscaImportByModel toscaImportByModel : allModelImports) {
+            var importPath = Path.of(toscaImportByModel.getFullPath());
+            if (addedPathList.contains(importPath)) {
+                importPath = ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId());
+            }
+            final String fileName = FilenameUtils.getBaseName(importPath.toString());
+            importList.add(Map.of(fileName, Map.of("file", importPath.toString())));
+            addedPathList.add(importPath);
         }
         return importList;
     }
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaDefaultImportHelperTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaDefaultImportHelperTest.java
new file mode 100644 (file)
index 0000000..675af36
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.tosca;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.nio.file.Path;
+import org.junit.jupiter.api.Test;
+
+class ToscaDefaultImportHelperTest {
+
+    @Test
+    void addModelAsFilePrefix_pathWithoutParent() {
+        final Path originalPath = Path.of("anImport");
+        final var modelId = "modelId";
+        final Path actualPath = ToscaDefaultImportHelper.addModelAsFilePrefix(originalPath, modelId);
+        assertEquals(Path.of("modelId-anImport"), actualPath);
+    }
+
+    @Test
+    void addModelAsFilePrefix_pathWithParent() {
+        final Path originalPath = Path.of("parent/anImport");
+        final var modelId = "modelId";
+        final Path actualPath = ToscaDefaultImportHelper.addModelAsFilePrefix(originalPath, modelId);
+        assertEquals(Path.of("parent/modelId-anImport"), actualPath);
+    }
+
+    @Test
+    void addModelAsFilePrefix_nullOrEmptyModel() {
+        final Path originalPath = Path.of("parent/anImport");
+        assertEquals(originalPath, ToscaDefaultImportHelper.addModelAsFilePrefix(originalPath, null));
+        assertEquals(originalPath, ToscaDefaultImportHelper.addModelAsFilePrefix(originalPath, ""));
+    }
+}
\ No newline at end of file
index 967ffdc..095b4e1 100644 (file)
@@ -193,6 +193,13 @@ public class ModelOperation {
                 }
             });
         }
+        toscaImportByModelList.sort((o1, o2) -> {
+            final int modelIdComparison = o1.getModelId().compareTo(o2.getModelId());
+            if (modelIdComparison == 0) {
+                return o1.getFullPath().compareTo(o2.getFullPath());
+            }
+            return modelIdComparison;
+        });
         return toscaImportByModelList;
     }