Source code for /engineering/autohit-2003/src/autohit/vm/VMLoader.javaOriginal file VMLoader.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.vm;
  22 import java.io.InputStream;
  23 import java.util.Hashtable;
  24 import java.util.Enumeration;
  25 
  26 import org.apache.commons.collections.ExtendedProperties;
  27 
  28 import autohit.call.Call;
  29 import autohit.call.CallException;
  30 import autohit.common.AutohitErrorCodes;
  31 import autohit.common.AutohitLogInjectorWrapper;
  32 import autohit.common.AutohitProperties;
  33 import autohit.server.SystemContext;
  34 import autohit.universe.Universe;
  35 import autohit.universe.UniverseException;
  36 
  37 
  38 /**
  39  * Root loader.  Basic caching loader half-singleton.  It shares the routine cache, but the
  40  * call cache is local.  It does not check to see if anything was updated.  Be
  41  * sure to call init after instantiation or behavior is undefined!  It isn't
  42  * entirely threadsafe, but good enough.
  43  * <p>
  44  * It is also responsible for creating cores, and giving logging and universe access to a VM.
  45  * <p>
  46  * A loader is not "valid" until both init() and create() are called.
  47  * <p>
  48  * @author Erich P. Gatejen
  49  * @version 1.0
  50  * <i>Version History</i>
  51  * <code>EPG - Initial - 12may03</code> 
  52  * 
  53  */
  54 public class VMLoader {
  55 
  56 	// universe
  57 	public SystemContext sc;
  58 
  59 	// logger
  60 	public AutohitLogInjectorWrapper log;
  61 
  62 	// routine cache
  63 	static private Hashtable cache;
  64 
  65 	// core factory cache
  66 	private VMCoreFactory corefactory;
  67 
  68 	/**
  69 	 * Default Constructor.
  70 	 */
  71 	public VMLoader() {
  72 		if (cache == null)
  73 			cache = new Hashtable();
  74 		corefactory = new VMCoreFactory();
  75 	}
  76 
  77 	/**
  78 	 * Initializer.
  79 	 * @param sctx the system context
  80 	 */
  81 	public void init(SystemContext sctx) {
  82 		sc = sctx;
  83 		log = sc.getRootLogger();
  84 	}
  85 
  86 	/**
  87 	 * Create a core.
  88 	 */
  89 	public VMCore create() {
  90 		
  91 		// create it
  92 		VMCore core = corefactory.allocate();
  93 		
  94 		// mirror all the invoker props
  95 		Hashtable iprop = sc.getInvokerProperties();
  96 		String ikey;
  97 		Object ivalue;
  98 		for (Enumeration e = iprop.keys(); e.hasMoreElements();) {
  99 
 100 			try {
 101 				ikey = (String)e.nextElement(); 
 102 				ivalue = iprop.get(ikey);
 103 				core.store(ikey, ivalue);
 104 			} catch (Exception ecc) {
 105 				// ignore and just disqualify that entry
 106 			}
 107 		}
 108 
 109 		return core;
 110 	}
 111 
 112 	/**
 113 	 *  Load
 114 	 *  @param name of routine to load
 115 	 *  @return an executable
 116 	 * 	@throws VMException unable to load.
 117 	 */
 118 	public VMExecutable load(String name) throws VMException {
 119 
 120 		if (cache.containsKey(name)) {
 121 			// cache hit
 122 			//log.debug("Loader(routine-basic): cache hit [" + name + "].");
 123 			return (VMExecutable) cache.get(name);
 124 		}
 125 
 126 		VMExecutableWrapper wrapper = new VMExecutableWrapper();
 127 		try {
 128 			log.debug(
 129 				"Loader(routine-basic): Loading [" + name + "].",
 130 				AutohitErrorCodes.CODE_INFORMATIONAL_OK_VERBOSE);
 131 
 132 			Universe u = sc.getUniverse();
 133 			InputStream is =
 134 				u.getStream(
 135 					AutohitProperties.literal_UNIVERSE_CACHE
 136 						+ AutohitProperties.literal_NAME_SEPERATOR
 137 						+ name);
 138 			wrapper.load(is);
 139 
 140 		} catch (UniverseException e) {
 141 			if (e.numeric == UniverseException.UE_OBJECT_DOESNT_EXIST) {
 142 				throw new VMException(
 143 					"Loader(routine-basic): Loading program "
 144 						+ name
 145 						+ " not compiled and available.  ",
 146 					VMException.CODE_VM_EXEC_DOES_NOT_EXIST_FAULT,
 147 					e);
 148 			} else {
 149 				throw new VMException(
 150 					"Loader(routine-basic): Loading program "
 151 						+ name
 152 						+ " caused a Universe Exception: "
 153 						+ e.getMessage(),
 154 					VMException.CODE_VM_SUBSYSTEM_FAULT,
 155 					e);
 156 			}
 157 		} catch (Exception e) {
 158 			throw new VMException(
 159 				"Loader(routine-basic): Loading program "
 160 					+ name
 161 					+ " caused a fundimental Exception: "
 162 					+ e.getMessage(),
 163 				VMException.CODE_VM_GENERAL_FAULT,
 164 				e);
 165 		}
 166 		cache.put(name, wrapper.exec);
 167 		return wrapper.exec;
 168 	}
 169 
 170 	/**
 171 	 *  Get a call.  If it isn't in the cache, load it.  There is no thread
 172 	 *  safety here at all!  However, it shouldn't matter since there is a
 173 	 *  loader per VM.
 174 	 *  @param name of routine to load
 175 	 * 	@param core a VMCore that holds a callcache
 176 	 *  @param li log injector to give to the call
 177 	 *  @return runnable call
 178 	 * 	@throws VMException unable to load.
 179 	 */
 180 	public Call get(String name, VMCore core, AutohitLogInjectorWrapper li) throws VMException {
 181 
 182 		if (core.callcache.containsKey(name)) {
 183 			// cache hit
 184 			//log.debug(
 185 			//	"Loader(call-basic): cache hit [" + name + "].",
 186 			//	AutohitErrorCodes.LOG_INFORMATIONAL_OK);
 187 			return (Call) core.callcache.get(name);
 188 		}
 189 
 190 		Call c = null;
 191 
 192 		try {
 193 			String decoratedName = "autohit.call.Call_" + name.toUpperCase();
 194 			Class t = Class.forName(decoratedName);
 195 			c = (Call) t.newInstance();
 196 			Universe u = sc.getUniverse();
 197 			c.load(core, sc, li);
 198 
 199 			log.debug(
 200 				"Loader(call-basic): Instantiated a [" + name + "].",
 201 				AutohitErrorCodes.CODE_INFORMATIONAL_OK_VERBOSE);
 202 
 203 			core.callcache.put(name, c);
 204 
 205 		} catch (ClassNotFoundException ef) {
 206 			throw new VMException(
 207 				"Loader(call-basic): CALL does not exist.  error="
 208 					+ ef.getMessage(),
 209 				VMException.CODE_VM_GENERAL_FAULT,
 210 				ef);
 211 
 212 		} catch (CallException ex) {
 213 			throw new VMException(
 214 				"Loader(call-basic): Instantiation error for ["
 215 					+ name
 216 					+ "].  Not aborting, but state of CALL undefined.  Error="
 217 					+ ex.getMessage(),
 218 				VMException.CODE_VM_CALL_FAULT,
 219 				ex);
 220 
 221 		} catch (Exception e) {
 222 			throw new VMException(
 223 				"Loader(call-basic): CALL does not exist.  error="
 224 					+ e.getMessage(),
 225 				VMException.CODE_VM_GENERAL_FAULT,
 226 				e);
 227 		}
 228 		return c;
 229 	}
 230 
 231 	/**
 232 	 *  Flush the entire routine cache
 233 	 * 	@throws VMException if it locked by something else.
 234 	 */
 235 	public void flush() {
 236 
 237 		Hashtable holding = cache;
 238 		synchronized (holding) {
 239 			cache = new Hashtable();
 240 		}
 241 	}
 242 
 243 	/**
 244 	 *  Flush a specific routine out fo the cache
 245 	 * 	@throws VMException if it locked by something else.
 246 	 */
 247 	public void flush(String name) {
 248 
 249 		Hashtable holding = cache;
 250 		synchronized (holding) {
 251 			try {
 252 				cache.remove(name);
 253 			} catch (Exception e) { // dont care
 254 			}
 255 		}
 256 	}
 257 	/**
 258 	 * Gets a property from the SystemContext.  Normally, you should handle
 259 	 * all system interaction through a Universe.  Don't use this unless you
 260 	 * have no choice.
 261 	 *  Returns the value or null if it does not exist
 262 	 * @param name of the property
 263 	 * @return the value as a String or null if it doesn't exist
 264 	 */
 265 	public String property(String name) {
 266 
 267 		String thang = null;
 268 		try {
 269 			ExtendedProperties ep = sc.getPropertiesSet();
 270 			thang = (String) ep.getProperty(name);
 271 		} catch (Exception e) {
 272 			// nothing.  null will return
 273 		}
 274 		return thang;
 275 	}
 276 
 277 }