001: /*
002: * <copyright>
003: *
004: * Copyright 2002-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.servicediscovery.transaction;
028:
029: import java.util.Collection;
030: import java.util.Collections;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.Set;
034: import java.io.Serializable;
035: import java.io.IOException;
036: import java.io.ObjectInputStream;
037: import java.io.ObjectOutputStream;
038:
039: import org.cougaar.core.mts.MessageAddress;
040: import org.cougaar.core.relay.Relay;
041: import org.cougaar.core.util.UID;
042: import org.cougaar.core.util.UniqueObject;
043:
044: /**
045: * Implementation of RelayAdapter.
046: * Declared abstract because it does not include the ability to convey content.
047: * Extenders are responsible for defining content semantics.
048: **/
049: abstract public class RelayAdapter implements Relay.Source,
050: Relay.Target, UniqueObject, Cloneable {
051:
052: // this is the target set which is synchronized using
053: // a copy-on-write pattern.
054: private final Object lock = new Serializable() {
055: };
056: protected transient Set myTargetSet = null;
057:
058: protected UID myUID = null;
059: protected MessageAddress mySource = null;
060:
061: /**
062: * Add a target message address.
063: * @param target the address of the target agent.
064: **/
065: public void addTarget(MessageAddress target) {
066: synchronized (lock) {
067: if (myTargetSet == null) {
068: myTargetSet = new HashSet();
069: }
070: myTargetSet.add(target);
071: }
072: }
073:
074: /**
075: * Add a collection of target message addresses.
076: * @param targets Collection of target agent addresses.
077: **/
078: public void addAllTargets(Collection targets) {
079: synchronized (lock) {
080: for (Iterator iterator = targets.iterator(); iterator
081: .hasNext();) {
082: Object target = iterator.next();
083: if (target instanceof MessageAddress) {
084: addTarget((MessageAddress) target);
085: } else {
086: throw new IllegalArgumentException(
087: "Invalid target class: "
088: + target.getClass()
089: + " all targets must extend MessageAddress.");
090: }
091: }
092: }
093: }
094:
095: /**
096: * Remove a target message address.
097: * @param target the address of the target agent to be removed.
098: **/
099: public void removeTarget(MessageAddress target) {
100: synchronized (lock) {
101: if (myTargetSet != null) {
102: myTargetSet.remove(target);
103: }
104: }
105: }
106:
107: public void clearTargets() {
108: synchronized (lock) {
109: myTargetSet = null;
110: }
111: }
112:
113: // UniqueObject interface
114: /** @return the UID of a UniqueObject. If the object was created
115: * correctly (e.g. via a Factory), will be non-null.
116: **/
117: public UID getUID() {
118: return myUID;
119: }
120:
121: /** set the UID of a UniqueObject. This should only be done by
122: * an LDM factory. Will throw a RuntimeException if
123: * the UID was already set.
124: **/
125: public void setUID(UID uid) {
126: if (myUID != null) {
127: RuntimeException rt = new RuntimeException(
128: "Attempt to call setUID() more than once.");
129: throw rt;
130: }
131:
132: myUID = uid;
133: }
134:
135: // Relay.Source interface
136:
137: /**
138: * @return MessageAddress of the source
139: */
140: public MessageAddress getSource() {
141: return mySource;
142: }
143:
144: /** set the MessageAddress of the source. This should only be done by
145: * an LDM factory. Will throw a RuntimeException if
146: * the source was already set.
147: **/
148: public void setSource(MessageAddress source) {
149: if (mySource != null) {
150: RuntimeException rt = new RuntimeException(
151: "Attempt to call setSource() more than once.");
152: throw rt;
153: }
154: mySource = source;
155: }
156:
157: /**
158: * Get all the addresses of the target agents to which this Relay
159: * should be sent.
160: **/
161: public Set getTargets() {
162: synchronized (lock) {
163: Set targets = (myTargetSet == null) ? Collections.EMPTY_SET
164: : Collections.unmodifiableSet(myTargetSet);
165: return targets;
166: }
167: }
168:
169: /**
170: * Set the addresses of the target agents to which this Relay
171: * should be sent.
172: **/
173: public void setTargets(Set targets) {
174: addAllTargets(targets);
175: }
176:
177: /**
178: * Get an object representing the value of this Relay suitable
179: * for transmission. This implementation uses itself to represent
180: * its Content.
181: **/
182: public Object getContent() {
183: return this ;
184: }
185:
186: protected boolean contentChanged(RelayAdapter newCCN) {
187: return true;
188: //return getContent().equals(newCCN.getContent());
189: }
190:
191: private static final class SimpleRelayFactory implements
192: TargetFactory, java.io.Serializable {
193:
194: public static final SimpleRelayFactory INSTANCE = new SimpleRelayFactory();
195:
196: private SimpleRelayFactory() {
197: }
198:
199: /**
200: * Convert the given content and related information into a Target
201: * that will be published on the target's blackboard.
202: **/
203: public Relay.Target create(UID uid, MessageAddress source,
204: Object content, Token token) {
205: RelayAdapter target = null;
206:
207: if (content instanceof RelayAdapter) {
208: RelayAdapter relayAdapter = (RelayAdapter) content;
209:
210: if (relayAdapter.myTargetSet != null) {
211: // intra-vm case so must clone
212: try {
213: target = (RelayAdapter) ((RelayAdapter) content)
214: .clone();
215:
216: // Relay.Target's should not have targets. Causes infinite loops
217: if (target != null) {
218: target.clearTargets();
219: }
220:
221: } catch (CloneNotSupportedException cnse) {
222: throw new IllegalArgumentException(
223: "content argument: " + content
224: + " does not support clone.");
225: }
226: } else {
227: target = relayAdapter;
228: }
229:
230: } else {
231: throw new IllegalArgumentException(
232: "content argument must extend RelayAdapter.");
233: }
234:
235: // Use arguments to customize the target.
236: if (!uid.equals(target.getUID())) {
237: throw new IllegalArgumentException(
238: "uid argument does not match source's UID.");
239: }
240: target.setSource(source);
241:
242: return target;
243: }
244:
245: private Object readResolve() {
246: return INSTANCE;
247: }
248: };
249:
250: /**
251: * Get a factory for creating the target.
252: */
253: public TargetFactory getTargetFactory() {
254: return SimpleRelayFactory.INSTANCE;
255: }
256:
257: /**
258: * Set the response that was sent from a target. For LP use only.
259: * Assume that all changes are meaningful.
260: **/
261: public int updateResponse(MessageAddress target, Object response) {
262: return Relay.RESPONSE_CHANGE;
263: }
264:
265: /**
266: * Get the current Response for this target. Null indicates that
267: * this target has no response.
268: */
269: public Object getResponse() {
270: return null;
271: }
272:
273: /**
274: * Update the target with the new content.
275: * @return true if the update changed the Relay, in which
276: * case the infrastructure should "publishChange" this
277: */
278: public int updateContent(Object content, Token token) {
279: return (contentChanged((RelayAdapter) content) ? Relay.CONTENT_CHANGE
280: : Relay.NO_CHANGE);
281: }
282:
283: protected Object clone() throws CloneNotSupportedException {
284: RelayAdapter clone;
285:
286: clone = (RelayAdapter) super .clone();
287:
288: // Make sure we have a distinct target hash set
289: clone.clearTargets();
290: if (getTargets().size() > 0) {
291: clone.addAllTargets(getTargets());
292: }
293: return clone;
294: }
295:
296: private void writeObject(ObjectOutputStream stream)
297: throws IOException {
298: stream.defaultWriteObject();
299: synchronized (lock) {
300: stream.writeObject(myTargetSet);
301: }
302: }
303:
304: private void readObject(ObjectInputStream stream)
305: throws ClassNotFoundException, IOException {
306: stream.defaultReadObject();
307: myTargetSet = (Set) stream.readObject();
308: }
309: }
|