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 }