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: /*
028: * This file is hand generated! Don't be fooled by the fact that most other
029: * asset-related classes are machine generated.
030: */
031:
032: package org.cougaar.planning.ldm.asset;
033:
034: import java.beans.IntrospectionException;
035: import java.beans.PropertyChangeListener;
036: import java.beans.PropertyChangeSupport;
037: import java.beans.PropertyDescriptor;
038: import java.io.IOException;
039: import java.io.ObjectInputStream;
040: import java.io.ObjectOutputStream;
041: import java.lang.reflect.Method;
042: import java.util.Enumeration;
043: import java.util.HashMap;
044: import java.util.HashSet;
045: import java.util.Vector;
046:
047: import org.cougaar.core.agent.ClusterContext;
048: import org.cougaar.core.agent.ClusterContextTable;
049: import org.cougaar.core.blackboard.ChangeReport;
050: import org.cougaar.core.blackboard.Publishable;
051: import org.cougaar.core.mts.MessageAddress;
052: import org.cougaar.core.util.UID;
053: import org.cougaar.core.util.UniqueObject;
054: import org.cougaar.planning.ldm.LDMContextTable;
055: import org.cougaar.planning.ldm.LDMServesPlugin;
056: import org.cougaar.planning.ldm.PlanningFactory;
057: import org.cougaar.planning.ldm.plan.RoleSchedule;
058: import org.cougaar.planning.ldm.plan.RoleScheduleImpl;
059: import org.cougaar.planning.ldm.plan.Schedule;
060: import org.cougaar.util.log.Logging;
061: import org.cougaar.util.log.Logger;
062: import org.cougaar.util.ToStringMemo;
063: import org.cougaar.util.PropertyParser;
064:
065: /**
066: * Base class for all instantiable assets.
067: *
068: * @property org.cougaar.planning.ldm.asset.Asset.regeneratePrototypeCache If set to true
069: * (the default), the prototypeCache will be regenerated as much as possible
070: * from persistence information on rehydration.
071: * @property org.cougaar.planning.ldm.asset.Asset.sendPrototypeAsID If set to false (the default)
072: * then when an Asset is sent through a messaging system, we will send the Asset's prototype
073: * as a real object if possible. When set to true, the prototype will be sent merely as the
074: * TypeIdentification string. This latter mode has the effect of allowing the "shape" of an
075: * asset to shift as it traverses the messaging system so that agents may choose to know exactly which
076: * prototypical parameters are required.
077: **/
078:
079: public class Asset extends org.cougaar.planning.ldm.asset.AssetSkeleton
080: implements Cloneable, UniqueObject, Publishable {
081: public static final boolean regeneratePrototypeCacheP = PropertyParser
082: .getBoolean(
083: "org.cougaar.planning.ldm.asset.Asset.regeneratePrototypeCache",
084: true);
085:
086: public static final boolean sendPrototypeAsIDP = PropertyParser
087: .getBoolean(
088: "org.cougaar.planning.ldm.asset.Asset.sendPrototypeAsID",
089: false);
090:
091: static final long serialVersionUID = -7188316484839955973L;
092:
093: private transient RoleSchedule roleschedule;
094:
095: private static final String AGGREGATE_TYPE_ID = "AggregateAsset";
096:
097: private static final Logger log = Logging.getLogger(Asset.class);
098:
099: public Asset() {
100: myPrototype = null; // no prototype, by default
101:
102: myItemIdentificationPG = PropertyGroupFactory
103: .newItemIdentificationPG();
104: myTypeIdentificationPG = PropertyGroupFactory
105: .newTypeIdentificationPG();
106: initRoleSchedule();
107: }
108:
109: protected Asset(Asset prototype) {
110: super (prototype);
111: // my prototype is who we're based on
112: myPrototype = prototype;
113: // I always get my own item ID which starts out as a copy of me.
114: myItemIdentificationPG = (ItemIdentificationPG) prototype
115: .getItemIdentificationPG().copy();
116: // instead, lets share the itemID, but make sure it is locked.
117: //myItemIdentificationPG=(ItemIdentificationPG)prototype.getItemIdentificationPG().lock();
118: // share the typeID with proto
119: myTypeIdentificationPG = prototype.getTypeIdentificationPG();
120: // new roleschedule
121: initRoleSchedule();
122: }
123:
124: /** Create an instance of a prototype asset **/
125: public Asset createInstance() {
126: return new Asset(this );
127: }
128:
129: /** Create an instance of a prototype asset, giving the new instance
130: * an itemid of id.
131: **/
132: public final Asset createInstance(String id) {
133: Asset a = createInstance();
134: ((NewItemIdentificationPG) a.getItemIdentificationPG())
135: .setItemIdentification(id);
136: return a;
137: }
138:
139: private UID uid = null;
140:
141: public UID getUID() {
142: return uid;
143: }
144:
145: public void setUID(UID uid) {
146: this .uid = uid;
147: }
148:
149: /** return all the properties as a new vector */
150: public Vector fetchAllProperties() {
151: Vector v = new Vector();
152: fillAllPropertyGroups(v);
153: return v;
154: }
155:
156: /** return all the properties as a new vector */
157: public Vector fetchAllProperties(long time) {
158: Vector v = new Vector();
159: fillAllPropertyGroups(v, time);
160: return v;
161: }
162:
163: protected void fillAllPropertyGroups(Vector v) {
164: // stick ours on the front - all others add to the end.
165: v.addElement(myItemIdentificationPG);
166: v.addElement(myTypeIdentificationPG);
167: super .fillAllPropertyGroups(v);
168: }
169:
170: protected void fillAllPropertyGroups(Vector v, long time) {
171: // stick ours on the front - all others add to the end.
172: v.addElement(myItemIdentificationPG);
173: v.addElement(myTypeIdentificationPG);
174: super .fillAllPropertyGroups(v, time);
175: }
176:
177: /** For internal use only - use Factory.copyInstance() instead.
178: * extended
179: **/
180: public Asset copy() {
181: try {
182: return (Asset) clone();
183: } catch (CloneNotSupportedException cnse) {
184: cnse.printStackTrace();
185: return null;
186: }
187: }
188:
189: /** For internal use only - use Factory.copyInstance() instead.
190: * extended
191: **/
192: public Object clone() throws CloneNotSupportedException {
193: Asset a = instanceForCopy();
194:
195: // bind the new asset to our LDM
196: a.bindToLDM(_ldm.getLDM()); // use the real LDM if we have a delegator
197:
198: a.privatelySetPrototype(getPrototype());
199: // set the itemID to a copy of the original
200: a.setItemIdentificationPG(getItemIdentificationPG().copy());
201: // share the typeid
202: a.setTypeIdentificationPG(getTypeIdentificationPG().lock());
203: // share the uid (for now, at least!)
204: a.setUID(getUID());
205:
206: // handle assetskeleton params immediately
207: for (Enumeration ops = getOtherProperties(); ops
208: .hasMoreElements();) {
209: Object p = ops.nextElement();
210:
211: if (p instanceof PropertyGroup) {
212: a.addOtherPropertyGroup(((PropertyGroup) p).lock());
213: } else {
214: a
215: .addOtherPropertyGroupSchedule((PropertyGroupSchedule) ((PropertyGroupSchedule) p)
216: .clone());
217: }
218:
219: }
220:
221: return a;
222: }
223:
224: /** creates an instance of the the right class, suitable for filling
225: * with properties by clone() methods.
226: *
227: **/
228:
229: public Asset instanceForCopy() {
230: //return new Asset();
231: try {
232: return (Asset) this .getClass().newInstance();
233: } catch (Exception e) {
234: return null;
235: }
236: }
237:
238: // myPrototype used to default property values for subs
239: // so we don't have to copy links or property groups.
240: protected transient Asset myPrototype;
241:
242: public Asset getPrototype() {
243: return myPrototype;
244: }
245:
246: public Asset setPrototype(Asset arg_Prototype) {
247: throw new RuntimeException(
248: "It is illegal to set the asset prototype explicitly");
249: /*
250: myPrototype= arg_Prototype;
251: return arg_Prototype;
252: */
253: }
254:
255: /** used internally **/
256: void privatelySetPrototype(Asset arg) {
257: myPrototype = arg;
258: }
259:
260: private transient ItemIdentificationPG myItemIdentificationPG;
261:
262: public ItemIdentificationPG getItemIdentificationPG() {
263: return myItemIdentificationPG;
264: }
265:
266: public void setItemIdentificationPG(
267: PropertyGroup arg_ItemIdentificationPG) {
268: if (!(arg_ItemIdentificationPG instanceof ItemIdentificationPG))
269: throw new IllegalArgumentException(
270: "setItemIdentificationPG requires a ItemIdentificationPG argument.");
271: myItemIdentificationPG = (ItemIdentificationPG) arg_ItemIdentificationPG;
272: }
273:
274: private transient TypeIdentificationPG myTypeIdentificationPG;
275:
276: public TypeIdentificationPG getTypeIdentificationPG() {
277: return myTypeIdentificationPG;
278: }
279:
280: public void setTypeIdentificationPG(
281: PropertyGroup arg_TypeIdentificationPG) {
282: if (!(arg_TypeIdentificationPG instanceof TypeIdentificationPG))
283: throw new IllegalArgumentException(
284: "setTypeIdentificationPG requires a TypeIdentificationPG argument.");
285: myTypeIdentificationPG = (TypeIdentificationPG) arg_TypeIdentificationPG;
286: }
287:
288: // for allocation/roleschedule stuff
289:
290: /** @return RoleSchedule - the RoleSchedule object associated with this Asset
291: * Note that the old Enumeration getRoleSchedule() is no longer used in asset
292: * use asset.getRoleSchedule().getRoleSchedule for the enumeration of the roleschedule
293: **/
294: public RoleSchedule getRoleSchedule() {
295: org.cougaar.core.blackboard.Blackboard.getTracker()
296: .checkAccess(this , "getRoleSchedule");
297: return roleschedule;
298: }
299:
300: //method should ONLY be called by the constructor and serialization
301: private void initRoleSchedule() {
302: roleschedule = new RoleScheduleImpl(this );
303: }
304:
305: //end of disposition container / roleschedule stuff
306:
307: // aggregate creation support
308: public Asset createAggregate(int quantity) {
309: AggregateAsset aa = new AggregateAsset();
310: aa.setAsset(this );
311: aa.setQuantity(quantity);
312: NewTypeIdentificationPG tip = PropertyGroupFactory
313: .newTypeIdentificationPG();
314: tip.setTypeIdentification(AGGREGATE_TYPE_ID);
315: tip.setNomenclature(AGGREGATE_TYPE_ID
316: + " aggregating quantity " + quantity + " of " + this );
317: aa.setTypeIdentificationPG(tip);
318: return aa;
319: }
320:
321: // compile-compatibility with org.cougaar.planning.ldm.plan.asset
322: public Enumeration getCapabilities() {
323: return null;
324: }
325:
326: public String getName() {
327: return null;
328: }
329:
330: public PropertyGroupSchedule searchForPropertyGroupSchedule(Class c) {
331: return super .searchForPropertyGroupSchedule(c);
332: }
333:
334: // Keep track of the enclosing LDM so that we can resolve
335: // late bindings and such.
336: private transient LDMServesPlugin _ldm = null;
337:
338: /** Called by readObject and factory to tell an asset where it
339: * is resident to allow such things as late binding of PGs.
340: **/
341: public final void bindToLDM(LDMServesPlugin ldm) {
342: _ldm = ldm;
343: }
344:
345: /** Called by Asset factories to register the asset with the LDM.
346: * This assigns a UID to the Asset and binds the instance to
347: * the ldm.
348: **/
349: public final void registerWithLDM(LDMServesPlugin ldm) {
350: setUID(ldm.getUIDServer().nextUID());
351: bindToLDM(ldm);
352: }
353:
354: // serialization
355:
356: private void writeObject(ObjectOutputStream out) throws IOException {
357: out.defaultWriteObject();
358: out.writeObject(myTypeIdentificationPG);
359: out.writeObject(myItemIdentificationPG);
360:
361: ClusterContextTable.ContextState cs = ClusterContextTable
362: .getContextState();
363: if (cs instanceof ClusterContextTable.MessageContext) {
364: // "Network" serialization
365:
366: // Urk! We really should be sending the TID of the prototype instead of the prototype
367: // itself. Older versions has a horrible hack here which needed to be dropped.
368: Object sp = myPrototype;
369: if (sp != null && sendPrototypeAsIDP) {
370: TypeIdentificationPG ptip = myPrototype
371: .getTypeIdentificationPG();
372: sp = ptip.getTypeIdentification();
373: }
374: out.writeObject(sp);
375: } else {
376: // "File" serialization
377: out.writeObject(myPrototype);
378:
379: if (out instanceof org.cougaar.core.persist.PersistenceOutputStream) {
380: out.writeObject(roleschedule.getAvailableSchedule());
381: }
382: } // End Network serialization
383: }
384:
385: private void readObject(ObjectInputStream in)
386: throws ClassNotFoundException, IOException {
387: in.defaultReadObject();
388: myTypeIdentificationPG = (TypeIdentificationPG) in.readObject();
389: myItemIdentificationPG = (ItemIdentificationPG) in.readObject();
390:
391: ClusterContextTable.ContextState cs = ClusterContextTable
392: .getContextState();
393: ClusterContext cc = cs.getClusterContext();
394: LDMServesPlugin ldm;
395: if (cc != null) {
396: MessageAddress ma = cc.getMessageAddress();
397: ldm = LDMContextTable.getLDM(ma);
398: bindToLDM(ldm);
399: } else {
400: log.error("Contextless deserialization of " + this );
401: ldm = null;
402: }
403:
404: Object proto = in.readObject();
405: myPrototype = grokPrototype(ldm, proto);
406:
407: initRoleSchedule();
408:
409: if (cs instanceof ClusterContextTable.MessageContext) { // a message?
410: // done
411: } else { // from a file?
412: if (in instanceof org.cougaar.core.persist.PersistenceInputStream) {
413: Schedule schedule = (Schedule) in.readObject();
414: ((RoleScheduleImpl) roleschedule)
415: .setAvailableSchedule(schedule);
416: }
417: }
418: }
419:
420: /** Figure out how to interpret an object which was supplied as the prototype
421: * of a deserialized Asset.
422: **/
423: private static Asset grokPrototype(LDMServesPlugin ldm, Object po) {
424: if (po == null) {
425: return null;
426: } else {
427: if (po instanceof Asset) {
428: return grokPrototypeAsAsset(ldm, (Asset) po);
429: } else if (po instanceof String) {
430: return grokPrototypeAsTID(ldm, (String) po);
431: } else {
432: log.error("Deserialized an unknown prototype class: "
433: + po);
434: return null;
435: }
436: }
437: }
438:
439: /** Figure out how to handle an asset's prototype when deserialized as
440: * a real (whole) asset.
441: **/
442: private static Asset grokPrototypeAsAsset(LDMServesPlugin ldm,
443: Asset pa) {
444: if (ldm != null) { // if we've got an LDM, check the prototype cache
445: TypeIdentificationPG ptip = pa.getTypeIdentificationPG();
446: String tid = ptip.getTypeIdentification();
447:
448: if (ldm.isPrototypeCached(tid)) { // is there a cached prototype already? yes.
449: // use the cached one instead of this
450: Asset putativeProto = ldm.getPrototype(tid);
451: if (putativeProto != pa) {
452: if (log.isInfoEnabled()) {
453: log
454: .info("Deserialization used cached prototype "
455: + putativeProto
456: + " instead of stored prototype "
457: + pa);
458: }
459: }
460: // use the cached one instead
461: pa = putativeProto;
462: } else { // is there a cached prototype already? no.
463: // consider caching it
464: // if we're trying to regenerate the prototype cache,
465: // AND we've got a prototype AND we have a live LDM, then try to cache it
466: if (regeneratePrototypeCacheP) {
467: ldm.cachePrototype(tid, pa);
468: if (log.isDebugEnabled()) {
469: log.debug("Deserialization cached prototype "
470: + pa);
471: }
472: }
473: }
474: } else {
475: // log.warn("Performance problem: Deserialization of Asset Prototypes without LDM context");
476: }
477: return pa;
478: }
479:
480: /** Figure out how to handle an asset's prototype when deserialized as
481: * a raw TypeIdentification string.
482: **/
483: private static Asset grokPrototypeAsTID(LDMServesPlugin ldm,
484: String tid) {
485: Asset pa = null;
486: if (ldm != null) {
487: // get the proto from OUR ldm...
488: // for now, we just look at the TId of the TIP sent.
489: pa = ldm.getPrototype(tid);
490:
491: // if no proto found, we're on our own,
492: // so we'll create a proto with the tid and no other
493: // props.
494: if (pa == null) {
495: PlanningFactory ldmf = (PlanningFactory) ldm
496: .getFactory("planning");
497: pa = ldmf.createPrototype(Asset.class, tid);
498: // even though there is no prototype provider, there
499: // might be property providers that can handle it, so
500: // we'll expose our new instance to them.
501: ldm.fillProperties(pa);
502: // might as well register it, since we're unlikely to get
503: // a proto provider later.
504: ldm.cachePrototype(tid, pa);
505: log
506: .error("Deserialized an Asset with an unknown prototype ID "
507: + tid + " (prototype will be empty)");
508: } // else got a prototype from the cache, so we're done
509: } else {
510: // no ldm, so we cannot do anything here
511: log
512: .error("Deserialized an asset with prototype "
513: + tid
514: + " without an LDM context (will not have a prototype)");
515: }
516: return pa;
517: }
518:
519: private transient ToStringMemo toStringMemo = null;
520:
521: public synchronized String toString() {
522: if (toStringMemo == null) {
523: toStringMemo = ToStringMemo.getInstance(new Object() {
524: public String toString() {
525: String cn = Asset.this .getClass().getName();
526: int p = cn.lastIndexOf('.');
527: if (p >= 0)
528: cn = cn.substring(p + 1);
529: String ti = myTypeIdentificationPG
530: .getTypeIdentification();
531: String ii = myItemIdentificationPG
532: .getItemIdentification();
533: if (ti == null) {
534: ti = "?";
535: }
536: if (ii == null) {
537: ii = "#" + hashCode();
538: }
539: return "<" + cn + " " + ti + " " + ii + ">";
540: }
541: });
542: }
543: return toStringMemo.toString();
544: }
545:
546: //dummy PropertyChangeSupport for the Jess Interpreter.
547: public transient PropertyChangeSupport pcs = new PropertyChangeSupport(
548: this );
549:
550: public void addPropertyChangeListener(PropertyChangeListener pcl) {
551: pcs.addPropertyChangeListener(pcl);
552: }
553:
554: public void removePropertyChangeListener(PropertyChangeListener pcl) {
555: pcs.removePropertyChangeListener(pcl);
556: }
557:
558: /** this is a table of AssetClass->settermap
559: * where settermap is a table of settername->method
560: **/
561: private static HashMap _classSetters = new HashMap(13);
562:
563: private static final Class[] _pgClassArgs = new Class[] { PropertyGroup.class };
564:
565: /**
566: * Introspection-based propertygroup setter. The property will be
567: * added to either the built-in-property slots or the Other property set
568: * as appropriate to the actual class of the asset.
569: **/
570: public void setPropertyGroup(NewPropertyGroup property) {
571: try {
572: String pS = property.getAssetSetMethod();
573: Method m;
574: HashMap _setterTable;
575: synchronized (_classSetters) {
576: _setterTable = (HashMap) _classSetters.get(this
577: .getClass());
578: if (_setterTable == null) {
579: _setterTable = new HashMap(3);
580: _classSetters.put(this .getClass(), _setterTable);
581: }
582: }
583: synchronized (_setterTable) {
584: m = (Method) _setterTable.get(pS);
585: if (m == null) {
586: Class assetC = this .getClass();
587: try {
588: m = assetC.getMethod(pS, _pgClassArgs);
589: } catch (NoSuchMethodException e) {
590: // add-on property. sigh.
591: try {
592: m = assetC.getMethod(
593: "addOtherPropertyGroup",
594: _pgClassArgs);
595: } catch (NoSuchMethodException e1) {
596: log.error(
597: "Couldn't find addOtherPropertyGroup in "
598: + this , e1);
599: }
600: }
601: _setterTable.put(pS, m);
602: /*
603: if (m != null) {
604: System.err.println("\n"+this.getClass()+"."+pS+"() found "+m);
605: }
606: */
607: }
608: }
609: if (m != null) {
610: // we could sync the calls to avoid consing the arglist
611: m.invoke(this , new Object[] { property });
612: }
613: } catch (Exception e) {
614: log.error("setPropertyGroup problem", e);
615: }
616: }
617:
618: private static PropertyDescriptor properties[];
619:
620: static {
621: try {
622: properties = new PropertyDescriptor[5];
623: properties[0] = new PropertyDescriptor("roleSchedule",
624: Asset.class, "getRoleSchedule", null);
625: properties[1] = new PropertyDescriptor("UID", Asset.class,
626: "getUID", null);
627: properties[2] = new PropertyDescriptor(
628: "typeIdentificationPG", Asset.class,
629: "getTypeIdentificationPG", null);
630: properties[3] = new PropertyDescriptor(
631: "itemIdentificationPG", Asset.class,
632: "getItemIdentificationPG", null);
633: properties[4] = new PropertyDescriptor("class",
634: Asset.class, "getClass", null);
635: } catch (IntrospectionException ie) {
636: }
637: }
638:
639: public PropertyDescriptor[] getPropertyDescriptors() {
640: return properties;
641: }
642:
643: public int hashCode() {
644: int hc = 1;
645: String tid = getTypeIdentificationPG().getTypeIdentification();
646: String iid = getItemIdentificationPG().getItemIdentification();
647: if (tid != null)
648: hc += tid.hashCode();
649: if (iid != null)
650: hc += iid.hashCode();
651: return hc;
652: }
653:
654: /** Equals for assets is defined as being exactly the same class
655: * and having equals TypeIdentification and ItemIdentification codes.
656: **/
657:
658: public boolean equals(Object o) {
659: if (this == o)
660: return true;
661: if (o == null)
662: return false;
663: if (!(getClass() == o.getClass()))
664: return false;
665: Asset oa = (Asset) o;
666: TypeIdentificationPG tpg = getTypeIdentificationPG();
667: TypeIdentificationPG opg = oa.getTypeIdentificationPG();
668: if (tpg == null || opg == null)
669: return false;
670: String ttid = tpg.getTypeIdentification();
671: String otid = opg.getTypeIdentification();
672: if (ttid == null || otid == null || !(ttid.equals(otid)))
673: return false;
674: ItemIdentificationPG tipg = getItemIdentificationPG();
675: ItemIdentificationPG oipg = oa.getItemIdentificationPG();
676: if (tipg == null || oipg == null)
677: return false;
678: String tiid = tipg.getItemIdentification();
679: String oiid = oipg.getItemIdentification();
680:
681: return compareStrings(tiid, oiid);
682: /*
683: if (tiid == null || oiid == null || !(tiid.equals(oiid))) return false;
684: return true;
685: */
686: }
687:
688: private final boolean compareStrings(String s1, String s2) {
689: if (s1 == s2)
690: return true; // catches null==null, x==x
691:
692: if (s1 != null) {
693: // x==null, x==y, x==x
694: return s1.equals(s2);
695: } else {
696: // null==*
697: return false;
698: }
699: }
700:
701: //
702: // new PG resolution support
703: //
704:
705: // search methods inherited from AssetSkeletonBase
706:
707: /** return the value of the specified PG if it is
708: * already present in a slot.
709: **/
710: protected PropertyGroup getLocalPG(Class pgc, long t) {
711: if (ItemIdentificationPG.class.equals(pgc))
712: return myItemIdentificationPG;
713: if (TypeIdentificationPG.class.equals(pgc))
714: return myTypeIdentificationPG;
715: return super .getLocalPG(pgc, t);
716: }
717:
718: /** Set the apropriate slot in the asset to the specified pg.
719: * Scheduled PGs have the time range in them, so the time (range)
720: * should not be specified in the arglist.
721: **/
722: protected void setLocalPG(Class pgc, PropertyGroup pg) {
723: if (ItemIdentificationPG.class.equals(pgc)) {
724: myItemIdentificationPG = (ItemIdentificationPG) pg;
725: } else if (TypeIdentificationPG.class.equals(pgc)) {
726: myTypeIdentificationPG = (TypeIdentificationPG) pg;
727: } else {
728: super .setLocalPG(pgc, pg);
729: }
730: }
731:
732: /** return the value of the specified PG if it is
733: * already present in a slot.
734: **/
735: protected PropertyGroupSchedule getLocalPGSchedule(Class pgc) {
736: return super .getLocalPGSchedule(pgc);
737: }
738:
739: /** Set the apropriate slot in the asset to the specified pg.
740: * Scheduled PGs have the time range in them, so the time (range)
741: * should not be specified in the arglist.
742: **/
743: protected void setLocalPGSchedule(PropertyGroupSchedule pgSchedule) {
744: super .setLocalPGSchedule(pgSchedule);
745: }
746:
747: /** @return true IFF the specified PG class is set, available and non-null on
748: * the Asset instance. No checks for late-binding or prototype are ever performed
749: * for this check.
750: **/
751: public final boolean isPGLocal(Class pgc) {
752: return isPGLocal(pgc, UNSPECIFIED_TIME);
753: }
754:
755: /** @return true IFF the specified PG class is set, available and non-null on
756: * the Asset instance. No checks for late-binding or prototype are ever performed
757: * for this check. This variation is for querying at a specific time.
758: * If time is specified as Asset.UNSPECIFIED_TIME, then this call is equivalent to
759: * the single-argument isPGLocal(class).
760: **/
761: public final boolean isPGLocal(Class pgc, long t) {
762: return getLocalPG(pgc, t) != null;
763: }
764:
765: /** @return true IFF the specified PGSchedule class is set, available and non-null on
766: * the Asset instance. No checks for late-binding or prototype are ever performed
767: * for this check.
768: **/
769: public final boolean isPGScheduleLocal(Class pgc) {
770: return getLocalPGSchedule(pgc) != null;
771: }
772:
773: /** get and possibly cache a PG value.
774: * The information can come from a number of places:
775: * a local slot
776: * a late binding
777: * the prototype (recurse to resolve on the prototype)
778: * a default value
779: *
780: * Will return Null_PG instances if present.
781: * Defined as abstract in AssetSkeletonBase
782: **/
783: public final PropertyGroup resolvePG(Class pgc, long t) {
784: // check local slots - this call never sets
785: PropertyGroup pg = getLocalPG(pgc, t);
786: if (pg != null)
787: return pg; // return it - already set
788:
789: // check late binding
790: if ((pg = lateBindPG(pgc, t)) != null) {
791: //setLocalPG(pgc, pg);
792: return pg;
793: }
794:
795: // check the prototype
796: if (myPrototype != null) {
797: // recurse
798: if ((pg = myPrototype.resolvePG(pgc, t)) != null) {
799: // should we cache the prototype's PG value?
800: // Let's not.
801: return pg;
802: }
803: }
804:
805: // possibly default
806: pg = generateDefaultPG(pgc);
807:
808: return pg;
809: }
810:
811: /** request late binding from the LDM for this asset/PGClass.
812: * Late binders should set the asset's PG as appropriate in
813: * addition to returning the PG.
814: * Implements an abstract method from AssetSkeletonBase.
815: * @return null or a PropertyGroup instance.
816: */
817: protected final PropertyGroup lateBindPG(Class pgc, long t) {
818: if (_ldm != null) {
819: // Pass along the requested time in case we can get just
820: // a single time slice late-bound. This brings up other
821: // issues which we will just hand wave about for now...
822: return _ldm.lateFillPropertyGroup(this , pgc, t);
823: } else {
824: log.error("Asset " + this
825: + " is not bound to an LDM instance!");
826: }
827: return null;
828: }
829:
830: /** get and possibly cache a PropertyGroupSchedule.
831: * The information can come from a number of places:
832: * a local slot
833: * the prototype (recurse to resolve on the prototype)
834: *
835: * Defined as abstract in AssetSkeletonBase
836: **/
837: public final PropertyGroupSchedule resolvePGSchedule(Class pgc) {
838: // check local slots - this call never sets
839: PropertyGroupSchedule pgSchedule = getLocalPGSchedule(pgc);
840: if (pgSchedule != null)
841: return pgSchedule; // return it - already set
842:
843: // check the prototype
844: if (myPrototype != null) {
845: // recurse
846: if ((pgSchedule = myPrototype.resolvePGSchedule(pgc)) != null) {
847: // should we cache the prototype's PG value?
848: // Let's not.
849: return pgSchedule;
850: }
851: }
852:
853: return null;
854: }
855:
856: //
857: // implement Publishable
858: //
859: public boolean isPersistable() {
860: return true;
861: }
862:
863: private transient TypeItemKey myKey = null;
864:
865: public Object getKey() {
866: if (myKey == null) {
867: myKey = new TypeItemKey(this );
868: }
869:
870: return myKey;
871: }
872:
873: private static class TypeItemKey implements java.io.Serializable {
874: private String myTypeString = null;
875: private String myItemString = null;
876: private int myHashCode;
877:
878: public TypeItemKey(Asset asset) {
879: TypeIdentificationPG tipg = asset.getTypeIdentificationPG();
880: if (tipg != null) {
881: myTypeString = tipg.getTypeIdentification();
882: }
883: if (myTypeString == null) {
884: myTypeString = "";
885: }
886:
887: ItemIdentificationPG iipg = asset.getItemIdentificationPG();
888: if (iipg != null) {
889: myItemString = iipg.getItemIdentification();
890: }
891: if (myItemString == null) {
892: myItemString = "";
893: }
894:
895: if ((myTypeString.equals("")) && (myItemString.equals(""))) {
896: log
897: .error("Unable to create unique key for asset "
898: + asset
899: + " - type and item identification are not set.");
900: }
901:
902: myHashCode = myTypeString.hashCode()
903: + myItemString.hashCode();
904: }
905:
906: public int hashCode() {
907: return myHashCode;
908: }
909:
910: public boolean equals(Object o) {
911: if (o == this ) {
912: return true;
913: }
914:
915: if (o instanceof TypeItemKey) {
916: TypeItemKey that = (TypeItemKey) o;
917: return (this .myTypeString.equals(that.myTypeString) && this .myItemString
918: .equals(that.myItemString));
919: }
920:
921: return false;
922: }
923:
924: public String toString() {
925: return "<" + myTypeString + " " + myItemString + ">";
926: }
927: }
928:
929: // ChangeReport tracking
930: //
931: public interface AssetChangeReport extends ChangeReport {
932: }
933: }
|