org.jclouds.vfs.provider.blobstore.BlobStoreFileObject.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.vfs.provider.blobstore.BlobStoreFileObject.java

Source

/**
 *
 * Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
 *
 * ====================================================================
 * 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 org.jclouds.vfs.provider.blobstore;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.blobstore.util.BlobStoreUtils.newBlob;
import static org.jclouds.util.Patterns.LEADING_SLASHES;
import static org.jclouds.util.Patterns.TRAILING_SLASHES;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.Channels;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.vfs.FileName;
import org.apache.commons.vfs.FileNotFolderException;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileType;
import org.apache.commons.vfs.FileTypeHasNoContentException;
import org.apache.commons.vfs.NameScope;
import org.apache.commons.vfs.RandomAccessContent;
import org.apache.commons.vfs.provider.AbstractFileObject;
import org.apache.commons.vfs.util.FileObjectUtils;
import org.apache.commons.vfs.util.MonitorOutputStream;
import org.apache.commons.vfs.util.RandomAccessMode;
import org.apache.log4j.Logger;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.ConcatenateContainerLists;
import org.jclouds.io.Payloads;
import org.jclouds.util.Utils;

import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

/**
 * @author Adrian Cole
 */
public class BlobStoreFileObject extends AbstractFileObject {
    private final BlobStoreContext context;
    private final ConcatenateContainerLists lister;
    private final String container;
    private StorageMetadata metadata;
    private static final Logger logger = Logger.getLogger(BlobStoreFileObject.class);
    private static final Pattern UNDESCRIBED = Pattern.compile("[^/]*//*");

    public BlobStoreFileObject(FileName fileName, BlobStoreFileSystem fileSystem, BlobStoreContext context,
            String container) throws FileSystemException {
        super(fileName, fileSystem);
        this.context = checkNotNull(context, "context");
        this.container = checkNotNull(container, "container");
        this.lister = checkNotNull(new ConcatenateContainerLists(context.getBlobStore()), "lister");

    }

    private class BlobStoreOutputStream extends MonitorOutputStream {

        private final BlobStore context;
        private final Blob blob;
        private final File file;

        public BlobStoreOutputStream(File file, BlobStore context, Blob blob) throws FileNotFoundException {
            super(Channels.newOutputStream(new RandomAccessFile(file, "rw").getChannel()));
            this.context = context;
            this.file = file;
            this.blob = blob;
        }

        protected void onClose() throws IOException {
            try {
                blob.setPayload(file);
                Payloads.calculateMD5(blob);
                logger.info(String.format(">> put: %s/%s %d bytes", getContainer(), getNameTrimLeadingSlashes(),
                        blob.getPayload().getContentMetadata().getContentLength()));
                String tag = context.putBlob(getContainer(), blob);
                logger.info(String.format("<< tag %s: %s/%s", tag, getContainer(), getNameTrimLeadingSlashes()));
            } finally {
                file.delete();
            }
        }
    }

    public static File allocateFile() throws IOException {
        return File.createTempFile("jclouds.", ".blobstore");
    }

    @Override
    protected long doGetContentSize() throws Exception {
        if (metadata == null && metadata.getType() == StorageType.BLOB)
            getMetadataAtPath(getNameTrimLeadingSlashes());

        if (metadata != null && metadata.getType() == StorageType.BLOB) {
            BlobMetadata blobMd = BlobMetadata.class.cast(metadata);
            return blobMd.getContentMetadata().getContentLength() != null
                    ? blobMd.getContentMetadata().getContentLength()
                    : 0;
        }
        return 0;
    }

    @Override
    protected InputStream doGetInputStream() throws Exception {
        if (!getType().hasContent()) {
            throw new FileSystemException("vfs.provider/read-not-file.error", getName());
        }
        if (metadata != null && metadata.getType() != StorageType.BLOB) {
            throw new FileTypeHasNoContentException(getName());
        }
        logger.info(String.format(">> get: %s/%s", getContainer(), getNameTrimLeadingSlashes()));
        Blob blob = getBlobStore().getBlob(getContainer(), getNameTrimLeadingSlashes());
        return blob.getPayload().getInput();
    }

