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 }