1   package org.apache.maven.wagon.providers.webdav;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  import org.apache.commons.httpclient.HttpException;
23  import org.apache.commons.httpclient.HttpStatus;
24  import org.apache.jackrabbit.webdav.DavConstants;
25  import org.apache.jackrabbit.webdav.DavException;
26  import org.apache.jackrabbit.webdav.MultiStatus;
27  import org.apache.jackrabbit.webdav.MultiStatusResponse;
28  import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
29  import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
30  import org.apache.jackrabbit.webdav.property.DavProperty;
31  import org.apache.jackrabbit.webdav.property.DavPropertyName;
32  import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
33  import org.apache.jackrabbit.webdav.property.DavPropertySet;
34  import org.apache.maven.wagon.PathUtils;
35  import org.apache.maven.wagon.ResourceDoesNotExistException;
36  import org.apache.maven.wagon.TransferFailedException;
37  import org.apache.maven.wagon.WagonConstants;
38  import org.apache.maven.wagon.authorization.AuthorizationException;
39  import org.apache.maven.wagon.repository.Repository;
40  import org.apache.maven.wagon.shared.http.AbstractHttpClientWagon;
41  import org.codehaus.plexus.util.FileUtils;
42  import org.codehaus.plexus.util.StringUtils;
43  import org.w3c.dom.Node;
44  
45  import java.io.File;
46  import java.io.IOException;
47  import java.net.URLDecoder;
48  import java.util.ArrayList;
49  import java.util.List;
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  public class WebDavWagon
65      extends AbstractHttpClientWagon
66  {
67      protected static final String CONTINUE_ON_FAILURE_PROPERTY = "wagon.webdav.continueOnFailure";
68  
69      private final boolean continueOnFailure = Boolean.getBoolean( CONTINUE_ON_FAILURE_PROPERTY );
70  
71      
72  
73  
74  
75  
76  
77  
78  
79      private static final String[][] protocolMap =
80          new String[][]{ { "dav:http://", "http://" },    
81              { "dav:https://", "https://" },  
82              { "dav+http://", "http://" },    
83              { "dav+https://", "https://" },  
84              { "dav://", "http://" },         
85              { "davs://", "https://" }        
86  
87      
88  
89  
90  
91  
92      public boolean supportsDirectoryCopy()
93      {
94          return true;
95      }
96  
97      
98  
99  
100 
101 
102 
103 
104 
105 
106     protected void mkdirs( String dir )
107         throws IOException
108     {
109         Repository repository = getRepository();
110         String basedir = repository.getBasedir();
111 
112         String baseUrl = repository.getProtocol() + "://" + repository.getHost();
113         if ( repository.getPort() != WagonConstants.UNKNOWN_PORT )
114         {
115             baseUrl += ":" + repository.getPort();
116         }
117 
118         
119         String relpath = FileUtils.normalize( getPath( basedir, dir ) + "/" );
120 
121         PathNavigator navigator = new PathNavigator( relpath );
122 
123         
124         
125         int status = SC_NULL;
126         do
127         {
128             String url = baseUrl + "/" + navigator.getPath();
129             status = doMkCol( url );
130             if ( status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED
131                 || status == HttpStatus.SC_METHOD_NOT_ALLOWED )
132             {
133                 break;
134             }
135         }
136         while ( navigator.backward() );
137 
138         
139         while ( navigator.forward() )
140         {
141             String url = baseUrl + "/" + navigator.getPath();
142             status = doMkCol( url );
143             if ( status != HttpStatus.SC_OK && status != HttpStatus.SC_CREATED )
144             {
145                 throw new IOException( "Unable to create collection: " + url + "; status code = " + status );
146             }
147         }
148     }
149 
150     private int doMkCol( String url )
151         throws IOException
152     {
153         MkColMethod method = null;
154         try
155         {
156             method = new MkColMethod( url );
157             return execute( method );
158         }
159         finally
160         {
161             if ( method != null )
162             {
163                 method.releaseConnection();
164             }
165         }
166     }
167 
168     
169 
170 
171 
172 
173 
174 
175 
176 
177     public void putDirectory( File sourceDirectory, String destinationDirectory )
178         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
179     {
180         File[] listFiles = sourceDirectory.listFiles();
181 
182         for ( int i = 0; i < listFiles.length; i++ )
183         {
184             if ( listFiles[i].isDirectory() )
185             {
186                 putDirectory( listFiles[i], destinationDirectory + "/" + listFiles[i].getName() );
187             }
188             else
189             {
190                 String target = destinationDirectory + "/" + listFiles[i].getName();
191 
192                 put( listFiles[i], target );
193             }
194         }
195 
196     }
197 
198     private boolean isDirectory( String url )
199         throws IOException, DavException
200     {
201         DavPropertyNameSet nameSet = new DavPropertyNameSet();
202         nameSet.add( DavPropertyName.create( DavConstants.PROPERTY_RESOURCETYPE ) );
203 
204         PropFindMethod method = null;
205         try
206         {
207             method = new PropFindMethod( url, nameSet, DavConstants.DEPTH_0 );
208             execute( method );
209             if ( method.succeeded() )
210             {
211                 MultiStatus multiStatus = method.getResponseBodyAsMultiStatus();
212                 MultiStatusResponse response = multiStatus.getResponses()[0];
213                 DavPropertySet propertySet = response.getProperties( HttpStatus.SC_OK );
214                 DavProperty property = propertySet.get( DavConstants.PROPERTY_RESOURCETYPE );
215                 if ( property != null )
216                 {
217                     Node node = (Node) property.getValue();
218                     return node.getLocalName().equals( DavConstants.XML_COLLECTION );
219                 }
220             }
221             return false;
222         }
223         finally
224         {
225             if ( method != null )
226             {
227                 method.releaseConnection();
228             }
229         }
230     }
231 
232     public List<String> getFileList( String destinationDirectory )
233         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
234     {
235         String repositoryUrl = repository.getUrl();
236         String url = repositoryUrl + ( repositoryUrl.endsWith( "/" ) ? "" : "/" ) + destinationDirectory;
237 
238         PropFindMethod method = null;
239         try
240         {
241             if ( isDirectory( url ) )
242             {
243                 DavPropertyNameSet nameSet = new DavPropertyNameSet();
244                 nameSet.add( DavPropertyName.create( DavConstants.PROPERTY_DISPLAYNAME ) );
245 
246                 method = new PropFindMethod( url, nameSet, DavConstants.DEPTH_1 );
247                 int status = execute( method );
248                 if ( method.succeeded() )
249                 {
250                     ArrayList<String> dirs = new ArrayList<String>();
251                     MultiStatus multiStatus = method.getResponseBodyAsMultiStatus();
252 
253                     for ( int i = 0; i < multiStatus.getResponses().length; i++ )
254                     {
255 
256                         MultiStatusResponse response = multiStatus.getResponses()[i];
257 
258                         String entryUrl = response.getHref();
259                         String fileName = PathUtils.filename( URLDecoder.decode( entryUrl ) );
260                         if ( entryUrl.endsWith( "/" ) )
261                         {
262                             if ( i == 0 )
263                             {
264                                 
265                                 
266                                 
267                                 
268                                 continue;
269                             }
270 
271                             
272                             fileName = PathUtils.filename( PathUtils.dirname( URLDecoder.decode( entryUrl ) ) ) + "/";
273                         }
274 
275                         if ( !StringUtils.isEmpty( fileName ) )
276                         {
277                             dirs.add( fileName );
278                         }
279                     }
280                     return dirs;
281                 }
282 
283                 if ( status == HttpStatus.SC_NOT_FOUND )
284                 {
285                     throw new ResourceDoesNotExistException( "Destination directory does not exist: " + url );
286                 }
287             }
288         }
289         catch ( DavException e )
290         {
291             throw new TransferFailedException( e.getMessage(), e );
292         }
293         catch ( IOException e )
294         {
295             throw new TransferFailedException( e.getMessage(), e );
296         }
297         finally
298         {
299             if ( method != null )
300             {
301                 method.releaseConnection();
302             }
303         }
304         throw new ResourceDoesNotExistException(
305             "Destination path exists but is not a " + "WebDAV collection (directory): " + url );
306     }
307 
308     public String getURL( Repository repository )
309     {
310         String url = repository.getUrl();
311 
312         
313         for ( int i = 0; i < protocolMap.length; i++ )
314         {
315             String protocol = protocolMap[i][0];
316             if ( url.startsWith( protocol ) )
317             {
318                 return protocolMap[i][1] + url.substring( protocol.length() );
319             }
320         }
321 
322         
323         return url;
324     }
325 
326 
327     public void put( File source, String resourceName )
328         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
329     {
330         try
331         {
332             super.put( source, resourceName );
333         }
334         catch ( TransferFailedException e )
335         {
336             if ( continueOnFailure )
337             {
338                 
339                 System.out.println(
340                     "WARN: Skip unable to transfer '" + resourceName + "' from '" + source.getPath() + "' due to "
341                         + e.getMessage() );
342             }
343             else
344             {
345                 throw e;
346             }
347         }
348     }
349 }