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