Package org.apache.commons.vfs.provider.webdav

Source Code of org.apache.commons.vfs.provider.webdav.WebdavFileObject$WebdavOutputStream

/*
* Copyright 2002-2005 The Apache Software Foundation.
*
* 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.apache.commons.vfs.provider.webdav;

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileType;
import org.apache.commons.vfs.NameScope;
import org.apache.commons.vfs.RandomAccessContent;
import org.apache.commons.vfs.provider.AbstractFileObject;
import org.apache.commons.vfs.provider.AbstractRandomAccessContent;
import org.apache.commons.vfs.provider.GenericFileName;
import org.apache.commons.vfs.provider.URLFileName;
import org.apache.commons.vfs.util.MonitorOutputStream;
import org.apache.commons.vfs.util.RandomAccessMode;
import org.apache.webdav.lib.BaseProperty;
import org.apache.webdav.lib.WebdavResource;
import org.apache.webdav.lib.methods.DepthSupport;
import org.apache.webdav.lib.methods.OptionsMethod;
import org.apache.webdav.lib.methods.XMLResponseMethodBase;
import org.apache.webdav.lib.properties.ResourceTypeProperty;

import java.io.DataInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
* A WebDAV file.
*
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
*/
public class WebdavFileObject
    extends AbstractFileObject
    implements FileObject
{
    private final WebDavFileSystem fileSystem;
    private final String urlCharset;
    private WebdavResource resource;
    private boolean redirectionResolved = false;
    private Set allowedMethods = null;
    // private HttpURL url;

    private static volatile int tmpFileCount = 0;
    private static final Object tmpFileCountSync = new Object();

    protected WebdavFileObject(final GenericFileName name,
                               final WebDavFileSystem fileSystem)
    {
        super(name, fileSystem);
        this.fileSystem = fileSystem;
        this.urlCharset = WebdavFileSystemConfigBuilder.getInstance().getUrlCharset(getFileSystem().getFileSystemOptions());
    }

    /**
     * Attaches this file object to its file resource.
     */
    protected void doAttach() throws Exception
    {
        if (resource == null)
        {
            setDavResource(null);
        }
    }

    protected void doDetach() throws Exception
    {
        if (resource != null)
        {
            // clear cached data
            redirectionResolved = false;
            allowedMethods = null;

            resource.close();
            resource = null;
        }
    }

    /**
     * set the davResource
     *
     * @param resource
     * @throws Exception
     */
    private void setDavResource(WebdavResource resource) throws Exception
    {
        redirectionResolved = false;

        final URLFileName name = (URLFileName) getName();

        if (resource == null)
        {
            // HttpURL url = new HttpURL(name.getHostName(), name.getPort(), name.getPath());
            String pathEncoded = name.getPathQueryEncoded(urlCharset);
            HttpURL url = new HttpURL(name.getUserName(), name.getPassword(), name.getHostName(), name.getPort());
            url.setEscapedPath(pathEncoded);
            resource = new WebdavResource(fileSystem.getClient())
            {
            };
            resource.setHttpURL(url, WebdavResource.NOACTION, 1);
        }

        this.resource = resource;

        // if (bCheckExists)
        {
            /* now fill the dav properties */
            String pathEncoded = name.getPathQueryEncoded(urlCharset);
            final OptionsMethod optionsMethod = new OptionsMethod(pathEncoded);
            try
            {
                optionsMethod.setFollowRedirects(true);
                final int status = fileSystem.getClient().executeMethod(optionsMethod);
                if (status < 200 || status > 299)
                {
                    if (status == 401 || status == 403)
                    {
                        setAllowedMethods(null);

                        // permission denied on this object, but we might get some informations from the parent
                        processParentDavResource();
                        return;
                    }
                    else
                    {
                        injectType(FileType.IMAGINARY);
                    }
                    return;
                }
                // handle the (maybe) redirected url
                redirectionResolved = true;
                resource.getHttpURL().setEscapedPath(optionsMethod.getURI().getPath());

                setAllowedMethods(optionsMethod.getAllowedMethods());
                boolean exists = false;
                for (Enumeration enumeration = optionsMethod.getAllowedMethods(); enumeration.hasMoreElements();)
                {
                    final String method = (String) enumeration.nextElement();
                    // IIS allows GET even if the file is non existend - so changed to COPY
                    // if (method.equals("GET"))
                    if (method.equals("COPY"))
                    {
                        exists = true;
                        break;
                    }
                }
                if (!exists)
                {
                    injectType(FileType.IMAGINARY);
                    return;
                }

                try
                {
                    resource.setProperties(WebdavResource.DEFAULT, 1);
                }
                catch (IOException e)
                {
                    throw new FileSystemException(e);
                }
            }
            finally
            {
                optionsMethod.releaseConnection();
            }
        }

        ResourceTypeProperty resourceType = resource.getResourceType();
        if (resourceType.isCollection())
        {
            injectType(FileType.FOLDER);
        }
        else
        {
            injectType(FileType.FILE);
        }
    }

    private void setAllowedMethods(Enumeration allowedMethods)
    {
        this.allowedMethods = new TreeSet();

        if (allowedMethods == null)
        {
            return;
        }

        while (allowedMethods.hasMoreElements())
        {
            this.allowedMethods.add(allowedMethods.nextElement());
        }
    }

    private boolean hasAllowedMethods(String method) throws IOException
    {
        if (allowedMethods == null)
        {
            getAllowedMethods();
        }

        return allowedMethods.contains(method);
    }

    private void resolveRedirection() throws IOException, FileSystemException
    {
        if (redirectionResolved)
        {
            return;
        }

        final OptionsMethod optionsMethod = new OptionsMethod(getName().getPath());
        try
        {
            optionsMethod.setFollowRedirects(true);
            final int status = fileSystem.getClient().executeMethod(optionsMethod);
            if (status >= 200 && status <= 299)
            {
                setAllowedMethods(optionsMethod.getAllowedMethods());
                resource.getHttpURL().setEscapedPath(optionsMethod.getPath());
                redirectionResolved = true;
            }
        }
        finally
        {
            optionsMethod.releaseConnection();
        }
    }

    private void processParentDavResource() throws FileSystemException
    {
        WebdavFileObject parent = (WebdavFileObject) getParent();
        try
        {
            // after this our resource should be reset
            parent.doListChildrenResolved();
        }
        catch (Exception e)
        {
            throw new FileSystemException(e);
        }
    }

    /**
     * Determines the type of the file, returns null if the file does not
     * exist.
     */
    protected FileType doGetType() throws Exception
    {
        // return doGetType(null);
        throw new IllegalStateException("this should not happen");
    }

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

    /**
     * Lists the children of the file.
     */
    protected FileObject[] doListChildrenResolved() throws Exception
    {
        doAttach();

        WebdavResource[] children = new org.apache.webdav.lib.WebdavResource[0];
        try
        {
            children = resource.listWebdavResources();
        }
        catch (HttpException e)
        {
            if (e.getReasonCode() == HttpStatus.SC_MOVED_PERMANENTLY || e.getReasonCode() == HttpStatus.SC_MOVED_TEMPORARILY)
            {
                resolveRedirection();
                children = resource.listWebdavResources();
            }
            else
            {
                throw e;
            }
        }

        if (children == null)
        {
            throw new FileSystemException("vfs.provider.webdav/list-children.error", resource.getStatusMessage());
        }

        List vfs = new ArrayList(children.length);
        // WebdavFileObject[] vfs = new WebdavFileObject[children.length];
        for (int i = 0; i < children.length; i++)
        {
            WebdavResource dav = children[i];

            String davName = dav.getHttpURL().getEscapedName();
            if ("".equals(davName))
            {
                // current file
                continue;
            }

            WebdavFileObject fo = (WebdavFileObject) getFileSystem().resolveFile(
                getFileSystem().getFileSystemManager().resolveName(
                    getName(),
                    davName,
                    NameScope.CHILD));
            fo.setDavResource(dav);

            // vfs[i] = fo;
            vfs.add(fo);
        }

        return (WebdavFileObject[]) vfs.toArray(new WebdavFileObject[vfs.size()]);
        // return vfs;
    }

    /**
     * Creates this file as a folder.
     */
    protected void doCreateFolder() throws Exception
    {
        // Adjust resource path
        //// resource.getHttpURL().setEscapedPath(getName().getPath() + '/');
        resource.getHttpURL().setPath(getName().getPathDecoded() + '/');
        final boolean ok = resource.mkcolMethod();
        if (!ok)
        {
            throw new FileSystemException("vfs.provider.webdav/create-collection.error", resource.getStatusMessage());
        }

        // reread allowed methods
        reattach();
    }

    /**
     * Deletes the file.
     */
    protected void doDelete() throws Exception
    {
        resolveRedirection();
        // final boolean ok = resource.deleteMethod(getName().getPathDecoded() /*url.getPath()*/);
        final boolean ok = resource.deleteMethod();
        if (!ok)
        {
            throw new FileSystemException("vfs.provider.webdav/delete-file.error", resource.getStatusMessage());
        }

        // reread allowed methods
        reattach();
    }

    /**
     * Rename the file.
     */
    protected void doRename(FileObject newfile) throws Exception
    {
        // final GenericFileName name = (GenericFileName) newfile.getName();
        // HttpURL url = new HttpURL(name.getUserName(), name.getPassword(), name.getHostName(), name.getPort(), newfile.getName().getPath());
        // String uri = url.getURI();

        final boolean ok = resource.moveMethod(newfile.getName().getPath());
        if (!ok)
        {
            throw new FileSystemException("vfs.provider.webdav/rename-file.error", resource.getStatusMessage());
        }

        // reread allowed methods
        reattach();
    }

    /**
     * Creates an input stream to read the file content from.
     */
    protected InputStream doGetInputStream() throws Exception
    {
        return resource.getMethodData();
    }

    /**
     * Creates an output stream to write the file content to.
     */
    protected OutputStream doGetOutputStream(boolean bAppend) throws Exception
    {
        int fileCount;
        FileObject webdavTmp;
        synchronized (tmpFileCountSync)
            {
                tmpFileCount++;
                fileCount = tmpFileCount;
            }
        webdavTmp = getFileSystem().getFileSystemManager().resolveFile("tmp://webdav_tmp.c" + fileCount);
        return new WebdavOutputStream(webdavTmp);
    }

    /**
     * Returns the size of the file content (in bytes).
     */
    protected long doGetContentSize() throws Exception
    {
        return resource.getGetContentLength();
    }

    /**
     * An OutputStream that writes to a Webdav resource.
     *
     * @todo Use piped stream to avoid temporary file
     */
    private class WebdavOutputStream
        extends MonitorOutputStream
    {
        private final FileObject webdavTmp;

        public WebdavOutputStream(FileObject webdavTmp) throws FileSystemException
        {
            super(webdavTmp.getContent().getOutputStream());
            this.webdavTmp = webdavTmp;
        }

        /**
         * Called after this stream is closed.
         */
        protected void onClose() throws IOException
        {
            // final ByteArrayOutputStream outstr = (ByteArrayOutputStream) out;

            // Adjust the resource path (this file object may have been a folder)
            resource.getHttpURL().setPath(getName().getPathDecoded());
            // final boolean ok = resource.putMethod(outstr.toByteArray());
            try
            {
                final boolean ok = resource.putMethod(webdavTmp.getContent().getInputStream());
                if (!ok)
                {
                    throw new FileSystemException("vfs.provider.webdav/write-file.error", resource.getStatusMessage());
                }
            }
            finally
            {
                // close and delete the temporary file
                webdavTmp.close();
                webdavTmp.delete();
            }
        }
    }

    protected void handleCreate(final FileType newType) throws Exception
    {
        // imario@apache.org: this is to reread the webdav internal state
        // Ill treat this as workaround
        reattach();
        super.handleCreate(newType);
    }

    /**
     * refresh the webdav internals
     *
     * @throws FileSystemException
     */
    private void reattach() throws FileSystemException
    {
        try
        {
            doDetach();
            doAttach();
        }
        catch (Exception e)
        {
            throw new FileSystemException(e);
        }
    }

    /**
     * Returns the last modified time of this file.  Is only called if
     * {@link #doGetType} does not return {@link FileType#IMAGINARY}.
     */
    protected long doGetLastModifiedTime() throws Exception
    {
        return resource.getGetLastModified();
    }

    /**
     * Returns the properties of the Webdav resource.
     */
    protected Map doGetAttributes() throws Exception
    {
        final Map attributes = new HashMap();
        final Enumeration e = resource.propfindMethod(DepthSupport.DEPTH_0);
        while (e.hasMoreElements())
        {
            final XMLResponseMethodBase.Response response = (XMLResponseMethodBase.Response) e.nextElement();
            final Enumeration properties = response.getProperties();
            while (properties.hasMoreElements())
            {
                final BaseProperty property = (BaseProperty) properties.nextElement();
                attributes.put(property.getLocalName(), property.getPropertyAsString());
            }
        }

        return attributes;
    }

    protected boolean doIsReadable() throws Exception
    {
        return hasAllowedMethods("GET");
    }

    protected boolean doIsWriteable() throws Exception
    {
        // Again to be IIS compatible
        // return hasAllowedMethods("POST");
        return hasAllowedMethods("DELETE");
    }

    private void getAllowedMethods() throws IOException
    {
        if (allowedMethods != null)
        {
            return;
        }

        final OptionsMethod optionsMethod = new OptionsMethod(getName().getPath());
        try
        {
            optionsMethod.setFollowRedirects(true);
            final int status = fileSystem.getClient().executeMethod(optionsMethod);
            if (status < 200 || status > 299)
            {
                if (status == 401 || status == 403)
                {
                    setAllowedMethods(null);
                    return;
                }
            }

            setAllowedMethods(optionsMethod.getAllowedMethods());
        }
        finally
        {
            optionsMethod.releaseConnection();
        }

        return;
    }

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

    public static class WebdavRandomAccesContent extends AbstractRandomAccessContent
    {
        private final WebdavFileObject fileObject;

        protected long filePointer = 0;

        private DataInputStream dis = null;

        private InputStream mis = null;

        protected WebdavRandomAccesContent(final WebdavFileObject fileObject, final RandomAccessMode mode)
        {
            super(mode);

            this.fileObject = fileObject;
        }

        public long getFilePointer() throws IOException
        {
            return filePointer;
        }

        public void seek(long pos) throws IOException
        {
            if (pos == filePointer)
            {
                // no change
                return;
            }

            if (pos < 0)
            {
                throw new FileSystemException(
                    "vfs.provider/random-access-invalid-position.error",
                    new Object[]{new Long(pos)});
            }
            if (dis != null)
            {
                close();
            }

            filePointer = pos;
        }

        private void createStream() throws IOException
        {
            if (dis != null)
            {
                return;
            }

            fileObject.resource.addRequestHeader("Range", "bytes="
                + filePointer + "-");
            final InputStream data = fileObject.resource.getMethodData();
            final int status = fileObject.resource.getStatusCode();

            if (status != HttpURLConnection.HTTP_PARTIAL)
            {
                data.close();
                throw new FileSystemException(
                    "vfs.provider.http/get-range.error", new Object[]{
                    fileObject.getName(), new Long(filePointer)});
            }

            mis = data;
            dis = new DataInputStream(new FilterInputStream(mis)
            {
                public int read() throws IOException
                {
                    int ret = super.read();
                    if (ret > -1)
                    {
                        filePointer++;
                    }
                    return ret;
                }

                public int read(byte b[]) throws IOException
                {
                    int ret = super.read(b);
                    if (ret > -1)
                    {
                        filePointer += ret;
                    }
                    return ret;
                }

                public int read(byte b[], int off, int len) throws IOException
                {
                    int ret = super.read(b, off, len);
                    if (ret > -1)
                    {
                        filePointer += ret;
                    }
                    return ret;
                }
            });
        }

        public void close() throws IOException
        {
            if (dis != null)
            {
                dis.close();
                dis = null;
                mis = null;
            }
        }

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

        public byte readByte() throws IOException
        {
            createStream();
            byte data = dis.readByte();
            return data;
        }

        public char readChar() throws IOException
        {
            createStream();
            char data = dis.readChar();
            return data;
        }

        public double readDouble() throws IOException
        {
            createStream();
            double data = dis.readDouble();
            return data;
        }

        public float readFloat() throws IOException
        {
            createStream();
            float data = dis.readFloat();
            return data;
        }

        public int readInt() throws IOException
        {
            createStream();
            int data = dis.readInt();
            return data;
        }

        public int readUnsignedByte() throws IOException
        {
            createStream();
            int data = dis.readUnsignedByte();
            return data;
        }

        public int readUnsignedShort() throws IOException
        {
            createStream();
            int data = dis.readUnsignedShort();
            return data;
        }

        public long readLong() throws IOException
        {
            createStream();
            long data = dis.readLong();
            return data;
        }

        public short readShort() throws IOException
        {
            createStream();
            short data = dis.readShort();
            return data;
        }

        public boolean readBoolean() throws IOException
        {
            createStream();
            boolean data = dis.readBoolean();
            return data;
        }

        public int skipBytes(int n) throws IOException
        {
            createStream();
            int data = dis.skipBytes(n);
            return data;
        }

        public void readFully(byte b[]) throws IOException
        {
            createStream();
            dis.readFully(b);
        }

        public void readFully(byte b[], int off, int len) throws IOException
        {
            createStream();
            dis.readFully(b, off, len);
        }

        public String readUTF() throws IOException
        {
            createStream();
            String data = dis.readUTF();
            return data;
        }

        public InputStream getInputStream() throws IOException
        {
            createStream();
            return dis;
        }
    }

}
TOP

Related Classes of org.apache.commons.vfs.provider.webdav.WebdavFileObject$WebdavOutputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.