001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2007 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.blackboard;
028:
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.Enumeration;
032: import java.util.Iterator;
033: import java.util.List;
034:
035: /**
036: * A container for blackboard add/change/remove {@link
037: * EnvelopeTuple}s of a single transaction.
038: * <p>
039: * An envelope is not synchronized; it is privately held by a
040: * subscriber and passes through the distributor in a thread-safe
041: * manner.
042: * <p>
043: * Several types of transaction operations are supported:
044: * <pre>
045: * ADD add an object to the set.
046: * REMOVE remove an object from the set.
047: * CHANGE mark the object as changed in the set.
048: * BULK like ADD of a set of Objects, with the
049: * slightly different functional semantics.
050: * In particular, since these are only emitted
051: * Blackboard on initialization of subscriptions,
052: * and by PersistenceSubscribers on Blackboard
053: * rehydration, LogicProviders function differently
054: * on BULKs than ADDs, for instance, business rules
055: * which fire on new Blackboard elements and produce
056: * other Blackboard elements will not fire on BULKs
057: * because the BULK delta should already include
058: * *those* products.
059: * </pre>
060: */
061: public class Envelope implements java.io.Serializable {
062:
063: /** a set of changes to make to a subscriber's data structures */
064: private final List deltas = new ArrayList(5);
065:
066: /**
067: * direct access to the internal structure to allow for more efficient
068: * traversal of deltas.
069: */
070: final List getRawDeltas() {
071: return deltas;
072: }
073:
074: public static final int ADD = 0;
075: public static final int REMOVE = 1;
076: public static final int CHANGE = 2;
077: /**
078: * BULK is a bulk add - then Object is a Container of objects
079: * Additionally, BULK tuples are generally handled differently than
080: * ADDs by LogicProviders (See documentation on individual LPs to see
081: * how they process BULK transactions.
082: */
083: public static final int BULK = 3;
084:
085: public static final int EVENT = 4;
086:
087: public Envelope() {
088: }
089:
090: /** Create a copy with no deltas */
091: public Envelope newInstance() {
092: return new Envelope();
093: }
094:
095: public final EnvelopeTuple addObject(Object o) {
096: if (o == null)
097: throw new IllegalArgumentException("Null Object");
098: EnvelopeTuple t = newAddEnvelopeTuple(o);
099: deltas.add(t);
100: return t;
101: }
102:
103: public final EnvelopeTuple changeObject(Object o, List changes) {
104: if (o == null)
105: throw new IllegalArgumentException("Null Object");
106: EnvelopeTuple t = newChangeEnvelopeTuple(o, changes);
107: deltas.add(t);
108: return t;
109: }
110:
111: public final EnvelopeTuple removeObject(Object o) {
112: if (o == null)
113: throw new IllegalArgumentException("Null Object");
114: EnvelopeTuple t = newRemoveEnvelopeTuple(o);
115: deltas.add(t);
116: return t;
117: }
118:
119: // only allow package-local subclass overrides for these:
120: AddEnvelopeTuple newAddEnvelopeTuple(Object o) {
121: return new AddEnvelopeTuple(o);
122: }
123:
124: ChangeEnvelopeTuple newChangeEnvelopeTuple(Object o, List changes) {
125: return new ChangeEnvelopeTuple(o, changes);
126: }
127:
128: RemoveEnvelopeTuple newRemoveEnvelopeTuple(Object o) {
129: return new RemoveEnvelopeTuple(o);
130: }
131:
132: public final void addTuple(EnvelopeTuple t) {
133: deltas.add(t);
134: }
135:
136: /** how many elements are in the Envelope?*/
137: public final int size() {
138: return deltas.size();
139: }
140:
141: public final Iterator getAllTuples() {
142: return deltas.iterator();
143: }
144:
145: /**
146: * Equivalent to adding a homogeneous Collection of objects
147: * as separate adds. Distributor-level predicate tests will
148: * assume that all objects in the Collection apply to the same
149: * degree to a given predicate instance.
150: * The container must be be immutable, as there is no guarantee
151: * that it will be unpacked at any specific time. If this is
152: * a problem, the Enumeration form should be used.
153: */
154: public final EnvelopeTuple bulkAddObject(Collection c) {
155: if (c == null)
156: throw new IllegalArgumentException("Null Collection");
157: EnvelopeTuple t = new BulkEnvelopeTuple(c);
158: deltas.add(t);
159: return t;
160: }
161:
162: /**
163: * Safer form of bulkAddObject does the equivalent
164: * of calling bulkAddObject on a container
165: * constructed by iterating over the elements of
166: * the Enumeration argument.
167: */
168: public final EnvelopeTuple bulkAddObject(Enumeration en) {
169: List v = new ArrayList();
170: while (en.hasMoreElements()) {
171: v.add(en.nextElement());
172: }
173:
174: EnvelopeTuple t = new BulkEnvelopeTuple(v);
175: deltas.add(t);
176: return t;
177: }
178:
179: /**
180: * Safer form of bulkAddObject does the equivalent
181: * of calling bulkAddObject on a container
182: * constructed by iterating over the elements of
183: * the argument.
184: */
185: public final EnvelopeTuple bulkAddObject(Iterator i) {
186: List v = new ArrayList();
187: while (i.hasNext()) {
188: v.add(i.next());
189: }
190:
191: EnvelopeTuple t = new BulkEnvelopeTuple(v);
192: deltas.add(t);
193: return t;
194: }
195:
196: /**
197: * Boolean used to decide on visibility of subscription modifications
198: * in applyToSubscription. Overridden by PersistenceEnvelope.
199: */
200: protected boolean isVisible() {
201: return true;
202: }
203:
204: /**
205: * Apply all object deltas in this envelope to the subscription.
206: */
207: public final boolean applyToSubscription(Subscription subscription) {
208: boolean vp = isVisible(); // in case we've got *lots* of tuples.
209: boolean somethingFired = false;
210: // we use the List directly instead of getAllTuples to avoid iterator overhead.
211: int l = deltas.size();
212: for (int i = 0; i < l; i++) {
213: EnvelopeTuple tuple = (EnvelopeTuple) deltas.get(i);
214: somethingFired |= tuple.applyToSubscription(subscription,
215: vp);
216: }
217: return vp && somethingFired;
218: }
219:
220: public String toString() {
221: return getClass().getName() + " [" + deltas.size() + "]";
222: }
223: }
|