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

io.milton.httpclient.Folder Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 io.milton.httpclient;

import io.milton.common.Path;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.ConflictException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.http.exceptions.NotFoundException;
import io.milton.common.LogUtils;
import io.milton.http.Response;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author mcevoyb
 */
public class Folder extends Resource {

    private static final Logger log = LoggerFactory.getLogger(Folder.class);
    final List folderListeners = new ArrayList<>();
    protected final Map> cache;

    /**
     * Special constructor for Host
     */
    Folder(Map> cache) {
        super();
        this.cache = cache;
        if (this.cache == null) {
            throw new IllegalArgumentException("cache cannot be null");
        }
    }

    public Folder(Folder parent, PropFindResponse resp, Map> cache) {
        super(parent, resp);
        this.cache = cache;
        if (this.cache == null) {
            throw new IllegalArgumentException("cache cannot be null");
        }
    }

    public Folder(Folder parent, String name, Map> cache) {
        super(parent, name);
        this.cache = cache;
        if (this.cache == null) {
            throw new IllegalArgumentException("cache cannot be null");
        }
    }

    public void addListener(FolderListener l) throws IOException, HttpException, NotAuthorizedException, BadRequestException {
        for (Resource r : this.children()) {
            l.onChildAdded(r.parent, r);
        }
        folderListeners.add(l);
    }

