1 package org.apache.maven.archiva.webdav;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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;
36 import javax.servlet.http.HttpServletResponse;
37 import java.util.List;
38 import java.util.ArrayList;
42 * @author <a href="mailto:james@atlassian.com">James William Dumay</a>
43 * Portions from the Apache Jackrabbit Project
45 public class ArchivaDavResource implements DavResource
47 public static final String HIDDEN_PATH_PREFIX = ".";
49 private final MimeTypes mimeTypes;
51 private final ArchivaDavResourceLocator locator;
53 private final DavResourceFactory factory;
55 private final File localResource;
57 private final String logicalResource;
59 private static final String METHODS = "OPTIONS, GET, HEAD, POST, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, PUT, DELETE, MOVE";
61 private static final String COMPLIANCE_CLASS = "1";
63 private DavPropertySet properties;
65 private boolean propsInitialized = false;
67 public ArchivaDavResource(String localResource, String logicalResource, MimeTypes mimeTypes, ArchivaDavResourceLocator locator, DavResourceFactory factory)
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();
77 public String getContentType()
79 return mimeTypes.getMimeType(localResource.getName());
82 public String getComplianceClass()
84 return COMPLIANCE_CLASS;
87 public String getSupportedMethods()
92 public boolean exists()
94 return localResource.exists();
97 public boolean isCollection()
99 return localResource.isDirectory();
102 public String getDisplayName()
104 String resPath = getResourcePath();
105 return (resPath != null) ? Text.getName(resPath) : resPath;
108 public DavResourceLocator getLocator()
113 public File getLocalResource()
115 return localResource;
118 public String getResourcePath()
120 return locator.getResourcePath();
123 public String getHref()
125 return locator.getHref(isCollection());
128 public long getModificationTime()
131 return localResource.lastModified();
134 public long getContentLength()
137 return localResource.length();
140 public void spool(OutputContext outputContext) throws IOException
144 FileInputStream is = null;
147 outputContext.setContentLength(getContentLength());
148 outputContext.setContentType(getContentType());
150 //Write content to stream
151 is = new FileInputStream(localResource);
152 IOUtils.copy(is, outputContext.getOutputStream());
156 IOUtils.closeQuietly(is);
161 IndexWriter writer = new IndexWriter(this, localResource, logicalResource);
162 writer.write(outputContext);
166 public DavPropertyName[] getPropertyNames()
168 return getProperties().getPropertyNames();
171 public DavProperty getProperty(DavPropertyName name)
174 return properties.get(name);
177 public DavPropertySet getProperties()
183 public void setProperty(DavProperty property) throws DavException
187 public void removeProperty(DavPropertyName propertyName) throws DavException
191 public MultiStatusResponse alterProperties(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames) throws DavException
196 public MultiStatusResponse alterProperties(List changeList) throws DavException
201 public DavResource getCollection()
203 DavResource parent = null;
204 if (getResourcePath() != null && !getResourcePath().equals("/")) {
205 String parentPath = Text.getRelativeParent(getResourcePath(), 1);
206 if (parentPath.equals("")) {
209 DavResourceLocator parentloc = locator.getFactory().createResourceLocator(locator.getPrefix(), parentPath);
211 parent = factory.createResource(parentloc, null);
212 } catch (DavException e) {
219 public void addMember(DavResource resource, InputContext inputContext) throws DavException
221 File localFile = new File(localResource, resource.getDisplayName());
222 if (isCollection() && inputContext.hasStream()) //New File
224 boolean deleteFile = false;
225 FileOutputStream stream = null;
228 stream = new FileOutputStream(localFile);
229 IOUtils.copy(inputContext.getInputStream(), stream);
230 if (inputContext.getContentLength() != localFile.length())
233 throw new DavException(HttpServletResponse.SC_BAD_REQUEST, "Content Header length was "
234 + inputContext.getContentLength() + " but was " + localFile.length());
237 catch (IOException e)
239 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
243 IOUtils.closeQuietly(stream);
246 FileUtils.deleteQuietly(localFile);
250 else if (!inputContext.hasStream() && isCollection()) //New directory
256 throw new DavException(HttpServletResponse.SC_BAD_REQUEST, "Could not write member "
257 + resource.getResourcePath() + " at " + getResourcePath());
261 public DavResourceIterator getMembers()
263 ArrayList list = new ArrayList();
264 if (exists() && isCollection())
266 for (String item : localResource.list())
270 if (!item.startsWith(HIDDEN_PATH_PREFIX))
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);
278 catch (DavException e)
284 return new DavResourceIteratorImpl(list);
287 public void removeMember(DavResource member) throws DavException
289 File localResource = checkDavResourceIsArchivaDavResource(member).getLocalResource();
291 if (!localResource.exists())
293 throw new DavException(HttpServletResponse.SC_NOT_FOUND, member.getResourcePath());
296 boolean suceeded = false;
298 if (localResource.isDirectory())
302 FileUtils.deleteDirectory(localResource);
305 catch (IOException e)
307 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
311 if (!suceeded && localResource.isFile())
313 suceeded = localResource.delete();
318 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not delete resource " + member.getResourcePath());
322 public void move(DavResource destination) throws DavException
326 throw new DavException(HttpServletResponse.SC_NOT_FOUND, "Resource to copy does not exist.");
331 ArchivaDavResource localResource = checkDavResourceIsArchivaDavResource(destination);
334 FileUtils.moveDirectory(getLocalResource(), localResource.getLocalResource());
338 FileUtils.moveFile(getLocalResource(), localResource.getLocalResource());
341 catch ( IOException e )
343 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
347 public void copy(DavResource destination, boolean shallow) throws DavException
351 throw new DavException(HttpServletResponse.SC_NOT_FOUND, "Resource to copy does not exist.");
354 if (shallow && isCollection())
356 throw new DavException(DavServletResponse.SC_FORBIDDEN, "Unable to perform shallow copy for collection");
361 ArchivaDavResource localResource = checkDavResourceIsArchivaDavResource(destination);
364 FileUtils.copyDirectory(getLocalResource(), localResource.getLocalResource());
368 FileUtils.copyFile(getLocalResource(), localResource.getLocalResource());
371 catch ( IOException e)
373 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
377 public boolean isLockable(Type type, Scope scope)
382 public boolean hasLock(Type type, Scope scope)
387 public ActiveLock getLock(Type type, Scope scope)
392 public ActiveLock[] getLocks()
394 return new ActiveLock[0];
397 public ActiveLock lock(LockInfo reqLockInfo) throws DavException
402 public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken) throws DavException
407 public void unlock(String lockToken) throws DavException
411 public void addLockManager(LockManager lockmgr)
415 public DavResourceFactory getFactory()
420 public DavSession getSession()
426 * Fill the set of properties
428 protected void initProperties() {
429 if (!exists() || propsInitialized) {
433 // set (or reset) fundamental properties
434 if (getDisplayName() != null) {
435 properties.add(new DefaultDavProperty(DavPropertyName.DISPLAYNAME, getDisplayName()));
437 if (isCollection()) {
438 properties.add(new ResourceType(ResourceType.COLLECTION));
439 // Windows XP support
440 properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "1"));
442 properties.add(new ResourceType(ResourceType.DEFAULT_RESOURCE));
444 // Windows XP support
445 properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "0"));
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);
453 properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED, modifiedDate));
455 properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, modifiedDate));
457 properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, localResource.length()));
459 propsInitialized = true;
462 private ArchivaDavResource checkDavResourceIsArchivaDavResource(DavResource resource) throws DavException
464 if (!(resource instanceof ArchivaDavResource))
466 throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "DavResource is not instance of ArchivaDavResource");
468 return (ArchivaDavResource)resource;