org.cryptomator.webdav.jackrabbit.AbstractEncryptedNode.java Source code

Java tutorial

Introduction

Here is the source code for org.cryptomator.webdav.jackrabbit.AbstractEncryptedNode.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Sebastian Stenzel
 * This file is licensed under the terms of the MIT license.
 * See the LICENSE.txt file for more info.
 * 
 * Contributors:
 *     Sebastian Stenzel - initial API and implementation
 ******************************************************************************/
package org.cryptomator.webdav.jackrabbit;

import java.io.IOException;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.FileTime;
import java.util.List;

import org.apache.commons.io.FilenameUtils;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavResource;
import org.apache.jackrabbit.webdav.DavResourceFactory;
import org.apache.jackrabbit.webdav.DavResourceLocator;
import org.apache.jackrabbit.webdav.DavServletResponse;
import org.apache.jackrabbit.webdav.DavSession;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.lock.ActiveLock;
import org.apache.jackrabbit.webdav.lock.LockInfo;
import org.apache.jackrabbit.webdav.lock.LockManager;
import org.apache.jackrabbit.webdav.lock.Scope;
import org.apache.jackrabbit.webdav.lock.Type;
import org.apache.jackrabbit.webdav.property.DavProperty;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import org.apache.jackrabbit.webdav.property.PropEntry;
import org.cryptomator.crypto.Cryptor;
import org.cryptomator.webdav.exceptions.IORuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

