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.core.mts;
028:
029: import java.io.ObjectInputStream;
030: import java.io.Serializable;
031: import java.util.ArrayList;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.Map;
035:
036: /**
037: * A standard implementation of {@link Attributes}, not just
038: * {@link MessageAttributes}.
039: */
040: public class SimpleMessageAttributes implements MessageAttributes,
041: AgentState, Serializable {
042: private HashMap data;
043: private transient HashMap local_data;
044:
045: public SimpleMessageAttributes() {
046: data = new HashMap();
047: local_data = new HashMap();
048: }
049:
050: private void dumpMap(StringBuffer buf, HashMap map) {
051: synchronized (map) {
052: buf.append(map);
053: }
054: }
055:
056: public String getAttributesAsString() {
057: StringBuffer buf = new StringBuffer();
058: buf.append("(attributes=");
059: dumpMap(buf, data);
060: buf.append(", transient_attributes=");
061: dumpMap(buf, local_data);
062: buf.append(")");
063: return buf.toString();
064: }
065:
066: private void readObject(ObjectInputStream ois)
067: throws java.io.IOException, ClassNotFoundException {
068: ois.defaultReadObject();
069: local_data = new HashMap();
070: }
071:
072: // MessageAttributes interface
073:
074: private static void deepCopy(HashMap src, HashMap dst) {
075: // dst.putAll(src); // shallow
076: synchronized (src) {
077: Iterator itr = src.entrySet().iterator();
078: Map.Entry entry = null;
079: Object value = null;
080: while (itr.hasNext()) {
081: entry = (Map.Entry) itr.next();
082: value = entry.getValue();
083: if (value instanceof ArrayList) {
084: value = new ArrayList((ArrayList) value);
085: }
086: dst.put(entry.getKey(), value);
087: }
088: }
089: }
090:
091: public Attributes cloneAttributes() {
092: SimpleMessageAttributes clone = new SimpleMessageAttributes();
093: deepCopy(data, clone.data);
094: deepCopy(local_data, clone.local_data);
095: return clone;
096: }
097:
098: public void clearAttributes() {
099: synchronized (data) {
100: data.clear();
101: }
102: synchronized (local_data) {
103: local_data.clear();
104: }
105: }
106:
107: // The attributes being merged in have precedence during load
108: public void mergeAttributes(Attributes attributes) {
109: if (!(attributes instanceof SimpleMessageAttributes)) {
110: throw new RuntimeException(
111: "SimpleMessageAttributes cannot merge wih "
112: + attributes);
113: }
114:
115: SimpleMessageAttributes attrs = (SimpleMessageAttributes) attributes;
116: merge(data, attrs.data);
117: merge(local_data, attrs.local_data);
118: }
119:
120: private void merge(HashMap current, HashMap merge) {
121: synchronized (current) {
122: synchronized (merge) {
123: Iterator itr = merge.entrySet().iterator();
124: while (itr.hasNext()) {
125: Map.Entry merge_entry = (Map.Entry) itr.next();
126: String key = (String) merge_entry.getKey();
127: Object value = merge_entry.getValue();
128: Object old = current.get(key);
129: if (old == null) {
130: setAttribute(key, value, current);
131: } else if (value instanceof ArrayList
132: && old instanceof ArrayList) {
133: // Both are multi-value -- merge the lists by adding
134: // the values to the end.
135: Iterator i2 = ((ArrayList) value).iterator();
136: while (i2.hasNext())
137: addValue(key, i2.next(), current);
138: } else {
139: // Either one value is multi and one is single or both
140: // are single. Either way, use the new value.
141: setAttribute(key, value, current);
142: }
143: }
144: }
145: }
146: }
147:
148: public Object getAttribute(String attribute) {
149: Object value = getAttribute(attribute, local_data);
150: if (value != null)
151: return value;
152: return getAttribute(attribute, data);
153: }
154:
155: public void setAttribute(String attribute, Object value) {
156: setAttribute(attribute, value, data);
157: }
158:
159: public void removeAttribute(String attribute) {
160: removeAttribute(attribute, data);
161: }
162:
163: public void addValue(String attribute, Object value) {
164: addValue(attribute, value, data);
165: }
166:
167: public void pushValue(String attribute, Object value) {
168: pushValue(attribute, value, data);
169: }
170:
171: public void removeValue(String attribute, Object value) {
172: removeValue(attribute, value, data);
173: }
174:
175: public void setLocalAttribute(String attribute, Object value) {
176: setAttribute(attribute, value, local_data);
177: }
178:
179: public void removeLocalAttribute(String attribute) {
180: removeAttribute(attribute, local_data);
181: }
182:
183: public void addLocalValue(String attribute, Object value) {
184: addValue(attribute, value, local_data);
185: }
186:
187: public void pushLocalValue(String attribute, Object value) {
188: pushValue(attribute, value, local_data);
189: }
190:
191: public void removeLocalValue(String attribute, Object value) {
192: removeValue(attribute, value, local_data);
193: }
194:
195: // Internal functions
196:
197: /**
198: * Returns the current value of the given attribute.
199: */
200: private Object getAttribute(String attribute, HashMap map) {
201: synchronized (map) {
202: return map.get(attribute);
203: }
204: }
205:
206: /**
207: * Modifies or sets the current value of the given attribute to the
208: * given value.
209: */
210: private void setAttribute(String attribute, Object value,
211: HashMap map) {
212: synchronized (map) {
213: map.put(attribute, value);
214: }
215: }
216:
217: /**
218: * Removes the given attribute.
219: */
220: private void removeAttribute(String attribute, HashMap map) {
221: synchronized (map) {
222: map.remove(attribute);
223: }
224: }
225:
226: /**
227: * Add a value to an attribute. If the current raw value of the
228: * attribute is an ArrayList, the new value will be added to it.
229: * If the current raw value is not an ArrayList, a new ArrayList
230: * will be created and the current value (if non-null) as well as
231: * the new value will be added to it.
232: */
233: private void addValue(String attribute, Object value, HashMap map) {
234: synchronized (map) {
235: Object old = map.get(attribute);
236: if (old == null) {
237: ArrayList list = new ArrayList();
238: list.add(value);
239: map.put(attribute, list);
240: } else if (old instanceof ArrayList) {
241: ((ArrayList) old).add(value);
242: } else {
243: ArrayList list = new ArrayList();
244: list.add(old);
245: list.add(value);
246: map.put(attribute, list);
247: }
248: }
249: }
250:
251: /**
252: * Like addValue but add to the front.
253: */
254: private void pushValue(String attribute, Object value, HashMap map) {
255: synchronized (map) {
256: Object old = map.get(attribute);
257: if (old == null) {
258: ArrayList list = new ArrayList();
259: list.add(value);
260: map.put(attribute, list);
261: } else if (old instanceof ArrayList) {
262: ((ArrayList) old).add(0, value);
263: } else {
264: ArrayList list = new ArrayList();
265: list.add(old);
266: list.add(0, value);
267: map.put(attribute, list);
268: }
269: }
270: }
271:
272: /**
273: * Remove a value to an attribute. The current raw value should
274: * either be an ArrayList or a singleton equal to the given value.
275: */
276: private void removeValue(String attribute, Object value, HashMap map) {
277: synchronized (map) {
278: Object old = map.get(attribute);
279: if (old == null) {
280: // Given attribute wasnt on the message. NOOP
281: } else if (old instanceof ArrayList) {
282: ((ArrayList) old).remove(value);
283: } else if (value.equals(old)) {
284: map.remove(attribute);
285: }
286: }
287: }
288: }
|