blob: e974ef7f61185377c2f219339af89fc5b9ad90b3 [file] [log] [blame]
package org.apache.maven.wagon.providers.webdav;
/*
* 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.
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import org.apache.jackrabbit.webdav.property.DavProperty;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import org.apache.maven.wagon.PathUtils;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.TransferFailedException;
import org.apache.maven.wagon.authorization.AuthorizationException;
import org.apache.maven.wagon.repository.Repository;
import org.apache.maven.wagon.resource.Resource;
import org.apache.maven.wagon.shared.http.AbstractHttpClientWagon;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
import org.w3c.dom.Node;
/**
* <p>WebDavWagon</p>
* <p/>
* <p>Allows using a webdav remote repository for downloads and deployments</p>
*
* @author <a href="mailto:hisidro@exist.com">Henry Isidro</a>
* @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @author <a href="mailto:james@atlassian.com>James William Dumay</a>
*
* @plexus.component role="org.apache.maven.wagon.Wagon"
* role-hint="dav"
* instantiation-strategy="per-lookup"
*/
public class WebDavWagon
extends AbstractHttpClientWagon
{
/**
* Puts a file into the remote repository
*
* @param source the file to transfer
* @param resourceName the name of the resource
* @throws TransferFailedException
* @throws ResourceDoesNotExistException
* @throws AuthorizationException
*/
public void put( File source, String resourceName )
throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
{
Repository repository = getRepository();
resourceName = StringUtils.replace( resourceName, "\\", "/" );
String dir = PathUtils.dirname( resourceName );
dir = StringUtils.replace( dir, "\\", "/" );
String dest = repository.getUrl();
Resource resource = new Resource( resourceName );
if ( dest.endsWith( "/" ) )
{
dest = dest + resource.getName();
}
else
{
dest = dest + "/" + resource.getName();
}
firePutInitiated( resource, source );
//Parent directories need to be created before posting
mkdirs( dir );
super.put(source, resource);
}
/**
* This wagon supports directory copying
*
* @return <code>true</code> always
*/
public boolean supportsDirectoryCopy()
{
return true;
}
/**
* Create directories in server as needed.
* They are created one at a time until the whole path exists.
*
* @param dir path to be created in server from repository basedir
* @throws TransferFailedException
*/
private void mkdirs( String dir )
throws TransferFailedException
{
Repository repository = getRepository();
String basedir = repository.getBasedir();
String relpath = FileUtils.normalize( getPath( basedir, dir ) + "/" );
PathNavigator navigator = new PathNavigator(relpath);
// traverse backwards until we hit a directory that already exists (OK/NOT_ALLOWED), or that we were able to
// create (CREATED), or until we get to the top of the path
int status = SC_NULL;
while ( navigator.backward() )
{
String url = getUrl( navigator );
status = doMkCol( url );
if ( status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED
|| status == HttpStatus.SC_METHOD_NOT_ALLOWED )
{
break;
}
}
// traverse forward creating missing directories
while ( navigator.forward() )
{
String url = getUrl( navigator );
status = doMkCol( url );
if ( status != HttpStatus.SC_OK && status != HttpStatus.SC_CREATED )
{
throw new TransferFailedException( "Unable to create collection: " + url + "; status code = " + status );
}
}
}
private int doMkCol(String url) throws TransferFailedException
{
MkColMethod method = null;
try
{
method = new MkColMethod(url);
return execute(method);
}
finally
{
if (method != null) method.releaseConnection();
}
}
private String getUrl(PathNavigator navigator)
{
String url = getRepository().getUrl().replaceAll(getRepository().getBasedir(), "");
return url + '/' + navigator.getPath();
}
/**
* Copy a directory from local system to remote webdav server
*
* @param sourceDirectory the local directory
* @param destinationDirectory the remote destination
* @throws TransferFailedException
* @throws ResourceDoesNotExistException
* @throws AuthorizationException
*/
public void putDirectory( File sourceDirectory, String destinationDirectory )
throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
{
File[] listFiles = sourceDirectory.listFiles();
for ( int i = 0; i < listFiles.length; i++ )
{
if ( listFiles[i].isDirectory() )
{
putDirectory( listFiles[i], destinationDirectory + "/" + listFiles[i].getName() );
}
else
{
String target = destinationDirectory + "/" + listFiles[i].getName();
put( listFiles[i], target );
}
}
}
private boolean isDirectory(String url) throws TransferFailedException
{
DavPropertyNameSet nameSet = new DavPropertyNameSet();
nameSet.add(DavPropertyName.create(DavConstants.PROPERTY_RESOURCETYPE));
PropFindMethod method = null;
try
{
method = new PropFindMethod(url, nameSet, DavConstants.DEPTH_0);
execute(method);
if (method.succeeded())
{
MultiStatus multiStatus = method.getResponseBodyAsMultiStatus();
MultiStatusResponse response = multiStatus.getResponses()[0];
DavPropertySet propertySet = response.getProperties(HttpStatus.SC_OK);
DavProperty property = propertySet.get(DavConstants.PROPERTY_RESOURCETYPE);
if (property != null)
{
Node node = (Node)property.getValue();
return node.getLocalName().equals(DavConstants.XML_COLLECTION);
}
}
return false;
}
catch (DavException e)
{
throw new TransferFailedException(e.getMessage(), e);
}
catch (IOException e)
{
throw new TransferFailedException(e.getMessage(), e);
}
finally
{
if (method != null) method.releaseConnection();
}
}
public List getFileList( String destinationDirectory )
throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
{
final String url = getRepository().getUrl() + '/' + destinationDirectory;
if (isDirectory(url))
{
PropFindMethod method = null;
try
{
DavPropertyNameSet nameSet = new DavPropertyNameSet();
nameSet.add(DavPropertyName.create(DavConstants.PROPERTY_DISPLAYNAME));
method = new PropFindMethod(url, nameSet, DavConstants.DEPTH_1);
int status = execute(method);
if (method.succeeded())
{
ArrayList dirs = new ArrayList();
MultiStatus multiStatus = method.getResponseBodyAsMultiStatus();
for (int i = 0; i < multiStatus.getResponses().length; i++)
{
MultiStatusResponse response = multiStatus.getResponses()[i];
String fileName = PathUtils.filename(response.getHref());
if (!StringUtils.isEmpty(fileName))
{
dirs.add(fileName);
}
}
return dirs;
}
if (status == HttpStatus.SC_NOT_FOUND)
{
throw new ResourceDoesNotExistException( "Destination directory does not exist: " + url );
}
}
catch (DavException e)
{
throw new TransferFailedException(e.getMessage(), e);
}
catch (IOException e)
{
throw new TransferFailedException(e.getMessage(), e);
}
finally
{
if (method != null) method.releaseConnection();
}
}
throw new ResourceDoesNotExistException("Destination path exists but is not a " + "WebDAV collection (directory): " + url );
}
protected String getURL( Repository repository )
{
String url = repository.getUrl();
String s = "dav:";
if ( url.startsWith( s ) )
{
return url.substring( s.length() );
}
else
{
return url;
}
}
}