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.planning.ldm.plan;
028:
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.ConcurrentModificationException;
032: import java.util.Date;
033: import java.util.Enumeration;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.ListIterator;
037: import java.util.NoSuchElementException;
038: import java.util.Vector;
039:
040: import org.cougaar.util.Collectors;
041: import org.cougaar.util.Enumerator;
042: import org.cougaar.util.Filters;
043: import org.cougaar.util.SynchronizedTimeSpanSet;
044: import org.cougaar.util.Thunk;
045: import org.cougaar.util.TimeSpan;
046: import org.cougaar.util.UnaryPredicate;
047:
048: /**
049: * A Schedule is an encapsulation of spatio-temporal relationships.
050: * It has a collection of ScheduleElements.
051: */
052:
053: public class ScheduleImpl extends SynchronizedTimeSpanSet implements
054: Schedule, NewSchedule {
055: protected String scheduleType = ScheduleType.OTHER;
056: protected Class scheduleElementType = ScheduleElement.class;
057:
058: /** Construct an empty schedule **/
059: public ScheduleImpl() {
060: // default scheduleType to Other since quantity and quantityrange schedule
061: // elements are probably the only schedules using meaningful scheuduletypes
062: // for 1999
063: scheduleType = ScheduleType.OTHER;
064: }
065:
066: /** Construct a schedule which has the same elements as the specified
067: * collection. If the specified collection needs to be sorted, it will
068: * be.
069: **/
070: public ScheduleImpl(Collection c) {
071: super (c.size());
072:
073: if (c instanceof Schedule) {
074: Schedule s = (Schedule) c;
075: scheduleType = s.getScheduleType();
076: scheduleElementType = s.getScheduleElementType();
077: unsafeUpdate(c);
078: } else {
079: scheduleType = ScheduleType.OTHER;
080: scheduleElementType = ScheduleElementType.MIXED;
081: addAll(c);
082: }
083:
084: }
085:
086: public String getScheduleType() {
087: return scheduleType;
088: }
089:
090: public Class getScheduleElementType() {
091: return scheduleElementType;
092: }
093:
094: public synchronized Date getStartDate() {
095: TimeSpan ts = (TimeSpan) first();
096: if (ts == null) {
097: throw new IndexOutOfBoundsException(
098: "Called getStartDate on an empty schedule");
099: }
100: return new Date(ts.getStartTime());
101: }
102:
103: public synchronized long getStartTime() {
104: TimeSpan ts = (TimeSpan) first();
105: if (ts == null) {
106: throw new IndexOutOfBoundsException(
107: "Called getStartTime on an empty schedule");
108: }
109: return ts.getStartTime();
110: }
111:
112: public synchronized Date getEndDate() {
113: if (isEmpty()) {
114: throw new IndexOutOfBoundsException(
115: "Called getEndDate on an empty schedule");
116: }
117: return new Date(getEndTime());
118: }
119:
120: public synchronized long getEndTime() {
121: if (isEmpty()) {
122: throw new IndexOutOfBoundsException(
123: "Called getEndTime on an empty schedule");
124: }
125: long max = MIN_VALUE;
126: for (int i = 0; i < size; i++) {
127: ScheduleElement se = (ScheduleElement) elementData[i];
128: long end = se.getEndTime();
129: if (end > max)
130: max = end;
131: }
132: return max;
133: }
134:
135: /** get an enumeration over a copy of all of the schedule elements of this
136: * schedule.
137: * Note that this is a copy, changes to the underlying schedule will not be
138: * reflected in the Enumeration.
139: * @return Enumeration{ScheduleElement}
140: */
141: public synchronized Enumeration getAllScheduleElements() {
142: ArrayList copy = new ArrayList(this );
143: return new Enumerator(copy);
144: }
145:
146: public synchronized Collection filter(UnaryPredicate predicate) {
147: return Filters.filter(this , predicate);
148: }
149:
150: /** get a colleciton of schedule elements that include this date.
151: * Note that the schedule element can have a start or end date
152: * that equals the given date or the date may fall in the time span
153: * of a schedule element.
154: * @return OrderedSet
155: */
156: public synchronized Collection getScheduleElementsWithDate(
157: Date aDate) {
158: return getScheduleElementsWithTime(aDate.getTime());
159: }
160:
161: public synchronized Collection getScheduleElementsWithTime(
162: final long aTime) {
163: return intersectingSet(aTime);
164: }
165:
166: public synchronized void applyThunkToScheduleElements(Thunk t) {
167: Collectors.apply(t, this );
168: }
169:
170: /** get a sorted Collection of schedule elements that have dates in the
171: * given range of dates. Note that these schedule elements may
172: * or may not be fully bound by the date range - they may overlap.
173: * @return OrderedSet
174: */
175: public synchronized Collection getOverlappingScheduleElements(
176: Date startDate, Date endDate) {
177: return getOverlappingScheduleElements(startDate.getTime(),
178: endDate.getTime());
179: }
180:
181: public synchronized Collection getOverlappingScheduleElements(
182: final long startTime, final long endTime) {
183: return intersectingSet(startTime, endTime);
184: }
185:
186: /** get a Collection of schedule elements that are fully bound
187: * or encapsulated by a date range.
188: * @return OrderedSet
189: */
190: public synchronized Collection getEncapsulatedScheduleElements(
191: Date startDate, Date endDate) {
192: return getEncapsulatedScheduleElements(startDate.getTime(),
193: endDate.getTime());
194: }
195:
196: public synchronized Collection getEncapsulatedScheduleElements(
197: final long startTime, final long endTime) {
198: return encapsulatedSet(startTime, endTime);
199: }
200:
201: /** add a single schedule element to the already existing Schedule.
202: * @param aScheduleElement
203: */
204: public synchronized void addScheduleElement(
205: ScheduleElement aScheduleElement) {
206: add(aScheduleElement);
207: }
208:
209: public synchronized void removeScheduleElement(
210: ScheduleElement aScheduleElement) {
211: remove(aScheduleElement);
212: }
213:
214: public synchronized void clearScheduleElements() {
215: clear();
216: }
217:
218: /** set a single schedule element - used for a simple schedule
219: * container will be cleared before it is added to ensure that
220: * there is only one schedule element.
221: * @param aScheduleElement
222: **/
223: public synchronized void setScheduleElement(
224: ScheduleElement aScheduleElement) {
225: clear();
226: add(aScheduleElement);
227: }
228:
229: /** Return the Collection.
230: * This is now a noop.
231: **/
232: public Collection UnderlyingContainer() {
233: return this ;
234: }
235:
236: public boolean isAppropriateScheduleElement(Object o) {
237: return (scheduleElementType.isAssignableFrom(o.getClass()));
238: }
239:
240: /** Set the schedule elements for this schedule.
241: * Note this method assumes that you are adding things to
242: * an empty container, hence it clears the container of old
243: * schedule elements before setting the new ones.
244: */
245: public synchronized void setScheduleElements(Collection collection) {
246: clear();
247: if (collection == null)
248: return; // setting it to null clears it
249:
250: addAll(collection);
251: }
252:
253: // Over write ArrayList methods
254:
255: /** add object to Schedule. Verifies that object matches specifed
256: * ScheduleElement type.
257: * @param o Object to add to Schedule
258: * @return boolean true if successful, else false
259: */
260: public synchronized boolean add(Object o) {
261: if (!isAppropriateScheduleElement(o)) {
262: ClassCastException cce = new ClassCastException(
263: "ScheduleImpl.add(Object o): o - "
264: + o
265: + " does not match schedule element type - "
266: + getScheduleElementType());
267: cce.printStackTrace();
268: return false;
269: }
270:
271: return super .add(o);
272: }
273:
274: /** returns Iterator over a copy of the Schedule. Prints a warning and
275: * dumps a stack trace.
276: * Use filter() to get an copy which can be iterated over without
277: * the warning.
278: * @return Iterator over a copy
279: * @deprecated Get a copy of the Schedule before iterating
280: */
281: public synchronized Iterator iterator() {
282: Throwable throwable = new Throwable(
283: "Returning an iterator over a copy of this Schedule."
284: + " Stack trace is included so that calling code can be modified");
285: throwable.printStackTrace();
286:
287: ArrayList copy = new ArrayList(this );
288: return copy.iterator();
289: }
290:
291: /** listIterator - Returns an iterator of the elements in this list
292: * (in proper sequence).
293: * Iterator does not support add(Object o)/set(Object o)
294: * @return ListIterator
295: */
296: public synchronized ListIterator listIterator() {
297: return listIterator(0);
298: }
299:
300: /** listIterator - Returns a list iterator of the elements in this list (in
301: * proper sequence), starting at the specified position in the list.
302: * Iterator does not support add(Object o)/set(Object o)
303: * @return ListIterator
304: */
305: public ListIterator listIterator(final int index) {
306: if (index < 0 || index > size)
307: throw new IndexOutOfBoundsException("Index: " + index
308: + ", Size: " + size);
309:
310: // System.out.println("ScheduleImpl.ListIterator()");
311: return new ListItr(index);
312: }
313:
314: /** returns a subset from a copy of the Schedule. Prints a warning and
315: * dumps a stack trace. Subset made from a copy of the Schedule so that
316: * the Schedule continues to Synchronization safe.
317: * Use filter() to get an copy which can be iterated over without
318: * the warning.
319: * @return Iterator over a copy
320: * @deprecated Get a copy of the Schedule before calling subList
321: */
322: public synchronized List subList(int fromIndex, int toIndex) {
323: Throwable throwable = new Throwable(
324: "Returning an subList over a copy of this Schedule."
325: + " Stack trace is included so that calling code can be modified");
326: throwable.printStackTrace();
327:
328: ArrayList copy = new ArrayList(this );
329: return copy.subList(fromIndex, toIndex);
330: }
331:
332: public synchronized void setScheduleElements(
333: Enumeration someScheduleElements) {
334: //clear the container
335: clear();
336: //unpack the enumeration
337: while (someScheduleElements.hasMoreElements()) {
338: Object o = someScheduleElements.nextElement();
339: if (o instanceof ScheduleElement) {
340: add((ScheduleElement) o);
341: } else {
342: throw new IllegalArgumentException(
343: "Schedule elements must be instanceof ScheduleElement");
344: }
345: }
346: }
347:
348: /* setScheduleType - type can only be set for empty schedule.
349: */
350: public synchronized void setScheduleType(String type) {
351: if (!isEmpty()) {
352: throw new ClassCastException(
353: "Can not set ScheduleType for non-empty schedule");
354: }
355: scheduleType = type;
356: }
357:
358: public synchronized void setScheduleElementType(Class setype) {
359: if (!ScheduleElement.class.isAssignableFrom(setype)) {
360: throw new ClassCastException(setype
361: + " is not a ScheduleElement");
362: } else if (!isEmpty()
363: && !setype.isAssignableFrom(scheduleElementType)) {
364: throw new ClassCastException(
365: setype
366: + " is not assignable from current ScheduleElement type "
367: + scheduleElementType);
368: }
369: scheduleElementType = setype;
370: }
371:
372: protected static final String EOL = System
373: .getProperty("line.separator");
374:
375: public String toString() {
376: String tstring = "?";
377: String setstring = "?";
378: if (scheduleType != null)
379: tstring = scheduleType;
380: if (scheduleElementType != null)
381: setstring = scheduleElementType.toString();
382: return EOL + "<Schedule " + tstring + "/" + setstring + " "
383: + super .toString() + ">";
384: }
385:
386: /* methods returned by ScheduleImplBeanInfo */
387:
388: public synchronized Date getStartDate_quiet() {
389: return (isEmpty() ? (new Date(-1)) : getStartDate());
390: }
391:
392: public synchronized Date getEndDate_quiet() {
393: return (isEmpty() ? (new Date(-1)) : getEndDate());
394: }
395:
396: public synchronized ScheduleElement[] getScheduleElements() {
397: ScheduleElement s[] = new ScheduleElement[size()];
398: return (ScheduleElement[]) toArray(s);
399: }
400:
401: public synchronized ScheduleElement getScheduleElement(int i) {
402: return (ScheduleElement) elementData[i];
403: }
404:
405: // Offered as an aid to extenders who want to get their hands on an
406: // iterator.
407: protected Iterator protectedIterator() {
408: return super .iterator();
409: }
410:
411: // Accessor for AbstractList.modCount - used by ListItr class
412: protected int getModCount() {
413: return modCount;
414: }
415:
416: // ScheduleImpl specific. Code from java.util.AbstractList but
417: // does not support add/set - don't want to mess up the sort order.
418: private class ListItr implements ListIterator {
419:
420: /**
421: * Index of element to be returned by subsequent call to next.
422: */
423: int cursor = 0;
424:
425: /**
426: * Index of element returned by most recent call to next or
427: * previous. Reset to -1 if this element is deleted by a call
428: * to remove.
429: */
430: int lastRet = -1;
431:
432: /**
433: * The modCount value that the iterator believes that the backing
434: * List should have. If this expectation is violated, the iterator
435: * has detected concurrent modification.
436: */
437: int expectedModCount = getModCount();
438:
439: ListItr(int index) {
440: cursor = index;
441: }
442:
443: public void set(Object o) {
444: throw new UnsupportedOperationException(
445: "ScheduleImpl.ListIterator.set(Object o) is not supported.");
446: }
447:
448: public void add(Object o) {
449: throw new UnsupportedOperationException(
450: "ScheduleImpl.ListIterator.add(Object o) is not supported.");
451: }
452:
453: public boolean hasNext() {
454: return cursor != size();
455: }
456:
457: public Object next() {
458: try {
459: Object next = get(cursor);
460: checkForComodification();
461: lastRet = cursor++;
462: return next;
463: } catch (IndexOutOfBoundsException e) {
464: checkForComodification();
465: throw new NoSuchElementException();
466: }
467: }
468:
469: public boolean hasPrevious() {
470: return cursor != 0;
471: }
472:
473: public Object previous() {
474: try {
475: Object previous = get(--cursor);
476: checkForComodification();
477: lastRet = cursor;
478: return previous;
479: } catch (IndexOutOfBoundsException e) {
480: checkForComodification();
481: throw new NoSuchElementException();
482: }
483: }
484:
485: public int nextIndex() {
486: return cursor;
487: }
488:
489: public int previousIndex() {
490: return cursor - 1;
491: }
492:
493: public void remove() {
494: if (lastRet == -1)
495: throw new IllegalStateException();
496:
497: try {
498: ScheduleImpl.this .remove(lastRet);
499: if (lastRet < cursor)
500: cursor--;
501: lastRet = -1;
502:
503: int newModCount = getModCount();
504: if (newModCount - expectedModCount > 1)
505: throw new ConcurrentModificationException();
506: expectedModCount = newModCount;
507: } catch (IndexOutOfBoundsException e) {
508: throw new ConcurrentModificationException();
509: }
510: }
511:
512: final void checkForComodification() {
513: if (getModCount() != expectedModCount)
514: throw new ConcurrentModificationException();
515: }
516:
517: }
518:
519: private static class TestScheduleElementImpl extends
520: LocationScheduleElementImpl implements
521: ScheduleElementWithValue {
522:
523: private double myValue;
524:
525: public TestScheduleElementImpl(double value) {
526: super ();
527: myValue = value;
528: }
529:
530: public double getValue() {
531: return myValue;
532: }
533:
534: public ScheduleElementWithValue newElement(long start,
535: long end, double value) {
536: TestScheduleElementImpl newElement = new TestScheduleElementImpl(
537: value);
538: newElement.stime = start;
539: newElement.etime = end;
540: return newElement;
541: }
542:
543: public String toString() {
544: return "<value:" + myValue + " " + stime + "-" + etime
545: + ">";
546: }
547: }
548:
549: public static void main(String[] args) {
550: Vector vector = new Vector();
551:
552: TestScheduleElementImpl lsei = new TestScheduleElementImpl(2.0);
553: lsei.setEndTime(10);
554: vector.add(lsei);
555:
556: lsei = new TestScheduleElementImpl(3.0);
557: lsei.setEndTime(100000);
558: vector.add(lsei);
559:
560: ScheduleImpl lsSchedule = new ScheduleImpl();
561: lsei = new TestScheduleElementImpl(4.0);
562: lsei.setEndTime(200);
563: lsei.setStartTime(5);
564: lsSchedule.add(lsei);
565:
566: ScheduleImpl schedule1 = new ScheduleImpl(vector);
567: System.out.println("Schedule1: " + schedule1);
568:
569: ScheduleImpl schedule2 = new ScheduleImpl(lsSchedule);
570: System.out.println("Schedule2: " + schedule2);
571:
572: schedule2.addAll(schedule1);
573: System.out.println("Schedule2 after adding Schedule1: "
574: + schedule2);
575:
576: ScheduleImpl schedule3 = (ScheduleImpl) ScheduleUtilities
577: .subtractSchedules(schedule2, schedule2);
578: System.out.println("Schedule3 (Schedule2 - Schedule2): "
579: + schedule3);
580:
581: schedule2.setScheduleElements(vector);
582: schedule2.addAll(1, vector);
583: }
584: }
|