View Javadoc
1   package org.nuiton.eugene.writer;
2   
3   /*
4    * #%L
5    * EUGene :: EUGene
6    * %%
7    * Copyright (C) 2004 - 2015 CodeLutin
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
23   */
24  
25  import org.apache.commons.collections4.CollectionUtils;
26  import org.apache.commons.io.IOUtils;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.nuiton.util.FileUtil;
30  import org.nuiton.util.Resource;
31  
32  import java.io.File;
33  import java.io.FileOutputStream;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.net.URI;
37  import java.net.URL;
38  import java.net.URLClassLoader;
39  import java.util.ArrayList;
40  import java.util.Collections;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.Set;
44  
45  /**
46   * Created on 5/24/15.
47   *
48   * @author Tony Chemit - chemit@codelutin.com
49   * @since 3.0
50   */
51  public class FileGrabberFromClassPath implements FileGrabber {
52  
53      /** Logger. */
54      private static final Log log = LogFactory.getLog(FileGrabberFromClassPath.class);
55  
56      private final ChainedFileWriterConfiguration configuration;
57  
58      public FileGrabberFromClassPath(ChainedFileWriterConfiguration configuration) {
59          this.configuration = configuration;
60      }
61  
62      @Override
63      public void addFilesToTreate(File extractDirectory,
64                                   String inputDirectory,
65                                   Set<String> includePatterns,
66                                   ChainedFileWriterData result) throws IOException {
67  
68          Map<File, List<File>> filesByRoot = result.getFilesByRoot();
69          Map<File, List<File>> resourcesByFile = result.getResourcesByFile();
70  
71          // final input directory to use
72  
73          File realInputDirectory;
74  
75          // use the extracted path as input directory, otherwise there
76          // will have a problem : the incoming inputPath will not be
77          // an ancestor of his resources, so prefer to use the extracted
78          // path which fix this problem.
79          String inputPath = inputDirectory;
80          if (inputPath.equals("/")) {
81              realInputDirectory = extractDirectory;
82          } else {
83              realInputDirectory = new File(extractDirectory, inputPath.substring(1));
84          }
85  
86          List<URL> newUrls = getFiles(inputDirectory, includePatterns);
87  
88          List<File> files = filesByRoot.get(realInputDirectory);
89          if (files == null) {
90              files = new ArrayList<>();
91              filesByRoot.put(realInputDirectory, files);
92          }
93  
94          for (URL url : newUrls) {
95  
96              // get the file
97              File file = extractFileFromClassPath(extractDirectory, url);
98  
99              // add the file in reactor
100             files.add(file);
101 
102             // get resources associated with the file
103             URL resourceFileUrl = getAssociatedResource(url);
104 
105             if (resourceFileUrl == null) {
106 
107                 // no resource associated with the file
108                 if (log.isDebugEnabled()) {
109                     log.debug("[" + file + "] No resource associated.");
110                 }
111 
112             } else {
113 
114                 // get the resource file
115                 File resourceFile = extractFileFromClassPath(extractDirectory, resourceFileUrl);
116                 if (log.isDebugEnabled()) {
117                     log.debug("[" + file + "] Detected resource " + resourceFile);
118                 }
119                 resourcesByFile.put(file, Collections.singletonList(resourceFile));
120 
121             }
122 
123         }
124 
125         if (CollectionUtils.isNotEmpty(files)) {
126 
127             // check that extracted directory exists, or creates it
128             boolean b = extractDirectory.exists() || extractDirectory.mkdirs();
129             if (!b) {
130                 throw new IOException("Could not create directory " + extractDirectory);
131             }
132 
133         }
134 
135     }
136 
137     protected List<URL> getFiles(String inputPath, Set<String> includePattern) {
138 
139         if (CollectionUtils.isEmpty(includePattern)) {
140             throw new IllegalArgumentException("Must have at least one include pattern");
141         }
142 
143         List<URL> result = new ArrayList<>();
144 
145         // search in class-path
146 
147         ClassLoader loader = configuration.getClassLoader();
148 
149         for (String pattern : includePattern) {
150 
151             String path = inputPath;
152 
153             //FIXME must change the file.separator to /
154             if (!path.endsWith("/")) {
155                 path += "/";
156             }
157             path += pattern;
158 
159             if (path.startsWith("/")) {
160                 path = path.substring(1);
161             }
162 
163             if (log.isDebugEnabled()) {
164                 log.debug("Try to seek class-path file " + path);
165             }
166 
167             if (pattern.contains("*")) {
168 
169                 // this is a multi-files to search
170                 List<URL> urlList = Resource.getURLs(path, (URLClassLoader) loader);
171                 if (CollectionUtils.isEmpty(urlList)) {
172 
173                     log.warn("Could not find in class-path files " + path);
174                 } else {
175                     for (URL url : urlList) {
176 
177                         if (configuration.isVerbose()) {
178                             log.info("Detected class-path file " + url);
179                         }
180                         result.add(url);
181                     }
182                 }
183             } else {
184 
185                 // this is a simple unique search, improve performance
186                 // by searching directly in classloader the resource
187                 URL url = loader.getResource(path);
188                 if (url == null) {
189 
190                     log.warn("Could not find in class-path the file " + path);
191                 } else {
192 
193                     if (configuration.isVerbose()) {
194                         log.info("Detected class-path file " + url);
195                     }
196                     result.add(url);
197                 }
198             }
199         }
200         return result;
201     }
202 
203     protected URL getAssociatedResource(URL file) throws IOException {
204 
205         // obtain the properties files associated with the file
206         String path = file.toString();
207 
208         String extension = "." + FileUtil.extension(path);
209 
210         String filename = FileUtil.basename(path, extension).concat(".properties");
211 
212         if (log.isDebugEnabled()) {
213             log.info("path of file : " + path);
214             log.info("path of resource : " + filename);
215         }
216 
217         URL result;
218 
219         URL propertiesFile = URI.create(filename).toURL();
220 
221         if (path.startsWith("file:")) {
222 
223             //FIXME-tchemit-2015-05-24 Does this case happen here ?
224             // local file (not from class-path)
225             // can test directly on resource if it exists
226             File file1 = new File(propertiesFile.getFile());
227             if (file1.exists()) {
228 
229                 // resource exist, keep it
230                 result = propertiesFile;
231 
232             } else {
233 
234                 result = null;
235 
236             }
237 
238         } else {
239 
240             InputStream in = null;
241             try {
242                 in = propertiesFile.openStream();
243 
244                 // resource exist, keep it
245                 result = propertiesFile;
246 
247             } catch (IOException eee) {
248 
249                 // resource does not exists
250                 log.warn("Could not find resource " + propertiesFile);
251                 result = null;
252 
253             } finally {
254 
255                 if (in != null) {
256                     in.close();
257                 }
258 
259             }
260 
261         }
262 
263         return result;
264 
265     }
266 
267     protected File extractFileFromClassPath(File extractDirectory, URL url) throws IOException {
268 
269         String path = url.getPath();
270 
271         // case where file is extracted from jar, "!" found into url, ex:
272         // url:  /home/.../agrosyst-api/target/agrosyst-api-1.0.1-SNAPSHOT.jar!/agrosyst.objectmodel
273         // path: /home/.../agrosyst-services/target/extracted-sources/model/agrosyst.objectmodel
274 
275         // case where file is no extracted from jar, "!" not found into url, ex:
276         // url:  /home/.../agrosyst-api/target/classes/agrosyst.objectmodel
277         // path: /home/.../agrosyst-services/target/extracted-sources/model/agrosyst.objectmodel
278 
279         int index = path.indexOf("!");
280         if (index == -1) {
281             // case where file is no extracted from jar:
282             index = path.lastIndexOf("/") - 1; // -1: because we need to keep the last "/" from path
283         }
284         String relativePath = path.substring(index + 1);
285 
286         File f = new File(extractDirectory, relativePath);
287         if (log.isDebugEnabled()) {
288             log.debug("extract " + url + " to " + f);
289         }
290         File parentFile = f.getParentFile();
291 
292         boolean b = parentFile.exists() || parentFile.mkdirs();
293         if (!b) {
294             throw new IOException("Could not create directory " + f);
295         }
296 
297         try (FileOutputStream out = new FileOutputStream(f)) {
298             IOUtils.copy(url.openStream(), out);
299         }
300         return f;
301 
302     }
303 
304 }