org.jahia.tools.files.FileWatcherJob.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.tools.files.FileWatcherJob.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2017 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.tools.files;

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

import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.comparator.PathFileComparator;
import org.apache.commons.io.filefilter.*;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Background job that allows to watch files for modifications and call appropriate observers.
 */
public class FileWatcherJob implements StatefulJob {

    private static class Walker extends DirectoryWalker<File> {

        private AgeFileFilter ageFileFilter;
        private List<File> results = new LinkedList<File>();

        Walker(long newerThan) {
            super();
            ageFileFilter = new AgeFileFilter(newerThan, false);
        }

        List<File> execute(File startFolder) throws IOException {
            walk(startFolder, results);
            return results;
        }

        protected boolean handleDirectory(File directory, int depth, Collection<File> results) throws IOException {
            if (ageFileFilter.accept(directory)) {
                results.add(directory);
            }
            return true;
        }

        protected void handleFile(File file, int depth, Collection<File> results) throws IOException {
            if (ageFileFilter.accept(file)) {
                results.add(file);
            }
        }
    }

    private static final Logger logger = LoggerFactory.getLogger(FileWatcherJob.class);;

    /**
     * Checks new files and builds the List of files to pass to Observers
     * 
     * @param folder
     *            the root folder where to watch files
     * @param fileOnly
     *            if <code>true</code> we consider only files; otherwise we also consider folders
     * @param recursive
     *            should we recurse into sub-folders
     * @param checkDate
     *            do we need to check the last modification date or in case of <code>false</code> value just return all found files
     * @param lastCheckTime
     *            the last check time
     * @return a list of files and folders matching the provided criteria
     */
    protected List<File> checkFiles(File folder, boolean fileOnly, boolean recursive, boolean checkDate,
            long lastCheckTime, IOFileFilter ignoreFilter) {
        if (!folder.isDirectory()) {
            return Collections.emptyList();
        }
        List<File> files = null;
        if (fileOnly || !checkDate) {
            IOFileFilter fileFilter;
            IOFileFilter dirFilter;
            if (ignoreFilter != null) {
                fileFilter = checkDate ? new AndFileFilter(new AgeFileFilter(lastCheckTime, false), ignoreFilter)
                        : ignoreFilter;
                dirFilter = recursive ? ignoreFilter : FalseFileFilter.INSTANCE;
            } else {
                fileFilter = checkDate ? new AgeFileFilter(lastCheckTime, false) : TrueFileFilter.INSTANCE;
                dirFilter = recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE;
            }
            Collection<File> foundFiles = fileOnly ? FileUtils.listFiles(folder, fileFilter, dirFilter)
                    : FileUtils.listFilesAndDirs(folder, fileFilter, dirFilter);
            files = (foundFiles instanceof List<?>) ? (List<File>) foundFiles : new LinkedList<File>(foundFiles);
        } else {
            if (recursive) {
                try {
                    files = new Walker(lastCheckTime).execute(folder);
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            } else {
                Collection<File> foundFiles = FileUtils.listFilesAndDirs(folder,
                        ignoreFilter != null
                                ? new AndFileFilter(new AgeFileFilter(lastCheckTime, false), ignoreFilter)
                                : null,
                        FalseFileFilter.INSTANCE);
                files = (foundFiles instanceof List<?>) ? (List<File>) foundFiles
                        : new LinkedList<File>(foundFiles);
            }
        }

        return files;
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        FileWatcher fileWatcher = (FileWatcher) jobDataMap.get("fileWatcher");
        if (fileWatcher != null) {
            File folder = fileWatcher.getFolder();
            boolean fileOnly = fileWatcher.getFileOnly();
            boolean recursive = fileWatcher.isRecursive();
            IOFileFilter ignoreFilter = fileWatcher.getIgnoreFilter();
            List<File> changedFiles = checkFiles(folder, fileOnly, recursive, fileWatcher.getCheckDate(),
                    fileWatcher.getLastCheckTime(), ignoreFilter);
            fileWatcher.setLastCheckTime(System.currentTimeMillis());
            if (fileWatcher.getRemovedFiles()) {
                Collection<File> currentFiles;
                IOFileFilter filter = ignoreFilter != null ? ignoreFilter : TrueFileFilter.INSTANCE;
                if (fileOnly) {
                    currentFiles = FileUtils.listFiles(folder, filter,
                            recursive ? filter : FalseFileFilter.INSTANCE);
                } else {
                    currentFiles = FileUtils.listFilesAndDirs(folder, filter,
                            recursive ? filter : FalseFileFilter.INSTANCE);
                }
                Set<File> deletedFiles = new TreeSet<File>(new PathFileComparator());
                deletedFiles.addAll(fileWatcher.getPreviousFiles());
                deletedFiles.removeAll(currentFiles);
                changedFiles.addAll(deletedFiles);
                fileWatcher.setPreviousFiles(currentFiles);
            }

            // Notify Observers if number of files > 0
            if (changedFiles.size() > 0) {
                fileWatcher.externalSetChanged(); // Alert the Observable Object That there are change in the folder
                fileWatcher.notifyObservers(changedFiles);
            }
        }
    }
}