Home | History | Annotate | Download | only in net
      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 }
    258