Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  //
  //  ========================================================================
  //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
  //  ------------------------------------------------------------------------
  //  All rights reserved. This program and the accompanying materials
  //  are made available under the terms of the Eclipse Public License v1.0
  //  and Apache License v2.0 which accompanies this distribution.
  //
  //      The Eclipse Public License is available at
 //      http://www.eclipse.org/legal/epl-v10.html
 //
 //      The Apache License v2.0 is available at
 //      http://www.opensource.org/licenses/apache2.0.php
 //
 //  You may elect to redistribute this code under either of these licenses.
 //  ========================================================================
 //
 
 
 package org.eclipse.jetty.util;
 
 import java.io.File;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
Scanner Utility for scanning a directory for added, removed and changed files and reporting these events via registered Listeners.
 
 public class Scanner extends AbstractLifeCycle
 {
     private static final Logger LOG = Log.getLogger(Scanner.class);
     private static int __scannerId=0;
     private int _scanInterval;
     private int _scanCount = 0;
     private final List<Listener_listeners = new ArrayList<Listener>();
     private final Map<String,TimeNSize_prevScan = new HashMap<String,TimeNSize> ();
     private final Map<String,TimeNSize_currentScan = new HashMap<String,TimeNSize> ();
     private FilenameFilter _filter;
     private final List<File_scanDirs = new ArrayList<File>();
     private volatile boolean _running = false;
     private boolean _reportExisting = true;
     private boolean _reportDirs = true;
     private Timer _timer;
     private TimerTask _task;
     private int _scanDepth=0;
     
     public enum Notification { ADDED, CHANGED, REMOVED };
     private final Map<String,Notification_notifications = new HashMap<String,Notification>();
 
     static class TimeNSize
     {
         final long _lastModified;
         final long _size;
         
         public TimeNSize(long lastModifiedlong size)
         {
              = lastModified;
              = size;
         }
         
         @Override
         public int hashCode()
         {
             return (int)^(int);
         }
         
         @Override
         public boolean equals(Object o)
         {
             if (o instanceof TimeNSize)
             {
                 TimeNSize tns = (TimeNSize)o;
                 return tns._lastModified== && tns._size==;
             }
             return false;
         }
         
         @Override
         public String toString()
        {
            return "[lm="++",s="++"]";
        }
    }
    
    
Listener Marker for notifications re file changes.
    public interface Listener
    {
    }
    public interface ScanListener extends Listener
    {
        public void scan();
    }
    
    public interface DiscreteListener extends Listener
    {
        public void fileChanged (String filenamethrows Exception;
        public void fileAdded (String filenamethrows Exception;
        public void fileRemoved (String filenamethrows Exception;
    }
    
    
    public interface BulkListener extends Listener
    {
        public void filesChanged (List<Stringfilenamesthrows Exception;
    }

    
Listener that notifies when a scan has started and when it has ended.
    public interface ScanCycleListener extends Listener
    {
        public void scanStarted(int cyclethrows Exception;
        public void scanEnded(int cyclethrows Exception;
    }

    
    public Scanner ()
    {       
    }

    
Get the scan interval

Returns:
interval between scans in seconds
    public int getScanInterval()
    {
        return ;
    }

    
Set the scan interval

Parameters:
scanInterval pause between scans in seconds, or 0 for no scan after the initial scan.
    public synchronized void setScanInterval(int scanInterval)
    {
         = scanInterval;
        schedule();
    }

    
Set the location of the directory to scan.

Deprecated:
use setScanDirs(List dirs) instead
Parameters:
dir
    @Deprecated
    public void setScanDir (File dir)
    {
        .clear(); 
        .add(dir);
    }

    
Get the location of the directory to scan

Deprecated:
use getScanDirs() instead
Returns:
the first directory (of getScanDirs() being scanned)
    @Deprecated
    public File getScanDir ()
    {
        return (==null?null:(File).get(0));
    }
    public void setScanDirs (List<Filedirs)
    {
        .clear(); 
        .addAll(dirs);
    }
    
    public synchronized void addScanDirFile dir )
    {
        .adddir );
    }
    
    public List<FilegetScanDirs ()
    {
        return Collections.unmodifiableList();
    }
    
    /* ------------------------------------------------------------ */
    

Parameters:
recursive True if scanning is recursive
See also:
setScanDepth(int)
    public void setRecursive (boolean recursive)
    {
        =recursive?-1:0;
    }
    
    /* ------------------------------------------------------------ */
    

Returns:
True if scanning is fully recursive (scandepth==-1)
See also:
getScanDepth()
    public boolean getRecursive ()
    {
        return ==-1;
    }
    
    /* ------------------------------------------------------------ */
    
Get the scanDepth.

Returns:
the scanDepth
    public int getScanDepth()
    {
        return ;
    }
    /* ------------------------------------------------------------ */
    
Set the scanDepth.

Parameters:
scanDepth the scanDepth to set
    public void setScanDepth(int scanDepth)
    {
         = scanDepth;
    }

    
Apply a filter to files found in the scan directory. Only files matching the filter will be reported as added/changed/removed.

Parameters:
filter
    public void setFilenameFilter (FilenameFilter filter)
    {
         = filter;
    }

    
Get any filter applied to files in the scan dir.

Returns:
the filename filter
    {
        return ;
    }
    /* ------------------------------------------------------------ */
    
Whether or not an initial scan will report all files as being added.

Parameters:
reportExisting if true, all files found on initial scan will be reported as being added, otherwise not
    public void setReportExistingFilesOnStartup (boolean reportExisting)
    {
         = reportExisting;
    }
    /* ------------------------------------------------------------ */
    public boolean getReportExistingFilesOnStartup()
    {
        return ;
    }
    
    /* ------------------------------------------------------------ */
    
Set if found directories should be reported.

Parameters:
dirs
    public void setReportDirs(boolean dirs)
    {
        =dirs;
    }
    
    /* ------------------------------------------------------------ */
    public boolean getReportDirs()
    {
        return ;
    }
    
    /* ------------------------------------------------------------ */
    
Add an added/removed/changed listener

Parameters:
listener
    public synchronized void addListener (Listener listener)
    {
        if (listener == null)
            return;
        .add(listener);   
    }



    
Remove a registered listener

Parameters:
listener the Listener to be removed
    public synchronized void removeListener (Listener listener)
    {
        if (listener == null)
            return;
        .remove(listener);    
    }


    
Start the scanning action.
    @Override
    public synchronized void doStart()
    {
        if ()
            return;
         = true;
        if ()
        {
            // if files exist at startup, report them
            scan();
            scan(); // scan twice so files reported as stable
        }
        else
        {
            //just register the list of existing files and only report changes
            scanFiles();
            .putAll();
        }
        schedule();
    }
    public TimerTask newTimerTask ()
    {
        return new TimerTask()
        {
            @Override
            public void run() { scan(); }
        };
    }
    public Timer newTimer ()
    {
        return new Timer("Scanner-"+++, true);
    }
    
    public void schedule ()
    {  
        if ()
        {
            if (!=null)
                .cancel();
            if (!=null)
                .cancel();
            if (getScanInterval() > 0)
            {
                 = newTimer();
                 = newTimerTask();
                .schedule(, 1010L*getScanInterval(),1010L*getScanInterval());
            }
        }
    }
    
Stop the scanning.
    @Override
    public synchronized void doStop()
    {
        if ()
        {
             = false
            if (!=null)
                .cancel();
            if (!=null)
                .cancel();
            =null;
            =null;
        }
    }

    
Perform a pass of the scanner and report changes
    public synchronized void scan ()
    {
        reportScanStart(++);
        scanFiles();
        .clear();
        .putAll();
        reportScanEnd();
        
        for (Listener l : )
        {
            try
            {
                if (l instanceof ScanListener)
                    ((ScanListener)l).scan();
            }
            catch (Exception e)
            {
                .warn(e);
            }
            catch (Error e)
            {
                .warn(e);
            }
        }
    }

    
Recursively scan all files in the designated directories.
    public synchronized void scanFiles ()
    {
        if (==null)
            return;
        
        .clear();
        Iterator<Fileitor = .iterator();
        while (itor.hasNext())
        {
            File dir = itor.next();
            
            if ((dir != null) && (dir.exists()))
                try
                {
                    scanFile(dir.getCanonicalFile(), ,0);
                }
                catch (IOException e)
                {
                    .warn("Error scanning files."e);
                }
        }
    }


    
Report the adds/changes/removes to the registered listeners

Parameters:
currentScan the info from the most recent pass
oldScan info from the previous pass
    public synchronized void reportDifferences (Map<String,TimeNSizecurrentScanMap<String,TimeNSizeoldScan
    {
        // scan the differences and add what was found to the map of notifications:
        Set<StringoldScanKeys = new HashSet<String>(oldScan.keySet());
        
        // Look for new and changed files
        for (Map.Entry<StringTimeNSizeentrycurrentScan.entrySet())
        {
            String file = entry.getKey(); 
            if (!oldScanKeys.contains(file))
            {
                Notification old=.put(file,.);
                if (old!=null)
                { 
                    switch(old)
                    {
                        case 
                        case :
                            .put(file,.);
                    }
                }
            }
            else if (!oldScan.get(file).equals(currentScan.get(file)))
            {
                Notification old=.put(file,.);
                if (old!=null)
                {
                    switch(old)
                    {
                        case :
                            .put(file,.);
                    }
                }
            }
        }
        
        // Look for deleted files
        for (String file : oldScan.keySet())
        {
            if (!currentScan.containsKey(file))
            {
                Notification old=.put(file,.);
                if (old!=null)
                {
                    switch(old)
                    {
                        case :
                            .remove(file);
                    }
                }
            }
        }
        
        if (.isDebugEnabled())
            .debug("scanned "++": "+);
                
        // Process notifications
        // Only process notifications that are for stable files (ie same in old and current scan).
        List<StringbulkChanges = new ArrayList<String>();
        for (Iterator<Entry<String,Notification>> iter = .entrySet().iterator();iter.hasNext();)
        {
            Entry<String,Notificationentry=iter.next();
            String file=entry.getKey();
            
            // Is the file stable?
            if (oldScan.containsKey(file))
            {
                if (!oldScan.get(file).equals(currentScan.get(file)))
                    continue;
            }
            else if (currentScan.containsKey(file))
                continue;
                            
            // File is stable so notify
            Notification notification=entry.getValue();
            iter.remove();
            bulkChanges.add(file);
            switch(notification)
            {
                case :
                    reportAddition(file);
                    break;
                case :
                    reportChange(file);
                    break;
                case :
                    reportRemoval(file);
                    break;
            }
        }
        if (!bulkChanges.isEmpty())
            reportBulkChanges(bulkChanges);
    }


    
Get last modified time on a single file or recurse if the file is a directory.

Parameters:
f file or directory
scanInfoMap map of filenames to last modified times
    private void scanFile (File fMap<String,TimeNSizescanInfoMapint depth)
    {
        try
        {
            if (!f.exists())
                return;
            if (f.isFile() || depth>0&&  && f.isDirectory())
            {
                if (( == null) || (( != null) && .accept(f.getParentFile(), f.getName())))
                {
                    String name = f.getCanonicalPath();
                    scanInfoMap.put(namenew TimeNSize(f.lastModified(),f.length()));
                }
            }
            
            // If it is a directory, scan if it is a known directory or the depth is OK.
            if (f.isDirectory() && (depth< || ==-1 || .contains(f)))
            {
                File[] files = f.listFiles();
                for (int i=0;i<files.length;i++)
                    scanFile(files[i], scanInfoMap,depth+1);
            }
        }
        catch (IOException e)
        {
            .warn("Error scanning watched files"e);
        }
    }
    private void warn(Object listener,String filename,Throwable th)
    {
        .warn(listener+" failed on '"+filenameth);
    }

    
Report a file addition to the registered FileAddedListeners

Parameters:
filename
    private void reportAddition (String filename)
    {
        Iterator<Listeneritor = .iterator();
        while (itor.hasNext())
        {
            Listener l = itor.next();
            try
            {
                if (l instanceof DiscreteListener)
                    ((DiscreteListener)l).fileAdded(filename);
            }
            catch (Exception e)
            {
                warn(l,filename,e);
            }
            catch (Error e)
            {
                warn(l,filename,e);
            }
        }
    }


    
Report a file removal to the FileRemovedListeners

Parameters:
filename
    private void reportRemoval (String filename)
    {
        Iterator<Listeneritor = .iterator();
        while (itor.hasNext())
        {
            Object l = itor.next();
            try
            {
                if (l instanceof DiscreteListener)
                    ((DiscreteListener)l).fileRemoved(filename);
            }
            catch (Exception e)
            {
                warn(l,filename,e);
            }
            catch (Error e)
            {
                warn(l,filename,e);
            }
        }
    }


    
Report a file change to the FileChangedListeners

Parameters:
filename
    private void reportChange (String filename)
    {
        Iterator<Listeneritor = .iterator();
        while (itor.hasNext())
        {
            Listener l = itor.next();
            try
            {
                if (l instanceof DiscreteListener)
                    ((DiscreteListener)l).fileChanged(filename);
            }
            catch (Exception e)
            {
                warn(l,filename,e);
            }
            catch (Error e)
            {
                warn(l,filename,e);
            }
        }
    }
    
    private void reportBulkChanges (List<Stringfilenames)
    {
        Iterator<Listeneritor = .iterator();
        while (itor.hasNext())
        {
            Listener l = itor.next();
            try
            {
                if (l instanceof BulkListener)
                    ((BulkListener)l).filesChanged(filenames);
            }
            catch (Exception e)
            {
                warn(l,filenames.toString(),e);
            }
            catch (Error e)
            {
                warn(l,filenames.toString(),e);
            }
        }
    }
    
    
signal any scan cycle listeners that a scan has started
    private void reportScanStart(int cycle)
    {
        for (Listener listener : )
        {
            try
            {
                if (listener instanceof ScanCycleListener)
                {
                    ((ScanCycleListener)listener).scanStarted(cycle);
                }
            }
            catch (Exception e)
            {
                .warn(listener + " failed on scan start for cycle " + cyclee);
            }
        }
    }

    
sign
    private void reportScanEnd(int cycle)
    {
        for (Listener listener : )
        {
            try
            {
                if (listener instanceof ScanCycleListener)
                {
                    ((ScanCycleListener)listener).scanEnded(cycle);
                }
            }
            catch (Exception e)
            {
                .warn(listener + " failed on scan end for cycle " + cyclee);
            }
        }
    }
New to GrepCode? Check out our FAQ X