Package pdfdb.data.db

Source Code of pdfdb.data.db.FileProvider

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

import java.io.File;
import java.io.IOException;
import java.sql.*;
import java.util.Hashtable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import pdfdb.indexing.plugins.Indexer;
import pdfdb.indexing.plugins.IndexingException;
import pdfdb.indexing.plugins.IndexingProvider;
import pdfdb.structure.*;

/** Provides external access to the database layer. A layer of abstraction
* ensuring external classes never deal with SQL, or connections. This class
* contains SQL and communicates directly with the DatabaseConnection class.
* @author ug22cmg */
public class FileProvider
{

    public final static int NO_LIMIT = Integer.MIN_VALUE;
    private static IndexableFileList fullList = new IndexableFileList();
    private static Hashtable<Integer, IndexableFileList> searchList =
            new Hashtable<Integer, IndexableFileList>();
    private static ReadWriteLock lock = new ReentrantReadWriteLock();

    /** Initializes the file provider by caching the contents of the
     * database. This is a slow operation and would be performed in a
     * multi-threaded context to allow other operations to continue.
     * @throws java.sql.SQLException If an error occurs. */
    public static void initialize() throws SQLException
    {
        for (IndexableFile file : getFiles(NO_LIMIT))
        {
            addToCache(file);
        }
    }

    /** Gets the total number of files.
     * @return The number of files. */
    public static int getFileCount()
    {
        return getList().size();
    }

    /** Gets the file cache for a specific word id.
     * @param wordId The word id.
     * @return The cached file list. */
    public static IndexableFileList getFilesForSearch(int wordId)
    {
        return getSearchList().get(wordId);
    }

    /** Clones the cached files.
     * @return An indexable file list instance. */
    public static IndexableFileList getCloneOfCache()
    {
        return (IndexableFileList) getList().clone();
    }

    /** Deletes a file from the database.
     * @param conn The connection to use.
     * @param fileName The filename to delete.
     * @throws java.sql.SQLException if an error occurs. */
    private static void deleteFile(Connection conn, String fileName) throws
            SQLException
    {
        String sql = "DELETE FROM Files WHERE FilePath = ?";
        PreparedStatement statement = null;
        try
        {
            removeFromCache(fileName);
            removeThumbnails(conn, fileName);
            statement = conn.prepareStatement(sql);
            statement.setString(1, fileName);
            statement.executeUpdate();
        }
        finally
        {
            DatabaseConnection.close(statement);
        }
    }

    /** Removes the thumbnail file associated with the specified indexed
     *  filename if one exists.
     * @param conn The connection to use to get required information.
     * @param fileName The filename that may have thumbnails associated. */
    private static void removeThumbnails(Connection conn, String fileName)
    {
        try
        {
            IndexableFile file = getFile(conn, fileName);
            Hashtable<String, String> properties = file.getProperties();
            String thumbnail = properties.get("THUMBNAIL");
            if (thumbnail != null)
            {
                File f = new File(thumbnail);
                if (f.exists()) f.delete();
            }
        }
        catch (Exception e)
        {
        }
    }

    /** Removes a file from the cache.
     * @param path The path to remove. */
    private static void removeFromCache(String path)
    {
        try
        {
            IndexableFile file = FileProvider.getFile(path);
            if (file != null)
            {
                getList().remove(path);
                for (Region r : file.getRegions())
                {
                    for (Integer wordId : r.getIndexes().keySet())
                    {
                        IndexableFileList list = getSearchList().get(wordId);
                        if (list != null) list.remove(file);
                    }
                }
            }
        }
        catch (SQLException ex)
        {
        }
    }

    /** Adds the file into the cache.
     * @param file The file to add. */
    private static void addToCache(IndexableFile file)
    {
        getList().add(file);
        for (Region r : file.getRegions())
        {
            for (Integer wordId : r.getIndexes().keySet())
            {
                IndexableFileList list = getSearchList().get(wordId);
                if (list == null)
                {
                    getSearchList().put(wordId, new IndexableFileList());
                    list = getSearchList().get(wordId);
                }
                if (!list.contains(file)) list.add(file);
            }
        }
    }

    /** Deletes a file from the database using a new connection.
     * @param fileName The filename.
     * @throws java.sql.SQLException If an error occurs. */
    public static void deleteFile(String fileName) throws SQLException
    {
        Lock l = lock.writeLock();
        Connection conn = null;
        try
        {
            l.lock();
            conn = DatabaseConnection.getNewConnection();
            deleteFile(conn, fileName);
        }
        finally
        {
            l.unlock();
            DatabaseConnection.close(conn);
        }
    }

    /** Gets a single file from the database.
     * @param path The path to get.
     * @return The file instance or null.
     * @throws SQLException If used after shutdown */
    public static IndexableFile getFile(String path) throws SQLException
    {
        Connection conn = null;
        Lock l = lock.readLock();
        try
        {
            l.lock();
            conn = DatabaseConnection.getNewConnection();
            return getFile(conn, path);
        }
        finally
        {
            l.unlock();
            DatabaseConnection.close(conn);
        }
    }

    /** Gets a file from the database using the connection specified.
     * @param conn The connection to use.
     * @param path The path to get.
     * @return The file instance or null.
     * @throws SQLException If used after shutdown. */
    private static IndexableFile getFile(Connection conn, String path) throws
            SQLException
    {
        PreparedStatement statement = null;
        ResultSet rs = null;
        try
        {
            final String sql = "SELECT LastIndexed FROM Files WHERE " +
                    "FilePath = ?";
            statement =
                    conn.prepareStatement(sql);
            statement.setString(1, path);
            rs =
                    statement.executeQuery();
            if (rs.next())
            {
                IndexableFile file = new IndexableFile(path, rs.getDate(
                        "LastIndexed"));
                file.setRegions(RegionProvider.getRegions(path));
                file.setProperties(PropertyProvider.getProperties(conn, path));
                return file;
            }
            else
                return null;
        }
        catch (SQLException se)
        {
            return null;
        }
        finally
        {
            DatabaseConnection.close(statement, rs);
        }

    }

