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.Serializable;
23 import java.util.HashMap;
24 import java.util.Hashtable;
25 import java.util.Set;
26 import java.util.Stack;
27
28 import autohit.vm.i.VMIScope;
29
30 /**
31 * There are four storage mechanisms.<p>
32 * 1- A UNIVERSE: A persistent store accessible by everyone and
33 * addressable by name.
34 * <p>
35 * 2- ENVIRONMENT core: A shared store accessible by everyone
36 * containing name/value pairs. There is only one per system, so
37 * all references point to a single static instance.<br>
38 * <pre>
39 * set(String name, Object o)
40 * read(String name)
41 * test(String name)
42 * lock(String name)
43 * unlock(String name)
44 * waitingLock(String name)
45 * </pre>
46 * <p>
47 * 3- PERSISTANT core: An owned store per VM that contains
48 * name/object pairs. It is not subject to scope rules. There can
49 * only be one instance of any named object. It is implemented as a
50 * HashMap. This primarily meant to move object data between services,
51 * executables, and calls. This is NOT syncronized and threadsafe.<br>
52 * <pre>
53 * persist(String name, Object o)
54 * free(String name)
55 * has(String name)
56 * get(String name)
57 * </pre>
58 * <p>
59 * 4- STORAGE code: An owned store per VM that contains name/value
60 * pairs. It is subject to scope rules. Within the reference of
61 * a single scope, there is only one valid instance of a new
62 * instance is created, it will supercede the previous. The storage
63 * system uses Stacks on Hashmaps to maintain scope rules. When
64 * the scope is discarded, it will take all instances
65 * with it. Of course, any instances created in the prior scope(s)
66 * will still be there. This is NOT syncronized and threadsafe.<br>
67 * <pre>
68 * store(String name, Object o)
69 * remove(String name)
70 * exists(String name)
71 * fetch(String name)
72 * replace(String name, Object o)
73 * getStorageNameSet()
74 * </pre>
75 * <p>
76 * You should not access the scope stack directly.
77 * <p>
78 * @see #set(String name, Object o)
79 * @see #read(String name)
80 * @see #test(String name)
81 * @see #lock(String name)
82 * @see #unlock(String name)
83 * @see #waitingLock(String name)
84 * @see #persist(String name, Object o)
85 * @see #free(String name)
86 * @see #has(String name)
87 * @see #get(String name)
88 * @see #store(String name, Object o)
89 * @see #remove(String name)
90 * @see #exists(String name)
91 * @see #fetch(String name)
92 * @see #replace(String name, Object o)
93 *
94 * @author Erich P. Gatejen
95 * @version 1.0
96 * <i>Version History</i>
97 * <code>EPG - Rewrite - 5Mayt03
98 *
99 */
100 public class VMCore implements Serializable {
101
102 final static long serialVersionUID = 1;
103
104 /**
105 * Storage space. It is subject to scope rules. If more than one
106 * item is stored in the same name, it is converted to a stack bucket
107 * and items are stacked.<p>
108 * @see #store(String name, Object o)
109 * @see #remove(String name)
110 * @see #exists(String name)
111 * @see #fetch(String name)
112 * @see #replace(String name, Object o)
113 */
114 protected HashMap storage;
115
116 /**
117 * Persistant storage space. It is NOT subject to scope rules. There cannot
118 * be more than one instance of an item.<p>
119 * @see #persist(String name, Object o)
120 * @see #free(String name)
121 * @see #has(String name)
122 * @see #get(String name)
123 */
124 protected HashMap persists;
125
126 /**
127 * Scope stack.
128 *
129 * Do NOT use scope.pop() or scope.push() yourself! We must maintain the
130 * scope cache dirty flag. However, you can use peek(), empty(), and
131 * search() at your leasure().
132 */
133 protected Stack scope;
134
135 /**
136 * Scope stack cache dirty flag. Will be automatically set when any
137 * scope stack methods are used.
138 */
139 protected boolean scDirty;
140
141 /**
142 * Environment. System wide store. Set by the factory.<p>
143 * @see #set(String name, Object o)
144 * @see #read(String name)
145 * @see #test(String name)
146 * @see #lock(String name)
147 * @see #unlock(String name)
148 * @see #waitingLock(String name)
149 */
150 public Hashtable environment;
151
152 /**
153 * Call cache.
154 */
155 public HashMap callcache;
156
157 /**
158 * Default constructor. Use this if you want a private environment.
159 * Of course, that might be pointless.
160 */
161 public VMCore() {
162 environment = new Hashtable();
163 init();
164 }
165
166 /**
167 * Constructor. Gets a reference to the environment.
168 */
169 public VMCore(Hashtable env) {
170 environment = env;
171 init();
172 }
173
174 /**
175 * Private initializer
176 */
177 private void init() {
178 storage = new HashMap();
179 persists = new HashMap();
180 callcache = new HashMap();
181 scope = new Stack();
182 scDirty = false;
183 }
184
185 /**
186 * Push an object onto the scope stack.
187 *
188 * @param o the object
189 */
190 public void push(Object o) {
191 scDirty = true;
192 scope.push(o);
193 }
194
195 /**
196 * Check to see if the stack is dirty. This is not thread safe.
197 * @return true is the stack is dirty
198 */
199 public boolean isDirty() {
200 return scDirty;
201 }
202
203 /**
204 * Pop an object off the stack. USE THIS instead of scope.pop()!!!
205 * Have to dirty the cache flag...
206 * <p>
207 * It'll throw any exception it encounters--most likely a EmptyStackException.
208 * @return an object reference
209 * @throws Exception
210 */
211 public Object pop() throws Exception {
212 scDirty = true;
213 return scope.pop();
214 }
215
216 /**
217 * Peek into the scope stack.
218 *
219 * @return a reference to the object or NULL if the stack is empty
220 */
221 public Object peek() {
222 Object ob = null;
223 try {
224 ob = scope.peek();
225 } catch (Exception e) {
226 // don't care
227 }
228 return ob;
229 }
230
231 /**
232 * Store an item. It is subject to scope rules. It will
233 * overload a prior instance with the same name, but not overwrite it.
234 *
235 * @param name object name as a string
236 * @param o the object
237 * @throws VMException
238 * @see autohit.vm.VMException
239 */
240 public void store(String name, Object o) throws VMException {
241 Object thang;
242 scope.push(name);
243 try {
244 // Is there something there already?
245 if (storage.containsKey(name)) {
246 // yes - is there more than one in a stack?
247 thang = storage.get(name);
248 if (thang instanceof Stack) {
249 // no. Add it to the stack
250 ((Stack) thang).push(o);
251
252 } else {
253 // Create a stack and add them both
254 Stack thangs = new Stack();
255 thangs.push(thang);
256 thangs.push(o);
257 storage.put(name, thangs);
258 }
259
260 } else {
261 // no. just toss it on
262 storage.put(name, o);
263 }
264
265 } catch (Exception e) {
266 throw new VMException(
267 "Core failed to store " + name + ". " + e.getMessage(),
268 VMException.CODE_VM_CORE_FAILED_STORE_FAULT,
269 e);
270 }
271 }
272
273 /**
274 * Removes an object from a store. No real reasion to use this.
275 * It will throw an exception only if something realy bad happened.
276 * This will not remove the item from the scope stack!
277 *
278 * @param name object name as a string
279 * @throws VMException
280 * @see autohit.vm.VMException
281 */
282 public void remove(String name) throws VMException {
283
284 Object thang;
285
286 try {
287 // Is it even in the store?
288 if (storage.containsKey(name)) {
289
290 thang = storage.get(name);
291 // is it a stack or a solo item
292 if (thang instanceof Stack) {
293
294 // Is there one or two items in the stack?
295 if (((Stack) thang).size() > 2) {
296 // there is a bunch. pop the one
297 ((Stack) thang).pop();
298
299 } else {
300 // there are only two. discard the stack and keep the
301 // last item
302 ((Stack) thang).pop();
303 thang = ((Stack) thang).pop();
304 storage.put(name, thang);
305 }
306
307 } else {
308 // Solo item - toss it
309 storage.remove(name);
310 }
311 }
312
313 } catch (Exception e) {
314 throw new VMException(
315 "VM: Core failed on remove for "
316 + name
317 + ". "
318 + e.getMessage(),
319 VMException.CODE_VM_CORE_GENERAL_FAULT,
320 e);
321 }
322 }
323
324 /**
325 * Check for an object in storage.
326 *
327 * @param name object name as a string
328 * @throws VMException
329 * @see autohit.vm.VMException
330 */
331 public boolean exists(String name) throws VMException {
332
333 try {
334 if (storage.containsKey(name)) {
335 return true;
336 }
337
338 } catch (Exception e) {
339 throw new VMException(
340 "VM: Core failed storage check for "
341 + name
342 + ". "
343 + e.getMessage(),
344 VMException.CODE_VM_CORE_GENERAL_FAULT,
345 e);
346 }
347 return false;
348 }
349
350 /**
351 * Fetch an object reference in storage.
352 *
353 * @param name object name as a string
354 * @return the object or null if it can't be found
355 * @throws VMException
356 * @see autohit.vm.VMException
357 */
358 public Object fetch(String name) throws VMException {
359
360 Object thang;
361
362 try {
363 // is it even there?
364 if (storage.containsKey(name)) {
365
366 thang = storage.get(name);
367
368 // a stack or naked?
369 if (thang instanceof Stack) {
370 return ((Stack) thang).peek();
371 } else {
372 return thang;
373 }
374 }
375
376 } catch (Exception e) {
377 throw new VMException(
378 "VM: Core failed to fetch " + name + ". " + e.getMessage(),
379 VMException.CODE_VM_CORE_FAILED_RETRIEVAL_FAULT,
380 e);
381 }
382 return null;
383 }
384
385 /**
386 * Get a Set of variables in scope in storage.
387 *
388 * @return A Set of Strings that are the variable names.
389 * @throws VMException
390 * @see autohit.vm.VMException
391 */
392 public Set getStorageNameSet() throws VMException {
393
394 Set keySet;
395
396 try {
397 keySet = storage.keySet();
398
399 } catch (Exception e) {
400 throw new VMException(
401 "VM: Core failed to getStorageNameSet() the variables. " + e.getMessage(),
402 VMException.CODE_VM_CORE_FAILED_RETRIEVAL_FAULT,
403 e);
404 }
405 return keySet;
406 }
407
408 /**
409 * Replace an object in storage. Obviously it will replace the nearest
410 * in scope. If the object doesn't exist, it will throw an exception.
411 *
412 * @param name object name as a string
413 * @param o object reference
414 * @throws VMException
415 * @see autohit.vm.VMException
416 */
417 public void replace(String name, Object o) throws VMException {
418
419 Object thang;
420
421 // Is there something there already?
422 if (storage.containsKey(name)) {
423
424 try {
425 // yes - is there more than one in a stack?
426 thang = storage.get(name);
427 if (thang instanceof Stack) {
428 // yes. pop the top and push the replacement
429 ((Stack) thang).pop();
430 ((Stack) thang).push(o);
431
432 } else {
433 // replace it
434 storage.put(name, o);
435 }
436 } catch (Exception e) {
437 throw new VMException(
438 "Core failed to replace " + name + ". " + e.getMessage(),
439 VMException.CODE_VM_CORE_FAILED_STORE_FAULT);
440 }
441
442 } else {
443 // no. just toss it on
444 throw new VMException(
445 "Object doesnt exist in core storage: " + name,
446 VMException.CODE_VM_CORE_DOESNT_EXIST_FAULT);
447 }
448
449 }
450
451 // -- PERSIST
452
453 /**
454 * Persist an item. It is NOT subject to scope rules. It will
455 * overwrite a prior instance of it.
456 *
457 * @param name object name as a string
458 * @param o the object
459 * @throws VMException
460 * @see autohit.vm.VMException
461 */
462 public void persist(String name, Object o) throws VMException {
463
464 try {
465 persists.put(name, o);
466 } catch (Exception e) {
467 throw new VMException(
468 "VM: Core failed to persist " + name + ". " + e.getMessage(),
469 VMException.CODE_VM_CORE_FAILED_STORE_FAULT,
470 e);
471 }
472 }
473
474 /**
475 * Free an item from persistant storage.
476 *
477 * @param name object name as a string
478 * @throws VMException
479 * @see autohit.vm.VMException
480 */
481 public void free(String name) throws VMException {
482
483 try {
484 if (persists.containsKey(name)) {
485 persists.remove(name);
486 }
487 } catch (Exception e) {
488 throw new VMException(
489 "VM: Core failed to free " + name + ". " + e.getMessage(),
490 VMException.CODE_VM_CORE_GENERAL_FAULT,
491 e);
492 }
493 }
494
495 /**
496 * Get an object in persistant storage.
497 *
498 * @param name object name as a string
499 * @return the object or null if it doesn't exist.
500 * @throws VMException
501 * @see autohit.vm.VMException
502 */
503 public Object get(String name) throws VMException {
504 try {
505 if (persists.containsKey(name)) {
506 return persists.get(name);
507 }
508 } catch (Exception e) {
509 throw new VMException(
510 "VM: Core failed to get " + name + ". " + e.getMessage(),
511 VMException.CODE_VM_CORE_FAILED_RETRIEVAL_FAULT,
512 e);
513 }
514 return null;
515 }
516
517 /**
518 * Check persistant storage for an object.
519 *
520 * @param name object name as a string
521 * @throws VMException
522 * @see autohit.vm.VMException
523 * @return if the object exists
524 */
525 public boolean has(String name) throws VMException {
526 try {
527 if (persists.containsKey(name)) {
528 return true;
529 }
530
531 } catch (Exception e) {
532 throw new VMException(
533 "VM: Core failed persistant storage check for "
534 + name
535 + ". "
536 + e.getMessage(),
537 VMException.CODE_VM_CORE_GENERAL_FAULT,
538 e);
539 }
540 return false;
541 }
542
543 /**
544 * Marks a scope on the scope stack
545 */
546 public void markScope() {
547 VMIScope vs = new VMIScope();
548 scope.push(vs);
549 }
550
551 /**
552 * Discard scope frame. This will remove all items on the scope to and
553 * including the top-most recent VMIScope object. It will pop the whole damned stack if it doesn't find one...
554 * @throws any VMException
555 */
556 public void discardScopeFrame() throws VMException {
557
558 scDirty = true;
559 Object item;
560
561 try {
562
563 // Just keep poping until we get to the scope.
564 item = scope.pop();
565 while (!(item instanceof VMIScope)) {
566
567 // If we are here, then it's going to be a string name
568 this.remove((String) item);
569 item = scope.pop();
570 }
571
572 } catch (VMException e) {
573 // This is bad. Propagate it.
574 throw e;
575 } catch (Exception e) {
576 // looks like we emptied the whole stack. BAD!
577 throw new VMException(
578 "VM: SOFTWARE DETECTED FAULT. Emptied the scope stack. Bad thing(tm)! "
579 + e.getMessage(),
580 VMException.CODE_VM_SOFTWARE_DETECTED_FAULT,
581 e);
582 }
583 }
584
585 // -- ENVIRONMENT
586
587 /**
588 * Lock an item in the environment. It will get a reference to the
589 * object.
590 * @param name object name as a string
591 * @return an vmobject reference or null if it is already locked
592 * @throws VMException for en error or if the item doesn't exist.
593 * @see autohit.vm.VMException
594 */
595 public Object lock(String name) throws VMException {
596
597 VMObject to;
598
599 try {
600 if (environment.containsKey(name)) {
601
602 // lock it if we can
603 to = (VMObject) environment.get(name);
604 if (to.test()) {
605 to.lock();
606 return to.get();
607 }
608
609 } else {
610 throw new VMException(
611 "VM: Core failed to lock " + name + ". It does not exist.",
612 VMException.CODE_VM_CORE_DOESNT_EXIST_FAULT);
613 }
614
615 } catch (VMException e) {
616 throw e;
617 } catch (Exception e) {
618 throw new VMException(
619 "VM: Core failed to lock due to system fault "
620 + name
621 + ". "
622 + e.getMessage(),
623 VMException.CODE_VM_CORE_FAILED_CONTROL_FAULT,
624 e);
625 }
626 return null;
627 }
628
629 /**
630 * Unlock an environment item if we can. Ignore errors except if the
631 * item doesn't exist or it is owned by someone else.
632 * @param name object name as a string
633 * @throws VMException for en error or if the item doesn't exist.
634 * @see autohit.vm.VMException
635 */
636 public void unlock(String name) throws VMException {
637
638 VMObject to;
639
640 try {
641 if (environment.containsKey(name)) {
642
643 // lock it if we can
644 to = (VMObject) environment.get(name);
645 if (to.test()) {
646 to.unlock();
647 }
648
649 } else {
650 throw new VMException(
651 "VM: Core failed to lock " + name + ". It does not exist.",
652 VMException.CODE_VM_CORE_DOESNT_EXIST_FAULT);
653 }
654
655 } catch (VMException e) {
656 throw e;
657 } catch (Exception e) {
658 throw new VMException(
659 "VM: Core failed to lock due to system fault "
660 + name
661 + ". "
662 + e.getMessage(),
663 VMException.CODE_VM_CORE_FAILED_CONTROL_FAULT,
664 e);
665 }
666 }
667
668 /**
669 * Read an environment item if we can. Ignore errors except if the
670 * item doesn't exist or it is owned by someone else.
671 * @param name object name as a string
672 * @throws VMException for en error or if the item doesn't exist.
673 * @return the item or null if it is empty
674 * @see autohit.vm.VMException
675 */
676 public Object read(String name) throws VMException {
677
678 VMObject to;
679
680 try {
681 if (environment.containsKey(name)) {
682
683 // lock it if we can
684 to = (VMObject) environment.get(name);
685 if (to.test()) {
686 return to.get();
687 }
688
689 } else {
690 throw new VMException(
691 "VM: Core failed to read() "
692 + name
693 + ". It does not exist.",
694 VMException.CODE_VM_CORE_DOESNT_EXIST_FAULT);
695 }
696
697 } catch (VMException e) {
698 throw e;
699 } catch (Exception e) {
700 throw new VMException(
701 "VM: Core failed to read() due to system fault "
702 + name
703 + ". "
704 + e.getMessage(),
705 VMException.CODE_VM_CORE_FAILED_RETRIEVAL_FAULT,
706 e);
707 }
708 return null;
709 }
710
711 /**
712 * Set an environment item if we can. This will throw an exception if
713 * the item exists and is locked. If it doesn't exist, this will create it.
714 * @param name object name as a string
715 * @throws VMException for en error or if the item doesn't exist.
716 * @return the item or null if it is empty
717 * @see autohit.vm.VMException
718 */
719 public Object set(String name, Object o) throws VMException {
720
721 VMObject to;
722
723 try {
724 // does it already exist?
725 if (environment.containsKey(name)) {
726
727 // lock it if we can
728 to = (VMObject) environment.get(name);
729 if (to.test()) {
730 to.set(o);
731 } else {
732 throw new VMException(
733 "VM: Core failed to set() "
734 + name
735 + ". It exists and is locked.",
736 VMException.CODE_VM_OBJECT_LOCKED_FAULT);
737 }
738
739 } else {
740
741 // no - create it
742 to = new VMObject(o);
743 environment.put(name, o);
744 }
745
746 } catch (VMException e) {
747 throw e;
748 } catch (Exception e) {
749 throw new VMException(
750 "VM: Core failed to set() due to system fault "
751 + name
752 + ". "
753 + e.getMessage(),
754 VMException.CODE_VM_CORE_FAILED_STORE_FAULT,
755 e);
756 }
757 return null;
758 }
759
760 /**
761 * Wait for a lock on an environment. It will get a reference to the
762 * object.
763 * @param name object name as a string
764 * @return an vmobject reference or null if it is already locked
765 * @throws VMException for en error or if the item doesn't exist.
766 * @see autohit.vm.VMException
767 */
768 public Object waitingLock(String name) throws VMException {
769
770 VMObject to;
771 Object thang;
772
773 try {
774 if (environment.containsKey(name)) {
775
776 // lock it if we can
777 to = (VMObject) environment.get(name);
778 to.waitingLock();
779 return to.get();
780
781 } else {
782 throw new VMException(
783 "VM: Core failed to waitlock "
784 + name
785 + ". It does not exist.",
786 VMException.CODE_VM_CORE_DOESNT_EXIST_FAULT);
787 }
788
789 } catch (VMException e) {
790 throw e;
791 } catch (Exception e) {
792 throw new VMException(
793 "VM: Core failed to waitlock due to system fault "
794 + name
795 + ". "
796 + e.getMessage(),
797 VMException.CODE_VM_CORE_FAILED_CONTROL_FAULT,
798 e);
799 }
800 //return null;
801 }
802
803 /**
804 * Test if environment item is accessable.
805 * @param name object name as a string
806 * @return true if it is available, otherwise false.
807 * @throws VMException for en error or if the item doesn't exist.
808 * @see autohit.vm.VMException
809 */
810 public boolean test(String name) throws VMException {
811
812 VMObject to;
813
814 try {
815 if (environment.containsKey(name)) {
816
817 // lock it if we can
818 to = (VMObject) environment.get(name);
819 return to.test();
820
821 } else {
822 throw new VMException(
823 "VM: Core failed to waitlock "
824 + name
825 + ". It does not exist.",
826 VMException.CODE_VM_CORE_DOESNT_EXIST_FAULT);
827 }
828
829 } catch (VMException e) {
830 throw e;
831 } catch (Exception e) {
832 throw new VMException(
833 "VM: Core failed to waitlock due to system fault "
834 + name
835 + ". "
836 + e.getMessage(),
837 VMException.CODE_VM_CORE_FAILED_CONTROL_FAULT,
838 e);
839 }
840 //return null;
841 }
842
843 /**
844 * Dump the core to a string.
845 *
846 * @return an empty string for now. this will be dangerous.
847 * TODO implement toString for VMCore
848 */
849 public String toString() {
850 return "not implemented yet";
851 }
852
853 }
|