com.opensymphony.webwork.util.classloader.monitor.FilesystemAlterationMonitor.java Source code

Java tutorial

Introduction

Here is the source code for com.opensymphony.webwork.util.classloader.monitor.FilesystemAlterationMonitor.java

Source

/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.opensymphony.webwork.util.classloader.monitor;

import com.opensymphony.webwork.util.classloader.utils.ThreadUtils;
import org.apache.commons.collections.MultiHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.io.FileFilter;
import java.util.*;

/**
 * @author tcurdt
 */
public final class FilesystemAlterationMonitor implements Runnable {

    private final static Log log = LogFactory.getLog(FilesystemAlterationMonitor.class);

    public class Entry {

        private final File root;
        private final File file;
        private long lastModified;
        private Set paths = new HashSet();
        private Set childs = new HashSet();
        private final boolean isDirectory;

        public Entry(final File pRoot, final File pFile) {
            root = pRoot;
            file = pFile;
            lastModified = -1;
            isDirectory = file.isDirectory();
        }

        public boolean hasChanged() {
            final long modified = file.lastModified();
            return modified != lastModified;
        }

        public boolean isDelected() {
            return !file.exists();
        }

        public boolean isDirectory() {
            return isDirectory;
        }

        public Entry[] getChilds() {
            final Entry[] r = new Entry[childs.size()];
            childs.toArray(r);
            return r;
        }

        private FileFilter getFileFilter() {
            return new FileFilter() {

                public boolean accept(final File pathname) {
                    final String p = pathname.getAbsolutePath();
                    return !paths.contains(p);
                }
            };
        }

        public Entry[] getNonChilds() {
            final File[] newFiles = file.listFiles(getFileFilter());
            final Entry[] r = new Entry[newFiles.length];
            for (int i = 0; i < newFiles.length; i++) {
                r[i] = new Entry(root, newFiles[i]);
            }
            return r;
        }

        public void add(final Entry entry) {
            childs.add(entry);
            paths.add(entry.toString());
            onCreate(root, entry);
        }

        private void deleteChilds() {
            final Entry[] childs = this.getChilds();
            for (int i = 0; i < childs.length; i++) {
                final Entry child = childs[i];
                delete(child);
            }
        }

        public void delete(final Entry entry) {
            childs.remove(entry);
            paths.remove(entry.toString());
            entry.deleteChilds();
            onDelete(root, entry);
        }

        public File getFile() {
            return file;
        }

        public void markNotChanged() {
            lastModified = file.lastModified();
        }

        public String toString() {
            return file.getAbsolutePath();
        }
    }

    private Map listeners = new MultiHashMap();
    private Map directories = new MultiHashMap();
    private Map entries = new HashMap();

    private final Object mutexListeners = new Object();
    private final Object mutexRunning = new Object();

    private long delay = 3000;
    private boolean running = true;

    public FilesystemAlterationMonitor() {
    }

    public void stop() {
        synchronized (mutexRunning) {
            running = false;
        }
    }

    public void setInterval(final long pDelay) {
        delay = pDelay;
    }

    public void addListener(final FilesystemAlterationListener listener, final File directory) {
        synchronized (mutexListeners) {
            // listerner -> dir1, dir2, dir3

            final MultiHashMap newListeners = new MultiHashMap(listeners);
            newListeners.put(listener, directory);
            listeners = newListeners;

            // directory -> listener1, listener2, listener3
            final MultiHashMap newDirectories = new MultiHashMap(directories);
            newDirectories.put(directory, listener);
            directories = newDirectories;
        }
    }

    public void removeListener(final FilesystemAlterationListener listener) {
        synchronized (mutexListeners) {
            // listerner -> dir1, dir2, dir3
            final MultiHashMap newListeners = new MultiHashMap(listeners);
            Collection d = (Collection) newListeners.remove(listener);
            listeners = newListeners;

            if (d != null) {
                // directory -> listener1, listener2, listener3
                final MultiHashMap newDirectories = new MultiHashMap(directories);
                for (Iterator it = d.iterator(); it.hasNext();) {
                    newDirectories.remove(it.next());
                    entries.remove(d);
                }
                directories = newDirectories;
            }
        }
    }

    private void onStart(final File root) {
        log.debug("start checking " + root);

        Map directories;
        synchronized (mutexListeners) {
            directories = this.directories;
        }
        final Collection l = (Collection) directories.get(root);
        if (l != null) {
            for (Iterator it = l.iterator(); it.hasNext();) {
                final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                listener.onStart(root);
            }
        }
    }

