001 /** 002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved. 003 * Licensed under the Apache License, Version 2.0 (the "License"); 004 * you may not use this file except in compliance with the License. 005 * You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software 010 * distributed under the License is distributed on an "AS IS" BASIS, 011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 * See the License for the specific language governing permissions and 013 * limitations under the License. See accompanying LICENSE file. 014 */ 015 package org.apache.oozie.util; 016 017 import java.io.IOException; 018 import java.io.InputStream; 019 import java.io.InputStreamReader; 020 import java.io.OutputStream; 021 import java.io.Reader; 022 import java.io.Writer; 023 import java.io.File; 024 import java.io.FileInputStream; 025 import java.io.FileOutputStream; 026 import java.util.zip.ZipOutputStream; 027 import java.util.zip.ZipEntry; 028 import java.util.jar.JarOutputStream; 029 import java.util.jar.Manifest; 030 031 /** 032 * IO Utility methods. 033 */ 034 public abstract class IOUtils { 035 036 /** 037 * Delete recursively a local directory. 038 * 039 * @param file directory to delete. 040 * @throws IOException thrown if the directory could not be deleted. 041 */ 042 public static void delete(File file) throws IOException { 043 ParamChecker.notNull(file, "file"); 044 if (file.getAbsolutePath().length() < 5) { 045 throw new RuntimeException(XLog.format("Path[{0}] is too short, not deleting", file.getAbsolutePath())); 046 } 047 if (file.exists()) { 048 if (file.isDirectory()) { 049 File[] children = file.listFiles(); 050 if (children != null) { 051 for (File child : children) { 052 delete(child); 053 } 054 } 055 } 056 if (!file.delete()) { 057 throw new RuntimeException(XLog.format("Could not delete path[{0}]", file.getAbsolutePath())); 058 } 059 } 060 } 061 062 /** 063 * Return a reader as string. <p/> 064 * 065 * @param reader reader to read into a string. 066 * @param maxLen max content length allowed, if -1 there is no limit. 067 * @return the reader content. 068 * @throws IOException thrown if the resource could not be read. 069 */ 070 public static String getReaderAsString(Reader reader, int maxLen) throws IOException { 071 ParamChecker.notNull(reader, "reader"); 072 StringBuffer sb = new StringBuffer(); 073 char[] buffer = new char[2048]; 074 int read; 075 int count = 0; 076 while ((read = reader.read(buffer)) > -1) { 077 count += read; 078 if (maxLen > -1 && count > maxLen) { 079 throw new IllegalArgumentException(XLog.format("stream exceeds limit [{0}]", maxLen)); 080 } 081 sb.append(buffer, 0, read); 082 } 083 reader.close(); 084 return sb.toString(); 085 } 086 087 088 /** 089 * Return a classpath resource as a stream. <p/> 090 * 091 * @param path classpath for the resource. 092 * @param maxLen max content length allowed. 093 * @return the stream for the resource. 094 * @throws IOException thrown if the resource could not be read. 095 */ 096 public static InputStream getResourceAsStream(String path, int maxLen) throws IOException { 097 ParamChecker.notEmpty(path, "path"); 098 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path); 099 if (is == null) { 100 throw new IllegalArgumentException(XLog.format("resource [{0}] not found", path)); 101 } 102 return is; 103 } 104 105 /** 106 * Return a classpath resource as a reader. <p/> It is assumed that the resource is a text resource. 107 * 108 * @param path classpath for the resource. 109 * @param maxLen max content length allowed. 110 * @return the reader for the resource. 111 * @throws IOException thrown if the resource could not be read. 112 */ 113 public static Reader getResourceAsReader(String path, int maxLen) throws IOException { 114 return new InputStreamReader(getResourceAsStream(path, maxLen)); 115 } 116 117 /** 118 * Return a classpath resource as string. <p/> It is assumed that the resource is a text resource. 119 * 120 * @param path classpath for the resource. 121 * @param maxLen max content length allowed. 122 * @return the resource content. 123 * @throws IOException thrown if the resource could not be read. 124 */ 125 public static String getResourceAsString(String path, int maxLen) throws IOException { 126 ParamChecker.notEmpty(path, "path"); 127 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path); 128 if (is == null) { 129 throw new IllegalArgumentException(XLog.format("resource [{0}] not found", path)); 130 } 131 Reader reader = new InputStreamReader(is); 132 return getReaderAsString(reader, maxLen); 133 } 134 135 /** 136 * Copies an inputstream into an output stream. 137 * 138 * @param is inputstream to copy from. 139 * @param os outputstream to copy to. 140 * @throws IOException thrown if the copy failed. 141 */ 142 public static void copyStream(InputStream is, OutputStream os) throws IOException { 143 ParamChecker.notNull(is, "is"); 144 ParamChecker.notNull(os, "os"); 145 byte[] buffer = new byte[4096]; 146 int read; 147 while ((read = is.read(buffer)) > -1) { 148 os.write(buffer, 0, read); 149 } 150 os.close(); 151 is.close(); 152 } 153 154 /** 155 * Copies an char input stream into an char output stream. 156 * 157 * @param reader reader to copy from. 158 * @param writer writer to copy to. 159 * @throws IOException thrown if the copy failed. 160 */ 161 public static void copyCharStream(Reader reader, Writer writer) throws IOException { 162 ParamChecker.notNull(reader, "reader"); 163 ParamChecker.notNull(writer, "writer"); 164 char[] buffer = new char[4096]; 165 int read; 166 while ((read = reader.read(buffer)) > -1) { 167 writer.write(buffer, 0, read); 168 } 169 writer.close(); 170 reader.close(); 171 } 172 173 /** 174 * Zips a local directory, recursively, into a ZIP stream. 175 * 176 * @param dir directory to ZIP. 177 * @param relativePath basePath in the ZIP for the files, normally "/". 178 * @param zos the ZIP output stream to ZIP the directory. 179 * @throws java.io.IOException thrown if the directory could not be zipped. 180 */ 181 public static void zipDir(File dir, String relativePath, ZipOutputStream zos) throws IOException { 182 zipDir(dir, relativePath, zos, true); 183 zos.close(); 184 } 185 186 private static void zipDir(File dir, String relativePath, ZipOutputStream zos, boolean start) throws IOException { 187 String[] dirList = dir.list(); 188 for (String aDirList : dirList) { 189 File f = new File(dir, aDirList); 190 if (!f.isHidden()) { 191 if (f.isDirectory()) { 192 if (!start) { 193 ZipEntry dirEntry = new ZipEntry(relativePath + f.getName() + "/"); 194 zos.putNextEntry(dirEntry); 195 zos.closeEntry(); 196 } 197 String filePath = f.getPath(); 198 File file = new File(filePath); 199 zipDir(file, relativePath + f.getName() + "/", zos, false); 200 } 201 else { 202 ZipEntry anEntry = new ZipEntry(relativePath + f.getName()); 203 zos.putNextEntry(anEntry); 204 InputStream is = new FileInputStream(f); 205 byte[] arr = new byte[4096]; 206 int read = is.read(arr); 207 while (read > -1) { 208 zos.write(arr, 0, read); 209 read = is.read(arr); 210 } 211 is.close(); 212 zos.closeEntry(); 213 } 214 } 215 } 216 } 217 218 /** 219 * Creates a JAR file with the specified classes. 220 * 221 * @param baseDir local directory to create the JAR file, the staging 'classes' directory is created in there. 222 * @param jarName JAR file name, including extesion. 223 * @param classes classes to add to the JAR. 224 * @return an absolute File to the created JAR file. 225 * @throws java.io.IOException thrown if the JAR file could not be created. 226 */ 227 public static File createJar(File baseDir, String jarName, Class... classes) throws IOException { 228 File classesDir = new File(baseDir, "classes"); 229 for (Class clazz : classes) { 230 String classPath = clazz.getName().replace(".", "/") + ".class"; 231 String classFileName = classPath; 232 if (classPath.lastIndexOf("/") > -1) { 233 classFileName = classPath.substring(classPath.lastIndexOf("/") + 1); 234 } 235 String packagePath = new File(classPath).getParent(); 236 File dir = new File(classesDir, packagePath); 237 if (!dir.exists()) { 238 if (!dir.mkdirs()) { 239 throw new IOException(XLog.format("could not create dir [{0}]", dir)); 240 } 241 } 242 InputStream is = getResourceAsStream(classPath, -1); 243 OutputStream os = new FileOutputStream(new File(dir, classFileName)); 244 copyStream(is, os); 245 } 246 File jar = new File(baseDir, jarName); 247 File jarDir = jar.getParentFile(); 248 if (!jarDir.exists()) { 249 if (!jarDir.mkdirs()) { 250 throw new IOException(XLog.format("could not create dir [{0}]", jarDir)); 251 } 252 } 253 JarOutputStream zos = new JarOutputStream(new FileOutputStream(jar), new Manifest()); 254 zipDir(classesDir, "", zos); 255 return jar; 256 } 257 }