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.blackboard;
028:
029: import java.lang.ref.ReferenceQueue;
030: import java.lang.ref.WeakReference;
031: import java.util.Date;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.Map;
035: import java.util.SortedSet;
036: import java.util.TreeSet;
037:
038: /**
039: * A record of the recent publication history, enabled by the
040: * {@link org.cougaar.core.blackboard.Distributor}'s
041: * "keepPublishHistory" option, that can be used to help debug
042: * apparently anomalous publish events.
043: */
044: public class PublishHistory {
045: /**
046: * Item records the current publication history of an object as a
047: * stack dump (Throwable) for each of add, change, and remove. It
048: * also has the time of the last publish event.
049: */
050: private static class Item implements Comparable {
051: public Throwable add, change, remove;
052: public long lastTime;
053:
054: public void recordAdd() {
055: add = new Throwable("add@" + new Date(lastTime));
056: }
057:
058: public void recordChange() {
059: change = new Throwable("change@" + new Date(lastTime));
060: }
061:
062: public void recordRemove() {
063: remove = new Throwable("remove@" + new Date(lastTime));
064: }
065:
066: public int compareTo(Object o) {
067: Item other = (Item) o;
068: if (other == this )
069: return 0;
070: long diff = lastTime - other.lastTime;
071: if (diff > 0L)
072: return 1;
073: if (diff < 0L)
074: return -1;
075: return this .hashCode() - other.hashCode();
076: }
077:
078: public void dumpStacks() {
079: if (add != null)
080: add.printStackTrace(System.out);
081: else
082: System.out.println("No add recorded");
083: if (change != null)
084: change.printStackTrace(System.out);
085: else
086: System.out.println("No change recorded");
087: if (remove != null)
088: remove.printStackTrace(System.out);
089: else
090: System.out.println("No remove recorded");
091: }
092: }
093:
094: /**
095: * WeakReference extension having a Object that is a key to the
096: * map Map. The values in that Map are Ref objects referring to an
097: * Item. When the Ref in the map is the only remaining reference
098: * to the Item, the map entry is removed. The key Object is kept
099: * in the Ref because it is much faster to remove the entry by
100: * using its key than by using its value.
101: */
102: private static class Ref extends WeakReference {
103: public Object object;
104:
105: public Ref(Object object, Item item, ReferenceQueue refQ) {
106: super (item, refQ);
107: this .object = object;
108: }
109: }
110:
111: /**
112: * A set of Items sorted by time. The least recently referenced
113: * Items should be at the head of the Set so they can be quickly
114: * removed as time elapses.
115: */
116: private static SortedSet items = new TreeSet();
117: private static long nextCheckItems = System.currentTimeMillis() + 60000L;
118:
119: /**
120: * Update the last reference time of an Item. The Item must be
121: * removed from the sorted set prior to modifying its time because
122: * the time is the basis for the sorting of the Set.
123: */
124: private static synchronized void updateItem(Item item) {
125: items.remove(item);
126: item.lastTime = System.currentTimeMillis();
127: items.add(item);
128: }
129:
130: /** Used to form the headset of items older than a certain time */
131: private static Item deleteItem = new Item();
132:
133: /**
134: * Remove Items older than 1 minute.
135: */
136: private static synchronized void checkItems() {
137: long now = System.currentTimeMillis();
138: if (now < nextCheckItems)
139: return;
140: nextCheckItems = now + 60000L;
141: deleteItem.lastTime = now - 60000L;
142: int removeCount = 0;
143: for (Iterator i = items.headSet(deleteItem).iterator(); i
144: .hasNext();) {
145: i.remove();
146: removeCount++;
147: }
148: /*
149: if (removeCount > 0) {
150: System.out.println("PublishHistory removed " + removeCount + " items");
151: }
152: */
153: }
154:
155: /**
156: * Map from published object to Ref to Item;
157: */
158: private Map map = new HashMap();
159:
160: private ReferenceQueue refQ = new ReferenceQueue();
161:
162: /**
163: * Get the Item corresponding to a published Object. A new item is
164: * created if necessary. In all cases, the lastTime of the Item is
165: * updated to now.
166: */
167: private Item getItem(Object o) {
168: Ref ref;
169: Item item;
170: checkItems();
171: do {
172: while ((ref = (Ref) refQ.poll()) != null) {
173: map.remove(ref.object);
174: }
175: ref = (Ref) map.get(o);
176: if (ref == null) {
177: item = new Item();
178: ref = new Ref(o, item, refQ);
179: map.put(o, ref);
180: } else {
181: item = (Item) ref.get();
182: }
183: } while (item == null);
184: updateItem(item);
185: return item;
186: }
187:
188: /**
189: * Record a stack trace in the add slot of the item corresponding
190: * to a Object.
191: */
192: public void publishAdd(Object o) {
193: getItem(o).recordAdd();
194: }
195:
196: /**
197: * Record a stack trace in the change slot of the item
198: * corresponding to a Object.
199: */
200: public void publishChange(Object o) {
201: getItem(o).recordChange();
202: }
203:
204: /**
205: * Record a stack trace in the remove slot of the item
206: * corresponding to a Object.
207: */
208: public void publishRemove(Object o) {
209: getItem(o).recordRemove();
210: }
211:
212: public void dumpStacks(Object o) {
213: Item item = getItem(o);
214: item.dumpStacks();
215: }
216: }
|