1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.plugin.webdav.resources.partial

File AbstractDavResource.java

 

Coverage histogram

../../../../../../../img/srcFileCovDistChart6.png
69% of files have more coverage

Code metrics

40
122
39
1
479
343
61
0.5
3.13
39
1.56

Classes

Class Line # Actions
AbstractDavResource 61 122 0% 61 87
0.567164256.7%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.plugin.webdav.resources.partial;
21   
22    import java.util.ArrayList;
23    import java.util.Date;
24    import java.util.List;
25    import java.util.Map;
26   
27    import org.apache.jackrabbit.webdav.DavConstants;
28    import org.apache.jackrabbit.webdav.DavException;
29    import org.apache.jackrabbit.webdav.DavMethods;
30    import org.apache.jackrabbit.webdav.DavResource;
31    import org.apache.jackrabbit.webdav.DavResourceFactory;
32    import org.apache.jackrabbit.webdav.DavResourceLocator;
33    import org.apache.jackrabbit.webdav.DavServletResponse;
34    import org.apache.jackrabbit.webdav.DavSession;
35    import org.apache.jackrabbit.webdav.MultiStatusResponse;
36    import org.apache.jackrabbit.webdav.io.InputContext;
37    import org.apache.jackrabbit.webdav.lock.ActiveLock;
38    import org.apache.jackrabbit.webdav.lock.LockDiscovery;
39    import org.apache.jackrabbit.webdav.lock.LockInfo;
40    import org.apache.jackrabbit.webdav.lock.LockManager;
41    import org.apache.jackrabbit.webdav.lock.Scope;
42    import org.apache.jackrabbit.webdav.lock.SupportedLock;
43    import org.apache.jackrabbit.webdav.lock.Type;
44    import org.apache.jackrabbit.webdav.property.DavProperty;
45    import org.apache.jackrabbit.webdav.property.DavPropertyName;
46    import org.apache.jackrabbit.webdav.property.DavPropertyNameIterator;
47    import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
48    import org.apache.jackrabbit.webdav.property.DavPropertySet;
49    import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
50    import org.apache.jackrabbit.webdav.property.ResourceType;
51   
52    import com.xpn.xwiki.plugin.webdav.resources.XWikiDavResource;
53    import com.xpn.xwiki.plugin.webdav.resources.domain.DavTempFile;
54    import com.xpn.xwiki.plugin.webdav.utils.XWikiDavContext;
55   
56    /**
57    * The superclass for all XWiki WebDAV resources.
58    *
59    * @version $Id: 4452dd9b15f5d3f29ca39eb0733d5c5eb88b8dc4 $
60    */
 
61    public abstract class AbstractDavResource implements XWikiDavResource
62    {
63    /**
64    * Name of this resource.
65    */
66    protected String name;
67   
68    /**
69    * Resource locator for this resource. {@link DavResourceLocator}.
70    */
71    protected DavResourceLocator locator;
72   
73    /**
74    * Parent resource (collection).
75    */
76    protected XWikiDavResource parentResource;
77   
78    /**
79    * XWiki WebDAV Context. {@link XWikiDavContext}
80    */
81    private XWikiDavContext context;
82   
 
83  180 toggle @Override
84    public void init(XWikiDavResource parent, String name, String relativePath) throws DavException
85    {
86  180 DavResourceLocator locator =
87    parent.getLocator().getFactory().createResourceLocator(parent.getLocator().getPrefix(),
88    parent.getLocator().getWorkspacePath(), parent.getLocator().getResourcePath() + relativePath);
89  180 init(name, locator, parent.getContext());
90  180 this.parentResource = parent;
91   
92    }
93   
 
94  264 toggle @Override
95    public void init(String name, DavResourceLocator locator, XWikiDavContext context) throws DavException
96    {
97  264 this.name = name;
98  264 this.locator = locator;
99  264 this.context = context;
100    // set fundamental properties (Will be overridden as necessary)
101    // Some properties are cached and should not be overwritten.
102  264 DavPropertySet propertySet = getVirtualProperties();
103  264 if (propertySet.get(DavPropertyName.CREATIONDATE) == null) {
104  37 String timeStamp = DavConstants.creationDateFormat.format(new Date());
105  37 propertySet.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, timeStamp));
106    }
107  264 propertySet.add(new DefaultDavProperty(DavPropertyName.DISPLAYNAME, getDisplayName()));
108  264 if (isCollection()) {
109  212 propertySet.add(new ResourceType(ResourceType.COLLECTION));
110    // Windows XP support
111  212 propertySet.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "1"));
112    } else {
113  52 propertySet.add(new ResourceType(ResourceType.DEFAULT_RESOURCE));
114    // Windows XP support
115  52 propertySet.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "0"));
116    }
117    /*
118    * set current lock information. If no lock is set to this resource, an empty lockdiscovery will be returned in
119    * the response.
120    */
121  264 propertySet.add(new LockDiscovery(getLock(Type.WRITE, Scope.EXCLUSIVE)));
122    /*
123    * lock support information: all locks are lockable.
124    */
125  264 SupportedLock supportedLock = new SupportedLock();
126  264 supportedLock.addEntry(Type.WRITE, Scope.EXCLUSIVE);
127  264 propertySet.add(supportedLock);
128    }
129   
130    /**
131    * The default decode implementation assumes the next resource in chain to be a temporary resource. Sub classes
132    * should override this method to provide their own implementation.
133    */
 
