You are viewing a plain text version of this content. The canonical link for it is here.
Posted to wagon-commits@maven.apache.org by jo...@apache.org on 2008/02/27 07:31:49 UTC

svn commit: r631500 - /maven/wagon/branches/wagon-http-with-webdav/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java

Author: joakime
Date: Tue Feb 26 22:31:48 2008
New Revision: 631500

URL: http://svn.apache.org/viewvc?rev=631500&view=rev
Log:
* Adding 409/Conflict failed PUT to MKCOL creation.

Modified:
    maven/wagon/branches/wagon-http-with-webdav/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java

Modified: maven/wagon/branches/wagon-http-with-webdav/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java
URL: http://svn.apache.org/viewvc/maven/wagon/branches/wagon-http-with-webdav/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java?rev=631500&r1=631499&r2=631500&view=diff
==============================================================================
--- maven/wagon/branches/wagon-http-with-webdav/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java (original)
+++ maven/wagon/branches/wagon-http-with-webdav/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java Tue Feb 26 22:31:48 2008
@@ -34,6 +34,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
+import java.util.Stack;
 import java.util.TimeZone;
 import java.util.zip.GZIPInputStream;
 
@@ -59,6 +60,7 @@
 import org.apache.maven.wagon.authorization.AuthorizationException;
 import org.apache.maven.wagon.events.TransferEvent;
 import org.apache.maven.wagon.providers.http.dav.DavResource;
+import org.apache.maven.wagon.providers.http.dav.MkColMethod;
 import org.apache.maven.wagon.providers.http.dav.MultiStatus;
 import org.apache.maven.wagon.providers.http.dav.PropFindMethod;
 import org.apache.maven.wagon.providers.http.links.LinkParser;
@@ -81,7 +83,7 @@
     private static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone( "GMT" );
 
     private HttpConnectionManager connectionManager;
-    
+
     private LinkParser linkParser = new LinkParser();
 
     protected boolean isDav;
@@ -163,11 +165,62 @@
 
         Resource resource = new Resource( resourceName );
 
