aboutsummaryrefslogtreecommitdiffstats
path: root/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintArchiveUtils.kt
diff options
context:
space:
mode:
Diffstat (limited to 'ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintArchiveUtils.kt')
-rwxr-xr-xms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintArchiveUtils.kt279
1 files changed, 279 insertions, 0 deletions
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintArchiveUtils.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintArchiveUtils.kt
new file mode 100755
index 000000000..1a7c23cf1
--- /dev/null
+++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintArchiveUtils.kt
@@ -0,0 +1,279 @@
+/*
+ * Copyright © 2017-2018 AT&T Intellectual Property.
+ * Modifications Copyright © 2019 Bell Canada.
+ * Modifications Copyright © 2019 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.
+ */
+
+package org.onap.ccsdk.cds.controllerblueprints.core.utils
+
+import com.google.common.base.Predicates
+import org.apache.commons.compress.archivers.ArchiveEntry
+import org.apache.commons.compress.archivers.ArchiveInputStream
+import org.apache.commons.compress.archivers.ArchiveOutputStream
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
+import org.apache.commons.compress.archivers.zip.ZipFile
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream
+import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.slf4j.LoggerFactory
+import java.io.BufferedInputStream
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.Closeable
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.InputStream
+import java.io.InputStreamReader
+import java.io.OutputStream
+import java.nio.file.FileVisitResult
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.SimpleFileVisitor
+import java.nio.file.attribute.BasicFileAttributes
+import java.util.Enumeration
+import java.util.function.Predicate
+import java.util.zip.Deflater
+
+enum class ArchiveType {
+ TarGz,
+ Zip
+}
+
+class BluePrintArchiveUtils {
+
+ companion object {
+
+ private val log = LoggerFactory.getLogger(BluePrintArchiveUtils::class.java)
+
+ /**
+ * Create a new Zip from a root directory
+ *
+ * @param source the base directory
+ * @param destination the output filename
+ * @return True if OK
+ */
+ fun compress(source: File, destination: File, archiveType: ArchiveType = ArchiveType.Zip): Boolean {
+ try {
+ if (!destination.parentFile.exists()) {
+ destination.parentFile.mkdirs()
+ }
+ destination.createNewFile()
+ val ignoreZipFiles = Predicate<Path> { path -> !path.endsWith(".zip") && !path.endsWith(".ZIP") }
+ FileOutputStream(destination).use { out ->
+ compressFolder(source.toPath(), out, archiveType, pathFilter = ignoreZipFiles)
+ }
+ } catch (e: Exception) {
+ log.error("Fail to compress folder($source) to path(${destination.path})", e)
+ return false
+ }
+ return true
+ }
+
+ /**
+ * In-memory compress an entire folder.
+ */
+ fun compressToBytes(
+ baseDir: Path,
+ archiveType: ArchiveType = ArchiveType.Zip,
+ compressionLevel: Int = Deflater.NO_COMPRESSION
+ ): ByteArray {
+ return compressFolder(baseDir, ByteArrayOutputStream(), archiveType, compressionLevel = compressionLevel)
+ .toByteArray()
+ }
+
+ /**
+ * Compress an entire folder.
+ *
+ * @param baseDir path of base folder to be packaged.
+ * @param output the output stream
+ * @param pathFilter filter to ignore files based on its path.
+ * @param compressionLevel the wanted compression level.
+ * @param fixedModificationTime to force every entry to have this modification time.
+ * Useful for reproducible operations, like tests, for example.
+ */
+ private fun <T> compressFolder(
+ baseDir: Path,
+ output: T,
+ archiveType: ArchiveType,
+ pathFilter: Predicate<Path> = Predicates.alwaysTrue(),
+ compressionLevel: Int = Deflater.DEFAULT_COMPRESSION,
+ fixedModificationTime: Long? = null
+ ): T
+ where T : OutputStream {
+ val stream: ArchiveOutputStream = if (archiveType == ArchiveType.Zip)
+ ZipArchiveOutputStream(output).apply { setLevel(compressionLevel) }
+ else
+ TarArchiveOutputStream(GzipCompressorOutputStream(output))
+ stream
+ .use { aos ->
+ Files.walkFileTree(
+ baseDir,
+ object : SimpleFileVisitor<Path>() {
+ @Throws(IOException::class)
+ override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
+ if (pathFilter.test(file)) {
+ var archiveEntry: ArchiveEntry = aos.createArchiveEntry(
+ file.toFile(),
+ baseDir.relativize(file).toString()
+ )
+ if (archiveType == ArchiveType.Zip) {
+ val entry = archiveEntry as ZipArchiveEntry
+ fixedModificationTime?.let {
+ entry.time = it
+ }
+ entry.time = 0
+ }
+ aos.putArchiveEntry(archiveEntry)
+ Files.copy(file, aos)
+ aos.closeArchiveEntry()
+ }
+ return FileVisitResult.CONTINUE
+ }
+
+ @Throws(IOException::class)
+ override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult {
+ var archiveEntry: ArchiveEntry?
+ if (archiveType == ArchiveType.Zip) {
+ val entry = ZipArchiveEntry(baseDir.relativize(dir).toString() + "/")
+ fixedModificationTime?.let {
+ entry.time = it
+ }
+ archiveEntry = entry
+ } else
+ archiveEntry = TarArchiveEntry(baseDir.relativize(dir).toString() + "/")
+ aos.putArchiveEntry(archiveEntry)
+ aos.closeArchiveEntry()
+ return FileVisitResult.CONTINUE
+ }
+ }
+ )
+ }
+ return output
+ }
+
+ private fun getDefaultEncoding(): String? {
+ val bytes = byteArrayOf('D'.toByte())
+ val inputStream: InputStream = ByteArrayInputStream(bytes)
+ val reader = InputStreamReader(inputStream)
+ return reader.encoding
+ }
+
+ fun deCompress(archiveFile: File, targetPath: String, archiveType: ArchiveType = ArchiveType.Zip): File {
+ var enumeration: ArchiveEnumerator? = null
+ if (archiveType == ArchiveType.Zip) {
+ val zipArchive = ZipFile(archiveFile, getDefaultEncoding())
+ enumeration = ArchiveEnumerator(zipArchive)
+ } else { // Tar Gz
+ var tarGzArchiveIs: InputStream = BufferedInputStream(archiveFile.inputStream())
+ tarGzArchiveIs = GzipCompressorInputStream(tarGzArchiveIs)
+ val tarGzArchive: ArchiveInputStream = TarArchiveInputStream(tarGzArchiveIs)
+ enumeration = ArchiveEnumerator(tarGzArchive)
+ }
+
+ enumeration.use {
+ while (enumeration!!.hasMoreElements()) {
+ val entry: ArchiveEntry? = enumeration.nextElement()
+ val destFilePath = File(targetPath, entry!!.name)
+ destFilePath.parentFile.mkdirs()
+
+ if (entry!!.isDirectory)
+ continue
+
+ val bufferedIs = BufferedInputStream(enumeration.getInputStream(entry))
+ destFilePath.outputStream().buffered(1024).use { bos ->
+ bufferedIs.copyTo(bos)
+ }
+
+ if (!enumeration.getHasSharedEntryInputStream())
+ bufferedIs.close()
+ }
+ }
+
+ val destinationDir = File(targetPath)
+ check(destinationDir.isDirectory && destinationDir.exists()) {
+ throw BluePrintProcessorException("failed to decompress blueprint(${archiveFile.absolutePath}) to ($targetPath) ")
+ }
+
+ return destinationDir
+ }
+ }
+
+ class ArchiveEnumerator : Enumeration<ArchiveEntry>, Closeable {
+
+ private val zipArchive: ZipFile?
+ private val zipEnumeration: Enumeration<ZipArchiveEntry>?
+ private val archiveStream: ArchiveInputStream?
+ private var nextEntry: ArchiveEntry? = null
+ private val hasSharedEntryInputStream: Boolean
+
+ constructor(zipFile: ZipFile) {
+ zipArchive = zipFile
+ zipEnumeration = zipFile.entries
+ archiveStream = null
+ hasSharedEntryInputStream = false
+ }
+
+ constructor(archiveStream: ArchiveInputStream) {
+ this.archiveStream = archiveStream
+ zipArchive = null
+ zipEnumeration = null
+ hasSharedEntryInputStream = true
+ }
+
+ fun getHasSharedEntryInputStream(): Boolean {
+ return hasSharedEntryInputStream
+ }
+
+ fun getInputStream(entry: ArchiveEntry): InputStream? {
+ return if (zipArchive != null)
+ zipArchive?.getInputStream(entry as ZipArchiveEntry?)
+ else
+ archiveStream
+ }
+
+ override fun hasMoreElements(): Boolean {
+ if (zipEnumeration != null)
+ return zipEnumeration?.hasMoreElements()
+ else if (archiveStream != null) {
+ nextEntry = archiveStream.nextEntry
+ if (nextEntry != null && !archiveStream.canReadEntryData(nextEntry))
+ return hasMoreElements()
+ return nextEntry != null
+ }
+ return false
+ }
+
+ override fun nextElement(): ArchiveEntry? {
+ if (zipEnumeration != null)
+ nextEntry = zipEnumeration.nextElement()
+ else if (archiveStream != null) {
+ if (nextEntry == null)
+ nextEntry = archiveStream.nextEntry
+ }
+ return nextEntry
+ }
+
+ override fun close() {
+ if (zipArchive != null)
+ zipArchive.close()
+ else archiveStream?.close()
+ }
+ }
+}