    String getNameTrimLeadingSlashes() {
        return Utils.replaceAll(getName().getPath(), LEADING_SLASHES, "");
    }

    @Override
    protected FileType doGetType() throws Exception {
        if (metadata == null)
            return FileType.IMAGINARY;
        if (getNameTrimLeadingSlashes().equals("") || getName().getParent() == null)
            return FileType.FOLDER;
        return (metadata.getType() == StorageType.BLOB) ? FileType.FILE : FileType.FOLDER;
    }

    @Override
    protected FileObject[] doListChildrenResolved() throws Exception {
        // if metadata is null, then the path does not exist, as doAttach would have certainly set
        // this.
        doAttach();
        if (metadata == null)
            throw new FileNotFolderException(getName());
        ListContainerOptions options = new ListContainerOptions();
        String name = getNameTrimLeadingSlashes();
        if (!name.equals("") && !name.equals("/")) {
            options.inDirectory(name + "/");
            logger.info(String.format(">> list: %s[%s]", getContainer(), name));
        } else {
            logger.info(String.format(">> list: %s", getContainer()));
        }
        Iterable<? extends StorageMetadata> list = lister.execute(getContainer(), options);
        Set<BlobStoreFileObject> children = Sets.newHashSet();
        loop: for (StorageMetadata md : list) {
            if (!md.getName().equals("")) {
                if (name.equals(md.getName()) && md.getType() != StorageType.BLOB) {
                    continue loop;
                }
                String childName = Utils.replaceAll(md.getName(), UNDESCRIBED, "");
                BlobStoreFileObject fo = (BlobStoreFileObject) FileObjectUtils
                        .getAbstractFileObject(getFileSystem().resolveFile(getFileSystem().getFileSystemManager()
                                .resolveName(getName(), childName, NameScope.CHILD)));
                children.add(fo);
            }
        }
        logger.info(String.format("<< list: %s", children));
        return children.toArray(new BlobStoreFileObject[] {});
    }

    @Override
    public FileObject[] getChildren() throws FileSystemException {
        if (metadata != null && metadata.getType() == StorageType.BLOB)
            throw new FileNotFolderException(getName());
        if (metadata == null) {
            try {
                FileType type = doGetType();
                if (type == FileType.FILE) {
                    throw new FileNotFolderException(getName());
                }
            } catch (Exception ex) {
                Throwables.propagateIfPossible(ex, FileNotFolderException.class);
                throw new FileNotFolderException(getName(), ex);
            }
        }
        return super.getChildren();
    }

    /**
     * Lists the children of the file.
     */
    protected String[] doListChildren() throws Exception {
        // use doListChildrenResolved for performance
        return null;
    }

    @Override
    protected void doDelete() throws Exception {
        logger.info(String.format(">> delete: %s/%s", getContainer(), getNameTrimLeadingSlashes()));
        if (metadata != null)
            deleteBasedOnType();
        else
            deleteBlob(getNameTrimLeadingSlashes());
    }

    private void deleteBasedOnType() {
        if (metadata.getType() != StorageType.CONTAINER) {
            deleteBlob(metadata.getProviderId());
        } else {
            getBlobStore().deleteContainer(getContainer());
            logger.info(String.format("<< deleted container: %s", getContainer()));
        }
    }

    private void deleteBlob(String id) {
        getBlobStore().removeBlob(getContainer(), getNameTrimLeadingSlashes());
        logger.info(String.format("<< deleted blob: %s/%s", getContainer(), getNameTrimLeadingSlashes()));
    }

    @Override
    protected OutputStream doGetOutputStream(boolean bAppend) throws Exception {
        File file = allocateFile();
        checkState(file != null, "file was null");
        if (metadata != null) {
            return new BlobStoreOutputStream(file, getBlobStore(), newBlob(getBlobStore(), metadata));
        } else {
            return new BlobStoreOutputStream(file, getBlobStore(),
                    getBlobStore().newBlob(getNameTrimLeadingSlashes()));
        }
    }

