View Javadoc

1   /*
2    * 
3    * © Copyright 2005-2010, Mike Odling-Smee.  All rights reserved.
4    * 	
5    * 	Licensed under the Artistic License: 
6    * 	http://www.opensource.org/licenses/artistic-license.php
7    * 	
8    * Preamble
9    * 
10   *         The intent of this document is to state the conditions under which a 
11   *         Package may be copied, such that the Copyright Holder maintains some 
12   *         semblance of artistic control over the development of the package, while 
13   *         giving the users of the package the right to use and distribute the Package
14   * 	       in a more-or-less customary fashion, plus the right to make reasonable 
15   *         modifications.
16   * 
17   * Definitions:
18   * 
19   *         * "Package" refers to the collection of files distributed by the 
20   *         Copyright Holder, and derivatives of that collection of files created 
21   *         through textual modification. 
22   * 
23   *         * "Standard Version" refers to such a Package if it has not been modified, 
24   *         or has been modified in accordance with the wishes of the Copyright Holder.
25   * 
26   *         * "Copyright Holder" is whoever is named in the copyright or copyrights for
27   *         the package. 
28   * 
29   *         * "You" is you, if you're thinking about copying or distributing this Package.
30   * 
31   *         * "Reasonable copying fee" is whatever you can justify on the basis of 
32   *         media cost, duplication charges, time of people involved, and so on. 
33   *         (You will not be required to justify it to the Copyright Holder, but 
34   *         only to the computing community at large as a market that must bear the 
35   *         fee.) 
36   * 
37   *         * "Freely Available" means that no fee is charged for the item 
38   *         itself, though there may be fees involved in handling the item. It also 
39   *         means that recipients of the item may redistribute it under the same 
40   *         conditions they received it.
41   * 
42   * 	1. You may make and give away verbatim copies of the source form of the Standard 
43   * 	Version of this Package without restriction, provided that you duplicate all of 
44   * 	the original copyright notices and associated disclaimers.
45   * 	
46   * 	2. You may apply bug fixes, portability fixes and other modifications derived 
47   * 	from the Public Domain or from the Copyright Holder. A Package modified in such 
48   * 	a way shall still be considered the Standard Version.
49   * 	
50   * 	3. You may otherwise modify your copy of this Package in any way, provided that 
51   * 	you insert a prominent notice in each changed file stating how and when you 
52   * 	changed that file, and provided that you do at least ONE of the following:
53   * 	
54   * 		a) place your modifications in the Public Domain or otherwise make them 
55   * 		Freely Available, such as by posting said modifications to Usenet or an 
56   * 		equivalent medium, or placing the modifications on a major archive site such 
57   * 		as ftp.uu.net, or by allowing the Copyright Holder to include your modifications 
58   * 		in the Standard Version of the Package.
59   * 	
60   * 		b) use the modified Package only within your corporation or organization.
61   * 	
62   * 		c) rename any non-standard executables so the names do not conflict with 
63   * 		standard executables, which must also be provided, and provide a separate 
64   * 		manual page for each non-standard executable that clearly documents how it 
65   * 		differs from the Standard Version.
66   * 	
67   * 		d) make other distribution arrangements with the Copyright Holder.
68   * 	
69   * 	4. You may distribute the programs of this Package in object code or executable 
70   * 	form, provided that you do at least ONE of the following:
71   * 	
72   * 		a) distribute a Standard Version of the executables and library files, 
73   * 		together with instructions (in the manual page or equivalent) on where to 
74   * 		get the Standard Version.
75   * 	
76   * 		b) accompany the distribution with the machine-readable source of the 
77   * 		Package with your modifications.
78   * 	
79   * 		c) accompany any non-standard executables with their corresponding Standard 
80   * 		Version executables, giving the non-standard executables non-standard names, 
81   * 		and clearly documenting the differences in manual pages (or equivalent), 
82   * 		together with instructions on where to get the Standard Version.
83   * 	
84   * 		d) make other distribution arrangements with the Copyright Holder.
85   * 	
86   * 	5. You may charge a reasonable copying fee for any distribution of this Package. 
87   * 	You may charge any fee you choose for support of this Package. You may not 
88   * 	charge a fee for this Package itself. However, you may distribute this Package 
89   * 	in aggregate with other (possibly commercial) programs as part of a larger 
90   * 	(possibly commercial) software distribution provided that you do not advertise 
91   * 	this Package as a product of your own.
92   * 	
93   * 	6. The scripts and library files supplied as input to or produced as output from 
94   * 	the programs of this Package do not automatically fall under the copyright of 
95   * 	this Package, but belong to whomever generated them, and may be sold 
96   * 	commercially, and may be aggregated with this Package.
97   * 	
98   * 	7. C or perl subroutines supplied by you and linked into this Package shall not 
99   * 	be considered part of this Package.
100  * 	
101  * 	8. The name of the Copyright Holder may not be used to endorse or promote 
102  * 	products derived from this software without specific prior written permission.
103  * 	
104  * 	9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 
105  * 	WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
106  * 	MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
107  * 
108  * The End
109  */
110 package net.sourceforge.xuse.utils;
111 
112 import java.io.File;
113 import java.io.FileFilter;
114 import java.io.FileInputStream;
115 import java.io.FileNotFoundException;
116 import java.io.FileOutputStream;
117 import java.io.FileWriter;
118 import java.io.IOException;
119 import java.io.InputStream;
120 import java.io.OutputStream;
121 import java.io.UnsupportedEncodingException;
122 import java.net.URL;
123 import java.net.URLDecoder;
124 import java.nio.channels.FileChannel;
125 import java.util.ArrayList;
126 import java.util.Arrays;
127 import java.util.Enumeration;
128 import java.util.Iterator;
129 import java.util.List;
130 import java.util.jar.JarEntry;
131 import java.util.jar.JarFile;
132 
133 import net.sourceforge.xuse.build.BuildException;
134 import net.sourceforge.xuse.build.XusePropertiesReader;
135 import net.sourceforge.xuse.log.Logger;
136 
137 import com.xmlsolutions.annotation.Requirement; 
138 
139 
140 public class FileUtils {
141 	
142 	private static final FileUtils LOG_INSTANCE = new FileUtils();
143 
144 	public static final File WORKING_DIR = new File(XusePropertiesReader.getXuseWorkingDir());
145 
146 	public static void copy(FileInputStream in, File destination) throws IOException {
147 		FileChannel srcChannel = null;
148 		FileChannel dstChannel = null;
149     	try {
150 			srcChannel = in.getChannel();
151 			dstChannel = new FileOutputStream(destination).getChannel();
152 			dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
153     	} finally {
154     		if (srcChannel != null) {
155     			srcChannel.close();
156     		}
157 			if (dstChannel != null) {
158 				dstChannel.close();
159 			}
160     	}
161     }
162 	
163 	public static final boolean fileExists(String path) {
164 		if (path != null) {
165 			String safePath = path;
166 			try {
167 				safePath = URLDecoder.decode(path, "UTF-8");
168 			} catch (UnsupportedEncodingException uee) {
169 				Logger.warn(LOG_INSTANCE, "Could not safely decode file path", uee);
170 			}
171 			File file = new File(safePath);
172 			return file.exists();
173 		}
174 		return false;
175 	}
176 	
177 	public static void copyFileToDir(String file, File destDir) throws IOException {
178 		if (file != null) {
179 			if (destDir != null) {
180 				if (!destDir.exists()) {
181 					destDir.mkdirs();
182 				} else if (!destDir.isDirectory()) {
183 					Logger.warn(LOG_INSTANCE, "Cannot copy file " + file + " to " + destDir.getAbsolutePath() + "; destination is not a directory");
184 				}
185 				Logger.debug(LOG_INSTANCE, "Copying " + file + " to " + destDir.getAbsolutePath());
186 				//OK we are ok to try and copy
187 				File input = new File(file);
188 				String fileName = input.getName();
189 				File destFile = new File(destDir, fileName);
190 				copyFile(input, destFile);
191 			} else {
192 				Logger.warn(LOG_INSTANCE, "Cannot copy file " + file + "; destination was null");
193 			}
194 		} else {
195 			Logger.warn(LOG_INSTANCE, "Cannot copy file as file was null");
196 		}
197 	}
198 	
199 	public static void copyFile(File input, File destination) throws IOException {
200 		if (input != null) {
201 			if (input.exists()) {
202 				Logger.debug(LOG_INSTANCE, "Copying " + input.getAbsolutePath() + " to " + destination.getAbsolutePath());
203 				copy(new FileInputStream(input), destination);
204 			} else {
205 				Logger.warn(LOG_INSTANCE, "Cannot copy " + input.getAbsolutePath() + " to " + destination.getAbsolutePath() + ", file does not exist");
206 			}
207 		} else {
208 			Logger.warn(LOG_INSTANCE, "Cannot copy file to source or destination was null");
209 		}
210 	}
211 	
212 	public static void copy(InputStream in, File destination) throws IOException {
213 		Logger.debug(LOG_INSTANCE, "Writing: " + destination.getAbsolutePath());
214 		OutputStream out = new FileOutputStream(destination);
215 		// Transfer bytes from in to out
216         byte[] buf = new byte[1024];
217         int len;
218         int totalSize = 0;
219         while ((len = in.read(buf)) > 0) {
220             out.write(buf, 0, len);
221             totalSize += len;
222         }
223         in.close();
224         out.flush();
225         out.close();
226         Logger.debug(LOG_INSTANCE, "Wrote: " + totalSize + " bytes");
227 	}
228 	
229 	public static void extractStyleSheets() throws IOException {
230 		//if (!hasBeenExtracted()) {
231 			File xslDir = new File(WORKING_DIR, XusePropertiesReader.getXslDirectory());
232 			xslDir.mkdirs();
233 			copyDirectory(XusePropertiesReader.getXslDirectory(), WORKING_DIR);
234 		//}
235 		
236 	}
237 
238 	public static void extractResources() throws IOException {
239 		File resourcesDir = new File(WORKING_DIR, XusePropertiesReader.getXuseResourcesDirectory());
240 		resourcesDir.mkdirs();
241 		copyDirectory(XusePropertiesReader.getXuseResourcesDirectory(), WORKING_DIR);
242 	}
243 	
244 	public static void extractSchemas() throws IOException {
245 		File dest = new File(System.getProperty("user.dir") + "/" + XusePropertiesReader.getXuseSchemaDir());
246 		copyDirectory("xsd", dest, false);
247 	}
248 	
249 	@Requirement(traceTo={"RQ40"})
250 	public static void extractTemplateProject() throws IOException {
251 		File dest = new File(System.getProperty("user.dir"));
252 		Logger.debug(LOG_INSTANCE, "Extracting template project to " + dest.getCanonicalPath());
253 		copyDirectory(XusePropertiesReader.getTemplateProjectPath(), dest, false);
254 	}
255 	
256 	public static void extractResourceFromJar(String directoryInJar, String filename, File destination) throws IOException {
257 		if (directoryInJar != null && destination != null) {
258 			JarFile jarFile = getJarFile();		
259 			Enumeration<JarEntry> enumeration = jarFile.entries();
260 			destination.getParentFile().mkdirs();
261 			while (enumeration.hasMoreElements()) {
262 				JarEntry entry = (JarEntry)enumeration.nextElement();
263 				String entryName = entry.getName();
264 				if (entryName.startsWith(directoryInJar + "/" + filename) && !entryName.endsWith("/")) {
265 					InputStream in = getInputStreamFromSystemOrClasspath(entry.getName());
266 					copy(in, destination);
267 				}
268 			}
269 		}
270 	}
271 	
272 	public static boolean hasBeenExtracted() throws IOException {
273 		File xslDir = new File(WORKING_DIR, XusePropertiesReader.getXslDirectory());
274 		return xslDir.exists() && xslDir.isDirectory() && xslDir.list() != null && xslDir.list().length > 0;
275 		
276 	}
277 	
278 	public static JarFile getJarFile() throws BuildException {
279 	    String path = "unknown";
280 		try {
281 		    URL jarPath = FileUtils.class.getResource("FileUtils.class");
282 		    Logger.debug(LOG_INSTANCE, "Getting Jar file URL: " + jarPath.toString());
283 			path = jarPath.toString().replaceAll("%20", " ");
284 			String os = System.getProperty("os.name");
285 			Logger.debug(LOG_INSTANCE, "OS: " + os);
286 			if (os != null && os.contains("windows")) {
287 				path = path.replaceAll("jar:file:/", "");
288 			} else {
289 				path = path.replaceAll("jar:file:", "");
290 			}
291 			path = path.substring(0, path.indexOf("!"));
292 			Logger.debug(LOG_INSTANCE, "Jar file location: " + path);
293 			return new JarFile(path);
294 		} catch (Throwable t) {
295 			throw new BuildException("Could not locate Xuse jar file: found path " + path, t);
296 		}
297 	}
298 	
299 	@Requirement(traceTo={"RQ19", "RQ60"})
300 	public static void copyHTMLResources(String outputDir) throws IOException {
301 		if (outputDir != null) {
302 		    copyHTMLResources(new File(outputDir));
303 		}
304 	}
305 	
306 	public static void copyHTMLResources(File outputDir) throws IOException {
307 		if (outputDir != null) {
308 			copyDirectory("css", outputDir);
309 			copyDirectory("images", outputDir);
310 			copyDirectory("themes/" + XusePropertiesReader.getHTMLTheme(), outputDir);
311 			copyDirectory("js", outputDir);
312 			//Now we need to copy any custom resources
313 			copyCustomResources(outputDir);
314 		}
315 	}
316 	
317 	public static void copyCustomResources(File outputDir) throws IOException {
318 		//Copy CSS stylesheets
319 		Logger.debug(LOG_INSTANCE, "in copyCustomResources()");
320 		if (XusePropertiesReader.isCustomTheme()) {
321 			String css = XusePropertiesReader.getHTMLTheme();
322 			String fullCss = XusePropertiesReader.getResourcesDirectory() + "/" + css + ".css"; 
323 			Logger.info(LOG_INSTANCE, "Got custom theme: " + css);
324 			Logger.debug(LOG_INSTANCE, "CSS is: " + fullCss);
325 			Logger.debug(LOG_INSTANCE, "before...");
326 			copyFileToDir(fullCss, new File(outputDir, "css"));
327 			Logger.debug(LOG_INSTANCE, "after...");
328 		}
329 		Logger.debug(LOG_INSTANCE, "here...");
330 		//Copy any custom images
331 		File imageDir = new File(outputDir, "images");
332 		String customerLogo = XusePropertiesReader.getCustomerLogo();
333 		Logger.debug(LOG_INSTANCE, "Customer logo: " + customerLogo);
334 		copyFileToDir(customerLogo, imageDir);
335 		String companyLogo = XusePropertiesReader.getCompanyLogo();
336 		Logger.debug(LOG_INSTANCE, "Company logo: " + companyLogo);
337 		copyFileToDir(companyLogo, imageDir);
338 		String projectLogo = XusePropertiesReader.getProjectLogo();
339 		Logger.debug(LOG_INSTANCE, "Project logo: " + projectLogo);
340 		copyFileToDir(projectLogo, imageDir);
341 	}
342 	
343 	public static void copyDirectory(File sourceDir, File destDir) throws IOException {
344 		if (sourceDir != null && sourceDir.isDirectory() && destDir != null) {
345 			if (destDir.exists() && destDir.isFile()) {
346 				throw new IOException("Cannot write files to location " + destDir.getCanonicalPath());
347 			} else if (!destDir.exists()) {
348 				destDir.mkdir();
349 			}
350 			List<File> srcFiles = Arrays.asList(sourceDir.listFiles());
351 			Iterator<File> iter = srcFiles.iterator();
352 			File currentFile = null;
353 			while (iter.hasNext()) {
354 				currentFile = (File)iter.next();
355 				if (currentFile.isDirectory()) {
356 					copyDirectory(currentFile, new File(destDir, currentFile.getName()));
357 				} else {
358 					copy(new FileInputStream(currentFile), new File(destDir, currentFile.getName()));
359 				}
360 			}
361 		}
362 	}
363 	
364 	public static void copyDirectory(String directoryInJar, File destination, boolean mirrorDir) throws IOException {
365 		Logger.debug(LOG_INSTANCE, "Copying directory from " + directoryInJar + " in jar file to " + destination.getCanonicalPath());
366 		if (directoryInJar != null && destination != null) {
367 			JarFile jarFile = getJarFile();		
368 			Enumeration<JarEntry> enumeration = jarFile.entries();
369 			File destDir = mirrorDir ? new File(destination, directoryInJar) : destination;
370 			destDir.mkdirs();
371 			while (enumeration.hasMoreElements()) {
372 				JarEntry entry = (JarEntry)enumeration.nextElement();
373 				String entryName = entry.getName();
374 				if (entryName.startsWith(directoryInJar + "/") && !entryName.endsWith("/")) {
375 					InputStream in = getInputStreamFromSystemOrClasspath(entry.getName());
376 					String outputFileName = null;
377 					if (mirrorDir) {
378 						outputFileName = entry.getName(); 
379 					} else {
380 						int index = entry.getName().indexOf(directoryInJar) + directoryInJar.length();
381 						outputFileName = entry.getName().substring(index);
382 					}
383 					
384 					File dest = new File(destination, outputFileName);
385 					File folder = dest.getParentFile();
386 					if (!folder.exists()) {
387 						if (!folder.mkdirs()) {
388 							throw new BuildException("Could not create folder: " + folder.getAbsolutePath());
389 						}
390 					}
391 					if (dest.exists() && dest.isFile()) {
392 						Logger.debug(LOG_INSTANCE, "Destination " + dest.getAbsolutePath() + " already exists");
393 						dest.delete();
394 					}
395 					copy(in, dest);
396 				}
397 			}
398 		}
399 	}
400 	
401 	public static void copyDirectory(String directoryInJar, File destination) throws IOException {
402 		if (directoryInJar != null && destination != null) {
403 			copyDirectory(directoryInJar, destination, true);	
404 		}
405 	}
406 	
407 	public static void copyResource(String file, String directory, File destDir) throws IOException {
408 		
409 		File destDirF = new File(destDir, directory);
410 		if (!destDirF.exists()) {
411 			destDirF.mkdirs();
412 		}
413 		File outfile = new File(destDirF, file);
414 		InputStream in = getInputStreamFromSystemOrClasspath(directory + "/" + file);
415 		copy(in, outfile);
416 	}
417 	
418 
419 	public static void archive(File file) throws Exception {
420 		if (file != null && file.isFile() && file.canWrite() && file.exists()) {
421 			File newFile = new File(file.getParent(), file.getName() + "." + System.currentTimeMillis() + ".old");
422 			Logger.info(LOG_INSTANCE, "Archiving old file: " + file.getAbsolutePath() + " to " + newFile.getAbsolutePath());
423 			if (!(file.renameTo(newFile))) {
424 				throw new IOException("Could not rename: " + file.getAbsolutePath());
425 			}
426 		}
427 	}
428 	
429 	public static void renameUpgraded(File file) throws Exception {
430 		if (file != null && file.isFile() && file.canWrite()) {
431 	Logger.info(LOG_INSTANCE, "Renaming upgraded file: " + file.getCanonicalPath());
432 			String newName = Utils.substringBefore(file.getName(), "-upgrade.xml");
433 			file.renameTo(new File(file.getParent(), newName + ".xml"));
434 		}
435 	}
436 	
437 	public static List<String> getFilesInDir(File dir, FileFilter filter) {
438 		if (dir != null && dir.isDirectory()) {
439 			Logger.debug(LOG_INSTANCE, "Looking for files in directory: " + dir.getAbsolutePath());
440 			List<String> allFiles = new ArrayList<String>();
441 			File[] children = dir.listFiles(filter);
442 			Logger.debug(LOG_INSTANCE, "Found " + children.length + " children");
443 			for (int i = 0; i < children.length; i++) {
444 				if (children[i].isDirectory()) {
445 					allFiles.addAll(getFilesInDir(children[i], filter));
446 				} else {
447 					Logger.debug(LOG_INSTANCE, "Adding child: " + children[i].getAbsolutePath());
448 					allFiles.add(children[i].getAbsolutePath());
449 				}
450 			}
451 			return allFiles;
452 		} else {
453 			Logger.warn(LOG_INSTANCE, "Could not find any files at " + dir);
454 		}
455 		return null;
456 	}
457 	
458 	public static void writeFileContents(File output, String contents) throws BuildException {
459 		if (output != null) {
460 			try {
461 				if (!output.exists()) {
462 					output.createNewFile();
463 				}
464 				FileWriter fileWriter = new FileWriter(output);
465 				fileWriter.append(contents);
466 				fileWriter.close();
467 			} catch (IOException ioe) {
468 				throw new BuildException("COuld not write file contents", ioe);
469 			}			
470 		}
471 	}
472 	
473 	private static InputStream getInputStreamFromSystemOrClasspath(String name) throws BuildException {
474 		File file = new File(name);
475 		try {
476 			return new FileInputStream(file);
477 		} catch (FileNotFoundException fnfe) {
478 			try {
479 				URL url = FileUtils.class.getClassLoader().getResource(name);
480 				File in = new File(url.getPath());
481 				if (!in.exists()) {
482 					InputStream inStream = FileUtils.class.getClassLoader().getResourceAsStream(name);
483 					if (inStream == null) {
484 						throw new BuildException("Cannot find file " + name);
485 					}
486 					return inStream;
487 				}
488 				return new FileInputStream(in.getAbsolutePath());
489 			} catch (Throwable t) {
490 				throw new BuildException("Error finding the file - " + name + " - in the classpath.", t);
491 			}
492 		} catch (Throwable t) {
493 			throw new BuildException("Error finding the file - " + name + " - in the classpath.", t);
494 		}
495 	}
496 
497 }