it.geosolutions.filesystemmonitor.neutral.monitorpolling.GBFileSystemMonitorJob.java Source code

Java tutorial

Introduction

Here is the source code for it.geosolutions.filesystemmonitor.neutral.monitorpolling.GBFileSystemMonitorJob.java

Source

/*
 *  GeoBatch - Open Source geospatial batch processing system
 *  http://geobatch.geo-solutions.it/
 *  Copyright (C) 2007-2012 GeoSolutions S.A.S.
 *  http://www.geo-solutions.it
 *
 *  GPLv3 + Classpath exception
 *
 *  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/>.
 */
package it.geosolutions.filesystemmonitor.neutral.monitorpolling;

import it.geosolutions.filesystemmonitor.monitor.FileSystemEventType;
import it.geosolutions.filesystemmonitor.monitor.FileSystemMonitorSPI;
import it.geosolutions.tools.io.file.IOUtils;

import java.io.File;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@PersistJobDataAfterExecution
public class GBFileSystemMonitorJob implements Job {
    private final static Logger LOGGER = LoggerFactory.getLogger(GBFileSystemMonitorJob.class);

    // protected static final String ROOT_PATH_KEY=FileSystemMonitorSPI.SOURCE_KEY;
    // protected static final String WILDCARD_KEY=FileSystemMonitorSPI.WILDCARD_KEY;
    // protected static final String EVENT_TYPE_KEY=FileSystemMonitorSPI.TYPE_KEY;

    protected static final String OBSERVER_KEY = "OBSERVER";

    protected static final String EVENT_NOTIFIER_KEY = "EVENT_NOTIFIER";

    // KEY time to wait to get the lock
    protected static final String WAITING_LOCK_TIME_KEY = "WAITING_LOCK_TIME";

    // VALUE time to wait to get the lock
    protected static final long WAITING_LOCK_TIME_DEFAULT = IOUtils.MAX_WAITING_TIME_FOR_LOCK; // milliseconds

    /**
     * Define a policy. Refer to the Quartz Exception Handler documentation to define a new policy
     * 
     * @author Carlo Cancellieri - carlo.cancellieri@geo-solutions.it
     */
    private enum ExcPolicy { // Exceptions Policy

        IMMEDIATELY
        // throw immediately
    }; // Exceptions Policy

    /*
     * The lock to synchronize multiple calls to this job instance
     */

    private Lock lock = new ReentrantLock();

    /**
     * This is called by the JobDetail constructor, you'll never should call this constructor by
     * hand.
     */
    public GBFileSystemMonitorJob() {
    }

    /**
     * Decide the Exception policy for this job
     * 
     * @param message
     *            - The message to use handling the exception
     * @param policy
     *            an ExcPolicy selecting the desired policy to apply
     * @return a JobExecutionException or null depending on the selected policy
     * @throws JobExecutionException
     *             can throw the JobExecutionException depending on the selected policy
     */
    private static JobExecutionException exceptionPolicy(ExcPolicy policy, String message, Throwable cause)
            throws JobExecutionException {
        JobExecutionException jee;

        if (cause != null)
            jee = new JobExecutionException(message, cause);
        else
            jee = new JobExecutionException(message);

        switch (policy) {
        case IMMEDIATELY:
            if (LOGGER.isErrorEnabled())
                LOGGER.error(message);
            jee.refireImmediately();
            break;
        // TODO OTHER POLICY HERE
        default:
            if (LOGGER.isErrorEnabled())
                LOGGER.error(message);
            jee.refireImmediately();
            break;
        }
        return jee;
    }

    /**
     * Commodity to call the default exception policy
     * 
     * @param message
     *            - The message to use handling the exception
     * @return a JobExecutionException or null depending on the default policy
     * @throws JobExecutionException
     *             can throw the JobExecutionException depending on the default policy
     */
    private static JobExecutionException exceptionPolicy(String message) throws JobExecutionException {
        return exceptionPolicy(null, message, null);
    }

    /**
     * Commodity to call the default exception policy
     * 
     * @param message
     *            - The message to use handling the exception
     * @return a JobExecutionException or null depending on the default policy
     * @throws JobExecutionException
     *             can throw the JobExecutionException depending on the default policy
     */
    private static JobExecutionException exceptionPolicy(ExcPolicy policy, String message)
            throws JobExecutionException {
        return exceptionPolicy(policy, message, null);
    }

    /**
     * Try to obtain the observer from a previous stored job
     * 
     * @param jdm
     * @return
     * @throws JobExecutionException
     */
    private static FileAlterationObserver getObserver(JobDataMap jdm) throws JobExecutionException {
        Object obj = null;
        if ((obj = jdm.get(OBSERVER_KEY)) != null) {
            if (obj instanceof FileAlterationObserver)
                return (FileAlterationObserver) obj;
            else {
                throw exceptionPolicy(ExcPolicy.IMMEDIATELY, "Unable to get previously generated observer!");
            }
        } else
            return null;

    }