    @Override
    protected void doCreateFolder() throws Exception {
        logger.info(String.format(">> put folder: %s/%s", getContainer(), getNameTrimLeadingSlashes()));
        getBlobStore().createDirectory(getContainer(), getNameTrimLeadingSlashes());
    }

    @Override
    protected void doAttach() throws Exception {
        String name = getNameTrimLeadingSlashes();
        if (name.equals("")) {
            logger.info(String.format(">> head: %s", getContainer()));
            getContainer(name);
        } else {
            logger.info(String.format(">> head: %s/%s", getContainer(), name));
            try {
                getMetadataAtPath(name);
            } catch (KeyNotFoundException e) {
                tryDirectoryAtPath(name);
            }
        }
    }

    private void getContainer(String name) {
        metadata = Iterables.find(getBlobStore().list(), new Predicate<StorageMetadata>() {
            @Override
            public boolean apply(StorageMetadata input) {
                return input.getType() == StorageType.CONTAINER && input.getName().equals(container);
            }
        });
        logger.info(String.format("<< container: %s/%s", container, name));
    }

    private void getMetadataAtPath(String name) {
        metadata = getBlobStore().blobMetadata(getContainer(), name);
        if (metadata.getType() != StorageType.BLOB) {
            logger.info(String.format("<< dir: %s/%s", getContainer(), name));
        } else {
            logger.info(String.format("<< blob: %s/%s", getContainer(), name));
        }
    }

    private void tryDirectoryAtPath(final String name) {
        ListContainerOptions options = new ListContainerOptions();
        if (getName().getParent() != null) {
            String dir = trimLeadingAndTrailingSlashes(getName().getParent().getPath());
            if (!dir.equals(""))
                options.inDirectory(dir);
        }
        try {
            metadata = Iterables.find(lister.execute(getContainer(), options), new Predicate<StorageMetadata>() {
                @Override
                public boolean apply(StorageMetadata input) {
                    return input.getType() != StorageType.BLOB && input.getName().equals(name);
                }
            });
            logger.info(String.format("<< dir: %s/%s", getContainer(), name));
        } catch (NoSuchElementException nse) {
            metadata = null;
            logger.info(String.format("<< not found: %s/%s", getContainer(), name));
        } catch (ContainerNotFoundException cnfe) {
            metadata = null;
            logger.info(String.format("<< not found: %s", getContainer()));
        }
    }

    public String trimLeadingAndTrailingSlashes(String in) {
        return Utils.replaceAll(Utils.replaceAll(in, LEADING_SLASHES, ""), TRAILING_SLASHES, "");
    }

    @Override
    protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception {
        return new BlobStoreRandomAccessContent(this, mode);
    }

    protected void doDetach() throws Exception {
        metadata = null;
    }

    @Override
    protected long doGetLastModifiedTime() throws Exception {
        if (metadata == null || metadata.getLastModified() == null) {
            getMetadataAtPath(getNameTrimLeadingSlashes());
        }
        return metadata.getLastModified() != null ? metadata.getLastModified().getTime()
                : super.doGetLastModifiedTime();
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Map doGetAttributes() throws Exception {
        if (metadata == null || metadata.getUserMetadata() == null) {
            getMetadataAtPath(getNameTrimLeadingSlashes());
        }
        return metadata.getUserMetadata() != null ? metadata.getUserMetadata() : super.doGetAttributes();
    }

    @Override
    protected void doSetAttribute(String atttrName, Object value) throws Exception {
        if (metadata == null || metadata.getUserMetadata() == null) {
            metadata.getUserMetadata().put(atttrName, value.toString());
        }
        super.doSetAttribute(atttrName, value);
    }

    public BlobStore getBlobStore() {
        return context.getBlobStore();
    }

    public String getContainer() {
        return container;
    }
}