001: /*
002: *
003: * Copyright 2007 by BBN Technologies Corporation
004: *
005: */
006:
007: package org.cougaar.core.plugin;
008:
009: import java.util.ArrayList;
010: import java.util.Collection;
011: import java.util.List;
012:
013: import org.cougaar.core.agent.service.alarm.Alarm;
014: import org.cougaar.core.agent.service.alarm.AlarmBase;
015: import org.cougaar.core.blackboard.TodoSubscription;
016: import org.cougaar.core.util.UniqueObject;
017:
018: /**
019: * Adds a {@link TodoSubscription} to an AnnotatedSubscriptionsPlugin. The items
020: * on this subscription should be considered as work to do, in the form of a
021: * Runnable, rather than as data. Work can be added with one of the executeLater
022: * methods, which are modeled after Swing's invokeLater.
023: *
024: * For convenience there are also predefined methods for adding work that just
025: * does a single publishAdd/Remove/Change of some {@link UniqueObject}.
026: */
027: public class TodoPlugin extends AnnotatedSubscriptionsPlugin {
028: private TodoSubscription todo;
029:
030: // Hackery to deal with work being added before the the
031: // subscription is operational.
032: private final Object pendingLock = new Object();
033: private List<Runnable> pendingWork = new ArrayList<Runnable>();
034:
035: /**
036: * Add some work to the TodoSubscription. The actual running happens in the
037: * execute thread.
038: *
039: * @param work
040: * The work to be performed in the execute thread
041: */
042: public void executeLater(Runnable work) {
043: synchronized (pendingLock) {
044: if (pendingWork != null) {
045: pendingWork.add(work);
046: return;
047: }
048: todo.add(work);
049: }
050: }
051:
052: /**
053: * Add some work to the TodoSubscription after a delay. The actual running
054: * happens in the execute thread.
055: *
056: * @param delayMillis
057: * How long to delay. If <= 0, the add happens immediately.
058: * @param work
059: * The work to be performed in the execute thread
060: *
061: * @return the Alarm used for the delay, or null if no delay. The Alarm can be
062: * cancelled by the caller to prevent the work from happening.
063: */
064: public Alarm executeLater(long delayMillis, Runnable work) {
065: if (delayMillis <= 0) {
066: executeLater(work);
067: return null;
068: } else {
069: Alarm alarm = new TodoAlarm(System.currentTimeMillis()
070: + delayMillis, work);
071: getAlarmService().addRealTimeAlarm(alarm);
072: return alarm;
073: }
074: }
075:
076: protected void execute() {
077: super .execute();
078: if (todo.hasChanged()) {
079: @SuppressWarnings("unchecked")
080: Collection<Runnable> items = todo.getAddedCollection();
081: for (Runnable item : items) {
082: item.run();
083: }
084: }
085: }
086:
087: protected void setupSubscriptions() {
088: super .setupSubscriptions();
089: todo = new TodoSubscription("me");
090: blackboard.subscribe(todo);
091:
092: // Add early work, if any
093: synchronized (pendingLock) {
094: todo.addAll(pendingWork);
095: // now disable pending work
096: pendingWork = null;
097: }
098: }
099:
100: // Convenience methods for simple work that does a single
101: // publishAdd/Remove/Change, with or without a delay (and
102: // in the case of Change, with or without change reports).
103:
104: protected void publishAddLater(UniqueObject object) {
105: publishAddLater(0, object);
106: }
107:
108: protected Alarm publishAddLater(long delay,
109: final UniqueObject object) {
110: return executeLater(delay, new Runnable() {
111: public void run() {
112: blackboard.publishAdd(object);
113: }
114: });
115: }
116:
117: protected void publishRemoveLater(UniqueObject object) {
118: publishRemoveLater(0, object);
119: }
120:
121: protected Alarm publishRemoveLater(long delay,
122: final UniqueObject object) {
123: return executeLater(delay, new Runnable() {
124: public void run() {
125: blackboard.publishRemove(object);
126: }
127: });
128: }
129:
130: protected void publishChangeLater(UniqueObject object) {
131: publishChangeLater(0, object);
132: }
133:
134: protected Alarm publishChangeLater(long delay,
135: final UniqueObject object) {
136: return executeLater(delay, new Runnable() {
137: public void run() {
138: blackboard.publishChange(object);
139: }
140: });
141: }
142:
143: protected void publishChangeLater(UniqueObject object,
144: Collection<?> changeReports) {
145: publishChangeLater(0, object, changeReports);
146: }
147:
148: protected Alarm publishChangeLater(long delay,
149: final UniqueObject object, final Collection<?> changeReports) {
150: return executeLater(delay, new Runnable() {
151: public void run() {
152: blackboard.publishChange(object, changeReports);
153: }
154: });
155: }
156:
157: private final class TodoAlarm extends AlarmBase {
158: private final Runnable item;
159:
160: public TodoAlarm(long futureTime, Runnable item) {
161: super (futureTime);
162: this .item = item;
163: }
164:
165: public void onExpire() {
166: todo.add(item);
167: }
168: }
169: }
|