blob: 08f2f026ca9416d59e140768b1dbc3e5cb10fb17 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.net;
27
28import java.util.ArrayList;
29import java.util.Iterator;
30import java.net.URL;
31
32/**
33 * ProgressMonitor is a class for monitoring progress in network input stream.
34 *
35 * @author Stanley Man-Kit Ho
36 */
37public class ProgressMonitor
38{
39 /**
40 * Return default ProgressMonitor.
41 */
42 public static synchronized ProgressMonitor getDefault() {
43 return pm;
44 }
45
46 /**
47 * Change default ProgressMonitor implementation.
48 */
49 public static synchronized void setDefault(ProgressMonitor m) {
50 if (m != null)
51 pm = m;
52 }
53
54 /**
55 * Change progress metering policy.
56 */
57 public static synchronized void setMeteringPolicy(ProgressMeteringPolicy policy) {
58 if (policy != null)
59 meteringPolicy = policy;
60 }
61
62
63 /**
64 * Return a snapshot of the ProgressSource list
65 */
66 public ArrayList<ProgressSource> getProgressSources() {
67 ArrayList<ProgressSource> snapshot = new ArrayList<ProgressSource>();
68
69 try {
70 synchronized(progressSourceList) {
71 for (Iterator<ProgressSource> iter = progressSourceList.iterator(); iter.hasNext();) {
72 ProgressSource pi = iter.next();
73
74 // Clone ProgressSource and add to snapshot
75 snapshot.add((ProgressSource)pi.clone());
76 }
77 }
78 }
79 catch(CloneNotSupportedException e) {
80 e.printStackTrace();
81 }
82
83 return snapshot;
84 }
85
86 /**
87 * Return update notification threshold
88 */
89 public synchronized int getProgressUpdateThreshold() {
90 return meteringPolicy.getProgressUpdateThreshold();
91 }
92
93 /**
94 * Return true if metering should be turned on
95 * for a particular URL input stream.
96 */
97 public boolean shouldMeterInput(URL url, String method) {
98 return meteringPolicy.shouldMeterInput(url, method);
99 }
100
101 /**
102 * Register progress source when progress is began.
103 */
104 public void registerSource(ProgressSource pi) {
105
106 synchronized(progressSourceList) {
107 if (progressSourceList.contains(pi))
108 return;
109
110 progressSourceList.add(pi);
111 }
112
113 // Notify only if there is at least one listener
114 if (progressListenerList.size() > 0)
115 {
116 // Notify progress listener if there is progress change
117 ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
118
119 // Copy progress listeners to another list to avoid holding locks
120 synchronized(progressListenerList) {
121 for (Iterator<ProgressListener> iter = progressListenerList.iterator(); iter.hasNext();) {
122 listeners.add(iter.next());
123 }
124 }
125
126 // Fire event on each progress listener
127 for (Iterator<ProgressListener> iter = listeners.iterator(); iter.hasNext();) {
128 ProgressListener pl = iter.next();
129 ProgressEvent pe = new ProgressEvent(pi, pi.getURL(), pi.getMethod(), pi.getContentType(), pi.getState(), pi.getProgress(), pi.getExpected());
130 pl.progressStart(pe);
131 }
132 }
133 }
134
135 /**
136 * Unregister progress source when progress is finished.
137 */
138 public void unregisterSource(ProgressSource pi) {
139
140 synchronized(progressSourceList) {
141 // Return if ProgressEvent does not exist
142 if (progressSourceList.contains(pi) == false)
143 return;
144
145 // Close entry and remove from map
146 pi.close();
147 progressSourceList.remove(pi);
148 }
149
150 // Notify only if there is at least one listener
151 if (progressListenerList.size() > 0)
152 {
153 // Notify progress listener if there is progress change
154 ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
155
156 // Copy progress listeners to another list to avoid holding locks
157 synchronized(progressListenerList) {
158 for (Iterator<ProgressListener> iter = progressListenerList.iterator(); iter.hasNext();) {
159 listeners.add(iter.next());
160 }
161 }
162
163 // Fire event on each progress listener
164 for (Iterator<ProgressListener> iter = listeners.iterator(); iter.hasNext();) {
165 ProgressListener pl = iter.next();
166 ProgressEvent pe = new ProgressEvent(pi, pi.getURL(), pi.getMethod(), pi.getContentType(), pi.getState(), pi.getProgress(), pi.getExpected());
167 pl.progressFinish(pe);
168 }
169 }
170 }
171
172 /**
173 * Progress source is updated.
174 */
175 public void updateProgress(ProgressSource pi) {
176
177 synchronized (progressSourceList) {
178 if (progressSourceList.contains(pi) == false)
179 return;
180 }
181
182 // Notify only if there is at least one listener
183 if (progressListenerList.size() > 0)
184 {
185 // Notify progress listener if there is progress change
186 ArrayList<ProgressListener> listeners = new ArrayList<ProgressListener>();
187
188 // Copy progress listeners to another list to avoid holding locks
189 synchronized(progressListenerList) {
190 for (Iterator<ProgressListener> iter = progressListenerList.iterator(); iter.hasNext();) {
191 listeners.add(iter.next());
192 }
193 }
194
195 // Fire event on each progress listener
196 for (Iterator<ProgressListener> iter = listeners.iterator(); iter.hasNext();) {
197 ProgressListener pl = iter.next();
198 ProgressEvent pe = new ProgressEvent(pi, pi.getURL(), pi.getMethod(), pi.getContentType(), pi.getState(), pi.getProgress(), pi.getExpected());
199 pl.progressUpdate(pe);
200 }
201 }
202 }
203
204 /**
205 * Add progress listener in progress monitor.
206 */
207 public void addProgressListener(ProgressListener l) {
208 synchronized(progressListenerList) {
209 progressListenerList.add(l);
210 }
211 }
212
213 /**
214 * Remove progress listener from progress monitor.
215 */
216 public void removeProgressListener(ProgressListener l) {
217 synchronized(progressListenerList) {
218 progressListenerList.remove(l);
219 }
220 }
221
222 // Metering policy
223 private static ProgressMeteringPolicy meteringPolicy = new DefaultProgressMeteringPolicy();
224
225 // Default implementation
226 private static ProgressMonitor pm = new ProgressMonitor();
227
228 // ArrayList for outstanding progress sources
229 private ArrayList<ProgressSource> progressSourceList = new ArrayList<ProgressSource>();
230
231 // ArrayList for progress listeners
232 private ArrayList<ProgressListener> progressListenerList = new ArrayList<ProgressListener>();
233}
234
235
236/**
237 * Default progress metering policy.
238 */
239class DefaultProgressMeteringPolicy implements ProgressMeteringPolicy {
240 /**
241 * Return true if metering should be turned on for a particular network input stream.
242 */
243 public boolean shouldMeterInput(URL url, String method)
244 {
245 // By default, no URL input stream is metered for
246 // performance reason.
247 return false;
248 }
249
250 /**
251 * Return update notification threshold.
252 */
253 public int getProgressUpdateThreshold() {
254 // 8K - same as default I/O buffer size
255 return 8192;
256 }
257}