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

com.redhat.ceylon.cmr.webdav.WebDAVContentStore 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.webdav;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.Proxy;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.redhat.ceylon.cmr.impl.NodeUtils;
import com.redhat.ceylon.cmr.impl.URLContentStore;
import com.redhat.ceylon.cmr.repository.webdav.WebDAVInputStream;
import com.redhat.ceylon.cmr.repository.webdav.WebDAVRepository;
import com.redhat.ceylon.cmr.repository.webdav.WebDAVResource;
import com.redhat.ceylon.cmr.spi.ContentHandle;
import com.redhat.ceylon.cmr.spi.ContentOptions;
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.common.log.Logger;
import com.redhat.ceylon.model.cmr.RepositoryException;

/**
 * WebDAV content store.
 *
 * @author Ales Justin
 * @author Stef Epardaud
 */
public class WebDAVContentStore extends URLContentStore {

    private boolean forcedAuthenticationForPutOnHerd = false;
    private WebDAVRepository repository;

    /**
     * For tests only!!!
     */
    public WebDAVContentStore(String root, Logger log, boolean offline, int timeout, Proxy proxy, String apiVersion) {
        super(root, log, offline, timeout, proxy, apiVersion);
        this.repository = new WebDAVRepository(timeout, null, null);
    }

    /**
     * WARNING: used by reflection from CeylonUtils
     */
    public WebDAVContentStore(String root, Logger log, boolean offline, int timeout, Proxy proxy, 
            String username, String password) {
        super(root, log, offline, timeout, proxy);
        setUsername(username);
        setPassword(password);
        this.repository = new WebDAVRepository(timeout, username, password);
    }

    @Override
    public OpenNode create(Node parent, String child) {
        if (!connectionAllowed()) {
            return null;
        }
        try {
            if (!isHerd())
                mkdirs(parent);
            return createNode(child);
        } catch (IOException e) {
            throw convertIOException(e);
        }
    }

    @Override
    public ContentHandle peekContent(Node node) {
        if (!connectionAllowed()) {
            return null;
        }
        try {
            final String url = getUrlAsString(node);
            return (repository.exists(url) ? new WebDAVContentHandle(url) : null);
        } catch (IOException e) {
            return null;
        }
    }

    @Override
    public ContentHandle getContent(Node node) throws IOException {
        return new WebDAVContentHandle(getUrlAsString(node));
    }

    @Override
    public ContentHandle putContent(Node node, InputStream stream, ContentOptions options) throws IOException {
        if (!connectionAllowed()) {
            return null;
        }
        try {
            /*
             * Most disgusting trick ever. Stef failed to set up Sardine to do preemptive auth on all hosts
             * and ports (may only work on port 80, reading the code), so when not using Herd we generate a ton
             * of requests that will trigger auth, but not for Herd. So we start with a PUT and that replies with
             * an UNAUTHORIZED response, which Sardine can't handle because the InputStream is not "restartable".
             * By making an extra HEAD request (restartable because no entity body) we force the auth to happen.
             * Yuk.
             */
            if (isHerd() && !forcedAuthenticationForPutOnHerd) {
                repository.exists(getUrlAsString(node));
                forcedAuthenticationForPutOnHerd = true;
            }
            final Node parent = NodeUtils.firstParent(node);
            if (!isHerd())
                mkdirs(parent);

            final String pUrl = getUrlAsString(parent);
            String token = null;
            if (!isHerd())
                token = repository.lock(pUrl); // local parent
            final String url = getUrlAsString(node);
            try {
                repository.put(url, stream);
                return new WebDAVContentHandle(url);
            } catch (SocketTimeoutException x) {
                SocketTimeoutException ret = new SocketTimeoutException("Timed out writing to "+url);
                ret.initCause(x);
                throw ret;
            } finally {
                if (!isHerd())
                    repository.unlock(pUrl, token);
            }
        } catch (IOException x) {
            throw convertIOException(x);
        }
    }

    private RepositoryException convertIOException(IOException x) {
        String msg = repository.getBetterExceptionMessage(x, this.root);
        if(msg != null){
            return new RepositoryException(msg);
        }
        return new RepositoryException(x);
    }

    private void mkdirs(Node parent) throws IOException {
        if (parent == null)
            return;

        mkdirs(NodeUtils.firstParent(parent));

        final String url = getUrlAsString(parent);
        if (repository.exists(url) == false) {
            repository.createDirectory(url);
        }
    }

    @Override
    protected ContentHandle createContentHandle(Node parent, String child, String path, Node node) {
        return new WebDAVContentHandle(root + path);
    }

    @Override
    public Iterable find(Node parent) {
        if (!connectionAllowed()) {
            return Collections.emptyList();
        }
        final String url = getUrlAsString(parent);
        try {
            final List nodes = new ArrayList<>();
            final List resources = repository.list(url);
            for (WebDAVResource dr : resources) {
                final String label = dr.getName();
                final RemoteNode node = new RemoteNode(label);
                if (dr.isDirectory())
                    node.setContentMarker();
                else
                    node.setHandle(new WebDAVContentHandle(url + label));
                nodes.add(node);
            }
            return nodes;
        } catch (IOException e) {
            log.debug("Failed to list url: " + url);
            return Collections.emptyList();
        }
    }

    @Override
    protected boolean urlExists(String path) {
        if (!connectionAllowed()) {
            return false;
        }
        try {
            return repository.exists(getUrlAsString(path));
        } catch (IOException e) {
            log.debug("Failed to check url: " + path);
            return false;
        }
    }

    @Override
    protected boolean urlExists(URL url) {
        if (!connectionAllowed()) {
            return false;
        }
        try {
            return repository.exists(url.toExternalForm());
        } catch (IOException e) {
            log.debug("Failed to check url: " + url);
            return false;
        }
    }

    @Override
    public String toString() {
        return "WebDAV content store: " + root;
    }

    private class WebDAVContentHandle implements ContentHandle {

        private final String url;

        private WebDAVContentHandle(String url) {
            this.url = url;
        }

        @Override
        public boolean hasBinaries() {
            if (!connectionAllowed()) {
                return false;
            }
            try {
                final List list = repository.list(url);
                return list.size() == 1 && list.get(0).isDirectory() == false;
            } catch (IOException e) {
                log.warning("Cannot list resources: " + url + "; error - " + e);
                return false;
            }
        }

        @Override
        public InputStream getBinariesAsStream() throws IOException {
            SizedInputStream ret = getBinariesAsSizedStream();
            return ret != null ? ret.getInputStream() : null;
        }
        
        @Override
        public SizedInputStream getBinariesAsSizedStream() throws IOException {
            if (!connectionAllowed()) {
                return null;
            }
            WebDAVInputStream inputStream = repository.get(url);
            Long length = inputStream.getLength();
            return new SizedInputStream(inputStream.getInputStream(), length != null ? length.longValue() : -1);
        }

        @Override
        public File getContentAsFile() throws IOException {
            return null;
        }

        @Override
        public long getSize() throws IOException {
            if (connectionAllowed()) {
                if (isHerd()) {
                    return size(new URL(url));
                }

                final List list = repository.list(url);
                if (list.isEmpty() == false && list.get(0).isDirectory() == false) {
                    Long length = list.get(0).getContentLength();
                    if (length != null) {
                        return length;
                    }
                }
            }
            return -1L;
        }

        @Override
        public long getLastModified() throws IOException {
            if (connectionAllowed()) {
                if (isHerd()) {
                    return lastModified(new URL(url));
                }

                final List list = repository.list(url);
                if (list.isEmpty() == false && list.get(0).isDirectory() == false) {
                    Date modified = list.get(0).getModified();
                    if (modified != null) {
                        return modified.getTime();
                    }
                }
            }
            return -1L;
        }

        @Override
        public void clean() {
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy