re base code
[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
17 package org.openecomp.sdc.translator.utils;
18
19 import java.io.BufferedReader;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.net.URI;
27 import java.net.URISyntaxException;
28 import java.net.URL;
29 import java.util.Enumeration;
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.function.BiConsumer;
33 import java.util.function.Predicate;
34 import java.util.zip.ZipEntry;
35 import java.util.zip.ZipFile;
36
37 import org.apache.commons.io.IOUtils;
38 import org.openecomp.sdc.common.errors.CoreException;
39 import org.openecomp.sdc.common.errors.ErrorCategory;
40 import org.openecomp.sdc.common.errors.ErrorCode;
41
42 public class ResourceWalker {
43
44   private static final String RESOURCE_FILE_READ_ERROR = "Can't read resource file from class path.";
45
46   private ResourceWalker() {
47   }
48
49   /**
50    * Read resources from directory map.
51    *
52    * @param resourceDirectoryToStart the resource directory to start
53    * @return the map of file where key is file name and value is its data
54    * @throws Exception the exception
55    */
56   public static Map<String, String> readResourcesFromDirectory(String resourceDirectoryToStart)
57       throws
58       Exception {
59     Map<String, String> filesContent = new HashMap<>();
60     traverse(resourceDirectoryToStart, (fileName, stream) -> {
61       try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
62         filesContent.put(fileName, IOUtils.toString(reader));
63       } catch (IOException exception) {
64         throw new CoreException((new ErrorCode.ErrorCodeBuilder())
65             .withMessage(RESOURCE_FILE_READ_ERROR
66                 + " File name = " + fileName)
67             .withId("Resource Read Error").withCategory(ErrorCategory.APPLICATION).build(),
68             exception);
69       }
70     });
71     return filesContent;
72   }
73
74   private static void traverse(String start, BiConsumer<String, InputStream> handler) throws
75       Exception {
76
77     URL url = ResourceWalker.class.getClassLoader().getResource(start);
78     if (url == null) {
79       throw new FileNotFoundException("Resource not found: " + start);
80     }
81
82     switch (url.getProtocol().toLowerCase()) {
83
84       case "file":
85         traverseFile(new File(url.getPath()), handler);
86         break;
87       case "zip":
88       case "jar":
89         String path = url.getPath();
90         int resourcePosition = path.lastIndexOf("!/" + start);
91         traverseArchive(path.substring(0, resourcePosition), start, handler);
92         break;
93       default:
94         throw new IllegalArgumentException("Unknown protocol");
95     }
96   }
97
98   private static void traverseArchive(String file, String resource, BiConsumer<String, InputStream>
99       handler)
100       throws URISyntaxException, IOException {
101
102     // There is what looks like a bug in Java:
103     // if "abc" is a directory in an archive,
104     // both "abc" and "abc/" will be found successfully.
105     // However, calling isDirectory() will return "true" for "abc/",
106     // but "false" for "abc".
107     try (ZipFile zip = new ZipFile(new URI(file).getPath())) {
108
109       Predicate<ZipEntry> predicate = buildPredicate(resource);
110       Enumeration<? extends ZipEntry> entries = zip.entries();
111       while (entries.hasMoreElements()) {
112         handleZipEntry(predicate, zip, entries.nextElement(), handler);
113       }
114     }
115   }
116
117   private static Predicate<ZipEntry> buildPredicate(String resource) {
118
119     if (resource.endsWith("/")) {
120       return zipEntry ->
121           zipEntry.getName().startsWith(resource) && !zipEntry.isDirectory();
122     } else {
123       return zipEntry -> {
124         String name = zipEntry.getName();
125         return (name.equals(resource) || name.startsWith(resource + "/"))
126             && !zipEntry.isDirectory() && !name.contains("../");
127       };
128     }
129   }
130
131   private static void handleZipEntry(Predicate<ZipEntry> predicate, ZipFile zip, ZipEntry zipEntry,
132                                      BiConsumer<String, InputStream> handler)
133       throws IOException {
134
135     if (predicate.test(zipEntry)) {
136
137       try (InputStream input = zip.getInputStream(zipEntry)) {
138         handler.accept(zipEntry.getName(), input);
139       }
140     }
141   }
142
143   private static void traverseFile(File file, BiConsumer<String, InputStream> handler) throws
144       IOException {
145
146     if (file.isDirectory()) {
147       File[] files = file.listFiles();
148       if (files != null) {
149         for (File sub : files) {
150           traverseFile(sub, handler);
151         }
152       }
153     } else {
154       try (FileInputStream stream = new FileInputStream(file)) {
155         handler.accept(file.getPath(), stream);
156       }
157     }
158   }
159 }