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