001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.timers;
042:
043: import java.beans.PropertyChangeListener;
044: import java.beans.PropertyChangeSupport;
045: import java.lang.ref.Reference;
046: import java.lang.ref.WeakReference;
047: import java.util.ArrayList;
048: import java.util.Collection;
049: import java.util.Collections;
050: import java.util.LinkedHashMap;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.WeakHashMap;
054: import javax.swing.event.ChangeEvent;
055: import javax.swing.event.ChangeListener;
056: import org.openide.util.RequestProcessor;
057: import org.openide.util.Utilities;
058: import org.openide.filesystems.FileObject;
059: import org.openide.filesystems.FileChangeAdapter;
060: import org.openide.filesystems.FileEvent;
061:
062: /**
063: *
064: * @author Jan Lahoda
065: */
066: public final class TimesCollectorPeer {
067:
068: private List<Reference<Object>> files;
069: private Map<Object, Map<String, Description>> fo2Key2Desc;
070:
071: private static final TimesCollectorPeer INSTANCE = new TimesCollectorPeer();
072:
073: private PropertyChangeSupport pcs;
074:
075: public static TimesCollectorPeer getDefault() {
076: return INSTANCE;
077: }
078:
079: /** Creates a new instance of TimesCollectorPeer */
080: private TimesCollectorPeer() {
081: files = new ArrayList<Reference<Object>>();
082: fo2Key2Desc = new WeakHashMap<Object, Map<String, Description>>();
083:
084: pcs = new PropertyChangeSupport(this );
085: }
086:
087: public void reportTime(Object fo, String key, String message,
088: long time) {
089: Map<String, Description> key2Desc = getKey2Desc(fo);
090: Description desc = new Description(message, time);
091:
092: key2Desc.put(key, desc);
093:
094: pcs.firePropertyChange("PROP", fo, key);
095: }
096:
097: public void reportReference(Object fo, String key, String message,
098: Object object) {
099: Map<String, Description> key2Desc = getKey2Desc(fo);
100:
101: // Little bit more complicated here
102: Description d = key2Desc.get(key);
103: assert d == null || d instanceof ObjectCountDescripton : "Illegal state";
104:
105: ObjectCountDescripton ocd = d == null ? new ObjectCountDescripton(
106: this , fo, key, message)
107: : (ObjectCountDescripton) d;
108: ocd.add(object);
109:
110: key2Desc.put(key, ocd);
111: pcs.firePropertyChange("PROP", fo, key);
112: }
113:
114: private synchronized Map<String, Description> getKey2Desc(
115: final Object fo) {
116: Map<String, Description> result = fo2Key2Desc.get(fo);
117:
118: if (result == null) {
119: files.add(new CleanableWeakReference<Object>(fo));
120: fo2Key2Desc
121: .put(
122: fo,
123: result = Collections
124: .synchronizedMap(new LinkedHashMap<String, Description>()));
125: pcs.firePropertyChange("fos", null, fo);
126:
127: if (fo instanceof FileObject) {
128: ((FileObject) fo)
129: .addFileChangeListener(new FileChangeAdapter() {
130: public void fileDeleted(FileEvent ev) {
131: for (Reference<Object> r : files) {
132: if (r.get() == fo) {
133: files.remove(r);
134: break;
135: }
136: }
137: fo2Key2Desc.remove(fo);
138: pcs.firePropertyChange("fos", null,
139: null);
140: }
141: });
142: }
143: }
144:
145: return result;
146: }
147:
148: public Description getDescription(Object fo, String key) {
149: return getKey2Desc(fo).get(key);
150: }
151:
152: public Collection<String> getKeysForFile(Object fo) {
153: return getKey2Desc(fo).keySet();
154: }
155:
156: public Collection<Object> getFiles() {
157: List<Object> result = new ArrayList<Object>();
158:
159: for (Reference<Object> r : files) {
160: Object f = r.get();
161:
162: if (f != null)
163: result.add(f);
164: }
165: return result;
166: }
167:
168: public void addPropertyChangeListener(PropertyChangeListener l) {
169: pcs.addPropertyChangeListener(l);
170: }
171:
172: public void removePropertyChangeListener(PropertyChangeListener l) {
173: pcs.removePropertyChangeListener(l);
174: }
175:
176: public void select(Object fo) {
177: getKey2Desc(fo);
178: pcs.firePropertyChange("selected", null, fo);
179: }
180:
181: public static class Description {
182: private String message;
183: private long time;
184:
185: public Description(String message, long time) {
186: this .message = message;
187: this .time = time;
188: }
189:
190: public String getMessage() {
191: return message;
192: }
193:
194: public long getTime() {
195: return time;
196: }
197:
198: }
199:
200: public static class ObjectCountDescripton extends Description
201: implements ChangeListener {
202:
203: private TimesCollectorPeer tcp;
204: private Reference<Object> fo;
205: private String key;
206: private InstanceWatcher iw = new InstanceWatcher();
207:
208: public ObjectCountDescripton(TimesCollectorPeer tcp, Object fo,
209: String key, String message) {
210: super (message, 0);
211: this .tcp = tcp;
212: this .fo = new WeakReference<Object>(fo);
213: this .key = key;
214: iw.addChangeListener(this );
215: }
216:
217: public long getTime() {
218: return iw.size();
219: }
220:
221: public Collection getInstances() {
222: return iw.getInstances();
223: }
224:
225: private void add(Object o) {
226: iw.add(o);
227: }
228:
229: public void stateChanged(ChangeEvent e) {
230: Object file = fo.get();
231:
232: if (file != null) {
233: tcp.pcs.firePropertyChange("PROP", file, key);
234: }
235: }
236:
237: }
238:
239: private class CleanableWeakReference<T> extends WeakReference<T>
240: implements Runnable {
241:
242: public CleanableWeakReference(T o) {
243: super (o, Utilities.activeReferenceQueue());
244: }
245:
246: public void run() {
247: files.remove(this );
248: RequestProcessor.getDefault().post(new Runnable() {
249: public void run() {
250: pcs.firePropertyChange("fos", null, null);
251: }
252: });
253: }
254:
255: }
256: }
|