    /** Gets limit number of files from the database in most recently
     *  indexed order.
     * @param limit Either the number of files to limit the query by
     * or NO_LIMIT.
     * @return IndexableFileList containing less than or equal to limit
     * files.
     * @throws java.sql.SQLException If an error occurs. */
    public static IndexableFileList getFiles(int limit) throws
            SQLException
    {
        Lock l = lock.readLock();
        Connection conn = null;
        IndexableFileList list = new IndexableFileList();
        Statement statement = null;
        ResultSet rs = null;
        String sql = "SELECT FilePath, LastIndexed FROM Files " +
                "ORDER BY LastIndexed DESC";
        try
        {
            l.lock();
            conn = DatabaseConnection.getNewConnection();
            statement = conn.createStatement();
            if (limit != NO_LIMIT)
                statement.setMaxRows(limit);
            rs =
                    statement.executeQuery(sql);
            while (rs.next())
            {
                String path = rs.getString("FilePath");
                IndexableFile file = new IndexableFile(path, rs.getDate(
                        "LastIndexed"));
                file.setRegions(RegionProvider.getRegions(path));
                file.setProperties(
                        PropertyProvider.getProperties(conn, path));
                list.add(file);
            }

        }
        catch (SQLException se)
        {
        }
        finally
        {
            l.unlock();
            DatabaseConnection.close(statement, rs);
            DatabaseConnection.close(conn);
        }

        return list;
    }

    /** Indexes a file using the indexer provided by the IndexingProvider.
     * @param path The path to index.
     * @return The region array that the indexer provides.
     * @throws pdfdb.indexing.plugins.IndexingException If the file is
     * unindexable. */
    private static Region[] indexFile(String path) throws IndexingException
    {
        Indexer indexer = IndexingProvider.getIndexer(path);
        Region[] regions = indexer.index(path);
        if (regions == null)
            throw new IndexingException();
        else
            return regions;
    }

    /** Starts a database transaction.
     * @param conn The connection to start a transaction with.
     * @throws java.sql.SQLException If there is a problem connecting to the
     * database. */
    private static void startTransaction(Connection conn) throws SQLException
    {
        Statement s = null;
        try
        {
            s = conn.createStatement();
            s.execute("CHECKPOINT");
        }
        finally
        {
            DatabaseConnection.close(s);
        }

    }

    /** Indexes and adds a file to the database.
     * @param path The path to add.
     * @return The IndexableFile instance or null if unsuccessful */
    public static IndexableFile addFile(String path)
    {
        Lock l = lock.writeLock();
        IndexableFile file = null;
        Connection conn = null;
        try
        {
            l.lock();
            conn = DatabaseConnection.getNewConnection();
            conn.setAutoCommit(false);
            startTransaction(conn);
            deleteFile(conn, path);
            java.util.Date d1 = new java.util.Date();
            long time = d1.getTime();
            java.sql.Date d2 = new java.sql.Date(time);
            file = insertFile(conn, path, d2);
            file.setProperties(PropertyProvider.getProperties(conn, path));
            conn.commit();
            addToCache(file);
            return file;
        }
        catch (Throwable ex)
        {
            try
            {
                rollback(conn);
            }
            catch (SQLException ex1)
            {
            }
            return null;
        }
        finally
        {
            l.unlock();
            DatabaseConnection.close(conn);
        }
    }

    /** Rolls back the database.
     * @param conn The connection to rollback.
     * @throws java.sql.SQLException If an error occurs. */
    private static void rollback(Connection conn) throws SQLException
    {
        Statement statement = null;
        try
        {
            if (conn != null)
            {
                statement = conn.createStatement();
                statement.execute("ROLLBACK");
            }

        }
        finally
        {
            if (statement != null) statement.close();
        }

    }

    /** Performs the database insert for adding a file, its regions and
     * indexes. The file should not exist before calling this method.
     * @param conn The connection object to use.
     * @param path The path of the file.
     * @param date The date of the indexing.
     * @return An instance of the IndexableFile object that represents the data
     * that has been added or null if an error occurred.
     * @throws java.sql.SQLException If the database cannot be accessed.
     * @throws java.io.IOException If the file cannot be read. */
    private static IndexableFile insertFile(Connection conn, String path,
            Date date)
            throws SQLException, IOException, IndexingException
    {
        String sql = "INSERT INTO Files(FilePath, LastIndexed) VALUES(?, ?)";
        PreparedStatement statement = null;
        try
        {
            IndexableFile file = new IndexableFile(path, date);
            Region[] regions = null;
            statement =
                    conn.prepareStatement(sql);
            statement.setString(1, path);
            statement.setDate(2, date);
            statement.executeUpdate();
            regions =
                    indexFile(path);
            if (regions == null) throw new IndexingException();
            file.setRegions(regions);
            return file;
        }
        finally
        {
            DatabaseConnection.close(statement);
        }

    }

    /** Gets the cached file list in a threadsafe way.
     * @return The list. */
    private static synchronized IndexableFileList getList()
    {
        return fullList;
    }

    /** Gets the cached search list in a threadsafe way.
     * @return The list. */
    private static synchronized Hashtable<Integer, IndexableFileList> getSearchList()
    {
        return searchList;
    }
}
TOP

Related Classes of pdfdb.data.db.FileProvider

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.