001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.qos.frame;
028:
029: import java.beans.PropertyChangeEvent;
030: import java.beans.PropertyChangeListener;
031: import java.beans.PropertyChangeSupport;
032: import java.io.PrintWriter;
033: import java.util.ArrayList;
034: import java.util.HashMap;
035: import java.util.HashSet;
036: import java.util.Iterator;
037: import java.util.List;
038: import java.util.Map;
039: import java.util.Properties;
040: import java.util.Set;
041:
042: import org.cougaar.core.qos.metrics.Metric;
043: import org.cougaar.core.util.UID;
044: import org.cougaar.util.log.Logger;
045: import org.cougaar.util.log.Logging;
046:
047: /**
048: * This extension to {@link Frame} is the basic representation of a frame
049: * representing data (cf {@link PrototypeFrame}). Classes generated from
050: * prototype xml extend this one, either directly or indirectly.
051: */
052: abstract public class DataFrame extends Frame implements
053: PropertyChangeListener {
054:
055: public static final String NIL = "NIL";
056:
057: private static Map<String, Map<String, FrameMaker>> FramePackages = new HashMap<String, Map<String, FrameMaker>>();
058:
059: private static Logger log = Logging
060: .getLogger(org.cougaar.core.qos.frame.DataFrame.class);
061:
062: private Properties props;
063:
064: private transient PropertyChangeSupport pcs;
065:
066: // Support for path dependencies
067:
068: // Next two are inverse dependencies: frame this frame depends on for
069: // path-derived
070: // slot values. We need to remember the inverse dependencies in order to
071: // clear
072: // the obsolete forward dependencies. Any given path-derived slot
073: // depends on
074: // exactly one data frame (ddeps) and one or moe relation frames
075: // (rdeps).
076: private transient Map<String, DataFrame> ddeps;
077:
078: private transient Map<String, List<RelationFrame>> rdeps;
079:
080: // Next two are in support of forward path dependencies: frames with
081: // path-derived
082: // slots that depend on this frame. When some slot of this frame change,
083: // dependents need
084: // to be notified that one of its slots is out of date.
085: private transient Map<String, Set<DataFrame>> path_dependents;
086:
087: private transient Map<String, String> slot_map;
088:
089: // lock for synchronized manipulation of path dependencies
090: private transient ReadLock rlock;
091:
092: protected DataFrame(FrameSet frameSet, UID uid) {
093: super (frameSet, uid);
094: initializeTransients();
095: }
096:
097: // Subclass responsibility
098: abstract protected Object getLocalValue(String slot);
099:
100: abstract protected void setLocalValue(String slot, Object value);
101:
102: // abstract protected void removeLocalValue(String slot);
103: abstract protected void initializeLocalValue(String slot,
104: Object value);
105:
106: public class ReadLock extends Object {
107: };
108:
109: // Serialization
110: private void readObject(java.io.ObjectInputStream in)
111: throws java.io.IOException, ClassNotFoundException {
112: in.defaultReadObject();
113: initializeTransients();
114: }
115:
116: private void initializeTransients() {
117: pcs = new PropertyChangeSupport(this );
118: ddeps = new HashMap<String, DataFrame>();
119: rdeps = new HashMap<String, List<RelationFrame>>();
120: slot_map = new HashMap<String, String>();
121: path_dependents = new HashMap<String, Set<DataFrame>>();
122: rlock = new ReadLock();
123: }
124:
125: // PropertyChangeListener
126:
127: public void propertyChange(PropertyChangeEvent event) {
128: // Some frame I depend on has changed (container only, for now).
129: // Resignal to my listeners.
130: if (log.isDebugEnabled())
131: log.debug("Propagate PropertyChange "
132: + event.getPropertyName() + " old value = "
133: + event.getOldValue() + " new value = "
134: + event.getNewValue());
135: ResourceablePropertyChangeEvent evt = (ResourceablePropertyChangeEvent) event;
136: Object source = evt.getSource();
137: evt.setSource(this );
138: pcs.firePropertyChange(event);
139: evt.setSource(source);
140: }
141:
142: // Path dependencies.
143:
144: Object get_rlock() {
145: return rlock;
146: }
147:
148: /**
149: * Clear all inverse path dependencies for the given slot. Caller should
150: * lock rlock
151: */
152: void clearRelationDependencies(String slot) {
153: List<RelationFrame> rframes = rdeps.get(slot);
154: if (rframes == null)
155: return;
156: for (RelationFrame rframe : rframes) {
157: rframe.removePathDependent(this , slot);
158: }
159: rdeps.remove(slot);
160: DataFrame dframe = ddeps.get(slot);
161: synchronized (slot_map) {
162: for (Map.Entry<String, String> entry : slot_map.entrySet()) {
163: if (entry.getValue().equals(slot)) {
164: dframe.removePathDependent(this , entry.getKey());
165: break;
166: }
167: }
168: }
169: ddeps.remove(slot);
170: }
171:
172: /**
173: * Informs this frame that the path-derived value of the my_slot depends
174: * on the value of owner_slot in the given frame (ie if the owner_slot
175: * changes in frame, my_slot will change).
176: */
177: void addRelationSlotDependency(DataFrame frame, String my_slot,
178: String owner_slot) {
179: ddeps.put(my_slot, frame);
180: synchronized (slot_map) {
181: slot_map.put(owner_slot, my_slot);
182: }
183: frame.addPathDependent(this , owner_slot);
184: }
185:
186: /**
187: * Informs this frame that the path-derived value of the given slot
188: * depends on the given relationship (ie, if the relationship changes,
189: * the value of the slot will change because the path will be
190: * different). Caller should lock rlock.
191: */
192: void addRelationDependency(RelationFrame rframe, String slot) {
193: List<RelationFrame> rframes = rdeps.get(slot);
194: if (rframes == null) {
195: rframes = new ArrayList<RelationFrame>();
196: rdeps.put(slot, rframes);
197: }
198: rframes.add(rframe);
199: rframe.addPathDependent(this , slot);
200: }
201:
202: /**
203: * Informs this frame that the path-derived value of the given slot no
204: * longer depends on the given relationship. Caller should lock rlock.
205: */
206: void removeRelationDependency(RelationFrame rframe, String slot) {
207: if (log.isDebugEnabled())
208: log.debug("Removing relation dependency " + rframe + " on "
209: + this + " for slot " + slot);
210: List<RelationFrame> rframes = rdeps.get(slot);
211: if (rframes != null)
212: rframes.remove(rframe);
213: rframe.removePathDependent(this , slot);
214: }
215:
216: /**
217: * Informs this frame that the given data frame depends on it (ie, if
218: * this frame changes, a dependent slot will change because the path
219: * will be different). If this frame is a relation, the slot arg is the
220: * dependent slot, since any change at all to a relations frame triggers
221: * a dependency change. If this frame is the final data frame in a path,
222: * the slot arg is that frame's slot: only changes to that slot are
223: * relevant.
224: */
225: void addPathDependent(DataFrame dependent, String slot) {
226: if (log.isDebugEnabled())
227: log.debug(this + " is adding dependent " + dependent
228: + " for slot " + slot);
229: synchronized (path_dependents) {
230: Set<DataFrame> dependents = path_dependents.get(slot);
231: if (dependents == null) {
232: dependents = new HashSet<DataFrame>();
233: path_dependents.put(slot, dependents);
234: }
235: dependents.add(dependent);
236: }
237: }
238:
239: /**
240: * Informs this frame that the given data frame no longer depends on it.
241: */
242: void removePathDependent(DataFrame dependent, String slot) {
243: if (log.isDebugEnabled())
244: log.debug(this + " is removing dependent " + dependent
245: + " for slot " + slot);
246: synchronized (path_dependents) {
247: Set<DataFrame> dependents = path_dependents.get(slot);
248: if (dependents != null)
249: dependents.remove(dependent);
250: }
251: }
252:
253: void pathDependencyChange(String slot) {
254: if (log.isInfoEnabled())
255: log.info("Path dependency has changed for frame " + this
256: + " and for slot " + slot);
257: Object new_value = getValue(slot);
258: PropertyChangeEvent evt = new ResourceablePropertyChangeEvent(
259: this , FrameGen.fixName(slot, true, true), null,
260: new_value);
261: pcs.firePropertyChange(evt);
262: notifyPathDependents(slot);
263: // slotModified(slot, null, new_value, true, true);
264: }
265:
266: private void notifyPathDependents(String owner_slot,
267: Set<DataFrame> dependents) {
268: for (DataFrame frame : dependents) {
269: String frame_slot = frame.slot_map.get(owner_slot);
270: frame.pathDependencyChange(frame_slot);
271: }
272: }
273:
274: // RelationFrame overrides this to invoke notifyAllPathDependents,
275: // since in this case the slot doesn't matter: changing any
276: // slot invalidates the relationship.
277: void notifyPathDependents(String owner_slot) {
278: Set<DataFrame> copy = null;
279: synchronized (path_dependents) {
280: Set<DataFrame> dependents = path_dependents.get(owner_slot);
281: if (dependents == null)
282: return;
283: copy = new HashSet(dependents);
284: }
285: notifyPathDependents(owner_slot, copy);
286: }
287:
288: void notifyAllPathDependents() {
289: synchronized (path_dependents) {
290: for (Map.Entry<String, Set<DataFrame>> entry : path_dependents
291: .entrySet()) {
292: String slot = entry.getKey(); // in this case it's the
293: // dependent's slot
294: Set<DataFrame> dependents = entry.getValue();
295: for (DataFrame frame : dependents) {
296: frame.pathDependencyChange(slot);
297: }
298: }
299: }
300: }
301:
302: // Jess ShadowFact
303: public void addPropertyChangeListener(PropertyChangeListener pcl) {
304: // IF the listener is a DataFrame, don't listen on
305: // uninherited slots
306: if (pcl instanceof DataFrame) {
307: DataFrame subscriber = (DataFrame) pcl;
308: Set<String> subfields = new HashSet<String>();
309: subscriber.collectSlotNames(subfields);
310: Set<String> allfields = new HashSet<String>();
311: collectSlotNames(allfields);
312: for (String slot : allfields) {
313: if (subfields.contains(slot))
314: pcs.addPropertyChangeListener(slot, pcl);
315: }
316: } else {
317: pcs.addPropertyChangeListener(pcl);
318: }
319: }
320:
321: public void removePropertyChangeListener(PropertyChangeListener pcl) {
322: if (pcl instanceof DataFrame) {
323: Map<String, SlotDescription> descriptions = new HashMap<String, SlotDescription>();
324: collectSlotDescriptions(descriptions);
325: for (String slot : descriptions.keySet()) {
326: pcs.removePropertyChangeListener(slot, pcl);
327: }
328: } else {
329: pcs.removePropertyChangeListener(pcl);
330: }
331: }
332:
333: // Public accesssors
334:
335: /**
336: * @return name/value pairs of the local slots. In this context "local"
337: * means: include slots the prototype tree but not from the
338: * container tree.
339: */
340: public Properties getLocalSlots() {
341: Properties props = new VisibleProperties();
342: collectSlotValues(props);
343: return props;
344: }
345:
346: /**
347: *
348: * @return name/value pairs of all slots.
349: */
350: public Properties getAllSlots() {
351: Properties props = new VisibleProperties();
352: collectSlotValues(props);
353: collectContainerSlotValues(props);
354: return props;
355: }
356:
357: /**
358: *
359: * @return a Map of slot metatdata.
360: */
361: public Map<String, SlotDescription> slotDescriptions() {
362: Map<String, SlotDescription> descriptions = new HashMap<String, SlotDescription>();
363: collectSlotDescriptions(descriptions);
364: return descriptions;
365: }
366:
367: /**
368: * Updates the given slot value.
369: */
370: public void setValue(String slot, Object value) {
371: setLocalValue(slot, value);
372: }
373:
374: public void initializeValues(Properties values) {
375: Iterator itr = values.entrySet().iterator();
376: while (itr.hasNext()) {
377: Map.Entry entry = (Map.Entry) itr.next();
378: try {
379: initializeLocalValue((String) entry.getKey(), entry
380: .getValue());
381: } catch (Throwable t) {
382: log.error("Error initializing slot " + entry.getKey()
383: + " of " + this + " to " + entry.getValue(), t);
384: }
385: }
386: postInitialize();
387: }
388:
389: /**
390: *
391: * @return the name of the container prototype, if any, where
392: * 'containment' is defined by the frame's frameset.
393: */
394: public String getContainerKind() {
395: Frame container = containerFrame();
396: return container == null ? null : container.getKind();
397: }
398:
399: /**
400: *
401: * @return the container frame, if any, where 'containment' is defined
402: * by the frame's frameset.
403: */
404: public DataFrame containerFrame() {
405: if (frameSet == null)
406: return null;
407: DataFrame result = frameSet.getContainer(this );
408: if (result == null) {
409: if (log.isDebugEnabled())
410: log.debug(this + " has no container!");
411: }
412: return result;
413: }
414:
415: /**
416: *
417: * @param role
418: * {@link FrameSet#PARENT} or {@link FrameSet#CHILD}
419: * @param relation
420: * The name of a relationship prototype
421: * @return All frames to which this one is related and in which this one
422: * plays the given role.
423: */
424: public Set<DataFrame> findRelations(String role, String relation) {
425: if (frameSet == null)
426: return null;
427: return frameSet.findRelations(this , role, relation);
428: }
429:
430: /**
431: *
432: * @param role
433: * {@link FrameSet#PARENT} or {@link FrameSet#CHILD}
434: * @param relation
435: * The name of a relationship prototype
436: * @return Some frame to which this one is related and in which this one
437: * plays the given role. If more than one such frame exists in the frameset,
438: * an arbitrary one is selected.
439: */
440: public DataFrame findFirstRelation(String role, String relation) {
441: if (frameSet == null)
442: return null;
443: return frameSet.findFirstRelation(this , role, relation);
444: }
445:
446: /**
447: *
448: * @param role
449: * {@link FrameSet#PARENT} or {@link FrameSet#CHILD}
450: * @param relation
451: * The name of a relationship prototype
452: * @return the number of RelationFrames that match the given prototype
453: * and in which this frame plays the given role.
454: */
455: public int countRelations(String role, String relation) {
456: if (frameSet == null)
457: return 0;
458: return frameSet.countRelations(this , role, relation);
459: }
460:
461: /**
462: *
463: * @param role
464: * {@link FrameSet#PARENT} or {@link FrameSet#CHILD}
465: * @param relation
466: * The name of a relationship prototype
467: * @return All RelationFrames that match the given prototype and in
468: * which this frame playes the given role.
469: */
470: public Map<RelationFrame, DataFrame> findRelationshipFrames(
471: String role, String relation) {
472: if (frameSet == null)
473: return null;
474: return frameSet.findRelationshipFrames(this , role, relation);
475: }
476:
477: /**
478: * @return true iff this frame matches the given prototype
479: */
480: public boolean isa(String kind) {
481: if (frameSet == null)
482: return kind.equals(getKind());
483: return frameSet.descendsFrom(this , kind);
484: }
485:
486: // Support
487:
488: protected void slotModified(String slot, Object old_value,
489: Object new_value, boolean notify_listeners,
490: boolean notify_blackboard) {
491: if (notify_blackboard && frameSet != null)
492: frameSet.valueUpdated(this , slot, new_value);
493: if (notify_listeners) {
494: String fixed_name = FrameGen.fixName(slot, true, true);
495: fireChange(fixed_name, old_value, new_value);
496: notifyPathDependents(slot);
497: }
498: }
499:
500: protected void slotInitialized(String slot, Object value) {
501: // nothing to be done at the moment
502: }
503:
504: protected void postInitialize() {
505: // Nothing at this level. Frame types with Metric-value slots
506: // should subscribe to the MetricsService here
507: }
508:
509: protected void collectSlotNames(Set<String> slots) {
510:
511: }
512:
513: // Converters used in generated code
514: protected String force_String(Object x) {
515: if (x instanceof String)
516: return ((String) x);
517: else
518: return x.toString(); // hmm
519: }
520:
521: protected Metric force_Metric(Object x) {
522: if (x instanceof Metric)
523: return ((Metric) x);
524: else
525: throw new RuntimeException(x
526: + " cannot be coerced to a Metric");
527: }
528:
529: protected double force_double(Object x) {
530: if (x instanceof String)
531: return Double.parseDouble((String) x);
532: else if (x instanceof Double)
533: return ((Double) x).doubleValue();
534: else
535: throw new RuntimeException(x
536: + " cannot be coerced to a double");
537: }
538:
539: protected Double force_Double(Object x) {
540: if (x instanceof String) {
541: return Double.valueOf((String) x);
542: } else if (x instanceof Double) {
543: return (Double) x;
544: } else {
545: throw new RuntimeException(x
546: + " cannot be coerced to a Double");
547: }
548: }
549:
550: protected float force_float(Object x) {
551: if (x instanceof String)
552: return Float.parseFloat((String) x);
553: else if (x instanceof Float)
554: return ((Float) x).floatValue();
555: else
556: throw new RuntimeException(x
557: + " cannot be coerced to a float");
558: }
559:
560: protected Float force_Float(Object x) {
561: if (x instanceof String)
562: return Float.valueOf((String) x);
563: else if (x instanceof Float)
564: return (Float) x;
565: else
566: throw new RuntimeException(x
567: + " cannot be coerced to a Float");
568: }
569:
570: protected long force_long(Object x) {
571: if (x instanceof String)
572: return Long.parseLong((String) x);
573: else if (x instanceof Long)
574: return ((Long) x).longValue();
575: else
576: throw new RuntimeException(x
577: + " cannot be coerced to a long");
578: }
579:
580: protected Long force_Long(Object x) {
581: if (x instanceof String)
582: return Long.valueOf((String) x);
583: else if (x instanceof Long)
584: return (Long) x;
585: else
586: throw new RuntimeException(x
587: + " cannot be coerced to a Long");
588: }
589:
590: protected int force_int(Object x) {
591: if (x instanceof String)
592: return Integer.parseInt((String) x);
593: else if (x instanceof Integer)
594: return ((Integer) x).intValue();
595: else
596: throw new RuntimeException(x
597: + " cannot be coerced to an int");
598: }
599:
600: protected Integer force_Integer(Object x) {
601: if (x instanceof String)
602: return Integer.valueOf((String) x);
603: else if (x instanceof Integer)
604: return (Integer) x;
605: else
606: throw new RuntimeException(x
607: + " cannot be coerced to a Long");
608: }
609:
610: protected boolean force_boolean(Object x) {
611: if (x instanceof String)
612: return ((String) x).equalsIgnoreCase("true");
613: else if (x instanceof Boolean)
614: return ((Boolean) x).booleanValue();
615: else
616: throw new RuntimeException(x
617: + " cannot be coerced to a boolean");
618: }
619:
620: protected Boolean force_Boolean(Object x) {
621: if (x instanceof String)
622: return Boolean.valueOf((String) x);
623: else if (x instanceof Boolean)
624: return (Boolean) x;
625: else
626: throw new RuntimeException(x
627: + " cannot be coerced to a Long");
628: }
629:
630: protected void fireChange(String property, Object old_value,
631: Object new_value) {
632: if (log.isDebugEnabled())
633: log.debug("Fire PropertyChange " + property
634: + " old value = " + old_value + " new value = "
635: + new_value);
636: // Both null: no change
637: if (old_value == null && new_value == null)
638: return;
639:
640: if (old_value == null || new_value == null // One null, one not
641: || !old_value.equals(new_value) // Different non-nulls
642: ) {
643: PropertyChangeEvent evt = new ResourceablePropertyChangeEvent(
644: this , property, old_value, new_value);
645: pcs.firePropertyChange(evt);
646: }
647: }
648:
649: protected void fireContainerChanges(DataFrame old_frame,
650: DataFrame new_frame) {
651: // default is no-op
652: }
653:
654: protected void fireContainerChanges(DataFrame new_frame) {
655: // default is no-op
656: }
657:
658: protected void collectSlotDescriptions(
659: Map<String, SlotDescription> map) {
660: // default is no-op
661: }
662:
663: protected void collectSlotValues(Properties props) {
664: // default is no-op
665: }
666:
667: protected void collectContainerSlotValues(Properties props) {
668: // default is no-op
669: }
670:
671: protected synchronized Object getProperty(String slot) {
672: if (props == null)
673: props = new Properties();
674: return props.get(slot);
675: }
676:
677: protected synchronized void setProperty(String slot, Object value) {
678: if (props == null)
679: props = new Properties();
680: props.put(slot, value);
681: }
682:
683: protected synchronized void removeProperty(String slot) {
684: if (props != null)
685: props.remove(slot);
686: }
687:
688: protected Object getInheritedValue(Frame origin, String slot) {
689: Object result = super .getInheritedValue(origin, slot);
690: if (result != null)
691: return result;
692:
693: if (frameSet == null)
694: return null;
695:
696: Frame container = frameSet.getContainer(this );
697: if (container != null) {
698: return container.getValue(slot);
699: } else {
700: return null;
701: }
702: }
703:
704: Object getValue(Frame origin, String slot) {
705: Object result = getLocalValue(slot);
706: if (result != null)
707: return result;
708: else
709: return getInheritedValue(origin, slot);
710: }
711:
712: void addToFrameSet(FrameSet frameSet) {
713: if (this .frameSet != null && this .frameSet != frameSet) {
714: throw new RuntimeException(this
715: + " is already in FrameSet " + this .frameSet
716: + ". It can't be added to FrameSet " + frameSet);
717: } else {
718: this .frameSet = frameSet;
719: frameSet.makeFrame(this );
720: postInitialize();
721: }
722: }
723:
724: void writeSlots(PrintWriter writer, Map slots, int indentation,
725: int offset) {
726: Iterator itr = slots.entrySet().iterator();
727: while (itr.hasNext()) {
728: Map.Entry entry = (Map.Entry) itr.next();
729: String slot_name = (String) entry.getKey();
730: Object slot_value = entry.getValue();
731: for (int i = 0; i < indentation; i++)
732: writer.print(' ');
733: writer.println(" " + slot_name + "=\"" + slot_value + "\"");
734: }
735: }
736:
737: void write(PrintWriter writer, int indentation, int offset,
738: boolean allSlots) {
739: for (int i = 0; i < indentation; i++)
740: writer.print(' ');
741: writer.println("<" + getKind());
742: Map slots = allSlots ? getAllSlots() : getLocalSlots();
743: writeSlots(writer, slots, indentation + offset, offset);
744: for (int i = 0; i < indentation; i++)
745: writer.print(' ');
746: writer.println("/>");
747: }
748:
749: void containerChange(DataFrame old_container,
750: DataFrame new_container) {
751: if (log.isDebugEnabled())
752: log.debug(" Old container = " + old_container
753: + " New container = " + new_container);
754: if (old_container != null) {
755: // No longer subscribe to changes on old container
756: old_container.removePropertyChangeListener(this );
757: }
758: if (new_container != null) {
759: // Subscribe to changes on new container. Must also do
760: // immediate property changes for all container accessors!
761: new_container.addPropertyChangeListener(this );
762: if (old_container != null)
763: fireContainerChanges(old_container, new_container);
764: else
765: fireContainerChanges(new_container);
766: }
767: }
768:
769: protected static void registerFrameMaker(String pkg, String proto,
770: FrameMaker maker) {
771: if (log.isDebugEnabled())
772: log.debug("Registering FrameMaker " + maker
773: + " for prototype " + proto + " in package " + pkg);
774: synchronized (FramePackages) {
775: Map<String, FrameMaker> frameTypeMap = FramePackages
776: .get(pkg);
777: if (frameTypeMap == null) {
778: frameTypeMap = new HashMap();
779: FramePackages.put(pkg, frameTypeMap);
780: }
781: frameTypeMap.put(proto, maker);
782: }
783: }
784:
785: protected static FrameMaker findFrameMaker(String pkg, String proto) {
786: synchronized (FramePackages) {
787: Map<String, FrameMaker> frameTypeMap = FramePackages
788: .get(pkg);
789: if (frameTypeMap != null)
790: return frameTypeMap.get(proto);
791: else
792: return null;
793: }
794: }
795:
796: protected static Logger getLogger() {
797: return log;
798: }
799:
800: public static DataFrame newFrame(FrameSet frameSet, String proto,
801: UID uid, Properties initial_values) {
802: String pkg = frameSet.getPackageName();
803: return newFrame(pkg, frameSet, proto, uid, initial_values);
804: }
805:
806: public static DataFrame newFrame(String pkg, FrameSet frameSet,
807: String proto, UID uid, Properties values) {
808: if (log.isDebugEnabled())
809: log.debug("Searching for FrameMaker for prototype " + proto
810: + " in package " + pkg);
811: // force a class load (ugh)
812: frameSet.classForPrototype(proto);
813: DataFrame frame = null;
814: FrameMaker maker = findFrameMaker(pkg, proto);
815: if (maker != null) {
816: frame = maker.makeFrame(frameSet, uid);
817: frame.initializeValues(values);
818: } else {
819: log.error("No FrameMaker for " + proto + " in package "
820: + pkg);
821: }
822: return frame;
823: }
824:
825: protected String displayString() {
826: return getUID().toString();
827: }
828:
829: public String toString() {
830: return "<" + getPrototype().getName() + " " + displayString()
831: + ">";
832: }
833:
834: }
|