diff options
Diffstat (limited to 'cps-rest/src/main')
-rw-r--r-- | cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java | 88 | ||||
-rw-r--r-- | cps-rest/src/main/resources/application.yml | 5 |
2 files changed, 84 insertions, 9 deletions
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java b/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java index c53d1a42a6..532a0ca848 100644 --- a/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java @@ -19,13 +19,18 @@ package org.onap.cps.rest.utils; -import static com.google.common.base.Preconditions.checkNotNull; import static org.opendaylight.yangtools.yang.common.YangConstants.RFC6020_YANG_FILE_EXTENSION; import com.google.common.collect.ImmutableMap; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Locale; import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.onap.cps.spi.exceptions.CpsException; @@ -35,26 +40,81 @@ import org.springframework.web.multipart.MultipartFile; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class MultipartFileUtil { + private static final String ZIP_FILE_EXTENSION = ".zip"; + private static final String YANG_FILE_EXTENSION = RFC6020_YANG_FILE_EXTENSION; + private static final int READ_BUFFER_SIZE = 1024; + /** * Extracts yang resources from multipart file instance. * * @param multipartFile the yang file uploaded * @return yang resources as {map} where the key is original file name, and the value is file content - * @throws ModelValidationException if the file name extension is not '.yang' + * @throws ModelValidationException if the file name extension is not '.yang' or '.zip' + * or if zip archive contain no yang files * @throws CpsException if the file content cannot be read */ public static Map<String, String> extractYangResourcesMap(final MultipartFile multipartFile) { - return ImmutableMap.of(extractYangResourceName(multipartFile), extractYangResourceContent(multipartFile)); + final String originalFileName = multipartFile.getOriginalFilename(); + if (resourceNameEndsWithExtension(originalFileName, YANG_FILE_EXTENSION)) { + return ImmutableMap.of(originalFileName, extractYangResourceContent(multipartFile)); + } + if (resourceNameEndsWithExtension(originalFileName, ZIP_FILE_EXTENSION)) { + return extractYangResourcesMapFromZipArchive(multipartFile); + } + throw new ModelValidationException("Unsupported file type.", + String.format("Filename %s matches none of expected extensions: %s", originalFileName, + Arrays.asList(YANG_FILE_EXTENSION, ZIP_FILE_EXTENSION))); + } + + private static Map<String, String> extractYangResourcesMapFromZipArchive(final MultipartFile multipartFile) { + final ImmutableMap.Builder<String, String> yangResourceMapBuilder = ImmutableMap.builder(); + + try ( + final InputStream inputStream = multipartFile.getInputStream(); + final ZipInputStream zipInputStream = new ZipInputStream(inputStream); + ) { + ZipEntry zipEntry; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + extractZipEntryToMapIfApplicable(yangResourceMapBuilder, zipEntry, zipInputStream); + } + zipInputStream.closeEntry(); + + } catch (final IOException e) { + throw new CpsException("Cannot extract resources from zip archive.", e.getMessage(), e); + } + + try { + final Map<String, String> yangResourceMap = yangResourceMapBuilder.build(); + if (yangResourceMap.isEmpty()) { + throw new ModelValidationException("Archive contains no YANG resources.", + String.format("Archive contains no files having %s extension.", YANG_FILE_EXTENSION)); + } + return yangResourceMap; + + } catch (final IllegalArgumentException e) { + throw new ModelValidationException("Invalid ZIP archive content.", + "Multiple resources with same name detected.", e); + } } - private static String extractYangResourceName(final MultipartFile multipartFile) { - final String fileName = checkNotNull(multipartFile.getOriginalFilename(), "Missing filename."); - if (!fileName.endsWith(RFC6020_YANG_FILE_EXTENSION)) { - throw new ModelValidationException("Unsupported file type.", - String.format("Filename %s does not end with '%s'", fileName, RFC6020_YANG_FILE_EXTENSION)); + private static void extractZipEntryToMapIfApplicable( + final ImmutableMap.Builder<String, String> yangResourceMapBuilder, final ZipEntry zipEntry, + final ZipInputStream zipInputStream) throws IOException { + + final String yangResourceName = extractResourceNameFromPath(zipEntry.getName()); + if (zipEntry.isDirectory() || !resourceNameEndsWithExtension(yangResourceName, YANG_FILE_EXTENSION)) { + return; } - return fileName; + yangResourceMapBuilder.put(yangResourceName, extractYangResourceContent(zipInputStream)); + } + + private static boolean resourceNameEndsWithExtension(final String resourceName, final String extension) { + return resourceName != null && resourceName.toLowerCase(Locale.ENGLISH).endsWith(extension); + } + + private static String extractResourceNameFromPath(final String path) { + return path == null ? "" : path.replaceAll("^.*[\\\\/]", ""); } private static String extractYangResourceContent(final MultipartFile multipartFile) { @@ -65,4 +125,14 @@ public class MultipartFileUtil { } } + private static String extractYangResourceContent(final ZipInputStream zipInputStream) throws IOException { + try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { + final byte[] buffer = new byte[READ_BUFFER_SIZE]; + int numberOfBytesRead; + while ((numberOfBytesRead = zipInputStream.read(buffer, 0, READ_BUFFER_SIZE)) > 0) { + byteArrayOutputStream.write(buffer, 0, numberOfBytesRead); + } + return byteArrayOutputStream.toString(StandardCharsets.UTF_8); + } + } } diff --git a/cps-rest/src/main/resources/application.yml b/cps-rest/src/main/resources/application.yml index b50a92662b..0f2ef20df7 100644 --- a/cps-rest/src/main/resources/application.yml +++ b/cps-rest/src/main/resources/application.yml @@ -24,6 +24,11 @@ spring: driverClassName: org.postgresql.Driver
initialization-mode: always
+ cache:
+ type: caffeine
+ cache-names: yangSchema
+ caffeine:
+ spec: maximumSize=10000,expireAfterAccess=10m
# Actuator
management:
endpoints:
|