org.apache.webdav.ant.taskdefs.Put.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.webdav.ant.taskdefs.Put.java

Source

/* 
 * $Header$
 * $Revision: 207687 $
 * $Date: 2004-08-20 18:53:22 +0800 (Fri, 20 Aug 2004) $
 * ========================================================================
 * Copyright 2004 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.webdav.ant.taskdefs;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.httpclient.URIException;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.AbstractFileSet;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.FilterSet;
import org.apache.tools.ant.types.FilterSetCollection;
import org.apache.tools.ant.types.ZipScanner;
import org.apache.tools.ant.util.LineTokenizer;
import org.apache.webdav.ant.Mimetypes;
import org.apache.webdav.ant.Utils;
import org.apache.webdav.lib.methods.DepthSupport;

/**
 * WebDAV task for writing files to an WebDAV server.
 * 
 * @see <a href="../doc-files/tasks.htm#davput">Tasks documentation</a> 
 * @version $Revision: 207687 $
 */
public class Put extends WebdavTask {
    private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
    /** Should we try to lock the remote resource as we upload it? */
    private boolean lock = true;
    /** The locktoken provided or or self created when lock is true. */
    private String locktoken = null;
    /** The timeout to be used with locking. */
    private int lockTimeout = 3600;
    private String lockOwnerInfo = null;
    /** The sets of files that will be sent to the web server. */
    private List filesets = new ArrayList();
    private List zipfilesets = new ArrayList();
    /** Single file to be putted. */
    private File file = null;
    private boolean overwrite = false;

    private FilterSetCollection filterSets = new FilterSetCollection();
    private String encoding = null;

    private int countWrittenFiles = 0;
    private int countOmittedFiles = 0;

    // configuration methods
    /**
     * Adds a set of files (nested fileset attribute).
     */
    public void addFileset(FileSet set) {
        filesets.add(set);
    }

    public void setLock(boolean lock) {
        this.lock = lock;
    }

    public void setOverwrite(boolean value) {
        this.overwrite = value;
    }

    public void setLocktoken(String token) {
        this.locktoken = token;
        if (!this.locktoken.startsWith("opaquelocktoken:")) {
            throw new BuildException("Invalid locktoken: " + token);
        }
    }

    public FilterSet createFilterSet() {
        FilterSet filterSet = new FilterSet();
        this.filterSets.addFilterSet(filterSet);
        return filterSet;
    }

