gov.redhawk.efs.sca.internal.cache.FileCache.java Source code

Java tutorial

Introduction

Here is the source code for gov.redhawk.efs.sca.internal.cache.FileCache.java

Source

/** 
 * This file is protected by Copyright. 
 * Please refer to the COPYRIGHT file distributed with this source distribution.
 * 
 * This file is part of REDHAWK IDE.
 * 
 * All rights reserved.  This program and the accompanying materials are made available under 
 * the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html.
 *
 */
package gov.redhawk.efs.sca.internal.cache;

import gov.redhawk.efs.sca.internal.Messages;
import gov.redhawk.efs.sca.internal.ScaFileInputStream;
import gov.redhawk.efs.sca.internal.ScaFileStore;
import gov.redhawk.sca.efs.ScaFileSystemPlugin;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import mil.jpeojtrs.sca.util.ProtectedThreadExecutor;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.omg.CORBA.SystemException;

import CF.FileException;
import CF.FileSystemOperations;
import CF.InvalidFileName;

public class FileCache implements IFileCache {

    private static final int DEFAULT_BUFFER_SIZE = 4096;
    private static File tempDir;
    private File localFile;
    private ScaFileStore store;
    private String[] names;
    private long namesTimestamp;
    private FileSystemCache parent;
    private long childInfosTimestamp;
    private IFileInfo[] childInfos;
    private Boolean directory;
    private long directoryTimestamp;

    public FileCache(final ScaFileStore store, FileSystemCache parent) {
        this.store = store;
        this.parent = parent;
    }

    @Override
    public void update() throws CoreException {
        final IFileInfo info = store.fetchInfo();
        if (!isValid(info)) {
            downloadFile(info);
        }
    }