abstract class AbstractEncryptedNode implements DavResource {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractEncryptedNode.class);
    private static final String DAV_COMPLIANCE_CLASSES = "1, 2";

    protected final DavResourceFactory factory;
    protected final DavResourceLocator locator;
    protected final DavSession session;
    protected final LockManager lockManager;
    protected final Cryptor cryptor;
    protected final DavPropertySet properties;

    protected AbstractEncryptedNode(DavResourceFactory factory, DavResourceLocator locator, DavSession session,
            LockManager lockManager, Cryptor cryptor) {
        this.factory = factory;
        this.locator = locator;
        this.session = session;
        this.lockManager = lockManager;
        this.cryptor = cryptor;
        this.properties = new DavPropertySet();
        this.determineProperties();
    }

    @Override
    public String getComplianceClass() {
        return DAV_COMPLIANCE_CLASSES;
    }

    @Override
    public String getSupportedMethods() {
        return METHODS;
    }

    @Override
    public boolean exists() {
        final Path path = ResourcePathUtils.getPhysicalPath(this);
        return Files.exists(path);
    }

    @Override
    public String getDisplayName() {
        final String resourcePath = getResourcePath();
        final int lastSlash = resourcePath.lastIndexOf('/');
        if (lastSlash == -1) {
            return resourcePath;
        } else {
            return resourcePath.substring(lastSlash);
        }
    }

    @Override
    public DavResourceLocator getLocator() {
        return locator;
    }

    @Override
    public String getResourcePath() {
        return locator.getResourcePath();
    }

    @Override
    public String getHref() {
        return locator.getHref(this.isCollection());
    }

    @Override
    public long getModificationTime() {
        final Path path = ResourcePathUtils.getPhysicalPath(this);
        try {
            return Files.getLastModifiedTime(path).toMillis();
        } catch (IOException e) {
            return -1;
        }
    }

    protected abstract void determineProperties();

    @Override
    public DavPropertyName[] getPropertyNames() {
        return getProperties().getPropertyNames();
    }

    @Override
    public DavProperty<?> getProperty(DavPropertyName name) {
        return getProperties().get(name);
    }

    @Override
    public DavPropertySet getProperties() {
        return properties;
    }

    @Override
    public void setProperty(DavProperty<?> property) throws DavException {
        getProperties().add(property);

        LOG.info("Set property {}", property.getName());

        try {
            final Path path = ResourcePathUtils.getPhysicalPath(this);
            if (DavPropertyName.CREATIONDATE.equals(property.getName()) && property.getValue() instanceof String) {
                final String createDateStr = (String) property.getValue();
                final FileTime createTime = FileTimeUtils.fromRfc1123String(createDateStr);
                final BasicFileAttributeView attrView = Files.getFileAttributeView(path,
                        BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
                attrView.setTimes(null, null, createTime);
                LOG.info("Updating Creation Date: {}", createTime.toString());
            } else if (DavPropertyName.GETLASTMODIFIED.equals(property.getName())
                    && property.getValue() instanceof String) {
                final String lastModifiedTimeStr = (String) property.getValue();
                final FileTime lastModifiedTime = FileTimeUtils.fromRfc1123String(lastModifiedTimeStr);
                final BasicFileAttributeView attrView = Files.getFileAttributeView(path,
                        BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
                attrView.setTimes(lastModifiedTime, null, null);
                LOG.info("Updating Last Modified Date: {}", lastModifiedTime.toString());
            }
        } catch (IOException e) {
            throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public void removeProperty(DavPropertyName propertyName) throws DavException {
        getProperties().remove(propertyName);
    }

    @Override
    public MultiStatusResponse alterProperties(List<? extends PropEntry> changeList) throws DavException {
        final DavPropertyNameSet names = new DavPropertyNameSet();
        for (final PropEntry entry : changeList) {
            if (entry instanceof DavProperty) {
                final DavProperty<?> prop = (DavProperty<?>) entry;
                this.setProperty(prop);
                names.add(prop.getName());
            } else if (entry instanceof DavPropertyName) {
                final DavPropertyName name = (DavPropertyName) entry;
                this.removeProperty(name);
                names.add(name);
            }
        }
        return new MultiStatusResponse(this, names);
    }

    @Override
    public DavResource getCollection() {
        if (locator.isRootLocation()) {
            return null;
        }

        final String parentResource = FilenameUtils.getPath(locator.getResourcePath());
        final DavResourceLocator parentLocator = locator.getFactory().createResourceLocator(locator.getPrefix(),
                locator.getWorkspacePath(), parentResource);
        try {
            return getFactory().createResource(parentLocator, session);
        } catch (DavException e) {
            throw new IllegalStateException(
                    "Unable to get parent resource with path " + parentLocator.getResourcePath(), e);
        }
    }

    @Override
    public void move(DavResource dest) throws DavException {
        final Path src = ResourcePathUtils.getPhysicalPath(this);
        final Path dst = ResourcePathUtils.getPhysicalPath(dest);
        try {
            // check for conflicts:
            if (Files.exists(dst)
                    && Files.getLastModifiedTime(dst).toMillis() > Files.getLastModifiedTime(src).toMillis()) {
                throw new DavException(DavServletResponse.SC_CONFLICT,
                        "File at destination already exists: " + dst.toString());
            }

            // move:
            try {
                Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
            } catch (AtomicMoveNotSupportedException e) {
                Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING);
            }
        } catch (IOException e) {
            LOG.error("Error moving file from " + src.toString() + " to " + dst.toString());
            throw new IORuntimeException(e);
        }
    }

    @Override
    public void copy(DavResource dest, boolean shallow) throws DavException {
        final Path src = ResourcePathUtils.getPhysicalPath(this);
        final Path dst = ResourcePathUtils.getPhysicalPath(dest);
        try {
            // check for conflicts:
            if (Files.exists(dst)
                    && Files.getLastModifiedTime(dst).toMillis() > Files.getLastModifiedTime(src).toMillis()) {
                throw new DavException(DavServletResponse.SC_CONFLICT,
                        "File at destination already exists: " + dst.toString());
            }

            // copy:
            try {
                Files.copy(src, dst, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING,
                        StandardCopyOption.ATOMIC_MOVE);
            } catch (AtomicMoveNotSupportedException e) {
                Files.copy(src, dst, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
            }
        } catch (IOException e) {
            LOG.error("Error copying file from " + src.toString() + " to " + dst.toString());
            throw new IORuntimeException(e);
        }
    }

    @Override
    public boolean isLockable(Type type, Scope scope) {
        return true;
    }

    @Override
    public boolean hasLock(Type type, Scope scope) {
        return lockManager.getLock(type, scope, this) != null;
    }

    @Override
    public ActiveLock getLock(Type type, Scope scope) {
        return lockManager.getLock(type, scope, this);
    }

    @Override
    public ActiveLock[] getLocks() {
        final ActiveLock exclusiveWriteLock = getLock(Type.WRITE, Scope.EXCLUSIVE);
        return new ActiveLock[] { exclusiveWriteLock };
    }

    @Override
    public ActiveLock lock(LockInfo reqLockInfo) throws DavException {
        return lockManager.createLock(reqLockInfo, this);
    }

    @Override
    public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken) throws DavException {
        return lockManager.refreshLock(reqLockInfo, lockToken, this);
    }

    @Override
    public void unlock(String lockToken) throws DavException {
        lockManager.releaseLock(lockToken, this);
    }

    @Override
    public void addLockManager(LockManager lockmgr) {
        throw new UnsupportedOperationException("Locks are managed");
    }

    @Override
    public DavResourceFactory getFactory() {
        return factory;
    }

    @Override
    public DavSession getSession() {
        return session;
    }

}