/* Copyright 2012 GanttProject Team This file is part of GanttProject, an opensource project management tool. GanttProject is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GanttProject is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GanttProject. If not, see <http://www.gnu.org/licenses/>. */ package net.sourceforge.ganttproject.document.webdav; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.io.ByteStreams; import com.google.common.io.OutputSupplier; 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.httpclient.File; import io.milton.httpclient.Folder; import io.milton.httpclient.Host; import io.milton.httpclient.HttpException; import io.milton.httpclient.ProgressListener; import io.milton.httpclient.Resource; import io.milton.httpclient.Utils.CancelledException; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.MessageFormat; import java.util.Collections; import java.util.List; /** * Implementation which uses Milton client library. * * @author dbarashev (Dmitry Barashev) */ public class MiltonResourceImpl implements WebDavResource { private static final ProgressListener PROGRESS_LISTENER_STUB = null; private Resource myImpl; private final WebDavUri myUrl; private final Host myHost; private Boolean myExistance; private MiltonResourceFactory myFactory; MiltonResourceImpl(WebDavUri webDavUri, Resource impl, MiltonResourceFactory factory) { myUrl = webDavUri; myImpl = impl; myFactory = factory; myExistance = true; myHost = impl.host(); } MiltonResourceImpl(WebDavUri uri, Host host, MiltonResourceFactory factory) { myFactory = factory; myUrl = uri; myHost = host; } @Override public boolean exists() throws WebDavException { if (myExistance == null) { Resource impl = getOptionalImpl(); myExistance = Boolean.valueOf(impl != null); } return myExistance; } private void assertExists() { try { if (!exists()) { throw new WebDavRuntimeException(MessageFormat.format("Resource {0} does not exist on {1}", myUrl.path, myUrl.hostName)); } } catch (WebDavException e) { throw new WebDavRuntimeException(MessageFormat.format("Resource {0} does not exist on {1}", myUrl.path, myUrl.hostName), e); } } @Override public boolean isCollection() { assertExists(); return (myImpl instanceof File) == false; } private Resource getOptionalImpl() throws WebDavException { if (myImpl != null) { return myImpl; } Host host = getHost(); try { Resource resolved = host.find(myUrl.path); if (resolved != null) { myImpl = resolved; return myImpl; } } catch (NotAuthorizedException e) { throw new WebDavException(MessageFormat.format("User {0} is not authorized to access {1}", getUsername(), myUrl.hostName), e); } catch (BadRequestException e) { throw new WebDavException(MessageFormat.format("Bad request when accessing {0}", myUrl.hostName), e); } catch (IOException e) { throw new WebDavException(MessageFormat.format("I/O problems when accessing {0}", myUrl.hostName), e); } catch (HttpException e) { throw new WebDavException(MessageFormat.format("HTTP problems when accessing {0}", myUrl.hostName), e); } return null; } private Host getHost() { return myHost; } @Override public boolean isLockSupported(boolean exclusive) { assertExists(); if (myImpl.getSupportedLock() == null) { return false; } if (exclusive) { return myImpl.getSupportedLock().exclusive; } return myImpl.getSupportedLock().shared; } @Override public List<String> getLockOwners() { String lockOwner = myImpl == null ? null : myImpl.getLockOwner(); return lockOwner == null ? Collections.<String>emptyList() : ImmutableList.<String>of(lockOwner); } public boolean canLock(String username) { assertExists(); if (!isLockSupported(true)) { return false; } List<String> lockOwners = getLockOwners(); return lockOwners.isEmpty() || lockOwners.equals(ImmutableList.of(username)); } @Override public boolean isLocked() { return !getLockOwners().isEmpty(); } @Override public void lock(int timeout) throws WebDavException { assertExists(); try { myImpl.lock(timeout); } catch (NotAuthorizedException e) { throw new WebDavException(MessageFormat.format("User {0} is probably not authorized to access {1}", getUsername(), myUrl.hostName), e); } catch (BadRequestException e) { throw new WebDavException(MessageFormat.format("Bad request when accessing {0}", myUrl.hostName), e); } catch (HttpException e) { throw new WebDavException(MessageFormat.format("HTTP problems when accessing {0}", myUrl.hostName), e); } catch (ConflictException e) { throw new WebDavException(MessageFormat.format("Conflict when accessing {0}", myUrl.hostName), e); } catch (NotFoundException e) { throw new WebDavException(MessageFormat.format("Resource {0} is not found on {1}", myUrl.path, myUrl.hostName), e); } } @Override public void unlock() throws WebDavException { if (!isLocked()) { return; } assertExists(); try { myImpl.unlock(); } catch (NotAuthorizedException e) { throw new WebDavException(MessageFormat.format("User {0} is probably not authorized to access {1}", getUsername(), myUrl.hostName), e); } catch (BadRequestException e) { throw new WebDavException(MessageFormat.format("Bad request when accessing {0}", myUrl.hostName), e); } catch (HttpException e) { throw new WebDavException(MessageFormat.format("HTTP problems when accessing {0}", myUrl.hostName), e); } catch (ConflictException e) { throw new WebDavException(MessageFormat.format("Conflict when accessing {0}", myUrl.hostName), e); } catch (NotFoundException e) { throw new WebDavException(MessageFormat.format("Resource {0} is not found on {1}", myUrl.path, myUrl.hostName), e); } } @Override public WebDavResource getParent() { if (myImpl != null) { return new MiltonResourceImpl(myUrl.buildParent(), myImpl.parent, myFactory); } return new MiltonResourceImpl(myUrl.buildParent(), myHost, myFactory); } @Override public WebDavUri getWebDavUri() { return myUrl; } @Override public String getUrl() { return myUrl == null ? myImpl.encodedUrl() : myUrl.buildUrl(); } @Override public List<WebDavResource> getChildResources() throws WebDavException { assertExists(); try { return Lists.transform(((Folder)myImpl).children(), new Function<Resource, WebDavResource>() { @Override public WebDavResource apply(Resource r) { return new MiltonResourceImpl(myUrl.buildChild(r.name), r, myFactory); } }); } catch (NotAuthorizedException e) { throw new WebDavException(MessageFormat.format("User {0} is probably not authorized to access {1}", getUsername(), myUrl.hostName), e); } catch (BadRequestException e) { throw new WebDavException(MessageFormat.format("Bad request when accessing {0}", myUrl.hostName), e); } catch (IOException e) { throw new WebDavException(MessageFormat.format("I/O problems when accessing {0}", myUrl.hostName), e); } catch (HttpException e) { throw new WebDavException(MessageFormat.format("HTTP problems when accessing {0}", myUrl.hostName), e); } } @Override public String getName() { if (myImpl != null) { return myImpl.name; } return Path.path(myUrl.path).getName(); } @Override public void write(byte[] byteArray) throws WebDavException { MiltonResourceImpl parent = (MiltonResourceImpl) getParent(); if (!parent.exists()) { throw new WebDavException(MessageFormat.format("Folder {0} does not exist", parent.getName())); } assert parent.myImpl instanceof Folder; Folder parentFolder = (Folder) parent.myImpl; try { final java.io.File tempFile = java.io.File.createTempFile("webdav-" + myUrl.hostUrl, ""); ByteStreams.write(byteArray, new OutputSupplier<OutputStream>() { @Override public OutputStream getOutput() throws IOException { return new BufferedOutputStream(new FileOutputStream(tempFile)); } }); parentFolder.uploadFile(getName(), tempFile, null); } catch (NotAuthorizedException e) { throw new WebDavException(MessageFormat.format("User {0} is probably not authorized to access {1}", getUsername(), myUrl.hostName), e); } catch (BadRequestException e) { throw new WebDavException(MessageFormat.format("Bad request when accessing {0}", myUrl.hostName), e); } catch (HttpException e) { throw new WebDavException(MessageFormat.format("HTTP problems when accessing {0}", myUrl.hostName), e); } catch (ConflictException e) { throw new WebDavException(MessageFormat.format("Conflict when accessing {0}", myUrl.hostName), e); } catch (NotFoundException e) { throw new WebDavException(MessageFormat.format("Resource {0} is not found on {1}", myUrl.path, myUrl.hostName), e); } catch (FileNotFoundException e) { throw new WebDavException(MessageFormat.format("I/O problems when uploading {0} to {1}", myUrl.path, myUrl.hostName), e); } catch (IOException e) { throw new WebDavException(MessageFormat.format("I/O problems when uploading {0} to {1}", myUrl.path, myUrl.hostName), e); } } @Override public InputStream getInputStream() throws WebDavException { assertExists(); assert myImpl instanceof File; File file = (File) myImpl; ByteArrayOutputStream content = new ByteArrayOutputStream(); try { file.download(content, PROGRESS_LISTENER_STUB); return new ByteArrayInputStream(content.toByteArray()); } catch (CancelledException e) { throw new WebDavException("File download has been canceled", e); } catch (HttpException e) { throw new WebDavException(MessageFormat.format("HTTP error {0} while downloading file", e.getResult()), e); } } @Override public boolean isWritable() { try { if (exists()) { return canLock(); } WebDavResource parent = getParent(); return parent.exists() && parent.isWritable(); } catch (WebDavException e) { e.printStackTrace(); return false; } } @Override public boolean canLock() throws WebDavException { assertExists(); if (myImpl.getSupportedLock() == null) { return false; } if (!myImpl.getSupportedLock().exclusive) { return false; } List<String> lockOwners = getLockOwners(); return lockOwners.isEmpty() || lockOwners.equals(ImmutableList.of(getUsername())); } private String getUsername() { return myHost.user; } @Override public void delete() throws WebDavException { assertExists(); try { myImpl.delete(); } catch (NotAuthorizedException e) { throw new WebDavException(MessageFormat.format("User {0} is probably not authorized to access {1}", getUsername(), myUrl.hostName), e); } catch (BadRequestException e) { throw new WebDavException(MessageFormat.format("Bad request when deleting {0}", myUrl.hostName), e); } catch (HttpException e) { throw new WebDavException(MessageFormat.format("HTTP problems when deleting {0}", myUrl.hostName), e); } catch (ConflictException e) { throw new WebDavException(MessageFormat.format("Conflict when deleting {0}", myUrl.hostName), e); } catch (NotFoundException e) { throw new WebDavException(MessageFormat.format("Resource {0} is not found on {1}", myUrl.path, myUrl.hostName), e); } catch (IOException e) { throw new WebDavException(MessageFormat.format("I/O problems when deleting {0}", myUrl.hostName), e); } } }