    @Override
    public synchronized InputStream openInputStream() throws CoreException {
        if (isDirectory()) {
            throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                    "Can not open input stream on directory.", new IOException().fillInStackTrace()));
        }
        update();
        try {
            return new FileInputStream(this.localFile);
        } catch (final FileNotFoundException e) {
            throw new CoreException(
                    new Status(IStatus.ERROR, ScaFileSystemPlugin.ID, "File cache error: " + this.localFile, e));
        }
    }

    private void downloadFile(IFileInfo info) throws CoreException {
        FileOutputStream fileStream = null;
        InputStream scaInputStream = null;
        File tmpFile = null;
        File parentDir = new File(
                FileCache.getTempDir() + "/" + parent.getRoot() + store.getEntry().getAbsolutePath())
                        .getParentFile();
        if (!parentDir.exists()) {
            try {
                FileUtils.forceMkdir(parentDir);
            } catch (IOException e) {
                throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                        "File cache error: Failed to create temporary file cache directory " + parentDir, e));
            }
        }
        localFile = new File(parentDir, store.getEntry().getName());
        if (localFile.exists() && localFile.lastModified() == info.getLastModified()) {
            if ((localFile.isDirectory() && info.isDirectory()) || (localFile.length() == info.getLength())) {
                return;
            }
        }

        boolean error = false;
        try {
            if (info.isDirectory()) {
                if (!info.exists()) {
                    FileUtils.forceMkdir(localFile);
                }
            } else {
                FileUtils.deleteQuietly(localFile);
                try {
                    tmpFile = File.createTempFile(localFile.getName(), ".tmp", parentDir);
                } catch (IOException e) {
                    throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                            "File cache error: Failed to create temporary file " + localFile, e));
                }
                tmpFile.deleteOnExit();
                scaInputStream = createScaInputStream();
                fileStream = new FileOutputStream(tmpFile);
                FileCache.copyLarge(scaInputStream, fileStream);
                localFile.setExecutable(info.getAttribute(EFS.ATTRIBUTE_EXECUTABLE));

                FileUtils.moveFile(tmpFile, localFile);
            }
            localFile.setLastModified(info.getLastModified());
        } catch (final FileNotFoundException e) {
            error = true;
            throw new CoreException(
                    new Status(IStatus.ERROR, ScaFileSystemPlugin.ID, "File cache error: " + localFile, e));
        } catch (final IOException e) {
            error = true;
            throw new CoreException(
                    new Status(IStatus.ERROR, ScaFileSystemPlugin.ID, "File cache error: " + localFile, e));
        } catch (CoreException e) {
            error = true;
            throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                    "File cache error: " + localFile + "\n" + e.getStatus().getMessage(),
                    e.getStatus().getException()));
        } catch (InterruptedException e) {
            error = true;
            throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                    "File download interrupted: " + localFile, e));
        } catch (ExecutionException e) {
            error = true;
            throw new CoreException(
                    new Status(IStatus.ERROR, ScaFileSystemPlugin.ID, "File cache error: " + localFile, e));
        } catch (TimeoutException e) {
            error = true;
            throw new CoreException(
                    new Status(IStatus.ERROR, ScaFileSystemPlugin.ID, "File download time-out: " + localFile, e));
        } finally {
            IOUtils.closeQuietly(fileStream);
            IOUtils.closeQuietly(scaInputStream);
            FileUtils.deleteQuietly(tmpFile);
            if (error) {
                if (localFile != null && localFile.exists()) {
                    FileUtils.deleteQuietly(localFile);
                }
                localFile = null;
            }
        }
    }

    private boolean isValid(IFileInfo info) {
        if (localFile == null || !localFile.exists() || localFile.lastModified() != info.getLastModified()) {
            return false;
        }
        return true;
    }

    private static long copyLarge(InputStream input, OutputStream output)
            throws IOException, InterruptedException, ExecutionException, TimeoutException {
        byte[] buffer = new byte[FileCache.DEFAULT_BUFFER_SIZE];
        long count = 0;
        int n = 0;
        while (-1 != (n = FileCache.readProtected(input, buffer))) {
            output.write(buffer, 0, n);
            count += n;
            if (Thread.currentThread().isInterrupted()) {
                throw new InterruptedException();
            }
        }
        return count;
    }

    private static int readProtected(final InputStream input, final byte[] buffer)
            throws IOException, InterruptedException, ExecutionException, TimeoutException {
        return ProtectedThreadExecutor.submit(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                return input.read(buffer);
            }

        }, 20, TimeUnit.SECONDS);
    }

    public static synchronized File getTempDir() {
        if (FileCache.tempDir == null) {
            String systemPath;
            try {
                IPath location = ScaFileSystemPlugin.getDefault().getStateLocation();
                systemPath = location.toFile().getAbsolutePath();
            } catch (IllegalStateException e) {
                String basePath = System.getProperty("java.io.tmpdir");
                String user = System.getProperty("user.name");
                systemPath = basePath + "/.redhawk/" + user;
            }

            String tempDirPath = systemPath + "/" + "fileCache";
            FileCache.tempDir = new File(tempDirPath);
        }
        return FileCache.tempDir;
    }

    private InputStream createScaInputStream() throws CoreException {
        final String path = store.getEntry().getAbsolutePath();
        try {
            FileSystemOperations fs = getScaFileSystem();

            return new ScaFileInputStream(fs.open(path, true));
        } catch (final InvalidFileName e) {
            throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                    NLS.bind(Messages.ScaFileStore__Open_Input_Stream_Error_Invalid_File_Name, path), e));
        } catch (final FileException e) {
            throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                    NLS.bind(Messages.ScaFileStore__Open_Input_Stream_Error_System, path), e));
        } catch (final SystemException e) {
            throw new CoreException(new Status(IStatus.ERROR, ScaFileSystemPlugin.ID,
                    NLS.bind(Messages.ScaFileStore__Open_Input_Stream_Error, path), e));
        }
    }

    @Override
    public synchronized String[] childNames(final int options, IProgressMonitor monitor) throws CoreException {
        final IFileInfo info = store.fetchInfo();
        long timestamp = info.getLastModified();
        if (names == null || namesTimestamp < timestamp) {
            namesTimestamp = timestamp;
            names = store.internalChildNames(options, monitor);
        }
        return names;
    }

    @Override
    public boolean isDirectory() {
        final IFileInfo info = store.fetchInfo();
        long timestamp = info.getLastModified();
        if (directory == null || directoryTimestamp < timestamp) {
            directoryTimestamp = timestamp;
            directory = store.fetchInfo().isDirectory();
        }
        return directory;
    }

    @Override
    public FileSystemOperations getScaFileSystem() throws CoreException {
        return parent.getScaFileSystem();
    }

    @Override
    public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException {
        final IFileInfo info = store.fetchInfo();
        long timestamp = info.getLastModified();
        if (childInfos == null || childInfosTimestamp < timestamp) {
            childInfosTimestamp = timestamp;
            childInfos = store.internalChildInfos(options, monitor);
        }
        return childInfos;
    }

    @Override
    public File toLocalFile() throws CoreException {
        update();
        if (isDirectory()) {
            IFileStore[] children = store.childStores(0, null);
            for (IFileStore child : children) {
                if (child instanceof ScaFileStore) {
                    IFileCache cache = ScaFileCache.INSTANCE.getCache((ScaFileStore) child);
                    cache.update();
                }
            }
        }
        return localFile;
    }
}