Source code for /engineering/autohit-2003/src/autohit/common/Utils.javaOriginal file Utils.java
   1 /**
   2  * AUTOHIT 2003
   3  * Copyright Erich P Gatejen (c) 1989,1997,2003,2004
   4  * 
   5  * This program is free software; you can redistribute it and/or modify 
   6  * it under the terms of the GNU General Public License as published by 
   7  * the Free Software Foundation; either version 2 of the License, or (at
   8  * your option) any later version.
   9  * This program is distributed in the hope that it will be useful, but
  10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12  * more details.
  13  * 
  14  * You should have received a copy of the GNU General Public License along
  15  * with this program; if not, write to the Free Software Foundation, Inc.,
  16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17  *
  18  * Additional license information can be found in the documentation.
  19  * @author Erich P Gatejen
  20  */
  21 package autohit.common;
  22 import java.io.BufferedInputStream;
  23 import java.io.BufferedOutputStream;
  24 import java.io.File;
  25 import java.io.FileInputStream;
  26 import java.io.FileOutputStream;
  27 import java.io.BufferedReader;
  28 import java.io.BufferedWriter;
  29 import java.io.FileReader;
  30 import java.io.FileWriter;
  31 import org.apache.commons.collections.ExtendedProperties;
  32 
  33 /**
  34  * A bunch of utils
  35  *
  36  * @author Erich P. Gatejen
  37  * @version 1.0
  38  * <i>Version History</i>
  39  * <code>EPG - Rewrite - 9Apr03 
  40  * 
  41  */
  42 public class Utils {
  43 	
  44 	// internal state values
  45 	private final static int STATE_FRESH = 0;
  46 	private final static int STATE_FRONT = 1;
  47 	private final static int STATE_READ  = 2;
  48 	private final static int STATE_TAIL  = 3;
  49 	// Again.  I can't beleive I have to do this.  This MAY break in future JDKs.
  50 	// It seems that BufferedReader.read() does NOT return -1 for an empty string; it
  51 	// returns the freaking 2scompliment of -1.  
  52 	// (2003-May: This may work now.  I'm too lazy to check it.)
  53 	private final static int MORONIC_TOP_VALUE = 65534;
  54 
  55 	/**
  56 	 *  Converts dot namespace to a path
  57 	 * @param header prefix for the path
  58 	 * @param dot path in dot notation
  59 	 * @return a converted path
  60 	 */
  61 	public static String dot2path(String header, String dot) {
  62 		return header
  63 			+ AutohitProperties.literal_PATH_SEPERATOR
  64 			+ dot.replace(
  65 				AutohitProperties.literal_NAME_SEPERATOR,
  66 				AutohitProperties.literal_PATH_SEPERATOR);
  67 	}
  68 
  69 	/**
  70 	 *  Make a file reference.  If the file already exists, kill it.
  71 	 *  If the path doesn't exist, make it.  It'll throw an exception if
  72 	 * it fails.
  73 	 * @param name path name
  74 	 * @return file object
  75 	 * @throws Exception
  76 	 */
  77 	public static File makeFile(String name) throws Exception {
  78 
  79 		File dir;
  80 		String dirpath;
  81 		int last;
  82 
  83 		// construct the path
  84 		File target = new File(name);
  85 
  86 		if (target.exists()) {
  87 			target.delete();
  88 		} else {
  89 			// futz with the directory and make it is neccessary
  90 			last = name.lastIndexOf(AutohitProperties.literal_PATH_SEPERATOR);
  91 			if (last > 1) {
  92 				dirpath = name.substring(0, last);
  93 				dir = new File(dirpath);
  94 				if (!dir.exists()) {
  95 					dir.mkdirs();
  96 				}
  97 			}
  98 		}
  99 		return target;
 100 	}
 101 
 102 	/**
 103 	 *  Test and get property.  Return null if not found or something went wrong.
 104 	 *  Traps all exceptions
 105 	 * @param key key for the property
 106 	 * @param props the property set
 107 	 * @return the property object
 108 	 */
 109 	public static Object testGetProperty(
 110 		String key,
 111 		ExtendedProperties props) {
 112 		Object thing = null;
 113 		try {
 114 			thing = props.getProperty(key);
 115 		} catch (Exception e) {
 116 			thing = null;
 117 		}
 118 		return thing;
 119 	}
 120 
 121 	/**
 122 	 *  Test and get property for truth.  If will return true if the property
 123 	 *  containts 'true', otherwise it will return false;
 124 	 *  Traps all exceptions
 125 	 * @param key key for the property
 126 	 * @param props the property set
 127 	 * @return true if the proprerty is 'true', otherwise false.
 128 	 */
 129 	public static boolean testGetPropertyTruth(
 130 		String key,
 131 		ExtendedProperties props) {
 132 		boolean thing = false;
 133 		String thang;
 134 		try {
 135 			thang = (String)props.getProperty(key);
 136 			thing = thang.equals(Constants.TRUE);
 137 		} catch (Exception e) {
 138 		}
 139 		return thing;
 140 	}
 141 	
 142 	/**
 143 	 *  Copy files.  I can't believe I have to write this.  It will always
 144 	 *  overwrite an existing file.
 145 	 * @param source source file path
 146 	 * @param dest destination file path
 147 	 * @return string containing errors or messages
 148 	 */
 149 	public static String copy(String source, String dest) {
 150 
 151 		String overwrite = " ";
 152 
 153 		BufferedOutputStream bos = null;
 154 		try {
 155 
 156 			File destf = new File(dest);
 157 			if (destf.exists()) {
 158 				destf.delete();
 159 				overwrite = " [overwrite] ";
 160 			}
 161 
 162 			byte[] buf = new byte[1024];
 163 			int sbuf;
 164 
 165 			BufferedInputStream bis =
 166 				new BufferedInputStream(new FileInputStream(source));
 167 			bos = new BufferedOutputStream(new FileOutputStream(dest));
 168 
 169 			sbuf = bis.read(buf, 0, 1024);
 170 			while (sbuf > 0) {
 171 				bos.write(buf, 0, sbuf);
 172 				sbuf = bis.read(buf, 0, 1024);
 173 			}
 174 		} catch (Exception e) {
 175 		}
 176 		try {
 177 			bos.close();
 178 		} catch (Exception e) {
 179 			return "Copy failed for=" + source + Constants.CRUDE_SEPERATOR;
 180 		}
 181 		return "Copied file=" + source + overwrite + Constants.CRUDE_SEPERATOR;
 182 	}
 183 
 184 	/**
 185 	 *  Merge a file with properties.  It will overwrite an existing file.
 186 	 *  This is not exactly FAST.
 187 	 * @param source source file
 188 	 * @param dest destination file
 189 	 * @param props properties that are candidates for substitution
 190 	 * @return string containing errors or messages
 191 	 */
 192 	public static String merge(
 193 		String source,
 194 		String dest,
 195 		ExtendedProperties props) {
 196 
 197 		int state = STATE_FRESH;
 198 		BufferedReader inBR = null;
 199 		BufferedWriter outT = null;
 200 		int workingC;
 201 		StringBuffer cBuf = null;
 202 		String theVar = null;
 203 		String ts = null;
 204 		StringBuffer messages = new StringBuffer();
 205 		String overwrite = " ";
 206 
 207 		// Read and fix
 208 		try {
 209 			// Clear an existing file
 210 			File destf = new File(dest);
 211 			if (destf.exists()) {
 212 				destf.delete();
 213 				overwrite = " [overwrite] ";
 214 			}
 215 			inBR = new BufferedReader(new FileReader(source));
 216 			outT = new BufferedWriter(new FileWriter(dest));
 217 			
 218 			// start the engine
 219 			workingC = inBR.read();
 220 			while ((workingC >= 0)
 221 				&& (workingC
 222 					< MORONIC_TOP_VALUE)) {
 223 
 224 				switch (state) {
 225 
 226 					case STATE_FRESH :
 227 						if (workingC == Constants.CONFIG_OPEN)
 228 							state = STATE_FRONT;
 229 						else
 230 							outT.write(workingC);
 231 						break;
 232 
 233 					case STATE_FRONT :
 234 						if (workingC == Constants.CONFIG_OPEN) {
 235 							state = STATE_READ;
 236 							cBuf = new StringBuffer();
 237 						} else {
 238 							state = STATE_FRESH;
 239 							outT.write(Constants.CONFIG_OPEN);
 240 							outT.write(workingC);
 241 						}
 242 						break;
 243 
 244 					case STATE_READ :
 245 						if (workingC == Constants.CONFIG_CLOSE) {
 246 							state = STATE_TAIL;
 247 						} else {
 248 							cBuf.append((char) workingC);
 249 						}
 250 						break;
 251 
 252 					case STATE_TAIL :
 253 						if (workingC == Constants.CONFIG_CLOSE) {
 254 							state = STATE_FRESH;
 255 							theVar = cBuf.toString();
 256 
 257 							if (props.containsKey(theVar)) {
 258 								ts = (String) props.get(theVar);
 259 								outT.write(ts, 0, ts.length());
 260 							} else {
 261 								outT.write(Constants.CONFIG_BLANK);
 262 							}
 263 						} else {
 264 							outT.write(Constants.CONFIG_CLOSE);
 265 							outT.write(workingC);
 266 						}
 267 						break;
 268 				} // end case
 269 				workingC = inBR.read();
 270 			}
 271 		} catch (Exception e) {
 272 			// Might just be EOF
 273 			//System.out.println(e);			
 274 		} finally {
 275 			try {
 276 				inBR.close();
 277 				outT.close();
 278 				if (state != STATE_FRESH) {
 279 					messages.append(
 280 						"Bad File.  Incomplete escape <<>> in file="
 281 							+ source + Constants.CRUDE_SEPERATOR);
 282 					messages.append(".........  Destination file might be corrupt.  file=" + dest + Constants.CRUDE_SEPERATOR);
 283 				}
 284 				messages.append("Merged file to=" + dest + overwrite + Constants.CRUDE_SEPERATOR);
 285 			} catch (Exception e) {
 286 				messages.append("Catastrophic error merging" + source + Constants.CRUDE_SEPERATOR);
 287 				messages.append(".........  Destination file might be corrupt.  file=" + dest + Constants.CRUDE_SEPERATOR);
 288 			}
 289 			
 290 		}
 291 		return messages.toString();
 292 	}
 293 
 294 	/**
 295 	 *  Copy entire directories.  I can't believe I have to write this.
 296 	 * @param source source is the source directory, without a training slash
 297 	 * @param dest destination is the destination directory, without a training slash
 298 	 * @param wipe destructive copy.  If true, it will destroy destination directories before
 299 	 * copying the files.  The files themselves are always overwritten.
 300 	 * @return string containing errors or messages
 301 	 */
 302 	public static String copyDir(String source, String dest, boolean wipe) {
 303 
 304 		String[] directory;
 305 		String destinationfile = "";
 306 		String sourcefile;
 307 		File fsource = new File(source);
 308 		File fdest = new File(dest);
 309 		int size;
 310 		StringBuffer messages = new StringBuffer();
 311 
 312 		try {
 313 
 314 			// get the source directory list
 315 			directory = fsource.list();
 316 
 317 			// create the destination directory.  If it already exists, wipe it.
 318 			if (fdest.exists()) {
 319 				if (wipe == true) {
 320 					messages.append(Utils.wipeDir(dest));
 321 					fdest.mkdirs();
 322 					messages.append(
 323 						"Make directory=" + dest + Constants.CRUDE_SEPERATOR);
 324 				}
 325 			} else {
 326 				fdest.mkdirs();
 327 				messages.append(
 328 					"Make directory=" + dest + Constants.CRUDE_SEPERATOR);
 329 			}
 330 
 331 			// rove the directory list
 332 			for (int i = 0; i < directory.length; i++) {
 333 				try {
 334 					destinationfile = dest + '/' + directory[i];
 335 					sourcefile = source + '/' + directory[i];
 336 					fsource = new File(sourcefile);
 337 					if (fsource.isDirectory()) {
 338 						messages.append(
 339 							"Is directory="
 340 								+ sourcefile
 341 								+ Constants.CRUDE_SEPERATOR);
 342 						messages.append(
 343 							Utils.copyDir(sourcefile, destinationfile, wipe));
 344 					} else {
 345 						messages.append(
 346 							Utils.copy(sourcefile, destinationfile));
 347 					}
 348 				} catch (Exception e) {
 349 					messages.append(
 350 						"Error on="
 351 							+ destinationfile
 352 							+ Constants.CRUDE_SEPERATOR);
 353 				}
 354 			}
 355 			messages.append(
 356 				"Done with directory= " + source + Constants.CRUDE_SEPERATOR);
 357 
 358 		} catch (Exception e) {
 359 			messages.append(
 360 				"Serious error on="
 361 					+ dest
 362 					+ " error="
 363 					+ e.getMessage()
 364 					+ Constants.CRUDE_SEPERATOR);
 365 		}
 366 		return messages.toString();
 367 	}
 368 
 369 	/**
 370 	 *  Wipe a directory and everything in it
 371 	 * @param dest path to the directory
 372 	 * @return string containing errors or messages
 373 	 */
 374 	public static String wipeDir(String dest) {
 375 
 376 		String[] directory;
 377 		File fsource = new File(dest);
 378 		StringBuffer messages = new StringBuffer();
 379 		String newdest;
 380 		File newf;
 381 
 382 		try {
 383 
 384 			// get the source directory list
 385 			directory = fsource.list();
 386 
 387 			// rove the directory list
 388 			for (int i = 0; i < directory.length; i++) {
 389 				try {
 390 					newdest = dest + '/' + directory[i];
 391 					newf = new File(newdest);
 392 					if (newf.isDirectory()) {
 393 						messages.append(
 394 							"Wipe directory="
 395 								+ newdest
 396 								+ Constants.CRUDE_SEPERATOR);
 397 						messages.append(Utils.wipeDir(newdest));
 398 					} else {
 399 						newf.delete();
 400 					}
 401 				} catch (Exception e) {
 402 					messages.append(
 403 						"Error on wipe=" + dest + Constants.CRUDE_SEPERATOR);
 404 				}
 405 			}
 406 			fsource.delete();
 407 			messages.append(
 408 				"Done wipe of directory= " + dest + Constants.CRUDE_SEPERATOR);
 409 
 410 		} catch (Exception e) {
 411 			messages.append(
 412 				"Serious error on wipe of= "
 413 					+ dest
 414 					+ " error="
 415 					+ e.getMessage()
 416 					+ Constants.CRUDE_SEPERATOR);
 417 		}
 418 		return messages.toString();
 419 	}
 420 	
 421 	/**
 422 	 *  Read a file into a String.
 423 	 * @param f File to read
 424 	 * @return string if successful or otherwise null
 425 	 */
 426 	public static String loadFile2String(File   f) {
 427 
 428 		StringBuffer	buffer = new StringBuffer();
 429 		try {
 430 
 431 			char[] buf = new char[1024];
 432 			int sbuf;
 433 
 434 			BufferedReader bis
 435 			   = new BufferedReader(new FileReader(f));
 436 
 437 			sbuf = bis.read(buf, 0, 1024);
 438 			while (sbuf > 0) {
 439 				buffer.append(buf, 0, sbuf);
 440 				sbuf = bis.read(buf, 0, 1024);
 441 			}
 442 		} catch (Exception e) {
 443 e.printStackTrace();
 444 			return null;
 445 		}
 446 		return buffer.toString();
 447 	}
 448 	
 449 	/**
 450 	 * Get a packed, big-endian integer.  The array better have 4 bytes or you'll get an exception 
 451 	 * @param buf arracy of bytes
 452 	 * @return the integer
 453 	 */	
 454 	public static int packInteger(byte[] buf) {
 455 		return ((buf[3] & 0xFF) << 0) +
 456 		((buf[2] & 0xFF) << 8) +
 457 		((buf[1] & 0xFF) << 16) +
 458 		((buf[0] & 0xFF) << 24);
 459 	}
 460 	
 461 	/**
 462 	 * Unpack an integer into an array--big-endian.  The array better have 4 bytes or you'll get an exception 
 463 	 * @param buf array of bytes.  better be at least 4 bytes
 464 	 * @param offset offset into the array to start the unpack
 465 	 * @param value the integer to unpack
 466 	 */	
 467 	public static void unpackInteger(byte[] buf, int offset, int value) {
 468 		buf[offset + 3] = (byte) (value >>> 0);
 469 		buf[offset + 2] = (byte) (value >>> 8);
 470 		buf[offset + 1] = (byte) (value >>> 16);
 471 		buf[offset + 0] = (byte) (value >>> 24);
 472 	}	
 473 	
 474 	// Total kludge.  don't use
 475 	public static String norfIt(int value) {
 476 		if (value < 10) {
 477 			return new String ("0" + value);
 478 		} else if (value < 100) {
 479 			return Integer.toString(value);
 480 		} else if (value < 385) {
 481 			StringBuffer zonk = new StringBuffer();
 482 			zonk.append((char)value / 65);
 483 			zonk.append((char)value % 65);
 484 			return zonk.toString();
 485 		} else {
 486 			return "xx";
 487 		}
 488 	}
 489 	
 490 }