09796731318f67eb3cb89f2088d83a5f402fbe65
[ccsdk/cds.git] /
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 Bell Canada.
4  * Modifications Copyright © 2019 Nordix Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 package org.onap.ccsdk.cds.controllerblueprints.core.utils
20
21 import com.google.common.base.Predicates
22 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
23 import org.slf4j.LoggerFactory
24 import java.io.*
25 import java.nio.charset.*
26 import java.nio.file.*
27 import java.nio.file.attribute.*
28 import java.util.function.*
29 import java.util.zip.*
30
31 class BluePrintArchiveUtils {
32
33     companion object {
34         private val log = LoggerFactory.getLogger(BluePrintArchiveUtils::class.java)
35
36         /**
37          * Create a new Zip from a root directory
38          *
39          * @param source the base directory
40          * @param destination the output filename
41          * @return True if OK
42          */
43         fun compress(source: File, destination: File): Boolean {
44             try {
45                 if(!destination.parentFile.exists()) {
46                     destination.parentFile.mkdirs()
47                 }
48                 destination.createNewFile()
49                 val ignoreZipFiles = Predicate<Path> { path -> !path.endsWith(".zip") && !path.endsWith(".ZIP") }
50                 FileOutputStream(destination).use { out ->
51                     compressFolder(source.toPath(), out, pathFilter = ignoreZipFiles)
52                 }
53             } catch (e: Exception) {
54                 log.error("Fail to compress folder($source) to path(${destination.path})", e)
55                 return false
56             }
57             return true
58         }
59
60         /**
61          * In-memory compress an entire folder.
62          */
63         fun compressToBytes(baseDir: Path, compressionLevel: Int = Deflater.NO_COMPRESSION): ByteArray {
64             return compressFolder(baseDir, ByteArrayOutputStream(), compressionLevel = compressionLevel)
65                     .toByteArray()
66         }
67
68         /**
69          * Compress an entire folder.
70          *
71          * @param baseDir path of base folder to be packaged.
72          * @param output the output stream
73          * @param pathFilter filter to ignore files based on its path.
74          * @param compressionLevel the wanted compression level.
75          * @param fixedModificationTime to force every entry to have this modification time.
76          * Useful for reproducible operations, like tests, for example.
77          */
78         private fun <T> compressFolder(baseDir: Path, output: T,
79                                        pathFilter: Predicate<Path> = Predicates.alwaysTrue(),
80                                        compressionLevel: Int = Deflater.DEFAULT_COMPRESSION,
81                                        fixedModificationTime: Long? = null): T
82                 where T : OutputStream {
83             ZipOutputStream(output)
84                     .apply { setLevel(compressionLevel) }
85                     .use { zos ->
86                         Files.walkFileTree(baseDir, object : SimpleFileVisitor<Path>() {
87                             @Throws(IOException::class)
88                             override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
89                                 if (pathFilter.test(file)) {
90                                     val zipEntry = ZipEntry(baseDir.relativize(file).toString())
91                                     fixedModificationTime?.let {
92                                         zipEntry.time = it
93                                     }
94                                     zipEntry.time = 0;
95                                     zos.putNextEntry(zipEntry)
96                                     Files.copy(file, zos)
97                                     zos.closeEntry()
98                                 }
99                                 return FileVisitResult.CONTINUE
100                             }
101
102                             @Throws(IOException::class)
103                             override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult {
104                                 val zipEntry = ZipEntry(baseDir.relativize(dir).toString() + "/")
105                                 fixedModificationTime?.let {
106                                     zipEntry.time = it
107                                 }
108                                 zos.putNextEntry(zipEntry)
109                                 zos.closeEntry()
110                                 return FileVisitResult.CONTINUE
111                             }
112                         })
113                     }
114             return output
115         }
116
117         fun deCompress(zipFile: File, targetPath: String): File {
118             val zip = ZipFile(zipFile, Charset.defaultCharset())
119             val enumeration = zip.entries()
120             while (enumeration.hasMoreElements()) {
121                 val entry = enumeration.nextElement()
122                 val destFilePath = File(targetPath, entry.name)
123                 destFilePath.parentFile.mkdirs()
124
125                 if (entry.isDirectory)
126                     continue
127
128                 val bufferedIs = BufferedInputStream(zip.getInputStream(entry))
129                 bufferedIs.use {
130                     destFilePath.outputStream().buffered(1024).use { bos ->
131                         bufferedIs.copyTo(bos)
132                     }
133                 }
134             }
135
136             val destinationDir = File(targetPath)
137             check(destinationDir.isDirectory && destinationDir.exists()) {
138                 throw BluePrintProcessorException("failed to decompress blueprint(${zipFile.absolutePath}) to ($targetPath) ")
139             }
140
141             return destinationDir
142         }
143     }
144
145 }