Release version 1.13.7
[sdc.git] / openecomp-be / lib / openecomp-sdc-translator-lib / openecomp-sdc-translator-core / src / main / java / org / openecomp / sdc / translator / utils / ResourceWalker.java
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.openecomp.sdc.translator.utils;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.net.URI;
26 import java.net.URISyntaxException;
27 import java.net.URL;
28 import java.util.Enumeration;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.function.BiConsumer;
32 import java.util.function.Predicate;
33 import java.util.zip.ZipEntry;
34 import java.util.zip.ZipFile;
35 import org.apache.commons.io.IOUtils;
36 import org.openecomp.sdc.common.errors.CoreException;
37 import org.openecomp.sdc.common.errors.ErrorCategory;
38 import org.openecomp.sdc.common.errors.ErrorCode;
39
40 public class ResourceWalker {
41
42     private static final String RESOURCE_FILE_READ_ERROR = "Can't read resource file from class path.";
43
44     private ResourceWalker() {
45     }
46
47     /**
48      * Read resources from directory map.
49      *
50      * @param resourceDirectoryToStart the resource directory to start
51      * @return the map of file where key is file name and value is its data
52      * @throws Exception the exception
53      */
54     public static Map<String, String> readResourcesFromDirectory(String resourceDirectoryToStart) throws Exception {
55         Map<String, String> filesContent = new HashMap<>();
56         traverse(resourceDirectoryToStart, (fileName, stream) -> {
57             try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
58                 filesContent.put(fileName, IOUtils.toString(reader));
59             } catch (IOException exception) {
60                 throw new CoreException((new ErrorCode.ErrorCodeBuilder()).withMessage(RESOURCE_FILE_READ_ERROR + " File name = " + fileName)
61                     .withId("Resource Read Error").withCategory(ErrorCategory.APPLICATION).build(), exception);
62             }
63         });
64         return filesContent;
65     }
66
67     private static void traverse(String start, BiConsumer<String, InputStream> handler) throws Exception {
68         URL url = ResourceWalker.class.getClassLoader().getResource(start);
69         if (url == null) {
70             throw new FileNotFoundException("Resource not found: " + start);
71         }
72         switch (url.getProtocol().toLowerCase()) {
73             case "file":
74                 traverseFile(new File(url.getPath()), handler);
75                 break;
76             case "zip":
77             case "jar":
78                 String path = url.getPath();
79                 int resourcePosition = path.lastIndexOf("!/" + start);
80                 traverseArchive(path.substring(0, resourcePosition), start, handler);
81                 break;
82             default:
83                 throw new IllegalArgumentException("Unknown protocol");
84         }
85     }
86
87     private static void traverseArchive(String file, String resource, BiConsumer<String, InputStream> handler)
88         throws URISyntaxException, IOException {
89         // There is what looks like a bug in Java:
90
91         // if "abc" is a directory in an archive,
92
93         // both "abc" and "abc/" will be found successfully.
94
95         // However, calling isDirectory() will return "true" for "abc/",
96
97         // but "false" for "abc".
98         try (ZipFile zip = new ZipFile(new URI(file).getPath())) {
99             Predicate<ZipEntry> predicate = buildPredicate(resource);
100             Enumeration<? extends ZipEntry> entries = zip.entries();
101             while (entries.hasMoreElements()) {
102                 handleZipEntry(predicate, zip, entries.nextElement(), handler);
103             }
104         }
105     }
106
107     private static Predicate<ZipEntry> buildPredicate(String resource) {
108         if (resource.endsWith("/")) {
109             return zipEntry -> zipEntry.getName().startsWith(resource) && !zipEntry.isDirectory();
110         } else {
111             return zipEntry -> {
112                 String name = zipEntry.getName();
113                 return (name.equals(resource) || name.startsWith(resource + "/")) && !zipEntry.isDirectory() && !name.contains("../");
114             };
115         }
116     }
117
118     private static void handleZipEntry(Predicate<ZipEntry> predicate, ZipFile zip, ZipEntry zipEntry, BiConsumer<String, InputStream> handler)
119         throws IOException {
120         if (predicate.test(zipEntry)) {
121             try (InputStream input = zip.getInputStream(zipEntry)) {
122                 handler.accept(zipEntry.getName(), input);
123             }
124         }
125     }
126
127     private static void traverseFile(File file, BiConsumer<String, InputStream> handler) throws IOException {
128         if (file.isDirectory()) {
129             File[] files = file.listFiles();
130             if (files != null) {
131                 for (File sub : files) {
132                     traverseFile(sub, handler);
133                 }
134             }
135         } else {
136             try (FileInputStream stream = new FileInputStream(file)) {
137                 handler.accept(file.getPath(), stream);
138             }
139         }
140     }
141 }