    private void onStop(final File root) {
        log.debug("stop checking " + root);

        Map directories;
        synchronized (mutexListeners) {
            directories = this.directories;
        }
        final Collection l = (Collection) directories.get(root);
        if (l != null) {
            for (Iterator it = l.iterator(); it.hasNext();) {
                final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                listener.onStop(root);
            }
        }
    }

    private void onCreate(final File root, final Entry entry) {

        log.debug("created " + ((entry.isDirectory()) ? "dir " : "file ") + entry);

        Map directories;
        synchronized (mutexListeners) {
            directories = this.directories;
        }

        final Collection l = (Collection) directories.get(root);
        if (l != null) {
            if (entry.isDirectory()) {
                for (Iterator it = l.iterator(); it.hasNext();) {
                    final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                    listener.onCreateDirectory(entry.getFile());
                }
            } else {
                for (Iterator it = l.iterator(); it.hasNext();) {
                    final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                    listener.onCreateFile(entry.getFile());
                }
            }
        }

        entry.markNotChanged();
    }

    private void onChange(final File root, final Entry entry) {

        log.debug("changed " + ((entry.isDirectory()) ? "dir " : "file ") + entry);

        Map directories;
        synchronized (mutexListeners) {
            directories = this.directories;
        }

        final Collection l = (Collection) directories.get(root);
        if (l != null) {
            if (entry.isDirectory()) {
                for (Iterator it = l.iterator(); it.hasNext();) {
                    final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                    listener.onChangeDirectory(entry.getFile());
                }
            } else {
                for (Iterator it = l.iterator(); it.hasNext();) {
                    final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                    listener.onChangeFile(entry.getFile());
                }
            }
        }

        entry.markNotChanged();
    }

    private void onDelete(final File root, final Entry entry) {

        log.debug("deleted " + ((entry.isDirectory()) ? "dir " : "file ") + entry);

        Map directories;
        synchronized (mutexListeners) {
            directories = this.directories;
        }

        final Collection l = (Collection) directories.get(root);
        if (l != null) {
            if (entry.isDirectory()) {
                for (Iterator it = l.iterator(); it.hasNext();) {
                    final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                    listener.onDeleteDirectory(entry.getFile());
                }
            } else {
                for (Iterator it = l.iterator(); it.hasNext();) {
                    final FilesystemAlterationListener listener = (FilesystemAlterationListener) it.next();
                    listener.onDeleteFile(entry.getFile());
                }
            }
        }

        entry.markNotChanged();
    }

    private void check(final File root, final Entry entry, final boolean create) {
        //log.debug("checking " + entry);

        if (entry.isDirectory()) {
            final Entry[] currentChilds = entry.getChilds();
            if (entry.hasChanged() || create) {
                //log.debug(entry + " has changed");
                if (!create) {
                    onChange(root, entry);
                    for (int i = 0; i < currentChilds.length; i++) {
                        final Entry child = currentChilds[i];
                        if (child.isDelected()) {
                            entry.delete(child);
                            currentChilds[i] = null;
                        }
                    }
                }
                final Entry[] newChilds = entry.getNonChilds();
                for (int i = 0; i < newChilds.length; i++) {
                    final Entry child = newChilds[i];
                    entry.add(child);
                }
                if (!create) {
                    for (int i = 0; i < currentChilds.length; i++) {
                        final Entry child = currentChilds[i];
                        if (child != null) {
                            check(root, child, false);
                        }
                    }
                }
                for (int i = 0; i < newChilds.length; i++) {
                    final Entry child = newChilds[i];
                    check(root, child, true);
                }
            } else {
                //log.debug(entry + " has not changed");
                for (int i = 0; i < currentChilds.length; i++) {
                    final Entry child = currentChilds[i];
                    check(root, child, false);
                }
            }
        } else {
            if (entry.isDelected()) {
                onDelete(root, entry);
            } else if (entry.hasChanged()) {
                onChange(root, entry);
            }
        }
    }

    public void run() {
        log.info("fam running");

        while (true) {

            synchronized (mutexRunning) {
                if (!running) {
                    break;
                }
            }

            doRun();
            ThreadUtils.sleep(delay);
        }

        log.info("fam exiting");
    }

    public void doRun() {
        Map directories;

        synchronized (mutexListeners) {
            directories = this.directories;
        }

        for (Iterator it = directories.keySet().iterator(); it.hasNext();) {
            final File directory = (File) it.next();
            if (directory.exists()) {
                onStart(directory);

                Entry root;
                synchronized (mutexListeners) {
                    root = (Entry) entries.get(directory);
                    if (root == null) {
                        root = new Entry(directory, directory);
                        entries.put(directory, root);
                    }
                }

                check(directory, root, false);
                onStop(directory);
            }
        }
    }
}