    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.jci.listeners;
    019
    020    import java.io.File;
    021    import java.util.ArrayList;
    022    import java.util.Collection;
    023
    024    import org.apache.commons.jci.monitor.FilesystemAlterationListener;
    025    import org.apache.commons.jci.monitor.FilesystemAlterationObserver;
    026    import org.apache.commons.logging.Log;
    027    import org.apache.commons.logging.LogFactory;
    028
    029    /**
    030     * AbstractFilesystemAlterationListener provides some convenience methods helping to
    031     * implement a FilesystemAlterationListener.
    032     * @author tcurdt
    033     */
    034    public abstract class AbstractFilesystemAlterationListener implements FilesystemAlterationListener {
    035
    036        private final Log log = LogFactory.getLog(AbstractFilesystemAlterationListener.class);
    037
    038        private final Collection<File> createdFiles = new ArrayList<File>();
    039        private final Collection<File> changedFiles = new ArrayList<File>();
    040        private final Collection<File> deletedFiles = new ArrayList<File>();
    041        private final Collection<File> createdDirectories = new ArrayList<File>();
    042        private final Collection<File> changedDirectories = new ArrayList<File>();
    043        private final Collection<File> deletedDirectories = new ArrayList<File>();
    044
    045
    046        private final static class Signal {
    047            public boolean triggered;
    048        }
    049
    050        private final Signal eventSignal = new Signal();
    051        private final Signal checkSignal = new Signal();
    052
    053        protected FilesystemAlterationObserver observer;
    054
    055        public void onDirectoryCreate( final File pDir ) {
    056            createdDirectories.add(pDir);
    057        }
    058        public void onDirectoryChange( final File pDir ) {
    059            changedDirectories.add(pDir);
    060        }
    061        public void onDirectoryDelete( final File pDir ) {
    062            deletedDirectories.add(pDir);
    063        }
    064
    065        public void onFileCreate( final File pFile) {
    066            createdFiles.add(pFile);
    067        }
    068        public void onFileChange( final File pFile ) {
    069            changedFiles.add(pFile);
    070        }
    071        public void onFileDelete( final File pFile ) {
    072            deletedFiles.add(pFile);
    073        }
    074
    075
    076        public Collection<File> getChangedDirectories() {
    077            return changedDirectories;
    078        }
    079
    080        public Collection<File> getChangedFiles() {
    081            return changedFiles;
    082        }
    083
    084        public Collection<File> getCreatedDirectories() {
    085            return createdDirectories;
    086        }
    087
    088        public Collection<File> getCreatedFiles() {
    089            return createdFiles;
    090        }
    091
    092        public Collection<File> getDeletedDirectories() {
    093            return deletedDirectories;
    094        }
    095
    096        public Collection<File> getDeletedFiles() {
    097            return deletedFiles;
    098        }
    099
    100        protected void signals() {
    101            if (createdFiles.size() > 0 || createdDirectories.size() > 0 ||
    102                changedFiles.size() > 0 || changedDirectories.size() > 0 ||
    103                deletedFiles.size() > 0 || deletedDirectories.size() > 0) {
    104
    105                log.debug("event signal");
    106
    107                synchronized(eventSignal) {
    108                    eventSignal.triggered = true;
    109                    eventSignal.notifyAll();
    110                }
    111            }
    112
    113            log.debug("check signal");
    114
    115            synchronized(checkSignal) {
    116                checkSignal.triggered = true;
    117                checkSignal.notifyAll();
    118            }
    119        }
    120
    121        public void onStart( final FilesystemAlterationObserver pObserver ) {
    122            observer = pObserver;
    123
    124            createdFiles.clear();
    125            changedFiles.clear();
    126            deletedFiles.clear();
    127            createdDirectories.clear();
    128            changedDirectories.clear();
    129            deletedDirectories.clear();
    130        }
    131
    132        public void onStop( final FilesystemAlterationObserver pObserver ) {
    133            signals();
    134            observer = null;
    135        }
    136
    137        public void waitForEvent() throws Exception {
    138            synchronized(eventSignal) {
    139                eventSignal.triggered = false;
    140            }
    141            log.debug("waiting for change");
    142            if (!waitForSignal(eventSignal, 10)) {
    143                throw new Exception("timeout");
    144            }
    145        }
    146
    147        /**
    148         * we don't reset the signal so if there was a check it is
    149         * already true and exit immediatly otherwise it will behave just
    150         * like waitForCheck()
    151         *
    152         * @throws Exception in case of a timeout
    153         */
    154        public void waitForFirstCheck() throws Exception {
    155            log.debug("waiting for first check");
    156            if (!waitForSignal(checkSignal, 10)) {
    157                throw new Exception("timeout");
    158            }
    159        }
    160
    161        /**
    162         * wait for the next filesystem check to happen
    163         *
    164         * @throws Exception in case of a timeout
    165         */
    166        public void waitForCheck() throws Exception {
    167            synchronized(checkSignal) {
    168                checkSignal.triggered = false;
    169            }
    170            log.debug("waiting for check");
    171            if (!waitForSignal(checkSignal, 10)) {
    172                throw new Exception("timeout");
    173            }
    174        }
    175
    176        private boolean waitForSignal(final Signal pSignal, final int pSecondsTimeout) {
    177            int i = 0;
    178            while(true) {
    179                synchronized(pSignal) {
    180                    if (!pSignal.triggered) {
    181                        try {
    182                            pSignal.wait(1000);
    183                        } catch (InterruptedException e) {
    184                        }
    185
    186                        if (++i > pSecondsTimeout) {
    187                            log.error("timeout after " + pSecondsTimeout + "s");
    188                            return false;
    189                        }
    190
    191                    } else {
    192                        pSignal.triggered = false;
    193                        break;
    194                    }
    195                }
    196            }
    197            return true;
    198        }
    199
    200    }