    public void setEncoding(String enc) {
        this.encoding = enc;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public void setTimeout(int value) {
        if (value > 0) {
            this.lockTimeout = value;
        } else {
            throw new BuildException("Invalid timeout value (Must be " + "positive integer)");
        }
    }

    public void setOwnerinfo(String value) {
        this.lockOwnerInfo = value;
    }

    /**
     * Does the work.
     * 
     * @exception BuildException Thrown in unrecoverable error.
     */
    public void execute() throws BuildException {
        boolean selfCreatedLock = false;

        validate();

        try {
            log("Uploading to: " + getUrl(), ifVerbose());

            if (this.file == null) {
                Utils.assureExistingCollection(getHttpClient(), getUrl(), this.locktoken);
            }

            // lock URL if requested and no locktoken explicitly provided
            if (this.lock && this.locktoken == null) {
                log("Locking " + getUrl(), ifVerbose());
                this.locktoken = Utils.lockResource(getHttpClient(), getUrl(), this.lockOwnerInfo,
                        DepthSupport.DEPTH_INFINITY, this.lockTimeout);
                log("locktoken: " + this.locktoken, Project.MSG_DEBUG);
                selfCreatedLock = true;
            }

            if (this.file != null) {
                // put a single file
                if (Utils.collectionExists(getHttpClient(), getUrl())) {
                    // if the given URL is a collection put a file named as the given one
                    setUrl(assureCollectionUrl(getUrl()));
                    uploadFile(this.file.getName(), this.file);
                } else {
                    if (getUrl().getURI().endsWith("/")) {
                        Utils.assureExistingCollection(getHttpClient(), getUrl(), this.locktoken);
                        uploadFile(this.file.getName(), this.file);
                    } else {
                        HttpURL targetColl = Utils.createHttpURL(getUrl(), ".");
                        Utils.assureExistingCollection(getHttpClient(), targetColl, this.locktoken);
                        uploadFile(getUrl(), this.file, this.file.getName());
                    }
                }
            } else {
                for (int i = 0; i < filesets.size(); i++) {
                    FileSet fileset = (FileSet) filesets.get(i);
                    uploadFileSet(fileset);
                }
                for (int i = 0; i < zipfilesets.size(); i++) {
                    ZipFileSet fileset = (ZipFileSet) zipfilesets.get(i);
                    uploadZipFileSet(fileset);
                }
            }

            log("Puted " + this.countWrittenFiles + (this.countWrittenFiles == 1 ? " file" : " files") + " to "
                    + getUrl(), this.countWrittenFiles > 0 ? Project.MSG_INFO : ifVerbose());

        } catch (IOException e) {
            throw Utils.makeBuildException("Put error!", e);
        } finally {
            try {
                if (this.locktoken != null && selfCreatedLock) {
                    log("Unlocking " + getUrl(), ifVerbose());
                    Utils.unlockResource(getHttpClient(), getUrl(), this.locktoken);
                }
            } catch (IOException e) {
                throw Utils.makeBuildException("Can't unlock!", e);
            }
        }
    }

    protected void validate() {
        super.validate();

        if (this.encoding == null && this.filterSets.hasFilters()) {
            log("If filterSets are used a file encoding should be specified!", Project.MSG_WARN);
            this.encoding = "ISO-8859-1"; // TODO what sould be the default
        }
        if (this.file != null && (this.filesets.size() > 0 || this.zipfilesets.size() > 0)) {
            throw new BuildException("No filesets allowed if file is set.");
        }

        if (this.file != null && !(this.file.isFile() && this.file.exists())) {
            throw new BuildException("File attribute must point to en existing file");
        }

        if (this.file == null) {
            try {
                setUrl(assureCollectionUrl(getUrl()));
            } catch (URIException e) {
                throw new BuildException("Problem with URI: " + getUrl(), e);
            }
        }
        if (this.lockOwnerInfo == null) {
            this.lockOwnerInfo = "ant-webdav " + getUserid();
        }
    }

    private void uploadFileSet(FileSet fileSet) throws IOException {
        DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject());
        String basedir = scanner.getBasedir().getAbsolutePath();

        // assert that all required collections does exist
        for (Iterator i = determineRequiredDirectories(scanner); i.hasNext();) {
            String dir = (String) i.next();
            if (dir.equals("")) {
                Utils.assureExistingCollection(getHttpClient(), getUrl(), this.locktoken);
            } else {
                HttpURL collURL = Utils.createHttpURL(getUrl(), dir + "/");
                Utils.assureExistingCollection(getHttpClient(), collURL, this.locktoken);
            }
        }

        // write all files
        String[] files = scanner.getIncludedFiles();
        for (int i = 0; i < files.length; ++i) {
            File file = getProject().resolveFile(basedir + File.separator + files[i]);
            uploadFile(asDavPath(files[i]), file);
        }
    }

    private Iterator determineRequiredDirectories(DirectoryScanner scanner) {
        Set result = new HashSet();

        // determine all directories that contain included files
        String[] files = scanner.getIncludedFiles();
        for (int i = 0; i < files.length; i++) {
            String file = asDavPath(files[i]);
            int slashPos = file.lastIndexOf('/');
            if (slashPos != -1) {
                result.add(file.substring(0, slashPos));
            }
        }

        // determine all included directories
        String[] dirs = scanner.getIncludedDirectories();
        for (int i = 0; i < dirs.length; i++) {
            result.add(asDavPath(dirs[i]));
        }

        return result.iterator();
    }

    /**
     * Puts a file to a resource relative to the url attribute.
     * @param relative path relative
     * @param file file to be written
     * @throws IOException
     */
    private void uploadFile(String relative, File file) throws IOException {
        HttpURL url = Utils.createHttpURL(getUrl(), relative);
        uploadFile(url, file, relative);
    }

