Package pdfdb.indexing.fileservice

Source Code of pdfdb.indexing.fileservice.DbFileChangeMonitor

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package pdfdb.indexing.fileservice;

import pdfdb.data.db.*;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import pdfdb.indexing.plugins.Indexer;
import pdfdb.indexing.plugins.IndexingProvider;
import pdfdb.settings.IgnoredFileManager;
import pdfdb.structure.*;

/** A concrete implementation of the FileChecker for checking changes to the
* database. The Filechecker is concretely implemented in this class by passing
* itself as an argument to the FileChecker. Additional house keeping
* functionality for the database is also kept in this class.
* @author ug22cmg */
public class DbFileChangeMonitor extends AbstractFileChangeMonitor
{

    private boolean inShutdown = false;
    private boolean alteringFile = false;
    private String directory = null;
    private ExecutorService pool = Executors.newCachedThreadPool();
    private final Vector<Observer> observers = new Vector<Observer>();
    private final static Object LOCK = new Object();

    /** Initializes the DatabaseChangeManager with an initial directory.
     * @param directory The initial directory.
     * @throws java.sql.SQLException If an error occurs reading the
     * embedded database. */
    public DbFileChangeMonitor(String directory) throws SQLException
    {
        this.directory = directory;
    }

    /** Adds an observer to the file change provider.
     * @param observer non null observer. */
    public void addObserver(Observer observer)
    {
        if (observer == null || observers.contains(observer))
        {
            throw new IllegalArgumentException();
        }
        getObservers().add(observer);
    }

    /** Removes an observer of the file change provider.
     * @param observer A non null observer. */
    public void removeObserver(Observer observer)
    {
        if (observer == null)
        {
            throw new IllegalArgumentException();
        }
        getObservers().remove(observer);
    }

    /** Gets whether the indexing service is still running in an active
     *  state. Once all execution has completed and the system is
     * shutdown, this will return false.
     * @return True if running in active state */
    @Override
    public synchronized boolean isActive()
    {
        return super.isActive() || alteringFile;
    }

    /** Updates the database with the specified file change in a multithreaded
     * way ensuring the requirement for prompt response is met.
     * @param path The updated file path.
     * @param type The update type. */
    @Override
    public void fileChange(String path, ChangeType type)
    {
        pool.execute(new Updater(path, type));
    }

    /** Performs an update based on a change type.
     * @param type The type of change that has occured.
     * @param path The path of the file.
     * @throws java.sql.SQLException If a problem with accessing the database
     * occurs.
     * @throws java.io.IOException If a problem with accessing the file
     * occurs. */
    private void performUpdate(ChangeType type, String path)
            throws SQLException, IOException
    {
        boolean error = false;
        switch (type)
        {
            case ADDED:
            case UPDATED:
                IndexableFile file = FileProvider.addFile(path);

                if (file == null)
                {
                    IgnoredFileManager manager = IgnoredFileManager.getInstance();
                    manager.set(path, "Failed to index.");
                    manager.save();
                    error = true;
                }
                break;
            case REMOVED:
                FileProvider.deleteFile(path);
                break;

        }
        if (!isInShutdown() && !error) // if the indexer errors out
        {
            for (Observer observer : getObservers())
            {
                pool.execute(new Notifier(observer, path, type));
            }
        }
    }

    /** Gets the list of observers in a thread-safe way.
     * @return The list of observers. */
    private synchronized Vector<Observer> getObservers()
    {
        return observers;
    }

    /** Gets whether the file has changed.
     * @param path Path of the file to check.
     * @return True if the file is considered changed. */
    @Override
    public boolean hasChanged(String path)
    {
        return getChangeType(path) != ChangeType.NO_CHANGE;
    }

    /** Gets whether the specified file is used by the system, i.e.
     *  if the system has not ignored it and if there is a valid
     *  indexer for the system.
     * @param path The path to check.
     * @return True if the file should be considered. */
    @Override
    protected boolean isUsed(String path)
    {
        Indexer i = IndexingProvider.getIndexer(path);
        IgnoredFileManager manager = IgnoredFileManager.getInstance();
        return i != null && manager.get(path) == null;
    }

    /** Gets the type of change that has occured since the last database index.
     * @param path The path to the file
     * @return An instance of ChangeType. */
    @Override
    protected ChangeType getChangeType(String path)
    {
        IndexableFile file = null;
        try
        {
            file = FileProvider.getFile(path);
            if (file == null)
            {
                return ChangeType.ADDED;
            }
            else
            {
                File actualFile = new File(path);
                long lastIndexed = file.getLastIndexed().getTime();
                if (!actualFile.exists())
                {
                    return ChangeType.REMOVED;
                }
                if (actualFile.lastModified() > lastIndexed)
                {
                    return ChangeType.UPDATED;
                }
                return ChangeType.NO_CHANGE;
            }
        }
        catch(SQLException se)
        {
            System.err.println(se.getErrorCode());
            return ChangeType.NO_CHANGE;
        }
        finally
        {
            file = null;
        }
    }

    /** Gets whether the indexing is in shutdown mode.
     * @return True if the system is in shutdown. */
    private synchronized boolean isInShutdown()
    {
        return inShutdown;
    }

    /** Blocks until the active thread that is under the control of the
     *  FileChangeManager has completed. If the change manager is part of
     *  a thread pool, the pool must be in shutdown state before executing
     *  this method. */
    @Override
    public synchronized void shutdown()
    {
        inShutdown = true;
        super.shutdown();
    }

    /** Thread for notifying the observers. Used to ensure the notification
     *  thread is not hung up. */
    private class Notifier implements Runnable
    {

        private Observer o;
        private String path;
        private ChangeType type;

        /** Initializes the Notifier.
         * @param o The observer to be notified.
         * @param path The path that has been updated.
         * @param type The change type. */
        public Notifier(Observer o, String path, ChangeType type)
        {
            this.o = o;
            this.path = path;
            this.type = type;
        }

        /** Runs the update on a separate thread. */
        @Override
        public void run()
        {
            try
            {
                // Quite slow
                IndexableFile file = null;
                if (path != null) file = FileProvider.getFile(path);
                o.update(file, type);
            }
            catch (SQLException ex)
            {
            }
        }
    }

    /** Command to update the database in a separate thread. */
    private class Updater implements Runnable
    {

        private String path;
        private ChangeType type;

        /** Initializes a new Updater command.
         * @param path The path of the file.
         * @param type The change type.*/
        public Updater(String path, ChangeType type)
        {
            if (type == null || type == ChangeType.NO_CHANGE)
            {
                throw new IllegalArgumentException();
            }
            if (path == null)
            {
                throw new IllegalArgumentException();
            }
            this.type = type;
            this.path = path;
        }

        /** Runs the update */
        @Override
        public void run()
        {
            try
            {
                synchronized (LOCK)
                {
                    alteringFile = true;
                }
                performUpdate(type, path);
            }
            catch (Throwable ex)
            {
            }
            finally
            {
                alteringFile = false;
            }
        }
    }
}
TOP

Related Classes of pdfdb.indexing.fileservice.DbFileChangeMonitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.