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 extends Resource> 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() + "/";
}
}