Source code for /engineering/autohit-2003/src/autohit/universe/service/UniverseLocal.javaOriginal file UniverseLocal.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.universe.service;
  22 
  23 import java.io.File;
  24 import java.io.FileInputStream;
  25 import java.io.FileOutputStream;
  26 import java.io.InputStream;
  27 import java.io.ObjectInputStream;
  28 import java.io.ObjectOutputStream;
  29 import java.io.OutputStream;
  30 import java.util.Random;
  31 
  32 import javax.activation.DataSource;
  33 import javax.activation.FileDataSource;
  34 
  35 import autohit.common.AutohitProperties;
  36 import autohit.common.Utils;
  37 import autohit.universe.Universe;
  38 import autohit.universe.UniverseDataSource;
  39 import autohit.universe.UniverseException;
  40 import autohit.universe.UniverseProperties;
  41 
  42 /**
  43 * Universe server implimentation for a local filesystem.  This
  44 * does NOT implement caching!  Every object is unique.
  45 * 
  46 * The 'root' property should be a path to the root of the 
  47 * universe on the filesystem.  It should begin with a '/', and
  48 * should have no trailing slashes.
  49 * 
  50 * This universe assumes that storable objects can be serialized completely.
  51 * If you plan on moving data that isn't in objects or are not inherently
  52 * able to seriously completely, then you should obtain streams for put and get, and handle
  53 * the IO yourself.
  54 *
  55 * @author Erich P. Gatejen
  56 * @version 1.0
  57 * <i>Version History</i>
  58 * <code>EPG - New - 24Apr03</code> 
  59 * 
  60 */
  61 public class UniverseLocal implements Universe {
  62 
  63 	private UniverseProperties myProp;
  64 	private String root;
  65 	private Random relement;
  66 
  67 	/**
  68 	 * Impliment the genesis.
  69 	 * 
  70 	 * @param props a universe properties set
  71 	 * @throws autohit.universe.UniverseException
  72 	 * @return the loaded object
  73 	 */
  74 	public void genesis(UniverseProperties props) throws UniverseException {
  75 
  76 		// Save the properties
  77 		myProp = props;
  78 		
  79 		// Get random element
  80 		relement = new Random();
  81 
  82 		// cleanse the root
  83 		root = myProp.getRoot().trim();
  84 		if ((root.length() < 1)
  85 			|| (root.charAt(0) != AutohitProperties.literal_PATH_SEPERATOR)) {
  86 			throw new UniverseException(
  87 				"Bad root.  Either empty or doesn't start with /.",
  88 				UniverseException.UE_MALFORMED_REFERENCE);
  89 		}
  90 		try {
  91 			while (root.charAt(root.length() - 1)
  92 				== AutohitProperties.literal_PATH_SEPERATOR) {
  93 				root = root.substring(0, root.length() - 2);
  94 			}
  95 		} catch (Exception e) {
  96 			throw new UniverseException(
  97 				"Malformed root property =" + myProp.getRoot(),
  98 				UniverseException.UE_MALFORMED_REFERENCE, e);
  99 		}
 100 	}
 101 
 102 	/**
 103 	 * This will always be called when the universe is destroyed
 104 	 * @throws autohit.universe.UniverseException
 105 	 */
 106 	public void close() throws UniverseException {
 107 		// Don't do anything
 108 	}
 109 
 110 	/**
 111 	 *  Load an object from the universe.  It will be unique.
 112 	 *  There is no caching. 
 113 	 * @param name universe name
 114 	 * @return the loaded object
 115 	 * @throws autohit.universe.UniverseException
 116 	 */
 117 	public Object get(String name) throws UniverseException {
 118 		Object thing = null;
 119 
 120 		try {
 121 			// construct the path
 122 			File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 123 			if (target.exists() == false) {
 124 				throw new UniverseException(
 125 					"No object =" + name,
 126 					UniverseException.UE_OBJECT_DOESNT_EXIST);
 127 			}
 128 			// deserialize it
 129 			FileInputStream istream = new FileInputStream(target);
 130 			ObjectInputStream p = new ObjectInputStream(istream);
 131 			thing = p.readObject();
 132 			istream.close();
 133 
 134 		} catch (UniverseException e) {
 135 			throw e;
 136 		} catch (Exception e) {
 137 			// Every other exception should be consider an IO error
 138 			throw new UniverseException(
 139 				"IO Error on object get.  Message=" + e.getMessage(),
 140 				UniverseException.UE_IO_ERROR, e);
 141 		}
 142 		return thing;
 143 	}
 144 
 145 	/**
 146 	 *  Same as get, so just chain it.
 147 	 * @param name universe name
 148 	 * @return the loaded object
 149 	 * @throws autohit.universe.UniverseException
 150 	 */
 151 	public Object getUnique(String name) throws UniverseException {
 152 		return get(name);
 153 	}
 154 
 155 	/**
 156 	 *  Reserve unique object universe.  Guarantee it is a unique
 157 	 *  instance of it.  Great for temp objects.
 158 	 * @param base base path for the object (including root object name)
 159 	 * @return name of the reserved unique object.
 160 	 * @throws autohit.universe.UniverseException
 161 	 * TODO make sure the object can actually be used
 162 	 */
 163 	public synchronized String reserveUnique(String base) throws UniverseException {
 164 
 165 		// Cludge hack!
 166 		String name = base + "-" + System.currentTimeMillis() + "-" + relement.nextInt(1000000);
 167 		
 168 		// Check to see if it is unique.  Since this is sychroninzed
 169 		// any wait will guarentee the new name is unique.
 170 		try {
 171 			File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 172 			if (target.exists() == true) {
 173 				this.wait(1);
 174 				name = base + "-" + System.currentTimeMillis() + "-" + relement.nextInt(1000000);
 175 			}
 176 		} catch (Exception io) {
 177 			// Every other exception should be consider an IO error
 178 			throw new UniverseException(
 179 				"IO Error on object.  Message=" + io.getMessage(),
 180 				UniverseException.UE_IO_ERROR, io);			
 181 		}
 182 		return name;
 183 	}
 184 	
 185 	/**
 186 	 * Get an InputStream that can read from a universe object dump.
 187 	 * It does not assume the target is anything--object, bytes, whatever.
 188 	 * @param name universe name
 189 	 * @return a stream to the object
 190 	 * @throws autohit.universe.UniverseException
 191 	 */
 192 	public InputStream getStream(String name) throws UniverseException {
 193 		InputStream thing = null;
 194 
 195 		try {
 196 			// construct the path
 197 			File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 198 			if (target.exists() == false) {
 199 				throw new UniverseException(
 200 					"No object =" + name,
 201 					UniverseException.UE_OBJECT_DOESNT_EXIST);
 202 			}
 203 			// get a stream reference to it
 204 			thing = new FileInputStream(target);
 205 
 206 		} catch (UniverseException e) {
 207 			throw e;
 208 		} catch (Exception e) {
 209 			// Every other exception should be consider an IO error
 210 			throw new UniverseException(
 211 				"IO Error on object.  Message=" + e.getMessage(),
 212 				UniverseException.UE_IO_ERROR, e);
 213 		}
 214 		return thing;
 215 	}
 216 
 217 	/**
 218 	 *  Get a Data Source that can interact with this universe object
 219 	 * @param name universe name
 220 	 * @return a data source
 221 	 * @throws autohit.universe.UniverseException
 222 	 * @throws autohit.universe.UniverseDataSource
 223 	 */
 224 	public DataSource getDataSource(String name) throws UniverseException {
 225 		
 226 		UniverseDataSource uds = new UniverseDataSource();
 227 		uds.init(name,this);
 228 		return uds;
 229 	}
 230 	
 231 	/**
 232 	 * Get a FileDataSource that can interact with this universe object.
 233 	 * The universe must handle making sure the object at least appears local to the
 234 	 * FileDataSource 
 235 	 * @param name universe name
 236 	 * @return a data source
 237 	 * @throws autohit.universe.UniverseException
 238 	 */
 239 	public FileDataSource getFileDataSource(String name) throws UniverseException {
 240 	    
 241 	    //This one is easy.  Just get the local file.
 242 	    FileDataSource candidate = null;
 243 	    
 244 		try {
 245 			// construct the path
 246 			File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 247 			if (target.exists() == false) {
 248 				throw new UniverseException(
 249 					"No object =" + name,
 250 					UniverseException.UE_OBJECT_DOESNT_EXIST);
 251 			}
 252 			// deserialize it
 253 			candidate = new FileDataSource(target);
 254 			
 255 		} catch (UniverseException e) {
 256 			throw e;
 257 		} catch (Exception e) {
 258 			// Every other exception should be consider an IO error
 259 			throw new UniverseException(
 260 				"IO Error while getting FileDataSource.  Message=" + e.getMessage(),
 261 				UniverseException.UE_IO_ERROR, e);
 262 		}
 263 		return candidate;
 264 	    
 265 	}
 266 
 267 
 268 	/**
 269 	 * Save an object into the universe.  If a file is already there,
 270 	 * it will overwrite it.
 271 	 * @param name universe name
 272 	 * @param o the object
 273 	 * @throws autohit.universe.UniverseException
 274 	 */
 275 	public void put(String name, Object o) throws UniverseException {
 276 
 277 		try {
 278 			// construct the path
 279 			File target = Utils.makeFile(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 280 
 281 			// deserialize it
 282 			FileOutputStream ostream = new FileOutputStream(target);
 283 			ObjectOutputStream sobj = new ObjectOutputStream(ostream);
 284 			sobj.writeObject(o);
 285 			sobj.flush();
 286 			ostream.close();
 287 
 288 		} catch (Exception e) {
 289 			// Every other exception should be consider an IO error
 290 
 291 			throw new UniverseException(
 292 				"IO Error on object put.  Message=" + e.getMessage(),
 293 				UniverseException.UE_IO_ERROR, e);
 294 		}
 295 	}
 296 
 297 	/**
 298 	 *  Get an output stream to a universe object.  CAller responsible
 299 	 * for streaming and closing.
 300 	 * @param name universe name
 301 	 * @return a stream to the object
 302 	 * @throws autohit.universe.UniverseException
 303 	 */
 304 	public OutputStream putStream(String name) throws UniverseException {
 305 		FileOutputStream tempOS = null;
 306 
 307 		try {
 308 			// construct the path
 309 			File target = Utils.makeFile(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 310 
 311 			// deserialize it
 312 			tempOS = new FileOutputStream(target);
 313 
 314 		} catch (Exception e) {
 315 
 316 			// Every other exception should be consider an IO error
 317 			throw new UniverseException(
 318 				"IO Error on object put.  Message=" + e.getMessage(),
 319 				UniverseException.UE_IO_ERROR, e);
 320 		}
 321 		return (OutputStream) tempOS;
 322 	}
 323 
 324 	/**
 325 	 *  There is no locking.  Always immeadiately return.
 326 	 * @param name universe name
 327 	 * @throws autohit.universe.UniverseException
 328 	 */
 329 	public void lock(String name) throws UniverseException {
 330 		// do nothing
 331 	}
 332 
 333 	/**
 334 	 *  There is no locking, so return true, since the caller is
 335 	 * always allowed to get an object.
 336 	 * @param name universe name
 337 	 * @return always true
 338 	 * @throws autohit.universe.UniverseException
 339 	 */
 340 	public boolean lockIfNotLocked(String name) throws UniverseException {
 341 		return true;
 342 	}
 343 
 344 	/**
 345 	 *  Since objects can never be locked, this will always return false.
 346 	 * @param name universe name
 347 	 * @return always false
 348 	 * @throws autohit.universe.UniverseException
 349 	 */
 350 	public boolean isLocked(String name) throws UniverseException {
 351 		return false;
 352 	}
 353 
 354 	/**
 355 	 *  Release a lock on an object.  Do nothing.
 356 	 * @param name universe name
 357 	 * @throws autohit.universe.UniverseException
 358 	 */
 359 	public void release(String name) throws UniverseException {
 360 		// do nothing
 361 	}
 362 
 363 	/**
 364 	 *  Check to see if an object exists
 365 	 * @param name universe name
 366 	 * @return true if the object exists, otherwise false
 367 	 * @throws autohit.universe.UniverseException
 368 	 */
 369 	public boolean exists(String name) throws UniverseException {
 370 		// assume it doesn't exist
 371 		boolean answer = false;
 372 
 373 		try {
 374 			// Check for the file
 375 			File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 376 			if (target.exists() == true) {
 377 				answer = true;
 378 			}
 379 
 380 		} catch (Exception e) {
 381 			// Every other exception should be consider an IO error
 382 			throw new UniverseException(
 383 				"IO Error on object check.  Message=" + e.getMessage(),
 384 				UniverseException.UE_IO_ERROR, e);
 385 		}
 386 		return answer;
 387 	}
 388 
 389 	/**
 390 	 *  Flush an object.  Does nothing, since there is no caching.
 391 	 * @param name universe name
 392 	 * @return true if the object exists, otherwise false
 393 	 * @throws autohit.universe.UniverseException
 394 	 */
 395 	public void flush(String name) throws UniverseException {
 396 		// do nothing
 397 	}
 398 
 399 	/**
 400 	 *  Discard an object.  Does nothing, since there is no caching.
 401 	 * @param name universe name
 402 	 * @return true if the object exists, otherwise false
 403 	 * @throws autohit.universe.UniverseException
 404 	 */
 405 	public void discard(String name) throws UniverseException {
 406 		// do nothing.
 407 	}
 408 
 409 	/**
 410 	 *  Remove an object from the universe
 411 	 * @param name universe name
 412 	 * @return true if the object exists, otherwise false
 413 	 * @throws autohit.universe.UniverseException
 414 	 */
 415 	public void remove(String name) throws UniverseException {
 416 
 417 		try {
 418 			// Check for the file
 419 			File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 420 			if (target.exists() == true) {
 421 				// object is there.  remove it
 422 				target.delete();
 423 			} else {
 424 				// object doesn't exist.  error.
 425 				throw new UniverseException(
 426 					"No object =" + name,
 427 					UniverseException.UE_OBJECT_DOESNT_EXIST);
 428 			}
 429 
 430 		} catch (Exception e) {
 431 			// Every other exception should be consider an IO error
 432 			throw new UniverseException(
 433 				"IO Error on object remove.  Message=" + e.getMessage(),
 434 				UniverseException.UE_IO_ERROR, e);
 435 		}
 436 	}
 437 
 438 	/**
 439 	 *  Report the size object from the universe
 440 	 * @param name universe name
 441 	 * @return the size or 0 if empty
 442 	 * @throws autohit.universe.UniverseException
 443 	 */
 444 	public long size(String name) throws UniverseException {
 445 
 446 	    long size = 0;
 447 		try {
 448 			// Check for the file
 449 			File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
 450 			if (target.exists() == true) {
 451 				// object is there.  remove it
 452 				size = target.length();
 453 			} else {
 454 				// object doesn't exist.  error.
 455 				throw new UniverseException(
 456 					"No object =" + name,
 457 					UniverseException.UE_OBJECT_DOESNT_EXIST);
 458 			}
 459 
 460 		} catch (Exception e) {
 461 			// Every other exception should be consider an IO error
 462 			throw new UniverseException(
 463 				"IO Error on object remove.  Message=" + e.getMessage(),
 464 				UniverseException.UE_IO_ERROR, e);
 465 		}
 466 		return size;
 467 	}
 468 
 469 	
 470 }