134  36 toggle public XWikiDavResource decode(String[] tokens, int next) throws DavException
135    {
136  36 if (!isCollection()) {
137  0 throw new DavException(DavServletResponse.SC_BAD_REQUEST);
138    }
139  36 String nextToken = tokens[next];
140  36 boolean last = (next == tokens.length - 1);
141  36 DavTempFile resource = new DavTempFile();
142  36 String method = getContext().getMethod();
143  36 if (method != null && DavMethods.getMethodCode(method) == DavMethods.DAV_MKCOL) {
144  5 resource.setCollection();
145    }
146  36 resource.init(this, nextToken, "/" + nextToken);
147    // Search inside session resources to see if we already have this resource stored
148  36 int index = getVirtualMembers().indexOf(resource);
149  36 if (index != -1) {
150    // Use the old resource instead.
151  26 resource = (DavTempFile) getVirtualMembers().get(index);
152    // Re-init the old resource.
153  26 resource.init(this, nextToken, "/" + nextToken);
154    }
155  36 return last ? resource : resource.decode(tokens, next + 1);
156    }
157   
 
158  0 toggle @Override
159    public boolean isLockable(Type type, Scope scope)
160    {
161  0 return Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope);
162    }
163   
 
164  264 toggle @Override
165    public ActiveLock getLock(Type type, Scope scope)
166    {
167  264 return getContext().getLockManager().getLock(type, scope, this);
168    }
169   
 
170  0 toggle @Override
171    public ActiveLock[] getLocks()
172    {
173  0 ActiveLock writeLock = getLock(Type.WRITE, Scope.EXCLUSIVE);
174  0 return (writeLock != null) ? new ActiveLock[] {writeLock} : new ActiveLock[0];
175    }
176   
 
177  0 toggle @Override
178    public boolean hasLock(Type type, Scope scope)
179    {
180  0 return getLock(type, scope) != null;
181    }
182   
 
183  0 toggle @Override
184    public ActiveLock lock(LockInfo reqLockInfo) throws DavException
185    {
186  0 ActiveLock lock = null;
187  0 if (isLockable(reqLockInfo.getType(), reqLockInfo.getScope())) {
188  0 lock = getContext().getLockManager().createLock(reqLockInfo, this);
189    } else {
190  0 throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
191    }
192  0 return lock;
193    }
194   
 
195  0 toggle @Override
196    public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken) throws DavException
197    {
198  0 if (!exists()) {
199  0 throw new DavException(DavServletResponse.SC_NOT_FOUND);
200    }
201  0 ActiveLock lock = getLock(reqLockInfo.getType(), reqLockInfo.getScope());
202  0 if (lock == null) {
203  0 throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
204    }
205  0 return getContext().getLockManager().refreshLock(reqLockInfo, lockToken, this);
206    }
207   
 
208  0 toggle @Override
209    public void unlock(String lockToken) throws DavException
210    {
211  0 ActiveLock lock = getLock(Type.WRITE, Scope.EXCLUSIVE);
212  0 if (lock != null && lock.isLockedByToken(lockToken)) {
213  0 getContext().getLockManager().releaseLock(lockToken, this);
214    }
215    }
216   
 
