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: /** Basic functionality for AssetSkeletons
028: * Implements otherProperties
029: **/package org.cougaar.planning.ldm.asset;
030:
031: import java.beans.SimpleBeanInfo;
032: import java.io.Serializable;
033: import java.util.ArrayList;
034: import java.util.Collection;
035: import java.util.Enumeration;
036: import java.util.Iterator;
037: import java.lang.reflect.Modifier;
038:
039: import org.cougaar.util.Empty;
040: import org.cougaar.util.Enumerator;
041:
042: public abstract class AssetSkeletonBase extends SimpleBeanInfo
043: implements Serializable, Cloneable {
044:
045: /** additional properties searched by default get*PG methods.
046: * Includes PropertyGroups and PropertyGroupSchedules
047: **/
048: private ArrayList otherProperties = null;
049:
050: protected boolean hasOtherTimePhasedProperties = false;
051:
052: public boolean hasOtherTimePhasedProperties() {
053: return hasOtherTimePhasedProperties;
054: }
055:
056: synchronized ArrayList copyOtherProperties() {
057: if (otherProperties == null)
058: return null;
059: else
060: return (ArrayList) otherProperties.clone();
061: }
062:
063: protected AssetSkeletonBase() {
064: }
065:
066: protected AssetSkeletonBase(AssetSkeletonBase prototype) {
067: otherProperties = prototype.copyOtherProperties();
068: hasOtherTimePhasedProperties = prototype
069: .hasOtherTimePhasedProperties();
070: }
071:
072: protected void fillAllPropertyGroups(Collection v) {
073: synchronized (this ) {
074: if (otherProperties != null) {
075: v.addAll(otherProperties);
076: }
077: }
078: }
079:
080: protected void fillAllPropertyGroups(Collection v, long time) {
081: if (!hasOtherTimePhasedProperties()) {
082: fillAllPropertyGroups(v);
083: return;
084: }
085:
086: synchronized (this ) {
087: if (otherProperties != null) {
088: for (Iterator i = otherProperties.iterator(); i
089: .hasNext();) {
090: Object o = i.next();
091: if (o instanceof PropertyGroupSchedule) {
092: PropertyGroup pg = (PropertyGroup) ((PropertyGroupSchedule) o)
093: .intersects(time);
094: if (pg != null) {
095: v.add(pg);
096: }
097: } else {
098: v.add(o);
099: }
100: }
101: }
102: }
103: }
104:
105: /** @return the set of additional properties (includes PropertyGroups and
106: * PropertyGroupSchedules) - not synchronized!**/
107: public synchronized Enumeration getOtherProperties() {
108: if (otherProperties == null || otherProperties.size() == 0)
109: return Empty.enumeration;
110: else
111: return new Enumerator(otherProperties);
112: }
113:
114: /** replace the existing set of other properties (PropertyGroups and
115: * PropertyGroupSchedules)
116: **/
117: protected synchronized void setOtherProperties(Collection newProps) {
118: hasOtherTimePhasedProperties = false;
119: if (newProps.isEmpty()) {
120: otherProperties = null;
121: } else {
122: if (otherProperties != null) {
123: otherProperties.clear();
124: otherProperties.addAll(newProps);
125: } else {
126: otherProperties = new ArrayList(newProps);
127: }
128:
129: // Check for time phased properties
130: for (Iterator i = otherProperties.iterator(); i.hasNext();) {
131: Object o = i.next();
132: if (o instanceof PropertyGroupSchedule) {
133: hasOtherTimePhasedProperties = true;
134: break;
135: }
136: }
137: }
138: }
139:
140: /** Add a PropertyGroup to the set of properties
141: * @param prop PropertyGroup to add
142: **/
143: public void addOtherPropertyGroup(PropertyGroup prop) {
144: setLocalPG(prop.getPrimaryClass(), prop);
145: }
146:
147: /** Add a PropertyGroupSchedule to the set of properties.
148: * @param pgs PropertyGroupSchedule to add
149: **/
150: public void addOtherPropertyGroupSchedule(PropertyGroupSchedule pgs) {
151: setLocalPGSchedule(pgs);
152: }
153:
154: /** Replace a PropertyGroup in the set of properties.
155: * @param prop PropertyGroup to replace
156: **/
157: public void replaceOtherPropertyGroup(PropertyGroup prop) {
158: setLocalPG(prop.getPrimaryClass(), prop);
159: }
160:
161: /** Replace a PropertyGroupSchedule in the set properties.
162: * @param schedule PropertyGroupSchedule to replace.
163: **/
164: public void replaceOtherPropertyGroupSchedule(
165: PropertyGroupSchedule schedule) {
166: setLocalPGSchedule(schedule);
167: }
168:
169: /** Removes the PropertyGroup matching the class passed in as an argument
170: * from the set of properties.
171: * Note: this implementation assumes that the set of properties
172: * holds one and only one instance of a given class.
173: * @param c Class to match.
174: * @return PropertyGroup Return the property instance that was removed;
175: * otherwise, return null.
176: **/
177: public PropertyGroup removeOtherPropertyGroup(Class c) {
178: return removeLocalPG(c);
179: }
180:
181: /** Removes the PropertyGroup passed in as an argument from the set of
182: * properties.
183: * @param pg PropertyGroup to remove
184: * @return PropertyGroup Return the property instance that was removed;
185: * otherwise, return null.
186: **/
187: public PropertyGroup removeOtherPropertyGroup(PropertyGroup pg) {
188: return removeLocalPG(pg);
189: }
190:
191: /** Removes the PropertyGroupSchedule whose PGClass matched the class passed
192: * in as an argument from the set of properties.
193: * Note: this implementation assumes that set of additional properties holds
194: * one and only one instance of this PropertyGroupSchedule
195: * @param c Class to match.
196: * @return PropertyGroupSchedule Return the PropertyGroupSchedule that was
197: * removed; otherwise, return null.
198: **/
199: public PropertyGroupSchedule removeOtherPropertyGroupSchedule(
200: Class c) {
201: return removeLocalPGSchedule(c);
202: }
203:
204: /** Removes the instance matching the PropertyGroupSchedule passed in as an
205: * argument
206: * Note: this implementation assumes that set of additional properties holds
207: * one and only one instance of a given PropertyGroupSchedule
208: * @param pgs PropertyGroupSchedule to remove. Match based on the schedule's
209: * PGClass.
210: * @return PropertyGroupSchedule Return the instance that was removed;
211: * otherwise, return null.
212: **/
213: public PropertyGroupSchedule removeOtherPropertyGroupSchedule(
214: PropertyGroupSchedule pgs) {
215: return removeLocalPGSchedule(pgs.getPGClass());
216: }
217:
218: /** return the PropertyGroupSchedule associated with the specified class.
219: * @param c Class of the PropertyGroup to look for
220: **/
221: public synchronized PropertyGroupSchedule searchForPropertyGroupSchedule(
222: Class c) {
223: if (!hasOtherTimePhasedProperties) {
224: return null;
225: }
226:
227: // Use time phased method
228: if (!TimePhasedPropertyGroup.class.isAssignableFrom(c)) {
229: return null;
230: }
231:
232: int index = findLocalPGScheduleIndex(c);
233:
234: if (index >= 0) {
235: return (PropertyGroupSchedule) otherProperties.get(index);
236: } else {
237: return null;
238: }
239: }
240:
241: /** Convenient equivalent to searchForPropertyGroupSchedule(pg.getPrimaryClass()) **/
242: public final PropertyGroupSchedule searchForPropertyGroupSchedule(
243: PropertyGroup pg) {
244: return searchForPropertyGroupSchedule(pg.getPrimaryClass());
245: }
246:
247: //
248: // new PG resolution support
249: //
250:
251: /** the (internal) time to mean unspecified **/
252: public final static long UNSPECIFIED_TIME = 0L;
253:
254: /** External api for finding a property group by class at no specific time **/
255: public final PropertyGroup searchForPropertyGroup(Class pgc) {
256: PropertyGroup pg = resolvePG(pgc, UNSPECIFIED_TIME);
257: return (pg instanceof Null_PG) ? null : pg;
258: }
259:
260: /** Convenient equivalent to searchForPropertyGroup(pg.getPrimaryClass()) **/
261: public final PropertyGroup searchForPropertyGroup(PropertyGroup pg) {
262: return searchForPropertyGroup(pg.getPrimaryClass());
263: }
264:
265: /** External api for finding a property group by class at a specific time **/
266: public final PropertyGroup searchForPropertyGroup(Class pgc, long t) {
267: PropertyGroup pg = resolvePG(pgc, t);
268: return (pg instanceof Null_PG) ? null : pg;
269: }
270:
271: /** Convenient equivalent to searchForPropertyGroup(pg.getPrimaryClass(), time) **/
272: public final PropertyGroup searchForPropertyGroup(PropertyGroup pg,
273: long time) {
274: return searchForPropertyGroup(pg.getPrimaryClass(), time);
275: }
276:
277: /** get and possibly cache a PG value.
278: * The information can come from a number of places:
279: * a local slot
280: * a late binding
281: * the prototype (recurse to resolve on the prototype)
282: * a default value
283: *
284: * Will return Null_PG instances if present.
285: * implemented in Asset
286: **/
287: public abstract PropertyGroup resolvePG(Class pgc, long t);
288:
289: public final PropertyGroup resolvePG(Class pgc) {
290: return resolvePG(pgc, UNSPECIFIED_TIME);
291: }
292:
293: /** request late binding from the LDM for this asset/PGClass.
294: * Late binders should set the asset's PG as appropriate in
295: * addition to returning the PG.
296: *
297: * Implemented in Asset
298: *
299: * @return null or a PropertyGroup instance.
300: */
301: protected abstract PropertyGroup lateBindPG(Class pgc, long t);
302:
303: public final PropertyGroup lateBindPG(Class pgc) {
304: return lateBindPG(pgc, UNSPECIFIED_TIME);
305: }
306:
307: /** get and possibly cache a PropertyGroupSchedule.
308: * The information can come from a number of places:
309: * a local slot
310: * the prototype (recurse to resolve on the prototype)
311: * implemented in Asset
312: **/
313: public abstract PropertyGroupSchedule resolvePGSchedule(Class pgc);
314:
315: /** generate and set a default PG instance (usually empty) for
316: * an asset. Generally will just do a new. Concrete.
317: * Asset implementations will override this.
318: **/
319: protected PropertyGroup generateDefaultPG(Class pgc) {
320: // if we wanted the PGs to *always* be there, we'd do something like:
321: /*
322: try {
323: PropertyGroup pg = (PropertyGroup) pgc.newInstance();
324: setLocalPG(pgc, pg);
325: return pg;
326: } catch (Exception e) {
327: e.printStackTrace();
328: return null;
329: }
330: */
331: // but, the default case wants to just return null
332: return null;
333: }
334:
335: /** return the value of the specified PG if it is
336: * already present in a slot.
337: **/
338: protected synchronized PropertyGroup getLocalPG(Class pgc, long t) {
339: if (otherProperties == null) {
340: return null;
341: }
342:
343: if (TimePhasedPropertyGroup.class.isAssignableFrom(pgc)) {
344: int index = findLocalPGScheduleIndex(pgc);
345: if (index >= 0) {
346: PropertyGroupSchedule pgs = (PropertyGroupSchedule) otherProperties
347: .get(index);
348: if (t == UNSPECIFIED_TIME) {
349: return pgs.getDefault();
350: } else {
351: return (PropertyGroup) pgs.intersects(t);
352: }
353: } else {
354: return null;
355: }
356: } else {
357: int index = findLocalPGIndex(pgc);
358:
359: if (index >= 0) {
360: return (PropertyGroup) otherProperties.get(index);
361: } else {
362: return null;
363: }
364: }
365: }
366:
367: /** Set the apropriate slot in the asset to the specified pg.
368: * Scheduled PGs have the time range in them, so the time (range)
369: * should not be specified in the arglist.
370: **/
371: protected synchronized void setLocalPG(Class pgc, PropertyGroup prop) {
372: if (prop instanceof TimePhasedPropertyGroup) {
373: int index = findLocalPGScheduleIndex(pgc);
374: TimePhasedPropertyGroup timePhasedProp = (TimePhasedPropertyGroup) prop;
375:
376: PropertyGroupSchedule schedule;
377: if (index >= 0) {
378: schedule = (PropertyGroupSchedule) otherProperties
379: .get(index);
380: schedule.removeAll(schedule
381: .intersectingSet(timePhasedProp));
382: } else {
383: hasOtherTimePhasedProperties = true;
384: schedule = new PropertyGroupSchedule();
385: if (otherProperties == null) {
386: otherProperties = new ArrayList(1);
387: }
388: otherProperties.add(schedule);
389: }
390:
391: schedule.add(prop);
392: } else {
393: addOrReplaceLocalPG(prop);
394: }
395: }
396:
397: /** return the value of the specified PropertyGroupSchedule if it is
398: * already present in a slot.
399: **/
400: protected synchronized PropertyGroupSchedule getLocalPGSchedule(
401: Class pgc) {
402: if ((!hasOtherTimePhasedProperties)
403: || (!TimePhasedPropertyGroup.class
404: .isAssignableFrom(pgc))) {
405: return null;
406: }
407:
408: int index = findLocalPGScheduleIndex(pgc);
409: if (index >= 0) {
410: return (PropertyGroupSchedule) otherProperties.get(index);
411: } else {
412: return null;
413: }
414: }
415:
416: /** Set the apropriate slot in the asset to the specified pgSchedule
417: **/
418: protected synchronized void setLocalPGSchedule(
419: PropertyGroupSchedule pgSchedule) {
420: if (hasOtherTimePhasedProperties) {
421: int index = findLocalPGScheduleIndex(pgSchedule
422: .getPGClass());
423: if (index >= 0) {
424: otherProperties.remove(index);
425: }
426: } else {
427: hasOtherTimePhasedProperties = true;
428: }
429:
430: if (otherProperties == null) {
431: otherProperties = new ArrayList(1);
432: }
433: otherProperties.add(pgSchedule);
434: }
435:
436: protected synchronized PropertyGroup removeLocalPG(Class c) {
437: // Better be a property group
438: // Need to verify because otherProperties contains both PGs and
439: // PGSchedules. Don't want to allow caller to remove an unspecified
440: // PGSchedule
441: if (!PropertyGroup.class.isAssignableFrom(c)) {
442: throw new IllegalArgumentException();
443: }
444:
445: PropertyGroup removed = null;
446:
447: // Use removeOtherPropertyGroupSchedule to remove entire schedules.
448: if (TimePhasedPropertyGroup.class.isAssignableFrom(c)) {
449:
450: int index = findLocalPGScheduleIndex(c);
451: if (index >= 0) {
452: PropertyGroupSchedule pgs = (PropertyGroupSchedule) otherProperties
453: .get(index);
454:
455: removed = pgs.getDefault();
456:
457: if ((removed == null) && (pgs.size() > 0)) {
458: removed = (PropertyGroup) pgs.get(0);
459: }
460:
461: otherProperties.remove(index);
462: }
463: } else {
464: int index = findLocalPGIndex(c);
465: if (index >= 0) {
466: removed = (PropertyGroup) otherProperties.get(index);
467: otherProperties.remove(index);
468: }
469: }
470: return removed;
471: }
472:
473: protected synchronized PropertyGroup removeLocalPG(PropertyGroup pg) {
474: // Better be a property group
475: // Need to verify because otherProperties contains both PGs and
476: // PGSchedules. Don't want to allow caller to remove an unspecified
477: // PGSchedule
478: if (!PropertyGroup.class.isAssignableFrom(pg.getPrimaryClass())) {
479: throw new IllegalArgumentException();
480: }
481:
482: PropertyGroup removed = null;
483: Class pgc = pg.getPrimaryClass();
484:
485: // Use removeOtherPropertyGroupSchedule to remove entire schedules.
486: if (TimePhasedPropertyGroup.class.isAssignableFrom(pgc)) {
487:
488: int index = findLocalPGScheduleIndex(pgc);
489: if (index >= 0) {
490: PropertyGroupSchedule pgs = (PropertyGroupSchedule) otherProperties
491: .get(index);
492:
493: if (pgs.getDefault() == pg) {
494: pgs.clearDefault();
495: removed = pg;
496: }
497:
498: if (pgs.remove(pg)) {
499: removed = pg;
500: }
501: }
502: } else {
503: int index = findLocalPGIndex(pg.getPrimaryClass());
504: if (index >= 0) {
505: removed = (PropertyGroup) otherProperties.get(index);
506: otherProperties.remove(index);
507: }
508: }
509: return removed;
510: }
511:
512: protected synchronized PropertyGroupSchedule removeLocalPGSchedule(
513: Class c) {
514: int index = findLocalPGScheduleIndex(c);
515:
516: if (index >= 0) {
517: return (PropertyGroupSchedule) otherProperties
518: .remove(index);
519: } else {
520: return null;
521: }
522: }
523:
524: /** add a PG, making sure to drop any previous PG of identical class which had
525: * already been there.
526: **/
527: private final synchronized void addOrReplaceLocalPG(
528: PropertyGroup prop) {
529: // Look through the list for a PG of a matching class. The hard part
530: // of this is that either the prop or any of the elements of the list
531: // may be natural (FooPGImpl), locked, Null, etc. So: our solution is
532: // to compare the "PrimaryClass" of each.
533: int index = findLocalPGIndex(prop.getPrimaryClass());
534:
535: if (index >= 0) {
536: otherProperties.set(index, prop);
537: } else {
538: if (otherProperties == null) {
539: otherProperties = new ArrayList(1);
540: }
541: otherProperties.add(prop);
542: }
543: }
544:
545: /** find index of specified PG in the set of additional properties.
546: **/
547: private final synchronized int findLocalPGIndex(
548: Class propertyGroupClass) {
549: if (otherProperties == null) {
550: return -1;
551: } else {
552: // Look through the list for a PG of a matching class. The hard part
553: // of this is that either the prop or any of the elements of the list
554: // may be natural (FooPGImpl), locked, Null, etc. So: our solution is
555: // to compare the "PrimaryClass" of each.
556: ArrayList ps = otherProperties;
557: int l = ps.size();
558:
559: for (int i = 0; i < l; i++) {
560: Object o = ps.get(i);
561: Class ok = null;
562:
563: if (o instanceof PropertyGroupSchedule) {
564: // Don't bother with PropertyGroupSchedules
565: continue;
566: } else if (o instanceof PropertyGroup) {
567: if (Modifier
568: .isAbstract(o.getClass().getModifiers())) {
569: throw new RuntimeException("properties[" + i
570: + "/" + l + "] is abstract: "
571: + o.getClass() + " asset was " + this );
572: }
573:
574: ok = ((PropertyGroup) o).getPrimaryClass();
575: } else {
576: throw new RuntimeException(
577: "Unable to handle object of Class: "
578: + o.getClass()
579: + " in otherProperties list.");
580: }
581: if (propertyGroupClass.isAssignableFrom(ok)) {
582: return i;
583: }
584: }
585: return -1;
586: }
587: }
588:
589: /** find index of specified PropertyGroupSchedule in the set of additional
590: * properties.
591: **/
592: private final synchronized int findLocalPGScheduleIndex(
593: Class propertyGroupClass) {
594: if (otherProperties == null) {
595: return -1;
596: } else {
597: // Look through the list for a PG of a matching class. The hard part
598: // of this is that either the prop or any of the elements of the list
599: // may be natural (FooPGImpl), locked, Null, etc. So: our solution is
600: // to compare the "PrimaryClass" of each.
601: ArrayList ps = otherProperties;
602: int l = ps.size();
603:
604: for (int i = 0; i < l; i++) {
605: Object o = ps.get(i);
606: Class ok = null;
607:
608: if (o instanceof PropertyGroup) {
609: // Don't bother with PropertyGroups
610: continue;
611: } else if (o instanceof PropertyGroup) {
612: ok = ((PropertyGroupSchedule) o).getPGClass();
613: } else {
614: throw new RuntimeException(
615: "Unable to handle object of Class: "
616: + o.getClass()
617: + " in otherProperties list.");
618: }
619: if (propertyGroupClass.equals(ok)) {
620: return i;
621: }
622: }
623: return -1;
624: }
625: }
626: }
|