    /**
     * Puts a file to a given URL.
     * @param relative for logging purposes only. 
     */
    private void uploadFile(HttpURL url, File file, String relative) throws IOException {

        boolean putit = false;
        try {
            if (this.overwrite) {
                putit = true;
            } else {
                // check last modified date (both GMT)
                long remoteLastMod = Utils.getLastModified(getHttpClient(), url);
                long localLastMod = file.lastModified();
                putit = localLastMod > remoteLastMod;
            }
        } catch (HttpException e) {
            switch (e.getReasonCode()) {
            case HttpStatus.SC_NOT_FOUND:
                putit = true;
                break;
            default:
                throw Utils.makeBuildException("Can't get lastmodified!?", e);
            }
        }

        if (putit) {
            log("Uploading: " + relative, ifVerbose());
            try {
                String contentType = Mimetypes.getMimeType(file, DEFAULT_CONTENT_TYPE);
                if (this.filterSets.hasFilters()) {
                    // TODO this part doesn't look nice
                    InputStreamReader reader = new InputStreamReader(new FileInputStream(file), this.encoding);
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    LineTokenizer tok = new LineTokenizer();
                    tok.setIncludeDelims(true);

                    for (String l = tok.getToken(reader); l != null; l = tok.getToken(reader)) {
                        out.write(this.filterSets.replaceTokens(l).getBytes(this.encoding));
                    }
                    Utils.putFile(getHttpClient(), url, new ByteArrayInputStream(out.toByteArray()), contentType,
                            this.locktoken);
                } else {
                    Utils.putFile(getHttpClient(), url, new FileInputStream(file), contentType, this.locktoken);
                }
                this.countWrittenFiles++;
            } catch (HttpException e) {
                throw Utils.makeBuildException("Can't upload " + url, e);
            }
        } else {
            countOmittedFiles++;
            log("Omitted: " + relative + " (uptodate)", ifVerbose());
        }
    }

    private void uploadZipFileSet(ZipFileSet fileSet) throws IOException {
        DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject());

        ZipFile zipFile = new ZipFile(fileSet.getSrc());

        // assert that all required collections does exist
        for (Iterator i = determineRequiredDirectories(scanner); i.hasNext();) {
            String dir = (String) i.next();
            if (dir.equals("")) {
                Utils.assureExistingCollection(getHttpClient(), getUrl(), this.locktoken);
            } else {
                HttpURL collURL = Utils.createHttpURL(getUrl(), dir + "/");
                Utils.assureExistingCollection(getHttpClient(), collURL, this.locktoken);
            }
        }

        // write all files
        String[] files = scanner.getIncludedFiles();
        for (int i = 0; i < files.length; ++i) {
            uploadZipEntry(Utils.createHttpURL(getUrl(), files[i]), files[i], zipFile);
        }
    }

    private void uploadZipEntry(HttpURL url, String name, ZipFile zipFile) throws IOException {
        boolean putit = false;
        ZipEntry entry = zipFile.getEntry(name);

        try {
            if (this.overwrite) {
                putit = true;
            } else {
                // check last modified date (both GMT)
                long remoteLastMod = Utils.getLastModified(getHttpClient(), url);
                long localLastMod = entry.getTime();
                putit = localLastMod > remoteLastMod;
            }
        } catch (HttpException e) {
            switch (e.getReasonCode()) {
            case HttpStatus.SC_NOT_FOUND:
                putit = true;
                break;
            default:
                throw Utils.makeBuildException("Can't get lastmodified!?", e);
            }
        }

        if (putit) {
            log("Uploading: " + name, ifVerbose());
            String contentType = Mimetypes.getMimeType(name, DEFAULT_CONTENT_TYPE);
            Utils.putFile(getHttpClient(), url, zipFile.getInputStream(entry), contentType, this.locktoken);
            this.countWrittenFiles++;
        } else {
            countOmittedFiles++;
            log("Omitted: " + name + " (uptodate)", ifVerbose());
        }
    }

    private String asDavPath(String path) {
        return path.replace('\\', '/');
    }

    public ZipFileSet createZipfileset() {
        ZipFileSet fileSet = new ZipFileSet();
        this.zipfilesets.add(fileSet);
        return fileSet;
    }

    public static class ZipFileSet extends AbstractFileSet {
        private File src = null;

        public void setSrc(File src) {
            this.src = src;
        }

        File getSrc() {
            if (this.src != null) {
                return this.src;
            } else {
                throw new BuildException("ZipFileSet requires a src attribute!");
            }
        }

        /* 
         * @see org.apache.tools.ant.types.AbstractFileSet#getDirectoryScanner(org.apache.tools.ant.Project)
         */
        public DirectoryScanner getDirectoryScanner(Project p) {
            ZipScanner zs = new ZipScanner();
            zs.setSrc(getSrc());
            super.setDir(p.getBaseDir());
            setupDirectoryScanner(zs, p);
            zs.init();
            return zs;
        }
    }
}