217  0 toggle @Override
218    public void copy(DavResource destination, boolean shallow) throws DavException
219    {
220  0 throw new DavException(DavServletResponse.SC_NOT_IMPLEMENTED);
221    }
222   
223    /**
224    * Default implementation simply returns all the cached properties.
225    *
226    * @return The set of properties associated with this resource.
227    */
 
228  592 toggle public DavPropertySet getProperties()
229    {
230  592 return getVirtualProperties();
231    }
232   
 
233  0 toggle @Override
234    public DavProperty getProperty(DavPropertyName name)
235    {
236  0 return getProperties().get(name);
237    }
238   
 
239  0 toggle @Override
240    public DavPropertyName[] getPropertyNames()
241    {
242  0 return getProperties().getPropertyNames();
243    }
244   
 
245  0 toggle @Override
246    public MultiStatusResponse alterProperties(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames)
247    throws DavException
248    {
249  0 getProperties().addAll(setProperties);
250  0 DavPropertyNameIterator it = removePropertyNames.iterator();
251  0 while (it.hasNext()) {
252  0 removeProperty(it.nextPropertyName());
253    }
254  0 return createPropStat();
255    }
256   
 
257  0 toggle @SuppressWarnings("unchecked")
258    @Override
259    public MultiStatusResponse alterProperties(List changeList) throws DavException
260    {
261  0 for (Object next : changeList) {
262  0 if (next instanceof DavProperty) {
263  0 DavProperty property = (DavProperty) next;
264  0 setProperty(property);
265    } else {
266  0 DavPropertyName propertyName = (DavPropertyName) next;
267  0 removeProperty(propertyName);
268    }
269    }
270  0 return createPropStat();
271    }
272   
273    /**
274    * @return A {@link MultiStatusResponse} with all property statuses.
275    */
 
276  0 toggle private MultiStatusResponse createPropStat()
277    {
278  0 DavPropertyNameSet propertyNameSet = new DavPropertyNameSet();
279  0 for (DavPropertyName propertyName : getPropertyNames()) {
280  0 propertyNameSet.add(propertyName);
281    }
282  0 return new MultiStatusResponse(this, propertyNameSet);
283    }
284   
 
285  0 toggle @Override
286    public void removeProperty(DavPropertyName propertyName) throws DavException
287    {
288  0 getProperties().remove(propertyName);
289    }
290   
 
291  0 toggle @Override
292    public void setProperty(DavProperty property) throws DavException
293    {
294  0 getProperties().add(property);
295    }
296   
 
297  0 toggle @Override
298    public void addLockManager(LockManager lockmgr)
299    {
300  0 throw new UnsupportedOperationException();
301    }
302   
 
303  368 toggle @Override
304    public String getDisplayName()
305    {
306  368 return this.name;
307    }
308   
 
309  0 toggle @Override
310    public String getComplianceClass()
311    {
312  0 return COMPLIANCE_CLASS;
313    }
314   
 
315  0 toggle @Override
316    public String getSupportedMethods()
317    {
318  0 return METHODS;
319    }
320   
 
321  0 toggle @Override
322    public DavResourceFactory getFactory()
323    {
324  0 return getContext().getResourceFactory();
325    }
326   
 
327  725 toggle @Override
328    public DavResourceLocator getLocator()
329    {
330  725 return this.locator;
331    }
332   
 
333  2586 toggle @Override
334    public String getResourcePath()
335    {
336  2586 return this.locator.getResourcePath();
337    }
338   
 
339  6 toggle @Override
340    public String getHref()
341    {
342  6 return this.locator.getHref(isCollection());
343    }
344   
 
345  0 toggle @Override
346    public DavSession getSession()
347    {
348  0 return getContext().getDavSession();
349    }
350   
 
351  58 toggle @Override
352    public DavResource getCollection()
353    {
354  58 return this.parentResource;
355    }
356   
 
357  1836 toggle @Override
358    public XWikiDavContext getContext()
359    {
360  1836 return context;
361    }
362   
 
363  152 toggle @Override
364    public List<XWikiDavResource> getVirtualMembers()
365    {
366  152 Map<String, List<XWikiDavResource>> vResourcesMap = getContext().getUserStorage().getResourcesMap();
367  152 if (vResourcesMap.get(getResourcePath()) == null) {
368  5 vResourcesMap.put(getResourcePath(), getInitMembers());
369    }
370  152 return vResourcesMap.get(getResourcePath());
371    }
372   
 
