001: /* ====================================================================
002: * The LateralNZ Software License, Version 1.0
003: *
004: * Copyright (c) 2003 LateralNZ. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by
021: * LateralNZ (http://www.lateralnz.org/) and other third parties."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. The names "LateralNZ" must not be used to endorse or promote
026: * products derived from this software without prior written
027: * permission. For written permission, please
028: * contact oss@lateralnz.org.
029: *
030: * 5. Products derived from this software may not be called "Panther",
031: * or "Lateral" or "LateralNZ", nor may "PANTHER" or "LATERAL" or
032: * "LATERALNZ" appear in their name, without prior written
033: * permission of LateralNZ.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of LateralNZ. For more
051: * information on Lateral, please see http://www.lateralnz.com/ or
052: * http://www.lateralnz.org
053: *
054: */
055: package org.lateralnz.common.util;
056:
057: import java.io.File;
058: import java.io.FileFilter;
059: import java.io.FileInputStream;
060: import java.io.FilenameFilter;
061: import java.io.FileOutputStream;
062: import java.io.InputStreamReader;
063: import java.io.IOException;
064: import java.lang.reflect.InvocationTargetException;
065: import java.lang.reflect.Method;
066: import java.lang.reflect.Modifier;
067: import java.net.InetAddress;
068: import java.net.NetworkInterface;
069: import java.nio.channels.FileChannel;
070: import java.util.Arrays;
071: import java.util.Enumeration;
072: import java.util.List;
073:
074: import org.apache.log4j.Logger;
075:
076: /**
077: * various 'System' related functions
078: *
079: * @author J R Briggs
080: */
081: public class SystemUtils {
082: private static final Logger log = Logger
083: .getLogger(SystemUtils.class.getName());
084: private static final String GET = "get";
085: private static final String SET = "set";
086: private static final Class MAIN_ARGS = (new String[] {}).getClass();
087:
088: private static final byte[] LOCALHOST_LOOPBACK = new byte[] {
089: (byte) 127, (byte) 0, (byte) 0, (byte) 1 };
090:
091: private SystemUtils() {
092: }
093:
094: public static final void copyFile(String f1, String f2)
095: throws IOException {
096: FileChannel source = new FileInputStream(f1).getChannel();
097: FileChannel dest = new FileOutputStream(f2).getChannel();
098: dest.transferFrom(source, 0, source.size());
099:
100: source.close();
101: dest.close();
102: }
103:
104: /**
105: * execute a given command. This essentially wraps the command with a monitor so we can
106: * kill it after a certain period of time. At the moment this is useful for Jikes, since it
107: * seems to hang after certain errors, with no meaningful syserr output
108: * @param cmd the command array
109: * @param env the environment array
110: * @param f the file to use during the exec (@see java.lang.Runtime#getRuntime)
111: * @param waitPeriod the length of time to wait until we assume something has gone wrong and kill the process
112: */
113: public static final String[] exec(String[] cmd, String[] env,
114: File f, long waitPeriod) throws IOException,
115: InterruptedException {
116: Process p = Runtime.getRuntime().exec(cmd, env, f);
117:
118: ProcessMonitor pm = new ProcessMonitor(p, waitPeriod);
119: p.waitFor();
120:
121: InputStreamReader is = null;
122: InputStreamReader es = null;
123: try {
124: is = new InputStreamReader(p.getInputStream());
125: es = new InputStreamReader(p.getErrorStream());
126:
127: if (pm.rtn[0] == null) {
128: pm.rtn[0] = StringUtils.readFrom(is).trim();
129: }
130: if (pm.rtn[1] == null) {
131: pm.rtn[1] = StringUtils.readFrom(es).trim();
132: }
133: } finally {
134: IOUtils.close(is);
135: IOUtils.close(es);
136: }
137:
138: return pm.rtn;
139: }
140:
141: /**
142: * taking an array of arguments (usually in the main() method) return the value at
143: * a particular index -- or if it is null/empty, return a default value
144: */
145: public static final String getArgument(String[] args, int idx,
146: String defaultValue) {
147: if (args == null || idx >= args.length
148: || StringUtils.isEmpty(args[idx])) {
149: return defaultValue;
150: } else {
151: return args[idx];
152: }
153: }
154:
155: /**
156: * get a list of files matching a regex
157: */
158: public static final String[] getFileList(String directory,
159: final String regex) {
160: File f = new File(directory);
161: if (!f.exists() || !f.isDirectory()) {
162: return new String[] {};
163: } else {
164: return f.list(new FilenameFilter() {
165: public boolean accept(File f, String name) {
166: if (StringUtils.matches(name, regex)) {
167: return true;
168: }
169: return false;
170: }
171: });
172: }
173: }
174:
175: /**
176: * loads the specified list with File objects (recursing through directories if required)
177: */
178: public static final void getFileList(List filelist,
179: String directory, final String includesRegex,
180: final String excludesRegex, boolean recursive) {
181: File f = new File(directory);
182: if (f.exists() && f.isDirectory()) {
183: File[] farray = f.listFiles(new FileFilter() {
184: public boolean accept(File f) {
185: if (f.isDirectory()) {
186: return true;
187: } else {
188: String name;
189: try {
190: name = f.getCanonicalPath();
191: if (StringUtils
192: .matches(name, includesRegex)
193: && !StringUtils.matches(name,
194: excludesRegex)) {
195: return true;
196: }
197: } catch (IOException ioe) {
198: ioe.printStackTrace();
199: }
200: }
201: return false;
202: }
203: });
204: for (int i = 0; i < farray.length; i++) {
205: if (farray[i].isDirectory() && recursive) {
206: getFileList(filelist, farray[i].getAbsolutePath(),
207: includesRegex, excludesRegex, recursive);
208: } else {
209: filelist.add(farray[i]);
210: }
211: }
212: }
213: }
214:
215: /**
216: * hopefully this will return the 'real' IP address even if the hosts file is configured
217: * incorrectly (as I discovered on my test machine... JRB). However, If it really can't
218: * figure out the address it will return the loopback address.
219: */
220: public static final byte[] getLocalhostIP() {
221: try {
222: InetAddress ia = InetAddress.getLocalHost();
223: if (!Arrays.equals(ia.getAddress(), LOCALHOST_LOOPBACK)) {
224: return ia.getAddress();
225: } else {
226: Enumeration en = NetworkInterface
227: .getNetworkInterfaces();
228: while (en.hasMoreElements()) {
229: NetworkInterface ni = (NetworkInterface) en
230: .nextElement();
231: Enumeration en2 = ni.getInetAddresses();
232: while (en2.hasMoreElements()) {
233: ia = (InetAddress) en2.nextElement();
234: if (!ia.isLoopbackAddress()) {
235: return ia.getAddress();
236: }
237: }
238: }
239: }
240: } catch (Exception e) {
241: e.printStackTrace();
242: }
243: return (byte[]) LOCALHOST_LOOPBACK.clone();
244: }
245:
246: /**
247: * get the "set" method for a property given a class and paramTypes array
248: */
249: public static final Method getSetterMethod(Class c,
250: String property, Class[] paramTypes)
251: throws NoSuchMethodException {
252: if (StringUtils.isEmpty(property)) {
253: return null;
254: }
255:
256: String tmp = SET + initCaps(property);
257:
258: return c.getMethod(tmp, paramTypes);
259: }
260:
261: private static final String initCaps(String s) {
262: return s.substring(0, 1).toUpperCase() + s.substring(1);
263: }
264:
265: /**
266: * invoke a method on an object
267: */
268: public static final Object invoke(Object obj, String method,
269: Object[] args) throws IllegalAccessException,
270: InvocationTargetException, NoSuchMethodException {
271: Class c = obj.getClass();
272: Class[] params = null;
273: if (args != null) {
274: params = new Class[args.length];
275: for (int i = 0; i < args.length; i++) {
276: params[i] = args[i].getClass();
277: }
278: }
279: Method m = c.getMethod(method, params);
280: return m.invoke(obj, args);
281: }
282:
283: /**
284: * invoke the main method of a class
285: */
286: public static final void invokeMain(Class c, String[] args)
287: throws IllegalAccessException, InvocationTargetException,
288: NoSuchMethodException {
289: Class argsClass;
290: if (args == null) {
291: argsClass = MAIN_ARGS;
292: } else {
293: argsClass = args.getClass();
294: }
295: Method m = c.getMethod("main", new Class[] { argsClass });
296: m.setAccessible(true);
297: int mods = m.getModifiers();
298: if (m.getReturnType() != void.class || !Modifier.isStatic(mods)
299: || !Modifier.isPublic(mods)) {
300: throw new NoSuchMethodException("main");
301: }
302: m.invoke(null, new Object[] { args });
303: }
304:
305: /**
306: * the process monitor used when exec'ing a command
307: */
308: static class ProcessMonitor extends Thread {
309: private String[] rtn = new String[2];
310: private boolean running = true;
311: private int count = 10;
312: private long waitPeriod;
313: private Process p;
314:
315: public ProcessMonitor(Process p, long waitPeriod) {
316: this .p = p;
317: this .waitPeriod = waitPeriod;
318: this .start();
319: }
320:
321: public void run() {
322: while (running) {
323: try {
324: this .sleep(waitPeriod);
325: p.exitValue();
326: } catch (InterruptedException ie) {
327: } catch (IllegalThreadStateException itse) {
328: count--;
329: InputStreamReader iisr = null;
330: InputStreamReader eisr = null;
331: try {
332: int incount = p.getInputStream().available();
333: int errcount = p.getErrorStream().available();
334: if (incount > 0 || errcount > 0 || count <= 0) {
335: log.warn("stdin(" + incount + "), stderr("
336: + errcount + ")");
337: log.warn("destroying hung process " + p);
338:
339: iisr = new InputStreamReader(p
340: .getInputStream());
341: eisr = new InputStreamReader(p
342: .getErrorStream());
343: rtn[0] = StringUtils
344: .readFrom(iisr, incount).trim();
345: rtn[1] = StringUtils.readFrom(eisr,
346: errcount).trim();
347: p.destroy();
348: running = false;
349: } else if (log.isInfoEnabled()) {
350: log
351: .info("SystemUtils.exec: process has still not completed after 10 seconds");
352: }
353: } catch (Exception e) {
354: log.error(e);
355: e.printStackTrace();
356: } finally {
357: IOUtils.close(iisr);
358: IOUtils.close(eisr);
359: }
360: }
361: }
362: }
363: }
364:
365: public static final void sleep(long time) {
366: try {
367: Thread.currentThread().sleep(time);
368: } catch (InterruptedException ie) {
369: }
370: }
371: }
|