]> source.dussan.org Git - archiva.git/blob
7b94e7488b77f3cbdac95da27b330d5b1db8e411
[archiva.git] /
1 package org.apache.maven.archiva.webdav;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import org.apache.jackrabbit.webdav.*;
23 import org.apache.jackrabbit.webdav.property.*;
24 import org.apache.jackrabbit.webdav.io.InputContext;
25 import org.apache.jackrabbit.webdav.io.OutputContext;
26 import org.apache.jackrabbit.webdav.lock.*;
27 import org.apache.jackrabbit.util.Text;
28 import org.apache.commons.io.IOUtils;
29 import org.apache.commons.io.FileUtils;
30 import org.apache.maven.archiva.webdav.util.MimeTypes;
31 import org.apache.maven.archiva.webdav.util.IndexWriter;
32 import org.joda.time.DateTime;
33 import org.joda.time.format.DateTimeFormatter;
34 import org.joda.time.format.ISODateTimeFormat;
35
36 import javax.servlet.http.HttpServletResponse;
37 import java.util.List;
38 import java.util.ArrayList;
39 import java.io.*;
40
41 /**
42  * @author <a href="mailto:james@atlassian.com">James William Dumay</a>
43  * Portions from the Apache Jackrabbit Project
44  */
45 public class ArchivaDavResource implements DavResource
46 {
47     public static final String HIDDEN_PATH_PREFIX = ".";
48
49     private final MimeTypes mimeTypes;
50
51     private final ArchivaDavResourceLocator locator;
52
53     private final DavResourceFactory factory;
54
55     private final File localResource;
56
57     private final String logicalResource;
58
59     private static final String METHODS = "OPTIONS, GET, HEAD, POST, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, PUT, DELETE, MOVE";
60
61     private static final String COMPLIANCE_CLASS = "1";
62
63     private DavPropertySet properties;
64
65     private boolean propsInitialized = false;
66
67     public ArchivaDavResource(String localResource, String logicalResource, MimeTypes mimeTypes, ArchivaDavResourceLocator locator, DavResourceFactory factory)
68     {
69         this.mimeTypes = mimeTypes;
70         this.localResource = new File(localResource);
71         this.logicalResource = logicalResource;
72         this.locator = locator;
73         this.factory = factory;
74         this.properties = new DavPropertySet();
75     }
76
77     public String getContentType()
78     {
79         return mimeTypes.getMimeType(localResource.getName());
80     }
81
82     public String getComplianceClass()
83     {
84         return COMPLIANCE_CLASS;
85     }
86
87     public String getSupportedMethods()
88     {
89         return METHODS;
90     }
91
92     public boolean exists()
93     {
94         return localResource.exists();
95     }
96
97     public boolean isCollection()
98     {
99         return localResource.isDirectory();
100     }
101
102     public String getDisplayName()
103     {
104         String resPath = getResourcePath();
105         return (resPath != null) ? Text.getName(resPath) : resPath;
106     }
107
108     public DavResourceLocator getLocator()
109     {
110         return locator;
111     }
112
113     public File getLocalResource()
114     {
115         return localResource;
116     }
117
118     public String getResourcePath()
119     {
120         return locator.getResourcePath();
121     }
122
123     public String getHref()
124     {
125         return locator.getHref(isCollection());
126     }
127
128     public long getModificationTime()
129     {
130         initProperties();
131         return localResource.lastModified();
132     }
133
134     public long getContentLength()
135     {
136         initProperties();
137         return localResource.length();
138     }
139
140     public void spool(OutputContext outputContext) throws IOException
141     {
142         if (!isCollection())
143         {
144                 FileInputStream is = null;
145                 try
146                 {
147                         outputContext.setContentLength(getContentLength());
148                                 outputContext.setContentType(getContentType());
149                 
150                                 //Write content to stream
151                                 is = new FileInputStream(localResource);
152                                 IOUtils.copy(is, outputContext.getOutputStream());
153                 }
154                 finally
155                 {
156                                 IOUtils.closeQuietly(is);
157                 }
158         }
159         else
160         {
161             IndexWriter writer = new IndexWriter(this, localResource, logicalResource);
162             writer.write(outputContext);
163         }
164     }
165
166     public DavPropertyName[] getPropertyNames()
167     {
168         return getProperties().getPropertyNames();
169     }
170
171     public DavProperty getProperty(DavPropertyName name)
172     {
173         initProperties();
174         return properties.get(name);
175     }
176
177     public DavPropertySet getProperties()
178     {
179         initProperties();
180         return properties;
181     }
182
183     public void setProperty(DavProperty property) throws DavException
184     {
185     }
186
187     public void removeProperty(DavPropertyName propertyName) throws DavException
188     {
189     }
190
191     public MultiStatusResponse alterProperties(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames) throws DavException
192     {
193         return null;
194     }
195
196     public MultiStatusResponse alterProperties(List changeList) throws DavException
197     {
198         return null;
199     }
200
201     public DavResource getCollection()
202     {
203         DavResource parent = null;
204         if (getResourcePath() != null && !getResourcePath().equals("/")) {
205             String parentPath = Text.getRelativeParent(getResourcePath(), 1);
206             if (parentPath.equals("")) {
207                 parentPath = "/";
208             }
209             DavResourceLocator parentloc = locator.getFactory().createResourceLocator(locator.getPrefix(), parentPath);
210             try {
211                 parent = factory.createResource(parentloc, null);
212             } catch (DavException e) {
213                 // should not occur
214             }
215         }
216         return parent;
217     }
218
219     public void addMember(DavResource resource, InputContext inputContext) throws DavException
220     {
221         File localFile = new File(localResource, resource.getDisplayName());
222         if (isCollection() && inputContext.hasStream()) //New File
223         {
224             boolean deleteFile = false;
225             FileOutputStream stream = null;
226             try
227             {
228                 stream = new FileOutputStream(localFile);
229                 IOUtils.copy(inputContext.getInputStream(), stream);
230                 if (inputContext.getContentLength() != localFile.length())
231                 {
232                     deleteFile = true;
233                     throw new DavException(HttpServletResponse.SC_BAD_REQUEST, "Content Header length was "
234                             + inputContext.getContentLength() + " but was " + localFile.length());
235                 }
236             }
237             catch (IOException e)
238             {
239                 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
240             }
241             finally
242             {
243                 IOUtils.closeQuietly(stream);
244                 if (deleteFile)
245                 {
246                     FileUtils.deleteQuietly(localFile);
247                 }
248             }
249         }
250         else if (!inputContext.hasStream() && isCollection()) //New directory
251         {
252             localFile.mkdir();
253         }
254         else
255         {
256             throw new DavException(HttpServletResponse.SC_BAD_REQUEST, "Could not write member "
257                     + resource.getResourcePath() + " at " + getResourcePath());
258         }
259     }
260
261     public DavResourceIterator getMembers()
262     {
263         ArrayList list = new ArrayList();
264         if (exists() && isCollection())
265         {
266             for (String item : localResource.list())
267             {
268                 try
269                 {
270                     if (!item.startsWith(HIDDEN_PATH_PREFIX))
271                     {
272                         String path = locator.getResourcePath() + '/' + item;
273                         DavResourceLocator resourceLocator = locator.getFactory().createResourceLocator(locator.getPrefix(), path);
274                         DavResource resource = factory.createResource(resourceLocator, null);
275                         if (resource != null) list.add(resource);
276                     }
277                 }
278                 catch (DavException e)
279                 {
280                     //Should not occur
281                 }
282             }
283         }
284         return new DavResourceIteratorImpl(list);
285     }
286
287     public void removeMember(DavResource member) throws DavException
288     {
289         File localResource = checkDavResourceIsArchivaDavResource(member).getLocalResource();
290
291         if (!localResource.exists())
292         {
293             throw new DavException(HttpServletResponse.SC_NOT_FOUND, member.getResourcePath());
294         }
295
296         boolean suceeded = false;
297
298         if (localResource.isDirectory())
299         {
300             try
301             {
302                 FileUtils.deleteDirectory(localResource);
303                 suceeded = true;
304             }
305             catch (IOException e)
306             {
307                 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
308             }
309         }
310
311         if (!suceeded && localResource.isFile())
312         {
313             suceeded = localResource.delete();
314         }
315
316         if (!suceeded)
317         {
318             throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not delete resource " + member.getResourcePath());
319         }
320     }
321
322     public void move(DavResource destination) throws DavException
323     {
324         if (!exists())
325         {
326             throw new DavException(HttpServletResponse.SC_NOT_FOUND, "Resource to copy does not exist.");
327         }
328
329         try
330         {
331             ArchivaDavResource localResource = checkDavResourceIsArchivaDavResource(destination);
332             if (isCollection())
333             {
334                 FileUtils.moveDirectory(getLocalResource(), localResource.getLocalResource());
335             }
336             else
337             {
338                 FileUtils.moveFile(getLocalResource(), localResource.getLocalResource());
339             }
340         }
341         catch ( IOException e )
342         {
343             throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
344         }
345     }
346
347     public void copy(DavResource destination, boolean shallow) throws DavException
348     {
349         if (!exists())
350         {
351             throw new DavException(HttpServletResponse.SC_NOT_FOUND, "Resource to copy does not exist.");
352         }
353
354         if (shallow && isCollection())
355         {
356             throw new DavException(DavServletResponse.SC_FORBIDDEN, "Unable to perform shallow copy for collection");
357         }
358
359         try
360         {
361             ArchivaDavResource localResource = checkDavResourceIsArchivaDavResource(destination);
362             if (isCollection())
363             {
364                 FileUtils.copyDirectory(getLocalResource(), localResource.getLocalResource());
365             }
366             else
367             {
368                 FileUtils.copyFile(getLocalResource(), localResource.getLocalResource());
369             }
370         }
371         catch ( IOException e)
372         {
373             throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
374         }
375     }
376
377     public boolean isLockable(Type type, Scope scope)
378     {
379         return false;
380     }
381
382     public boolean hasLock(Type type, Scope scope)
383     {
384         return false;
385     }
386
387     public ActiveLock getLock(Type type, Scope scope)
388     {
389         return null;
390     }
391
392     public ActiveLock[] getLocks()
393     {
394         return new ActiveLock[0];
395     }
396
397     public ActiveLock lock(LockInfo reqLockInfo) throws DavException
398     {
399         return null;
400     }
401
402     public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken) throws DavException
403     {
404         return null;
405     }
406
407     public void unlock(String lockToken) throws DavException
408     {
409     }
410
411     public void addLockManager(LockManager lockmgr)
412     {
413     }
414
415     public DavResourceFactory getFactory()
416     {
417         return factory;
418     }
419
420     public DavSession getSession()
421     {
422         return null;
423     }
424
425     /**
426      * Fill the set of properties
427      */
428     protected void initProperties() {
429         if (!exists() || propsInitialized) {
430             return;
431         }
432
433         // set (or reset) fundamental properties
434         if (getDisplayName() != null) {
435             properties.add(new DefaultDavProperty(DavPropertyName.DISPLAYNAME, getDisplayName()));
436         }
437         if (isCollection()) {
438             properties.add(new ResourceType(ResourceType.COLLECTION));
439             // Windows XP support
440             properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "1"));
441         } else {
442             properties.add(new ResourceType(ResourceType.DEFAULT_RESOURCE));
443
444             // Windows XP support
445             properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "0"));
446         }
447
448         //Need to get the ISO8601 date for properties
449         DateTime dt = new DateTime(localResource.lastModified());
450         DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
451         String modifiedDate = fmt.print(dt);
452
453         properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED, modifiedDate));
454
455         properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, modifiedDate));
456
457         properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, localResource.length()));
458
459         propsInitialized = true;
460     }
461
462     private ArchivaDavResource checkDavResourceIsArchivaDavResource(DavResource resource) throws DavException
463     {
464         if (!(resource instanceof ArchivaDavResource))
465         {
466             throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "DavResource is not instance of ArchivaDavResource");
467         }
468         return (ArchivaDavResource)resource;
469     }
470 }