PerstDirectory.java :  » Database-DBMS » perst » org » garret » perst » continuous » Java Open Source

Java Open Source » Database DBMS » perst 
perst » org » garret » perst » continuous » PerstDirectory.java
package org.garret.perst.continuous;

import org.garret.perst.*;
import org.apache.lucene.store.*;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.*;

//
// For some strange reasons designed of Lucene have made Directory and anstract class and not interface
// (although all its methods are abstract)
// Frankly speaking I do not understand logic of Lucene designers - there completely no sense in
// delcaring abstract class with all abstract methods. Using interfaces is much flexible, natural and 
// convenient.
// Because Java doesn't support multiple inheritace I can no use inheritance and implement
// Directory methods directly, but use adapter class which just perform rediretion of method invocation.
//
class PerstDirectory extends Directory 
{    
    public PerstDirectory(RootObject root) { 
        impl = root.catalogue;            
        if (impl == null) { 
            impl = new PerstCatalogue(root.getStorage());
            root.setCatalogue(impl);
        }
    }

    static class PerstFile extends Persistent { 
        String name;
        long   timestamp;
        Blob   content;
        
        public void deallocate() {
            content.deallocate();
            super.deallocate();
        }

        PerstFile() {}
        PerstFile(String name) {
            this.name = name;
            timestamp = System.currentTimeMillis();
        }                              
    }

    static class PerstOutputStream extends BufferedIndexOutput { 
        PerstOutputStream(RandomAccessOutputStream stream) { 
            this.stream = stream;
        }

        protected void flushBuffer(byte[] b, int len) throws IOException {
            stream.write(b, 0, len);
        }

        public void seek(long pos) throws IOException {
            super.seek(pos);
            stream.setPosition(pos);
        }

        public long length() throws IOException { 
            return stream.size();
        }

        public void close() throws IOException {
            super.close();
            stream.close();
        }

        RandomAccessOutputStream stream;
    }

    static class PerstInputStream extends BufferedIndexInput { 
        PerstInputStream(RandomAccessInputStream stream) { 
            this.stream = stream;
        }

        public long length() { 
            return stream.size();
        }

        public Object clone() {
            PerstInputStream clone = (PerstInputStream)super.clone();
            clone.isClone = true;
            return clone;
        }


        protected void readInternal(byte[] b, int offset, int length) throws IOException {
            synchronized (stream) {
                stream.setPosition(getFilePointer());
                int rc = stream.read(b, offset, length);
                if (rc != length) { 
                    throw new IOException("Failed to read all requested data");
                }
            }
        }

        public void close() throws IOException {
            if (!isClone) { 
                stream.close();
            }
        }
        
        protected void seekInternal(long pos) throws IOException { 
        }
        
        RandomAccessInputStream stream;
        boolean                 isClone;
    }

    
    static class PerstLock extends Lock { 
        private boolean   locked;
        private IResource resource;

        /** Attempts to obtain exclusive access and immediately return
         *  upon success or failure.
         * @return true iff exclusive access is obtained
         */
        public boolean obtain() { 
            return locked = resource.exclusiveLock(0); 
        }

        /** Attempts to obtain an exclusive lock within amount
         *  of time given. Currently polls once per second until
         *  lockWaitTimeout is passed.
         * @param lockWaitTimeout length of time to wait in ms
         * @return true if lock was obtained
         * @throws IOException if lock wait times out or obtain() throws an IOException
         */
        public boolean obtain(long lockWaitTimeout) {
            return locked = resource.exclusiveLock(lockWaitTimeout);            
        }
            
        public void release() {
            if (locked) { 
                resource.unlock();
                locked = false;
            }
        }

        /** Returns true if the resource is currently locked.  Note that one must
         * still call {@link #obtain()} before using the resource. */
        public boolean isLocked() { 
            return locked;
        }

        PerstLock(IResource resource) { 
            this.resource = resource;
        }
    }

    static class PerstCatalogue extends PersistentResource { 
        private FieldIndex index;
                
        PerstCatalogue() {}
        
        PerstCatalogue(Storage storage) { 
            super(storage);
            index = storage.createFieldIndex(PerstFile.class, "name", true);
        }

        /** Returns an array of strings, one for each file in the directory. */
        public String[] list()
        {
            String[] names = new String[index.size()];
            Iterator iterator = index.entryIterator();
            for (int i = 0; i < names.length; i++) {
                names[i] = (String)((Map.Entry)iterator.next()).getKey();
            }
            return names;
        }
        
        /** Returns true iff a file with the given name exists. */
        public boolean fileExists(String name) 
        {
            return index.get(name) != null;
        }
        
        /** Returns the time the named file was last modified. */
        public long fileModified(String name) throws IOException 
        { 
            PerstFile file = (PerstFile)index.get(name);
            if (file == null) { 
                throw new FileNotFoundException(name);
            }
            return file.timestamp;
        }
        
        /** Set the modified time of an existing file to now. */
        public void touchFile(String name) throws IOException 
        {
            PerstFile file = (PerstFile)index.get(name);
            if (file == null) { 
                throw new FileNotFoundException(name);
            }
            file.timestamp = System.currentTimeMillis();
            file.modify();
        }
        
        /** Removes an existing file in the directory. */
        public void deleteFile(String name)throws IOException
        {        
            PerstFile file = (PerstFile)index.get(name);
            if (file == null) { 
                throw new FileNotFoundException(name);
            }
            index.remove(file);
            file.deallocate();
        }
        
        /** Renames an existing file in the directory.
            If a file already exists with the new name, then it is replaced.
            This replacement should be atomic. */
        public void renameFile(String from, String to) throws IOException
        {
            if (from.equals(to)) { 
                return;
            }
            PerstFile fromFile = (PerstFile)index.get(from);
            if (fromFile == null) { 
                throw new FileNotFoundException(from);
            }
            PerstFile toFile = (PerstFile)index.get(to);
            index.remove(fromFile);
            fromFile.name = to;
            index.set(fromFile);
            fromFile.modify();
            if (toFile != null) { 
                toFile.deallocate();
            }
        }

        /** Returns the length of a file in the directory. */
        public long fileLength(String name) throws IOException
        {        
            PerstFile file = (PerstFile)index.get(name);
            if (file == null) { 
                throw new FileNotFoundException(name);
            }
            return file.content.getInputStream().size();
        }
        
        /** Creates a new, empty file in the directory with the given name.
            Returns a stream writing this file. */
        public IndexOutput createOutput(String name) throws IOException
        {
            PerstFile file = (PerstFile)index.get(name);
            if (file == null) { 
                file = new PerstFile(name);
                index.put(file);
            } else { 
                file.content.deallocate();
            }
            file.content = getStorage().createRandomAccessBlob();
            file.modify();
            return new PerstOutputStream(file.content.getOutputStream(Blob.DOUBLE_SEGMENT_SIZE|Blob.ENABLE_SEGMENT_CACHING));
        }
        
        /** Returns a stream reading an existing file. */
        public IndexInput openInput(String name) throws IOException
        {
            PerstFile file = (PerstFile)index.get(name);
            if (file == null) { 
                throw new FileNotFoundException(name);
            }
            return new PerstInputStream(file.content.getInputStream(Blob.ENABLE_SEGMENT_CACHING));
        }
        
        /** Construct a {@link Lock}.
         * @param name the name of the lock file
         */
        public Lock makeLock(String name) { 
            return new PerstLock(this);
        }
        
        /** Closes the store. */
        public void close() {}
    }


    /** Returns an array of strings, one for each file in the directory. */
    public String[] list() throws IOException {
        return impl.list();
    }

    /** Returns true iff a file with the given name exists. */
    public boolean fileExists(String name) throws IOException {
        return impl.fileExists(name);
    }
    
    /** Returns the time the named file was last modified. */
    public long fileModified(String name) throws IOException {
        return impl.fileModified(name); 
    }

    /** Set the modified time of an existing file to now. */
    public void touchFile(String name) throws IOException {
        impl.touchFile(name); 
    }
        
    /** Removes an existing file in the directory. */
    public void deleteFile(String name) throws IOException {
        impl.deleteFile(name); 
    }

    /** Renames an existing file in the directory.
        If a file already exists with the new name, then it is replaced.
        This replacement should be atomic. 
        * @deprecated 
        */
    public void renameFile(String from, String to) throws IOException {
        impl.renameFile(from, to);
    }

    /** Returns the length of a file in the directory. */
    public long fileLength(String name) throws IOException {
        return impl.fileLength(name);
    }

    /** Creates a new, empty file in the directory with the given name.
        Returns a stream writing this file. */
    public IndexOutput createOutput(String name) throws IOException {
        return impl.createOutput(name);
    }

    /** Returns a stream reading an existing file. */
    public IndexInput openInput(String name) throws IOException {
        return impl.openInput(name);
    }

    /** Construct a {@link Lock}.
     * @param name the name of the lock file
     */
    public Lock makeLock(String name) {
        return impl.makeLock(name);
    }

    /** Closes the store. */
    public void close() throws IOException {
        impl.close();
    }

    private PerstCatalogue impl;
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.