View Javadoc
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       */
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  */
239 class 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 }