/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.eclipse.utils.io; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.ebayopensource.turmeric.eclipse.utils.classloader.SOAToolFileUrlHandler; import org.ebayopensource.turmeric.eclipse.utils.plugin.ProgressUtil; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; /** * Standard SOA IO Utility class. Basic IO operations are being used from here. * Most of the APIs deals with files and directories even if the name says it is * generic IO :). * * @author smathew * */ public class IOUtil { /** * Creates a new file under the root adding segments one by one * incrementally. Basically, here we first create the parent directory and * then create the child incrementally. It checks for the readability of the * parent and the validity of the segment before creating every child. * * @param root * the File base directory (ignored if null or not readable * @param segment * the String[] of path elements to add to root (ignored if null) * @return null if root not readable or File otherwise */ public static File newFile(File root, String... segments) { if (readableDir(root)) { if (null != segments) { for (String segment : segments) { if (validSegment(segment)) { root = new File(root, segment); } } } return root; } return null; } private static boolean validSegment(String segment) { return null != segment && 0 < segment.length(); } /** * Checks if the directory is readable. Null Safe. Returns true only if the * file is not null, is a directory , if it exists and if it is readable. * * @param dir the dir * @return true, if successful */ public static boolean readableDir(File dir) { return null != dir && dir.isDirectory() && dir.canRead(); } /** * Join all. * * @param parts the parts * @return the string */ public static String joinAll(final String... parts) { final String dirStr = StringUtils.join(Arrays.asList(parts), File.separator); return dirStr; } private IOUtil() { } /** * This function checks for null, empty String, URLMalformed exception, URI * exception and finally checks file existence In any of the case where it * fails, it will return false. Clients doesnt have to handle null * explicitly. * * @param url the url * @return true, if successful */ public static boolean validateURL(String url) { if (!StringUtils.isEmpty(url)) { try { URL objUrl = new URL(url); objUrl.openStream().close(); } catch (Exception exception) { return false; } } return true; } /** * Writes the contents to this file. This is just a convenience wrapper. If * the file does not exist it will create one and sets the contents. * Additionally it will close the stream whatever is the case. * * @param contents the contents * @param file the file * @param progressMonitor the progress monitor * @throws CoreException the core exception */ public static void writeTo(String contents, final IFile file, IProgressMonitor progressMonitor) throws CoreException { progressMonitor = ProgressUtil.getDefaultMonitor(progressMonitor); InputStream input = IOUtils.toInputStream(contents); try { if (file.exists()) { file.setContents(input, true, true, progressMonitor); } else { file.create(input, true, progressMonitor); } } finally { IOUtils.closeQuietly(input); } } /** * Loads the properties file residing inside a jar. The enclosed jar file is * queried for the given jar entry path and is parsed into a properties * file. Most of the cases this is being used to load some SOA properties * file from a jar project which is not imported to the workspace but is * stored somewhere in the file system. But any client who wants to load a * properties file can use this. There is nothing SOA specific here in this * API. * * @param enclosedJarFile the enclosed jar file * @param jarEntryPath the jar entry path * @return the properties * @throws IOException This is a special case where we want the consumers to * continue without failures, because most of the cases consumes * this in a loop. */ public static Properties loadProperties(JarFile enclosedJarFile, String jarEntryPath) throws IOException { JarEntry jarEntry = enclosedJarFile.getJarEntry(jarEntryPath); InputStream inputStream = enclosedJarFile.getInputStream(jarEntry); Properties properties = new Properties(); properties.load(inputStream); return properties; } /** * Returns the java.io.tmpdir property. Clients are advised to use this * wrapper because at a later stage we can easily change this location. * * @return the default temp dir */ public static File getTempDirectory() { return new File(System.getProperty("java.io.tmpdir")); } /** * In the normal jar URLs usage in Windows Java puts a lock on it. And the * SOA Tool Handler will create a non locking URL by setting the caching * off. There is obviously a performance compromise made here by disabling * the cache. * * @param jarFileUrl the jar file url * @param jarEntryPath the jar entry path * @return the non locking url * @throws IOException Signals that an I/O exception has occurred. */ public static URL getNonLockingURL(URL jarFileUrl, String jarEntryPath) throws IOException { File file = FileUtils.toFile(jarFileUrl); JarFile jarFile; jarFile = new JarFile(file); JarEntry jarEntry = jarFile.getJarEntry(jarEntryPath); if (jarEntry != null) { SOAToolFileUrlHandler handler = new SOAToolFileUrlHandler(jarFile, jarEntry); URL retUrl = new URL("jar", "", -1, new File(jarFile.getName()) .toURI().toURL() + "!/" + jarEntry.getName(), handler); handler.setExpectedUrl(retUrl); return retUrl; } return null; } /** * Return the URL representation of the String. One important thing to note * here is that this API tries to address Malformed URL issue. The new URL * is created as per RFC2396 and there is a high chance that clients run * into the MalformedURLException even if the String can be converted into * an URL in a different way. This is the standard way of addressing the * issue. * * @param url the url * @return the uRL * @throws MalformedURLException the malformed url exception * @throws UnsupportedEncodingException the unsupported encoding exception */ public static URL toURL(String url) throws MalformedURLException, UnsupportedEncodingException { URL retURL = null; try { retURL = new URL(url); } catch (Exception exception) { File file = new File(url); retURL = file.toURI().toURL(); } String vmFileEncoding = System.getProperty("file.encoding"); retURL = new URL(URLDecoder.decode(retURL.toString(), vmFileEncoding)); return retURL; } /** * Returns the list of files contained in the given directory. Null safe. * Returns an empty list if the directory is null or is not a directory or * if it is empty. If the dirOrFile is true it will return only the child * directories else it will return only the file children. * * @param dir the dir * @param dirOrFile the dir or file * @return returns the list of file in the directory, */ public static List<File> listFile(File dir, boolean dirOrFile) { List<File> fileList = new ArrayList<File>(); if (dir != null && dir.isDirectory()) { for (File file : dir.listFiles()) if (dirOrFile) { if (file.isDirectory()) { fileList.add(file); } } else { if (file.isFile()) { fileList.add(file); } } } return fileList; } }