    /**
     * Try to build the Observer using informations stored into the JobDataMap
     * 
     * @note this method is not sync
     * @param jdm
     * @return
     * @throws JobExecutionException
     */
    private static FileAlterationObserver buildObserver(JobDataMap jdm) throws JobExecutionException {

        FileAlterationObserver observer = null;
        final GBEventNotifier notifier;
        // first time build
        try {
            final File directory = new File(jdm.getString(FileSystemMonitorSPI.SOURCE_KEY));

            observer = new FileAlterationObserver(directory,
                    new WildcardFileFilter(jdm.getString(FileSystemMonitorSPI.WILDCARD_KEY)));

            notifier = (GBEventNotifier) jdm.get(EVENT_NOTIFIER_KEY);

            final FileAlterationListener fal = new GBFileAlterationListener(notifier);

            observer.addListener(fal);
        } catch (ClassCastException cce) {
            // ClassCastException - if the identified object is not a String.
            throw exceptionPolicy(ExcPolicy.IMMEDIATELY,
                    "The identified object is not a String.\n" + cce.getLocalizedMessage(), cce);

        } catch (NullPointerException npe) {
            // NullPointerException - If the pathname argument is null
            throw exceptionPolicy(ExcPolicy.IMMEDIATELY,
                    "The pathname argument is null.\n" + npe.getLocalizedMessage(), npe);
        } catch (IllegalArgumentException iae) {
            // IllegalArgumentException - if the pattern is null
            throw exceptionPolicy(ExcPolicy.IMMEDIATELY, "The pattern is null.\n" + iae.getLocalizedMessage(), iae);
        } catch (Throwable e) {
            throw exceptionPolicy(ExcPolicy.IMMEDIATELY,
                    "Probably the consumer cannot start.\n" + e.getLocalizedMessage(), e);
        }

        try {
            observer.initialize();
        } catch (Throwable t) {
            throw exceptionPolicy(ExcPolicy.IMMEDIATELY, "An error occurs.\n" + t.getLocalizedMessage(), t);
        }

        jdm.put(OBSERVER_KEY, observer);

        return observer;
    }

    /**
     * the job. You'll never may call this method manually, (this is executed by the quartz
     * Scheduler).
     */
    public void execute(JobExecutionContext context) throws JobExecutionException {

        final JobDetail detail = context.getJobDetail();

        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Starting FSM job named: " + detail.getKey()); // TODO or key?
        }

        final JobDataMap jdm = detail.getJobDataMap();

        // WORKAROUND
        /*
         * 1Giu2011 Carlo: 
         * Added POLLING_EVENT to implement a Quartz EventGenerator using quartz file system.
         * The returned file path represent the instant when the event is executed (in millisecs)
         */
        if (jdm.get(FileSystemMonitorSPI.TYPE_KEY) == FileSystemEventType.POLLING_EVENT) {
            final GBEventNotifier notifier = (GBEventNotifier) jdm.get(EVENT_NOTIFIER_KEY);
            notifier.notifyEvent(new File(Long.toString(System.currentTimeMillis())),
                    FileSystemEventType.POLLING_EVENT);
            return;
        }
        //WORKAROUND

        FileAlterationObserver observer = null;

        if ((observer = getObserver(jdm)) == null) {
            // System.out.println("if1 done sync");
            try {
                long wait = WAITING_LOCK_TIME_DEFAULT; // default wait in seconds
                try {
                    wait = jdm.getLong(WAITING_LOCK_TIME_KEY);
                } catch (ClassCastException cce) {
                    // NOT HANDLED: using default value
                }
                // System.out.println("WAIT"+wait);
                lock.tryLock(wait, TimeUnit.MILLISECONDS);
                // System.out.println("if1 + synch done if2");
                if ((observer = getObserver(jdm)) == null) {
                    // System.out.println("all is done building");
                    if (LOGGER.isDebugEnabled())
                        LOGGER.debug("Building the observer tree...");

                    observer = buildObserver(jdm);

                    if (LOGGER.isDebugEnabled())
                        LOGGER.debug("Observer tree complete.");
                }
            } catch (InterruptedException ex) {
                LOGGER.error("GBFileSystemMonitorJob interrupted during setup", ex);

            } catch (Exception ex) {
                LOGGER.error("GBFileSystemMonitorJob interrupted during setup", ex);

            } finally {
                lock.unlock();
            }

        } // first time initializer ends

        // do the job
        observer.checkAndNotify();
        // DEBUG
        // System.out.println("DOTHEJOB");

        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("job named: " + detail.getKey() + " completed");
        }
    }
}