+        // Try simple put first (works 90% of the time) 
+        int statusCode = putSource( url, source, resource );
+        if ( isSuccessfulPUT( statusCode ) )
+        {
+            // expected path.
+            return;
+        }
+
+        // Problem. Check that the collections exist.
+        if ( statusCode == HttpStatus.SC_CONFLICT )
+        {
+            URI absoluteURI = toURI( url );
+            URI parentURI = absoluteURI.resolve( "./" ).normalize();
+            Stack/*<URI>*/missingPaths = davGetMissingPaths( parentURI );
+
+            if ( missingPaths.empty() )
+            {
+                throw new TransferFailedException( "Unable to put (Conflict, collections exist) file "
+                    + source.getAbsolutePath() + " to " + absoluteURI.toASCIIString() );
+            }
+
+            while ( !missingPaths.empty() )
+            {
+                URI missingPath = (URI) missingPaths.pop();
+                davCreateCollection( missingPath );
+            }
+
+            statusCode = putSource( url, source, resource );
+            if ( isSuccessfulPUT( statusCode ) )
+            {
+                // Expected Good result.
+                return;
+            }
+        }
+    }
+
+    /**
+     * HTTP RFC 2616 section 9.6 "PUT": "If an existing resource is modified,
+     * either the 200 (OK) or 204 (No Content) response codes SHOULD be sent
+     * to indicate successful completion of the request." 
+     */
+    private boolean isSuccessfulPUT( int status )
+    {
+        return ( ( status == HttpStatus.SC_CREATED ) || ( status == HttpStatus.SC_OK ) || ( status == HttpStatus.SC_NO_CONTENT ) );
+    }
+
+    private int putSource( String url, File source, Resource resource )
+        throws ResourceDoesNotExistException, TransferFailedException, AuthorizationException
+    {
         firePutInitiated( resource, source );
 
         PutMethod putMethod = new PutMethod( url );
         putMethod.getParams().setSoTimeout( getTimeout() );
 
+        // TODO: worry about setting the Mime-Type on the request header.
+
         try
         {
             InputStream is = new PutInputStream( source, resource, this, getTransferEventSupport() );
@@ -188,12 +241,26 @@
         switch ( statusCode )
         {
             // Success Codes
+            /**
+             * HTTP RFC 2616 section 9.6 "PUT": "If an existing resource is modified,
+             * either the 200 (OK) or 204 (No Content) response codes SHOULD be sent
+             * to indicate successful completion of the request." 
+             */
             case HttpStatus.SC_OK: // 200
             case HttpStatus.SC_CREATED: // 201
             case HttpStatus.SC_ACCEPTED: // 202
             case HttpStatus.SC_NO_CONTENT: // 204
                 break;
 
+            /* 409/Conflict is usually seen when attempting to PUT on a 
+             * WebDAV server without the parent Collections existing first.
+             * 
+             * We want to exit out of this and allow the put() routine to 
+             * manage the creation of the collections.
+             */
+            case HttpStatus.SC_CONFLICT: // 409 
+                break;
+
             case SC_NULL:
                 throw new TransferFailedException( "Failed to transfer file: " + url );
 
@@ -212,6 +279,132 @@
         putMethod.releaseConnection();
 
         firePutCompleted( resource, source );
+
+        return statusCode;
+    }
+
+    public void davCreateCollection( URI uri )
+        throws TransferFailedException
+    {
+        MkColMethod method = new MkColMethod( uri );
+        try
+        {
+            int status = client.executeMethod( method );
+            if ( status == HttpStatus.SC_CREATED )
+            {
+                return;
+            }
+
+            throw new TransferFailedException( "Unable to create collection (" + status + "/"
+                + HttpStatus.getStatusText( status ) + "): " + uri.toASCIIString() );
+        }
+        catch ( HttpException e )
+        {
+            throw new TransferFailedException( "Unable to create collection: " + uri.toASCIIString(), e );
+        }
+        catch ( IOException e )
+        {
+            throw new TransferFailedException( "Unable to create collection: " + uri.toASCIIString(), e );
+        }
+        finally
+        {
+            method.releaseConnection();
+        }
+    }
+
+    /**
+     * Collect the stack of missing paths.
+     * 
+     * @param absoluteURI the abosoluteURI to start from.
+     * @return
+     * @throws TransferFailedException 
+     */
+    public Stack/*<URI>*/davGetMissingPaths( URI targetURI )
+        throws TransferFailedException
+    {
+        URI baseuri = toURI( getRepository().getUrl() );
+
+        Stack/*<URI>*/missingPaths = new Stack/*<URI>*/();
+        URI currentURI = targetURI;
+        if ( !currentURI.getPath().endsWith( "/" ) )
+        {
+            try
+            {
+                currentURI = new URI( targetURI.toASCIIString() + "/" );
+            }
+            catch ( URISyntaxException e )
+            {
+                fireTransferDebug( "Should never happen: " + e.getMessage() );
+            }
+        }
+
+        boolean done = false;
+        while ( !done )
+        {
+            if ( targetURI.equals( baseuri ) )
+            {
+                done = true;
+                break;
+            }
+
+            if ( davCollectionExists( currentURI ) )
+            {
+                done = true;
+                break;
+            }
+
+            missingPaths.push( currentURI );
+
+            currentURI = currentURI.resolve( "../" ).normalize();
+        }
+
+        return missingPaths;
+    }
+
+    public boolean davCollectionExists( URI uri )
+        throws TransferFailedException
+    {
+        PropFindMethod method = new PropFindMethod( uri );
+        try
+        {
+            method.setDepth( 1 );
+            int status = client.executeMethod( method );
+            if ( ( status == HttpStatus.SC_MULTI_STATUS ) || ( status == HttpStatus.SC_OK ) )
+            {
+                MultiStatus multistatus = method.getMultiStatus();
+                if ( multistatus == null )
+                {
+                    return false;
+                }
+
+                DavResource resource = multistatus.getResource( uri.getPath() );
+                if ( resource == null )
+                {
+                    return false;
+                }
+
+                return resource.isCollection();
+            }
+
+            if ( status == HttpStatus.SC_BAD_REQUEST )
+            {
+                throw new TransferFailedException( "Bad HTTP Request (400) during PROPFIND on \"" + uri.toASCIIString()
+                    + "\"" );
+            }
+        }
+        catch ( HttpException e )
+        {
+            fireTransferDebug( "Can't determine if collection exists: " + uri + " : " + e.getMessage() );
+        }
+        catch ( IOException e )
+        {
+            fireTransferDebug( "Can't determine if collection exists: " + uri + " : " + e.getMessage() );
+        }
+        finally
+        {
+            method.releaseConnection();
+        }
+        return false;
     }
 
     public void closeConnection()
@@ -474,10 +667,11 @@
 
     }
 
-    private List getHttpListing( String url ) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    private List getHttpListing( String url )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
     {
         URI absoluteURI = toURI( url );
-        
+
         GetMethod getMethod = new GetMethod( url );
         getMethod.getParams().setSoTimeout( getTimeout() );
 
@@ -527,7 +721,7 @@
 
             Set/*<String>*/links = linkParser.collectLinks( absoluteURI, is );
 
-            return new ArrayList(links);
+            return new ArrayList( links );
         }
         catch ( IOException e )
         {



---------------------------------------------------------------------
To unsubscribe, e-mail: wagon-commits-unsubscribe@maven.apache.org
For additional commands, e-mail: wagon-commits-help@maven.apache.org