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 }
|