    /**
     *
     * @param relativePath - encoded but relative path. Must not start with a
     * slash
     * @param params
     * @return
     * @throws HttpException
     */
    public String post(String relativePath, Map params) throws HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        return host().doPost(encodedUrl() + relativePath, params);
    }

    @Override
    public File downloadTo(File destFolder, ProgressListener listener) throws IOException, HttpException, NotAuthorizedException, BadRequestException {
        File thisDir = new File(destFolder, this.name);
        thisDir.mkdir();
        for (Resource r : this.children()) {
            r.downloadTo(thisDir, listener);
        }
        return thisDir;
    }

    /**
     * Empty the cached children for this folder
     *
     * @throws IOException
     */
    public void flush() throws IOException {
        cache.remove(this);
    }

    public boolean hasChildren() throws IOException, HttpException, NotAuthorizedException, BadRequestException {
        return !children().isEmpty();
    }

    public int numChildren() throws IOException, HttpException, NotAuthorizedException, BadRequestException {
        return children().size();
    }

    public List children() throws IOException, HttpException, NotAuthorizedException, BadRequestException {
        List children = cache.get(this);
        if (children == null) {
            children = new ArrayList<>();
            String thisHref = href();
            if (log.isTraceEnabled()) {
                log.trace("load children for: " + thisHref);
            }
            List responses = host()._doPropFind(encodedUrl(), 1, null);
            if (responses != null) {
                for (PropFindResponse resp : responses) {
                    try {
                        Resource r = Resource.fromResponse(this, resp, cache);
                        if (!r.href().equals(thisHref)) {
                            children.add(r);
                        }
                        this.notifyOnChildAdded(r);
                    } catch (Exception e) {
                        log.error("couldnt process record", e);
                    }

                }
            } else {
                log.trace("null responses");
            }

            cache.put(this, children);
        }

        return children;
    }

    public Resource getChild(int num) throws IOException, HttpException, NotAuthorizedException, BadRequestException {
        int x = 0;
        for (Resource r : children()) {
            if (x++ == num) {
                return r;
            }
        }
        return null;
    }

    public void removeListener(FolderListener folderListener) {
        this.folderListeners.remove(folderListener);
    }

    @Override
    public String toString() {
        return href() + " (is a folder)";
    }

    public void upload(File f) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        upload(f, null);
    }

    /**
     *
     * @param f
     * @param listener
     * @param throttle - optional, can be used to slow down the transfer
     * @throws IOException
     */
    public void upload(File f, ProgressListener listener) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        if (f.isDirectory()) {
            uploadFolder(f, listener);
        } else {
            uploadFile(f, listener);
        }
    }

    public io.milton.httpclient.File uploadFile(File f) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        return uploadFile(f, null);
    }

    /**
     * Load a new file into this folder, and return a reference
     *
     * @param f
     * @param listener
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     * @throws HttpException
     */
    public io.milton.httpclient.File uploadFile(File f, ProgressListener listener) throws FileNotFoundException, IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        return uploadFile(f.getName(), f, listener);
    }

    /**
     * Upload a new file
     *
     * @param newName
     * @param f
     * @param listener
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     * @throws HttpException
     * @throws NotAuthorizedException
     * @throws ConflictException
     * @throws BadRequestException
     * @throws NotFoundException
     */
    public io.milton.httpclient.File uploadFile(String newName, File f, ProgressListener listener) throws FileNotFoundException, IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        Path newPath = path().child(newName);
        children(); // ensure children are loaded
        HttpResult result = host().doPut(newPath, f, null, listener);
        int resultCode = result.getStatusCode();
        LogUtils.trace(log, "uploadFile", newPath, " result", resultCode);
        Utils.processResultCode(resultCode, newPath.toString());
        String newEtag = result.getHeaders().get(Response.Header.ETAG.code);
        io.milton.httpclient.File child = new io.milton.httpclient.File(this, newName, null, f.length(), newEtag);
        flush();
        notifyOnChildAdded(child);
        return child;
    }

    protected void uploadFolder(File folder, ProgressListener listener) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        if (folder.getName().startsWith(".")) {
            return;
        }
        Folder newFolder = createFolder(folder.getName());
        for (File f : folder.listFiles()) {
            newFolder.upload(f, listener);
        }
    }

    public io.milton.httpclient.File upload(String name, InputStream content, Integer contentLength, ProgressListener listener) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        Long length = null;
        if (contentLength != null) {
            length = (long) contentLength;
        }
        return upload(name, content, length, listener);
    }

    /**
     * Upload a new file
     *
     * @param name
     * @param content
     * @param contentLength
     * @param listener
     * @return
     * @throws IOException
     * @throws HttpException
     * @throws NotAuthorizedException
     * @throws ConflictException
     * @throws BadRequestException
     * @throws NotFoundException
     */
    public io.milton.httpclient.File upload(String name, InputStream content, Long contentLength, ProgressListener listener) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        String contentType = URLConnection.guessContentTypeFromName(name);
        return upload(name, content, contentLength, contentType, null, listener);
    }

    /**
     *
     * @param name
     * @param content
     * @param contentLength
     * @param contentType
     * @param etag - the expected etag of the file being overwritten, or null if
     * expecting to create new
     * @param listener
     * @return
     * @throws IOException
     * @throws HttpException
     * @throws NotAuthorizedException
     * @throws ConflictException
     * @throws BadRequestException
     * @throws NotFoundException
     */
    public io.milton.httpclient.File upload(String name, InputStream content, Long contentLength, String contentType, IfMatchCheck matchCheck, ProgressListener listener) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        children(); // ensure children are loaded
        String newUri = encodedUrl() + io.milton.common.Utils.percentEncode(name);
        log.trace("upload: " + newUri);
        HttpResult result = host().doPut(newUri, content, contentLength, contentType, matchCheck, listener);
        int resultCode = result.getStatusCode();
        Utils.processResultCode(resultCode, newUri);
        String newEtag = result.getHeaders().get(Response.Header.ETAG.code);
        io.milton.httpclient.File child = new io.milton.httpclient.File(this, name, contentType, contentLength, newEtag);
        io.milton.httpclient.Resource oldChild = this.child(child.name);
        flush();
        notifyOnChildAdded(child);
        return child;
    }

    public Folder createFolder(String name) throws IOException, HttpException, NotAuthorizedException, ConflictException, BadRequestException, NotFoundException {
        children(); // ensure children are loaded
        String newUri = encodedUrl() + io.milton.common.Utils.percentEncode(name);
        try {
            try {
                host().doMkCol(newUri);
            } catch (URISyntaxException ex) {
                throw new RuntimeException(ex);
            }
            flush();
            Folder child = (Folder) child(name);
            notifyOnChildAdded(child);
            return child;
        } catch (ConflictException | MethodNotAllowedException e) {
            return handlerCreateFolderException(newUri, name);
        }
    }

    private Folder handlerCreateFolderException(String newUri, String name) throws IOException, HttpException, NotAuthorizedException, BadRequestException {
        // folder probably exists, so flush children
        this.flush();
        Resource child = this.child(name);
        if (child instanceof Folder) {
            return (Folder) child;
        } else {
            if (child == null) {
                log.error("Couldnt create remote collection");
            } else {
                log.error("Remote resource exists and is not a collection");
            }
            throw new GenericHttpException(405, newUri);
        }

    }

    public Resource child(String childName) throws IOException, HttpException, NotAuthorizedException, BadRequestException {
//        log.trace( "child: current children: " + children().size());
        for (Resource r : children()) {
            if (r.name.equals(childName)) {
                return r;
            }
        }
        return null;
    }

    void notifyOnChildAdded(Resource child) {
        List l2 = new ArrayList<>(folderListeners); // defensive copy in case the folderListeners is changed by the listeners
        for (FolderListener l : l2) {
            l.onChildAdded(this, child);
        }
        // the list of children in the cache for this folder is no longer valid, so flush it
        cache.remove(this);
    }

    void notifyOnChildRemoved(Resource child) {
        List l2 = new ArrayList<>(folderListeners);// defensive copy in case the folderListeners is changed by the listeners
        for (FolderListener l : l2) {
            l.onChildRemoved(this, child);
        }
        // the list of children in the cache for this folder is no longer valid, so flush it
        cache.remove(this);
    }

    @Override
    public String href() {
        return super.href() + "/";
    }

    @Override
    public String encodedUrl() {
        return parent.encodedUrl() + encodedName() + "/";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy