001: /*
002: * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.net;
027:
028: import java.util.ArrayList;
029: import java.util.Iterator;
030: import java.net.URL;
031:
032: /**
033: * ProgressMonitor is a class for monitoring progress in network input stream.
034: *
035: * @author Stanley Man-Kit Ho
036: */
037: public class ProgressMonitor {
038: /**
039: * Return default ProgressMonitor.
040: */
041: public static synchronized ProgressMonitor getDefault() {
042: return pm;
043: }
044:
045: /**
046: * Change default ProgressMonitor implementation.
047: */
048: public static synchronized void setDefault(ProgressMonitor m) {
049: if (m != null)
050: pm = m;
051: }
052:
053: /**
054: * Change progress metering policy.
055: */
056: public static synchronized void setMeteringPolicy(
057: ProgressMeteringPolicy policy) {
058: if (policy != null)
059: meteringPolicy = policy;
060: }
061:
062: /**
063: * Return a snapshot of the ProgressSource list
064: */
065: public ArrayList<ProgressSource> getProgressSources() {
066: ArrayList<ProgressSource> snapshot = new ArrayList<ProgressSource>();
067:
068: try {
069: synchronized (progressSourceList) {
070: for (Iterator<ProgressSource> iter = progressSourceList
071: .iterator(); iter.hasNext();) {
072: ProgressSource pi = iter.next();
073:
074: // Clone ProgressSource and add to snapshot
075: snapshot.add((ProgressSource) pi.clone());
076: }
077: }
078: } catch (CloneNotSupportedException e) {
079: e.printStackTrace();
080: }
081:
082: return snapshot;
083: }
084:
085: /**
086: * Return update notification threshold
087: */
088: public synchronized int getProgressUpdateThreshold() {
089: return meteringPolicy.getProgressUpdateThreshold();
090: }
091:
092: /**
093: * Return true if metering should be turned on
094: * for a particular URL input stream.
095: */
096: public boolean shouldMeterInput(URL url, String method) {
097: return meteringPolicy.shouldMeterInput(url, method);
098: }
099:
100: /**
101: * Register progress source when progress is began.
102: */
103: public void registerSource(ProgressSource pi) {
104:
105: synchronized (progressSourceList) {
106: if (progressSourceList.contains(pi))
107: return;
108:
109: progressSourceList.add(pi);
110: }
111:
112: // Notify only if there is at least one listener
113: if (progressListenerList.size() > 0) {
114: // Notify progress listener if there is progress change
115: ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
116:
117: // Copy progress listeners to another list to avoid holding locks
118: synchronized (progressListenerList) {
119: for (Iterator<ProgressListener> iter = progressListenerList
120: .iterator(); iter.hasNext();) {
121: listeners.add(iter.next());
122: }
123: }
124:
125: // Fire event on each progress listener
126: for (Iterator<ProgressListener> iter = listeners.iterator(); iter
127: .hasNext();) {
128: ProgressListener pl = iter.next();
129: ProgressEvent pe = new ProgressEvent(pi, pi.getURL(),
130: pi.getMethod(), pi.getContentType(), pi
131: .getState(), pi.getProgress(), pi
132: .getExpected());
133: pl.progressStart(pe);
134: }
135: }
136: }
137:
138: /**
139: * Unregister progress source when progress is finished.
140: */
141: public void unregisterSource(ProgressSource pi) {
142:
143: synchronized (progressSourceList) {
144: // Return if ProgressEvent does not exist
145: if (progressSourceList.contains(pi) == false)
146: return;
147:
148: // Close entry and remove from map
149: pi.close();
150: progressSourceList.remove(pi);
151: }
152:
153: // Notify only if there is at least one listener
154: if (progressListenerList.size() > 0) {
155: // Notify progress listener if there is progress change
156: ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
157:
158: // Copy progress listeners to another list to avoid holding locks
159: synchronized (progressListenerList) {
160: for (Iterator<ProgressListener> iter = progressListenerList
161: .iterator(); iter.hasNext();) {
162: listeners.add(iter.next());
163: }
164: }
165:
166: // Fire event on each progress listener
167: for (Iterator<ProgressListener> iter = listeners.iterator(); iter
168: .hasNext();) {
169: ProgressListener pl = iter.next();
170: ProgressEvent pe = new ProgressEvent(pi, pi.getURL(),
171: pi.getMethod(), pi.getContentType(), pi
172: .getState(), pi.getProgress(), pi
173: .getExpected());
174: pl.progressFinish(pe);
175: }
176: }
177: }
178:
179: /**
180: * Progress source is updated.
181: */
182: public void updateProgress(ProgressSource pi) {
183:
184: synchronized (progressSourceList) {
185: if (progressSourceList.contains(pi) == false)
186: return;
187: }
188:
189: // Notify only if there is at least one listener
190: if (progressListenerList.size() > 0) {
191: // Notify progress listener if there is progress change
192: ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
193:
194: // Copy progress listeners to another list to avoid holding locks
195: synchronized (progressListenerList) {
196: for (Iterator<ProgressListener> iter = progressListenerList
197: .iterator(); iter.hasNext();) {
198: listeners.add(iter.next());
199: }
200: }
201:
202: // Fire event on each progress listener
203: for (Iterator<ProgressListener> iter = listeners.iterator(); iter
204: .hasNext();) {
205: ProgressListener pl = iter.next();
206: ProgressEvent pe = new ProgressEvent(pi, pi.getURL(),
207: pi.getMethod(), pi.getContentType(), pi
208: .getState(), pi.getProgress(), pi
209: .getExpected());
210: pl.progressUpdate(pe);
211: }
212: }
213: }
214:
215: /**
216: * Add progress listener in progress monitor.
217: */
218: public void addProgressListener(ProgressListener l) {
219: synchronized (progressListenerList) {
220: progressListenerList.add(l);
221: }
222: }
223:
224: /**
225: * Remove progress listener from progress monitor.
226: */
227: public void removeProgressListener(ProgressListener l) {
228: synchronized (progressListenerList) {
229: progressListenerList.remove(l);
230: }
231: }
232:
233: // Metering policy
234: private static ProgressMeteringPolicy meteringPolicy = new DefaultProgressMeteringPolicy();
235:
236: // Default implementation
237: private static ProgressMonitor pm = new ProgressMonitor();
238:
239: // ArrayList for outstanding progress sources
240: private ArrayList<ProgressSource> progressSourceList = new ArrayList<ProgressSource>();
241:
242: // ArrayList for progress listeners
243: private ArrayList<ProgressListener> progressListenerList = new ArrayList<ProgressListener>();
244: }
245:
246: /**
247: * Default progress metering policy.
248: */
249: class DefaultProgressMeteringPolicy implements ProgressMeteringPolicy {
250: /**
251: * Return true if metering should be turned on for a particular network input stream.
252: */
253: public boolean shouldMeterInput(URL url, String method) {
254: // By default, no URL input stream is metered for
255: // performance reason.
256: return false;
257: }
258:
259: /**
260: * Return update notification threshold.
261: */
262: public int getProgressUpdateThreshold() {
263: // 8K - same as default I/O buffer size
264: return 8192;
265: }
266: }
|