1 /* 2 * Copyright (c) 2004, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.net; 27 28 import java.util.ArrayList; 29 import java.util.Iterator; 30 import 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 */ 37 public class ProgressMonitor 38 { 39 /** 40 * Return default ProgressMonitor. 41 */ getDefault()42 public static synchronized ProgressMonitor getDefault() { 43 return pm; 44 } 45 46 /** 47 * Change default ProgressMonitor implementation. 48 */ setDefault(ProgressMonitor m)49 public static synchronized void setDefault(ProgressMonitor m) { 50 if (m != null) 51 pm = m; 52 } 53 54 /** 55 * Change progress metering policy. 56 */ setMeteringPolicy(ProgressMeteringPolicy policy)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 */ getProgressSources()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 */ getProgressUpdateThreshold()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 */ shouldMeterInput(URL url, String method)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 */ registerSource(ProgressSource pi)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 */ unregisterSource(ProgressSource pi)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 */ updateProgress(ProgressSource pi)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 */ addProgressListener(ProgressListener l)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 */ removeProgressListener(ProgressListener l)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 */ 239 class DefaultProgressMeteringPolicy implements ProgressMeteringPolicy { 240 /** 241 * Return true if metering should be turned on for a particular network input stream. 242 */ shouldMeterInput(URL url, String method)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 */ getProgressUpdateThreshold()253 public int getProgressUpdateThreshold() { 254 // 8K - same as default I/O buffer size 255 return 8192; 256 } 257 } 258