All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.cmr.impl.FileContentStore Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright 2011 Red Hat inc. and third party contributors as noted 
 * by the author tags.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.redhat.ceylon.cmr.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.redhat.ceylon.cmr.spi.ContentHandle;
import com.redhat.ceylon.cmr.spi.ContentOptions;
import com.redhat.ceylon.cmr.spi.ContentStore;
import com.redhat.ceylon.cmr.spi.Node;
import com.redhat.ceylon.cmr.spi.OpenNode;
import com.redhat.ceylon.cmr.spi.SizedInputStream;
import com.redhat.ceylon.cmr.spi.StructureBuilder;
import com.redhat.ceylon.common.FileUtil;

/**
 * File content store.
 *
 * @author Ales Justin
 */
public class FileContentStore implements ContentStore, StructureBuilder {

    private final File root;
    private final ConcurrentMap cache = new ConcurrentHashMap<>();

    public FileContentStore(File root) {
        if (root == null)
            throw new IllegalArgumentException("Null root!");
        this.root = root;
    }

    @Override
    public String toString() {
        return "FileContentStore: " + root;
    }

    @Override
    public String getDisplayString() {
        return root.getPath();
    }

    File getFile(Node node) {
        if (node == null)
            throw new IllegalArgumentException("Null node");

        return getFileInternal(node);
    }

    private File getFileInternal(Node node) {
        if (node == null)
            return root;

        File file = cache.get(node);
        if (file == null) {
            File parent = getFileInternal(NodeUtils.firstParent(node));
            file = new File(parent, node.getLabel()); // bevare of concatinated names; e.g sha1.local
            cache.put(node, file);
        }
        return file;
    }

    void removeFile(Node node) {
        File file = cache.remove(node);
        if (file == null)
            file = getFile(node);

        delete(file, node);
    }

    void clear() {
        cache.clear();
    }

    protected ContentHandle createContentHandle(Node owner, File file) {
        return file.isDirectory() ? new FolderContentHandle(owner, file) : new FileContentHandle(owner, file);
    }

    public ContentHandle peekContent(Node node) {
        final File file = getFile(node);
        return file.exists() ? createContentHandle(node, file) : null;
    }

    public ContentHandle getContent(Node node) throws IOException {
        final File file = getFile(node);
        if (file.exists() == false)
            throw new IOException("Content doesn't exist: " + file);

        return createContentHandle(node, file);
    }

    public ContentHandle putContent(Node node, InputStream stream, ContentOptions options) throws IOException {
        if (stream == null)
            throw new IllegalArgumentException("Null stream!");
        if (options == null)
            throw new IllegalArgumentException("Null options!");

        if (!root.exists() && !FileUtil.mkdirs(root)) {
            throw new IOException("Cannot create Ceylon repository directory: " + root);
        }
        if (!root.isDirectory()) {
            throw new IOException("Ceylon repository is not a directory: " + root);
        }
        final File parent = getFile(NodeUtils.firstParent(node));
        if (parent.exists() == false && parent.mkdirs() == false)
            throw new IOException("Cannot create dirs: " + parent);

        File file;
        if (parent.isDirectory()) {
            file = new File(parent, node.getLabel());
        } else {
            final String path = parent.getPath();
            file = new File(path + node.getLabel()); // just concat paths
        }

        boolean success = false;
        try{
            IOUtils.writeToFile(file, stream);
            success = true;
        }catch(SocketTimeoutException ex){
            SocketTimeoutException newEx = new SocketTimeoutException("Timed out reading "+node.getDisplayString()+" from "+node.getStoreDisplayString());
            newEx.initCause(ex);
            throw newEx;
        }finally{
            // at least try to clean it up if it's partial
            if(!success)
                file.delete();
        }
        return new FileContentHandle(node, file);
    }

    public OpenNode createRoot() {
        return new RootNode(this, this);
    }

    public OpenNode create(Node parent, String child) {
        final File pf = getFile(parent);
        final File file = new File(pf, child);
        final DefaultNode node = new DefaultNode(child);
        node.setHandle(new FolderContentHandle(node, file));
        return node;
    }

    public OpenNode find(Node parent, String child) {
        final File pf = getFile(parent);

        File file;
        if (pf.isDirectory()) {
            file = new File(pf, child);
        } else {
            final String path = pf.getPath();
            file = new File(path + child); // just concat paths
        }

        if (file.exists()) {
            final DefaultNode node = new DefaultNode(child);
            node.setHandle(createContentHandle(node, file));
            return node;
        } else {
            return null;
        }
    }

    public Iterable find(Node parent) {
        final File pf = getFile(parent);
        if (pf.exists()) {
            List nodes = new ArrayList<>();
            for (File file : pf.listFiles()) {
                DefaultNode node = new DefaultNode(file.getName());
                node.setHandle(createContentHandle(node, file));
                nodes.add(node);
            }
            return nodes;
        } else {
            return Collections.emptyList();
        }
    }

    protected void delete(File file, Node node) {
        if (file == null)
            throw new IllegalArgumentException("Null file");
        if (node == null)
            throw new IllegalArgumentException("Null node");

        if (root.equals(file))
            return;

        File[] files = file.listFiles();
        if ((files == null || files.length == 0) && (file.exists() == false || file.delete())) {
            cache.remove(node); // remove from cache, since probably not used anymore
            delete(file.getParentFile(), NodeUtils.firstParent(node));
        }
    }

    private class FileContentHandle implements ContentHandle {

        protected Node owner;
        protected File file;

        private FileContentHandle(Node owner, File file) {
            this.owner = owner;
            this.file = file;
        }

        public boolean hasBinaries() {
            return true;
        }

        public InputStream getBinariesAsStream() throws IOException {
            return new FileInputStream(file);
        }

        public SizedInputStream getBinariesAsSizedStream() throws IOException {
            return new SizedInputStream(getBinariesAsStream(), file.length());
        }

        public File getContentAsFile() throws IOException {
            return file;
        }

        public long getLastModified() throws IOException {
            return file.lastModified();
        }

        public long getSize() throws IOException {
            return file.length();
        }

        public void clean() {
            delete(file, owner);
        }
    }

    private class FolderContentHandle extends FileContentHandle {

        private FolderContentHandle(Node owner, File file) {
            super(owner, file);
        }

        @Override
        public boolean hasBinaries() {
            return false;
        }

        @Override
        public InputStream getBinariesAsStream() throws IOException {
            return null;
        }

        @Override
        public void clean() {
            try {
                IOUtils.deleteRecursively(file);
            } finally {
                super.clean();
            }
        }
    }

    @Override
    public boolean isOffline() {
        return true;
    }

    @Override
    public int getTimeout() {
        return 0;
    }

    @Override
    public boolean isHerd() {
        return false;
    }

    @Override
    public boolean canHandleFolders() {
        return true;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy