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.node;
028:
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.Map;
032: import java.util.Set;
033: import java.util.HashSet;
034: import org.cougaar.core.mts.MessageAddress;
035: import org.cougaar.util.log.Logger;
036:
037: /**
038: * The quiescence state of a particular agent
039: */
040: class QuiescenceState {
041: public QuiescenceState(MessageAddress me, Logger logger) {
042: this .me = me;
043: this .logger = logger;
044: }
045:
046: public Map getOutgoingMessageNumbers() {
047: return outgoingMessageNumbers;
048: }
049:
050: public Map getIncomingMessageNumbers() {
051: return incomingMessageNumbers;
052: }
053:
054: public Integer getOutgoingMessageNumber(MessageAddress receiver) {
055: return (Integer) getOutgoingMessageNumbers().get(receiver);
056: }
057:
058: public Integer getIncomingMessageNumber(MessageAddress sender) {
059: return (Integer) getIncomingMessageNumbers().get(sender);
060: }
061:
062: public Set getOutgoingEntrySet() {
063: return getOutgoingMessageNumbers().entrySet();
064: }
065:
066: public Set getIncomingEntrySet() {
067: return getIncomingMessageNumbers().entrySet();
068: }
069:
070: public boolean isEnabled() {
071: return enabled;
072: }
073:
074: public void setEnabled(boolean newEnabled) {
075: enabled = newEnabled;
076: }
077:
078: /**
079: * Is the agent "alive" - as in, not marked as dead cause its a duplicate
080: */
081: public boolean isAlive() {
082: return isAlive;
083: }
084:
085: /**
086: * Called when the agent is dead - another instance of the agent elsewhere
087: * is the real instance, and this one should be ignored. Not un-doable.
088: */
089: public void setDead() {
090: isAlive = false;
091: }
092:
093: public boolean isQuiescent() {
094: return blockers.isEmpty();
095: }
096:
097: public void setQuiescent(boolean isQuiescent, String requestor) {
098: if (isQuiescent) {
099: // Remove this blocker, and log if that fails
100: if (!removeBlocker(requestor) && logger.isDebugEnabled())
101: logger
102: .debug("Requestor "
103: + requestor
104: + " tried to say was quiescent, but was not on blockers list.");
105: if (logger.isDetailEnabled()) {
106: logger.detail("nonQuiescentCount is " + blockers.size()
107: + " for " + (enabled ? "" : "disabled ")
108: + (isAlive ? "" : "dead ") + me);
109: if (!blockers.isEmpty())
110: logger.detail(me + " Blockers: "
111: + getBlockersString());
112: } else if (blockers.isEmpty() && logger.isDebugEnabled()) {
113: logger.debug(me + " is quiescent");
114: }
115: } else {
116: // Add this blocker, and log if that fails
117: if (!addBlocker(requestor) && logger.isDebugEnabled())
118: logger
119: .debug("Requestor "
120: + requestor
121: + " tried to say was blocking, but was already on blockers list.");
122: if (logger.isDetailEnabled()) {
123: logger.detail("nonQuiescentCount is " + blockers.size()
124: + " for " + (enabled ? "" : "disabled ")
125: + (isAlive ? "" : "dead ") + me);
126: logger.detail(me + " Blockers: " + getBlockersString());
127: } else if (!blockers.isEmpty() && logger.isDebugEnabled()) {
128: logger.debug(me + " is not quiescent");
129: }
130: }
131: }
132:
133: public void setMessageNumbers(Map outgoing, Map incoming) {
134: outgoingMessageNumbers = updateMap(outgoingMessageNumbers,
135: outgoing);
136: incomingMessageNumbers = updateMap(incomingMessageNumbers,
137: incoming);
138: if (logger.isDetailEnabled()) {
139: logger.detail("setMessageNumbers for " + me + ", outgoing="
140: + outgoing + ", incoming=" + incoming);
141: } else if (logger.isDebugEnabled()) {
142: logger.debug("setMessageNumbers for " + me);
143: }
144: }
145:
146: public MessageAddress getAgent() {
147: return me;
148: }
149:
150: public String getAgentName() {
151: return me.toString();
152: }
153:
154: /**
155: * Update an existing map to equal a new Map while minimizing
156: * additional memory allocation where the keys in the old map are
157: * very likely to be the same as the keys in the new Map.
158: */
159: private static Map updateMap(Map oldMap, Map newMap) {
160: if (newMap == null) {
161: throw new IllegalArgumentException("Null Map");
162: }
163: if (oldMap == null)
164: return new HashMap(newMap);
165: // Flush all keys missing from the new map
166: oldMap.keySet().retainAll(newMap.keySet());
167: // Avoid oldMap.putAll(newMap) since it expands the (Hash)Map
168: // assuming the newMap has a non-intersecting keyset.
169: for (Iterator i = newMap.entrySet().iterator(); i.hasNext();) {
170: Map.Entry entry = (Map.Entry) i.next();
171: oldMap.put(entry.getKey(), entry.getValue());
172: }
173: return oldMap;
174: }
175:
176: private boolean addBlocker(String blocker) {
177: // if not already in blockers list, add it.
178: // If we added it, return true. Else false.
179: return blockers.add(blocker);
180: }
181:
182: private boolean removeBlocker(String blocker) {
183: // if present, remove blocker. Return true if removed
184: return blockers.remove(blocker);
185: }
186:
187: public String getBlockersString() {
188: // Iterate thru blocker list, producing a String
189: return blockers.toString();
190: }
191:
192: // RFE 3760: Add a Collection of Strings - blockers of quiescence.
193: // FIXME: Synchronize this object? Or where?
194: private Set blockers = new HashSet();
195:
196: private Map incomingMessageNumbers = new HashMap(13);
197: private Map outgoingMessageNumbers = new HashMap(13);
198: // private int nonQuiescenceCount = 0;
199: private MessageAddress me;
200: private boolean enabled = false;
201: private Logger logger;
202: // Until we have agent suicide, agents can be local, enabled, but dead -- no one
203: // should be communicating with them, and we don't want to consider them for local quiescence
204: private boolean isAlive = true;
205: }
|