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