373  856 toggle @Override
374    public DavPropertySet getVirtualProperties()
375    {
376  856 Map<String, DavPropertySet> vPropertiesMap = getContext().getUserStorage().getPropertiesMap();
377  856 if (vPropertiesMap.get(getResourcePath()) == null) {
378  37 vPropertiesMap.put(getResourcePath(), new DavPropertySet());
379    }
380  856 return vPropertiesMap.get(getResourcePath());
381    }
382   
 
383  3 toggle @Override
384    public List<XWikiDavResource> getInitMembers()
385    {
386  3 return new ArrayList<XWikiDavResource>();
387    }
388   
 
389  27 toggle @Override
390    public void clearCache()
391    {
392  27 Map<String, List<XWikiDavResource>> vResourcesMap = getContext().getUserStorage().getResourcesMap();
393  27 Map<String, DavPropertySet> vPropertiesMap = getContext().getUserStorage().getPropertiesMap();
394  27 vResourcesMap.remove(getResourcePath());
395  27 vPropertiesMap.remove(getResourcePath());
396    }
397   
398    /**
399    * Utility method for adding virtual members.
400    *
401    * @param resource {@link XWikiDavResource} instance.
402    * @param inputContext {@link InputContext}
403    */
 
404  6 toggle public void addVirtualMember(DavResource resource, InputContext inputContext) throws DavException
405    {
406  6 XWikiDavResource davResource = (XWikiDavResource) resource;
407  6 boolean isFile = (inputContext.getInputStream() != null);
408  6 long modificationTime = inputContext.getModificationTime();
409  6 if (davResource instanceof DavTempFile) {
410  6 DavTempFile tempFile = (DavTempFile) davResource;
411  6 if (isFile) {
412  2 byte[] data = null;
413  2 data = getContext().getFileContentAsBytes(inputContext.getInputStream());
414  2 tempFile.update(data, new Date(modificationTime));
415    } else {
416  4 tempFile.setModified(new Date(modificationTime));
417    }
418    }
419    // It's possible that we are updating an existing resource.
420  6 if (!getVirtualMembers().contains(davResource)) {
421  6 getVirtualMembers().add(davResource);
422    }
423    }
424   
425    /**
426    * Utility method for removing virtual members.
427    *
428    * @param member {@link XWikiDavResource} to be removed.
429    */
 
430  6 toggle public void removeVirtualMember(DavResource member) throws DavException
431    {
432  6 XWikiDavResource davResource = (XWikiDavResource) member;
433  6 if (getVirtualMembers().contains(davResource)) {
434  6 getVirtualMembers().remove(davResource);
435  6 davResource.clearCache();
436    } else {
437  0 throw new DavException(DavServletResponse.SC_NOT_FOUND);
438    }
439    }
440   
441    /**
442    * Checks if the given resource name corresponds to an excluded resource, ie a resource asked by the OS but that
443    * we want to ignore. This is because some WebDAV clients (such as Mac OSX Finder) send PROPFIND requests for
444    * special resources that are not real resources and thus we don't want to handle those.
445    *
446    * Note 1: Mac OSX sends a *lot* of unnecessary PROPFIND requests for special filesystem resources (a.k.a
447    * <a href="http://en.wikipedia.org/wiki/Resource_fork">Resource Forks</a>) + some other exotic stuff. See a
448    * <a href="http://code.google.com/p/sabredav/wiki/Finder">good description</a> for what's happening.
449    *
450    * Note 2: As a consequence this means that XWiki Document names cannot start with ".", end with "~" or match
451    * "mach_kernel" or "Backups.backupdb".
452    *
453    * @param resourceName Name of the resource.
454    * @return True if the resourceName corresponds to a temporary file / directory. False otherwise.
455    */
 
456  147 toggle public boolean isTempResource(String resourceName)
457    {
458  147 return resourceName.startsWith(".")
459    || resourceName.endsWith("~")
460    || resourceName.equals("mach_kernel")
461    || resourceName.equals("Backups.backupdb");
462    }
463   
 
464  0 toggle @Override
465    public int hashCode()
466    {
467  0 return getResourcePath().hashCode();
468    }
469   
 
470  105 toggle @Override
471    public boolean equals(Object obj)
472    {
473  105 if (obj instanceof DavResource) {
474  105 DavResource other = (DavResource) obj;
475  105 return getResourcePath().equals(other.getResourcePath());
476    }
477  0 return false;
478    }
479    }