001: package com.ibm.webdav.impl;
002:
003: /*
004: * (C) Copyright IBM Corp. 2000 All rights reserved.
005: *
006: * The program is provided "AS IS" without any warranty express or
007: * implied, including the warranty of non-infringement and the implied
008: * warranties of merchantibility and fitness for a particular purpose.
009: * IBM will not be liable for any damages suffered by you as a result
010: * of using the Program. In no event will IBM be liable for any
011: * special, indirect or consequential damages or lost profits even if
012: * IBM has been advised of the possibility of their occurrence. IBM
013: * will not be liable for any third party claims against you.
014: *
015: * Portions Copyright (C) Simulacra Media Ltd, 2004.
016: */
017: import java.io.*;
018: import java.net.*;
019: import java.util.*;
020:
021: import org.w3c.dom.*;
022:
023: import com.ibm.webdav.*;
024: import com.ibm.webdav.Collection;
025:
026: /** A CollectionImpl is a ResourceImpl that contains other
027: * resources including other CollectionImpls. It provides a
028: * concrete, server side implementation of Collection.
029: * <p>
030: * CollectionImpl should inherit from ResourceImpl and CollectionP.
031: * However, Java doesn't support multiple inheritance, so CollectionImpl
032: * must re-implement all of CollectionP's methods. Many of these methods
033: * are overridden anyway for server-side behavior.
034: */
035: public class CollectionImpl extends ResourceImpl implements
036: IRCollection {
037: private Vector members = null;
038:
039: // lazy retrieve the members of the collection for the server
040: public CollectionImpl() {
041: super ();
042: }
043:
044: /** Construct a CollectionImpl for the given URL.
045: *
046: * @param url the URL of the resource
047: * @param localName a translation of the URL (filePortion) into
048: * a name that has local meaning to a server.
049: * @param targetSelector the revision target selector for this Collection
050: * @exception com.ibm.webdav.WebDAVException
051: */
052: public CollectionImpl(URL url, String localName,
053: TargetSelector targetSelector) throws WebDAVException {
054: super (url, localName);
055: String file = url.getFile();
056: if (!file.endsWith("/")) {
057: file = file + "/";
058: try {
059: this .url = new URL(url, file);
060: } catch (java.net.MalformedURLException exc) {
061: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
062: "Malformed URL");
063: }
064:
065: }
066: }
067:
068: /** Copy this resource to the destination URL.
069: * Partial results are possible, check the returned status for details.
070: *
071: * @param destinationURL the destination
072: * @param overwrite true implies overrite the destination if it exists
073: * @param propertiesToCopy a collection of properties that must be copied or
074: * the method will fail. propertiesToCopy may have one of the following values:
075: * <ul>
076: * <li>null - ignore properties that cannot be copied</li>
077: * <li>empty collection - all properties must be copied or the method will fail</li>
078: * <li>a collection of URIs - a list of the properties that must be copied
079: * or the method will fail</li>
080: * </ul>
081: *
082: * @return the status of the copy operation for each resource copied
083: * @exception com.ibm.webdav.WebDAVException
084: */
085: public MultiStatus copy(ResourceContext context,
086: String destinationURL, boolean overwrite,
087: Vector propertiesToCopy) throws WebDAVException {
088: return copy(context, destinationURL, overwrite,
089: propertiesToCopy, Collection.deep);
090: }
091:
092: /** Copy this resource to the destination URL.
093: * Partial results are possible, check the returned status for details.
094: *
095: * @param destinationURL the destination
096: * @param overwrite true implies overrite the destination if it exists
097: * @param propertiesToCopy a collection of properties that must be copied or
098: * the method will fail. propertiesToCopy may have one of the following values:
099: * <ul>
100: * <li>null - ignore properties that cannot be copied</li>
101: * <li>empty collection - all properties must be copied or the method will fail</li>
102: * <li>a collection of URIs - a list of the properties that must be copied
103: * or the method will fail</li>
104: * </ul>
105: * @param depth an indicator for immediate members or recursively all children.
106: * <ul>
107: * <li>shallow: copy only this resource</li>
108: * <li>deep: copy this resource and recursively all of its children</li>
109: * </ul>
110: *
111: * @return the status of the copy operation for each resource copied
112: * @exception com.ibm.webdav.WebDAVException
113: */
114: public MultiStatus copy(ResourceContext context,
115: String destinationURL, boolean overwrite,
116: Vector propertiesToCopy, String depth)
117: throws WebDAVException {
118: this .context = context;
119:
120: setStatusCode(WebDAVStatus.SC_CREATED);
121:
122: // create a MultiStatus to hold the results
123: MultiStatus result = new MultiStatus();
124:
125: // validate the uri
126: if (!hasValidURI()) {
127: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
128: "Invalid URI");
129: }
130:
131: // check the depth parameter
132: if (!(depth.equals(Collection.shallow) || depth
133: .equals(Collection.deep))) {
134: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
135: "Invalid depth on copy");
136: }
137:
138: // make sure the resource exists
139: if (!exists()) {
140: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
141: "Resource does not exist");
142: }
143:
144: // the destination may be a relative URL
145: Collection destination = null;
146: try {
147: URL destURL = new URL(getURL(), destinationURL);
148: destination = new Collection(destURL.toString());
149: } catch (WebDAVException exc) {
150: throw exc;
151: } catch (java.net.MalformedURLException exc) {
152: } catch (java.io.IOException exc) {
153: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
154: "Malformed URL");
155: }
156:
157: // are the source and destination the same?
158: if (this .equals(destination)) {
159: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
160: "Can't copy source on top of itself");
161: }
162:
163: // is the destination locked?
164: destination.getRequestContext().precondition(
165: getRequestContext().precondition());
166: destination.getRequestContext().authorization(
167: getRequestContext().authorization());
168: if (destination.exists() && destination.isLocked()
169: && !destination.isLockedByMe()) {
170: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
171: "Destination resource is locked");
172: }
173:
174: // check to see if the destination exists and its OK to overwrite it
175: if (destination.exists() && !overwrite) {
176: throw new WebDAVException(
177: WebDAVStatus.SC_PRECONDITION_FAILED,
178: "Destination exists and overwrite not specified");
179: }
180:
181: // Ready to copy. For collections, copy the members
182: // First, create the destination collection
183: if (destination.exists()) {
184: destination.delete();
185: setStatusCode(WebDAVStatus.SC_NO_CONTENT);
186: }
187: destination.createCollection();
188:
189: // now copy the members if necessary
190: if (depth.equals(Collection.deep)) {
191: Enumeration members = namespaceManager.getMembers()
192: .elements();
193: while (members.hasMoreElements()) {
194: ResourceImpl member = (ResourceImpl) members
195: .nextElement();
196: // calculate the destination URL
197: String this URL = getURL().toString();
198: String memberURL = member.getURL().toString();
199: String memberPart = memberURL.substring(this URL
200: .length());
201: String dest = destination.getURL().toString()
202: + memberPart;
203: try {
204: MultiStatus memberResult = null;
205: if (member.isCollection()) {
206: memberResult = ((CollectionImpl) member).copy(
207: context, dest, overwrite,
208: propertiesToCopy, depth);
209: } else {
210: memberResult = member.copy(context, dest,
211: overwrite, propertiesToCopy);
212: }
213: if (!memberResult.isOK()) {
214: result.mergeWith(memberResult);
215: }
216: } catch (WebDAVException exc) {
217: MethodResponse response = new MethodResponse(member
218: .getURL().toString(), exc.getStatusCode());
219: result.addResponse(response);
220: } catch (Exception e) {
221: e.printStackTrace();
222: throw new WebDAVException(
223: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
224: "unable to delete resource");
225: }
226: }
227: }
228:
229: // copy the properties
230: WebDAVStatus savedStatusCode = context.getStatusCode();
231: // might be overritten by copying proerties or unlocking
232: MultiStatus ms2 = copyProperties(destination, propertiesToCopy);
233: if (!ms2.isOK()) {
234: // todo: add code here to back out this partial copy. That might require
235: // restoring the resource that used to be at the destination. For now, we'll throw
236: // an exception.
237: throw new WebDAVException(
238: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
239: "problem copying properties");
240: }
241:
242: // remove all locks on the destination. Copy doesn't copy locks
243: // become super-user for this operation
244: String authorization = getRequestContext().authorization();
245: destination.getRequestContext().setBasicAuthorization("root",
246: "");
247: Enumeration locks = destination.getLocks().elements();
248: while (locks.hasMoreElements()) {
249: ActiveLock lock = (ActiveLock) locks.nextElement();
250: // ignore exceptions, the unlock should work
251: try {
252: destination.unlock(lock.getLockToken());
253: } catch (Exception exc) {
254: }
255: }
256: destination.getRequestContext().authorization(authorization);
257: context.setStatusCode(savedStatusCode);
258:
259: // everything must have gone OK, there
260: // is no response for a successful delete
261: getResponseContext().contentType("text/xml");
262: return result;
263: }
264:
265: /** Actually create the collection in the repository. The resource indicated
266: * by the URL must not already exist. All ancestors of this URL must already
267: * exist.
268: *
269: * @param contents an XML Document describing the members of this collection, bodies
270: * of members, and properties on the collections or members. Not completely defined in
271: * version 10 of the WebDAV specification
272: *
273: * @return Multistatus describing the result
274: * of the operation
275: * @exception com.ibm.webdav.WebDAVException
276: */
277: public MultiStatus createCollection(ResourceContext context,
278: Document contents) throws WebDAVException {
279: this .context = context;
280:
281: setStatusCode(WebDAVStatus.SC_CREATED);
282: String fileName = ResourceFactory.getRealPath(getURL());
283:
284: // validate the uri
285: if (!hasValidURI() || fileName.indexOf(File.separator) < 0) {
286: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
287: "Invalid URI");
288: }
289:
290: // see if the resource already exists
291: if (exists()) {
292: if (isCollection()) {
293: throw new WebDAVException(
294: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
295: "Collection already exists");
296: } else {
297: throw new WebDAVException(
298: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
299: "Resource already exists");
300: }
301: }
302:
303: // make sure the parent collection exists
304: CollectionImpl parent = (CollectionImpl) getParentCollection();
305: if (parent != null && !parent.exists()) {
306: throw new WebDAVException(WebDAVStatus.SC_CONFLICT,
307: "Parent collection does not exist");
308: }
309:
310: // make sure the parent collection is not locked, or is locked by this user
311: if (parent != null) {
312: parent.getRequestContext().precondition(
313: getRequestContext().precondition());
314: parent.getRequestContext().authorization(
315: getRequestContext().authorization());
316: if (parent.isLocked() && !parent.isLockedByMe()) {
317: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
318: "Parent collection is locked by another user");
319: }
320: }
321:
322: // check for an unsupported contents argument. The request entity format
323: // for MKCOL is not yet defined, so all contents are unsupported
324: if (contents != null) {
325: throw new WebDAVException(
326: WebDAVStatus.SC_UNSUPPORTED_MEDIA_TYPE,
327: "Creating collections from contents not supported yet");
328: }
329:
330: // create the collection
331: namespaceManager.createCollection(ResourceFactory
332: .getRealPath(getURL()));
333:
334: // get the default properties, and write them out too.
335: Document properties = loadProperties();
336: saveProperties(properties);
337:
338: // inherit any deep locks on the parent collection
339: inheritParentDeepLocks();
340: MultiStatus status = new MultiStatus();
341: MethodResponse response = new MethodResponse(getURL()
342: .toString(), WebDAVStatus.SC_CREATED);
343: status.addResponse(response);
344: getResponseContext().contentType("text/xml");
345: return status;
346: }
347:
348: /** Delete this resouce collection and all its members from the server.
349: * The actual effect of the delete operation is determined by the underlying
350: * repository manager. The visible effect to WebDAV is that the resource
351: * is no longer available.
352: *
353: * @return a MultiStatus containing the status of the delete method on each
354: * effected resource.
355: * @exception com.ibm.webdav.WebDAVException
356: */
357: public MultiStatus delete(ResourceContext context)
358: throws WebDAVException {
359: this .context = context;
360:
361: MultiStatus result = new MultiStatus();
362:
363: // delete all the members first
364: Enumeration members = namespaceManager.getMembers().elements();
365: while (members.hasMoreElements()) {
366: ResourceImpl member = (ResourceImpl) members.nextElement();
367: try {
368: MultiStatus memberResult = null;
369: memberResult = member.delete(context);
370: if (!memberResult.isOK()) {
371: result.mergeWith(memberResult);
372: }
373: } catch (WebDAVException exc) {
374: MethodResponse response = new MethodResponse(member
375: .getURL().toString(), exc);
376: result.addResponse(response);
377: } catch (Exception e) {
378: e.printStackTrace();
379: throw new WebDAVException(
380: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
381: "unable to delete resource");
382: }
383: }
384:
385: // now delete this collection
386: if (result.isOK()) {
387: try {
388: MultiStatus this Result = super .delete(context);
389: if (!this Result.isOK()) {
390: result.mergeWith(this Result);
391: }
392: } catch (WebDAVException exc) {
393: //MethodResponse response = new MethodResponse(getURL().toString(), exc.getStatusCode());
394: MethodResponse response = new MethodResponse(getURL()
395: .toString(), exc);
396: result.addResponse(response);
397: } catch (Exception e) {
398: e.printStackTrace();
399: throw new WebDAVException(
400: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
401: "unable to delete resource");
402: }
403: }
404: getResponseContext().contentType("text/xml");
405: return result;
406: }
407:
408: /** Unlock the lock identified by the lockToken on this resource. This method
409: * is used internally to unlock resources copied or moved as well as unlocked.
410: * For a resource collection, unlock all the members that are locked with the
411: * same lock token.
412: *
413: * @param lockToken the lock token obtained from the ActiveLock of a previous <code>lock() </code>
414: * or <code>getLocks()</code>.
415: *
416: * @return a MultiStatus containing any responses on resources that could not
417: * be unlocked.
418: * @exception com.ibm.webdav.WebDAVException
419: */
420: protected MultiStatus doUnlock(String lockToken)
421: throws WebDAVException {
422: // find all the locks identified by this lockToken, and unlock them.
423:
424: MultiStatus result = new MultiStatus();
425:
426: // get the ActiveLock to unlock
427: ActiveLock lockToUnlock = null;
428: Enumeration activeLocks = getLocks().elements();
429: while (activeLocks.hasMoreElements()) {
430: ActiveLock activeLock = (ActiveLock) activeLocks
431: .nextElement();
432: if (activeLock.getLockToken().equals(lockToken)) {
433: lockToUnlock = activeLock;
434: break;
435: }
436: }
437:
438: // unlock the lock on this collection and then check all its
439: // members for a lock using the same lockToken.
440: if (lockToUnlock != null
441: && lockToUnlock.getDepth().equals(Collection.deep)) {
442: Enumeration members = namespaceManager.getMembers()
443: .elements();
444: while (members.hasMoreElements()) {
445: ResourceImpl member = (ResourceImpl) members
446: .nextElement();
447: member.getRequestContext().precondition(
448: getRequestContext().precondition());
449: member.getRequestContext().authorization(
450: getRequestContext().authorization());
451: try {
452: MultiStatus memberResult = member
453: .doUnlock(lockToken);
454: result.mergeWith(memberResult);
455: } catch (WebDAVException exc) {
456: MethodResponse response = new MethodResponse(member
457: .getURL().toString(), exc.getStatusCode());
458: result.addResponse(response);
459: } catch (Exception e) {
460: e.printStackTrace();
461: throw new WebDAVException(
462: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
463: "unable to delete resource");
464: }
465: }
466: }
467:
468: // Unlock this lock
469: MultiStatus r = super .doUnlock(lockToken);
470: if (!r.isOK()) {
471: result.mergeWith(r);
472: }
473: getResponseContext().contentType("text/xml");
474: return result;
475: }
476:
477: /** Get the URL of a child of this resource treating the resource
478: * as a collection
479: *
480: * @param childName the local repository name for the child resource
481: * @return the child URL
482: * @exception com.ibm.webdav.WebDAVException
483: */
484: public URL getChildURL(String childName) throws WebDAVException {
485: String uri = getURL().getFile();
486: if (!uri.endsWith("/")) {
487: uri = uri + "/";
488: }
489: URL child = null;
490: try {
491: child = new URL(getURL(), uri + childName);
492: } catch (java.net.MalformedURLException exc) {
493: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
494: "Malformed URL");
495: }
496: return child;
497: }
498:
499: /** The WebDAV spec does not explicitly define the contents of a collection.
500: * Rather it obtains the members of a collection by doing a PROPFIND with
501: * depth="infinity" and gets the href elements from the response elements
502: * to determine the members of a collection. This implementation returns
503: * and XML document containing the URLs of the members of the collection.
504: * @return an InputStream on an XML document containing the members of this collection
505: * @exception com.ibm.webdav.WebDAVException
506: */
507: public InputStream getContentsInputStream() throws WebDAVException {
508: // validate the uri
509: if (!hasValidURI()) {
510: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
511: "Invalid URI");
512: }
513: InputStream is = namespaceManager.getContentsInputStream();
514:
515: // set the content type
516: getResponseContext().contentType("text/xml");
517: return is;
518: }
519:
520: /** WebDAV does not allow PUT to collections. Use Collection.createCollection()
521: * (MKCOL) instead.
522: * @return nothing
523: * @exception com.ibm.webdav.WebDAVException throws METHOD_NOT_ALLOWED for all collections
524: */
525: public OutputStream getContentsOutputStream()
526: throws WebDAVException {
527: throw new WebDAVException(WebDAVStatus.SC_METHOD_NOT_ALLOWED,
528: "Cannot use PUT on collections, use MKCOL instead.");
529: }
530:
531: /** Get the members of this Collection.
532: * @return an Vector of CollectionMembers
533: * @exception com.ibm.webdav.WebDAVException
534: * @see CollectionMember
535: */
536: public Vector getMembers() throws WebDAVException {
537: return namespaceManager.getMembers();
538: }
539:
540: /** Get the named properties for this resource and (potentially) its children.
541: *
542: * @param names an array of PropertyNames to retrieve.
543: * @param depth an indicator for immediate members or recursively all children.
544: * <ul>
545: * <li>immediateMembers: propeprties of this resource and its immediate children</li>
546: * <li>allMembers: properties of this resource and recursively all its children</li>
547: * </ul>
548: *
549: * @return a MultiStatus of PropertyResponses
550: * @exception com.ibm.webdav.WebDAVException
551: */
552: public MultiStatus getProperties(ResourceContext context,
553: PropertyName names[], String depth) throws WebDAVException {
554: this .context = context;
555:
556: // check the depth parameter
557: if (!(depth.equals(Collection.this Resource)
558: || depth.equals(Collection.immediateMembers) || depth
559: .equals(Collection.allMembers))) {
560: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
561: "Invalid depth on copy");
562: }
563:
564: MultiStatus result = super .getProperties(context, names);
565: String memberDepth = depth;
566: if (depth.equals(Collection.immediateMembers)) {
567: memberDepth = Collection.this Resource;
568: }
569:
570: // now get the properties of the members if necessary
571: if (!depth.equals(Collection.this Resource)) {
572: Enumeration members = namespaceManager.getMembers()
573: .elements();
574: while (members.hasMoreElements()) {
575: ResourceImpl member = (ResourceImpl) members
576: .nextElement();
577: try {
578: MultiStatus memberResult = null;
579: if (member.isCollection()) {
580: memberResult = ((CollectionImpl) member)
581: .getProperties(context, names,
582: memberDepth);
583: } else {
584: memberResult = member.getProperties(context,
585: names);
586: }
587: result.mergeWith(memberResult);
588: } catch (WebDAVException exc) {
589: exc.printStackTrace();
590: MethodResponse response = new MethodResponse(member
591: .getURL().toString(), exc.getStatusCode());
592: result.addResponse(response);
593: } catch (Exception e) {
594: e.printStackTrace();
595: throw new WebDAVException(
596: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
597: "Error getting properties");
598: }
599: }
600: }
601: getResponseContext().contentType("text/xml");
602: return result;
603: }
604:
605: /** Get all the properties for this resource and (potentially) its children.
606: *
607: * @param depth an indicator for immediate members or recursively all children.
608: * <ul>
609: * <li>thisResource: propeprties of this resource</li>
610: * <li>immediateMembers: propeprties of this resource and its immediate children</li>
611: * <li>allMembers: properties of this resource and recursively all its children</li>
612: * </ul>
613: *
614: * @return a MultiStatus of PropertyResponses
615: * @exception com.ibm.webdav.WebDAVException
616: */
617: public MultiStatus getProperties(ResourceContext context,
618: String depth) throws WebDAVException {
619: this .context = context;
620:
621: // check the depth parameter
622: if (!(depth.equals(Collection.this Resource)
623: || depth.equals(Collection.immediateMembers) || depth
624: .equals(Collection.allMembers))) {
625: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
626: "Invalid depth on copy");
627: }
628:
629: MultiStatus result = super .getProperties(context);
630: String memberDepth = depth;
631: if (depth.equals(Collection.immediateMembers)) {
632: memberDepth = Collection.this Resource;
633: }
634:
635: // now get the properties of the members if necessary
636: if (!depth.equals(Collection.this Resource)) {
637: Enumeration members = namespaceManager.getMembers()
638: .elements();
639: while (members.hasMoreElements()) {
640: ResourceImpl member = (ResourceImpl) members
641: .nextElement();
642: try {
643: MultiStatus memberResult = null;
644: if (member.isCollection()) {
645: memberResult = ((CollectionImpl) member)
646: .getProperties(context, memberDepth);
647: } else {
648: memberResult = member.getProperties(context);
649: }
650: result.mergeWith(memberResult);
651: } catch (WebDAVException exc) {
652: exc.printStackTrace();
653: MethodResponse response = new MethodResponse(member
654: .getURL().toString(), exc.getStatusCode());
655: result.addResponse(response);
656: } catch (Exception e) {
657: e.printStackTrace();
658: throw new WebDAVException(
659: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
660: "unable to get properties");
661: }
662: }
663: }
664: getResponseContext().contentType("text/xml");
665: return result;
666: }
667:
668: /** Get the names of all properties for this resource and (potentially) its children.
669: *
670: * @param depth an indicator for immediate members or recursively all children.
671: * <ul>
672: * <li>thisResource: propeprties of this resource</li>
673: * <li>immediateMembers: propeprties of this resource and its immediate children</li>
674: * <li>allMembers: properties of this resource and recursively all its children</li>
675: * </ul>
676: *
677: * @return a MultiStatus of PropertyResponses
678: * (PropertyValue.value is always null, PropertyValue.status contains the status)
679: * @exception com.ibm.webdav.WebDAVException
680: */
681: public MultiStatus getPropertyNames(ResourceContext context,
682: String depth) throws WebDAVException {
683: this .context = context;
684:
685: // check the depth parameter
686: if (!(depth.equals(Collection.this Resource)
687: || depth.equals(Collection.immediateMembers) || depth
688: .equals(Collection.allMembers))) {
689: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
690: "Invalid depth on copy");
691: }
692: MultiStatus result = super .getPropertyNames(context);
693: String memberDepth = depth;
694: if (depth.equals(Collection.immediateMembers)) {
695: memberDepth = Collection.this Resource;
696: }
697:
698: // now get the properties of the members if necessary
699: if (!depth.equals(Collection.this Resource)) {
700: Enumeration members = namespaceManager.getMembers()
701: .elements();
702: while (members.hasMoreElements()) {
703: ResourceImpl member = (ResourceImpl) members
704: .nextElement();
705: try {
706: MultiStatus memberResult = null;
707: if (member.isCollection()) {
708: memberResult = ((CollectionImpl) member)
709: .getPropertyNames(context, memberDepth);
710: } else {
711: memberResult = member.getPropertyNames(context);
712: }
713: result.mergeWith(memberResult);
714: } catch (WebDAVException exc) {
715: exc.printStackTrace();
716: MethodResponse response = new MethodResponse(member
717: .getURL().toString(), exc.getStatusCode());
718: result.addResponse(response);
719: } catch (Exception e) {
720: e.printStackTrace();
721: throw new WebDAVException(
722: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
723: "unable to delete resource");
724: }
725: }
726: }
727: getResponseContext().contentType("text/xml");
728: return result;
729: }
730:
731: /** Returns true if this Resource is a collection. Returns false otherwise.
732: *
733: * @return true if this Resource is a collection.
734: * @exception com.ibm.webdav.WebDAVException
735: */
736: public boolean isCollection() throws WebDAVException {
737: return true;
738: }
739:
740: /** Lock this resource with the information contained in the given active lock.
741: * @param activeLock information about the lock
742: * @return a MultiStatus containing a lockdiscovery property indicating
743: * @exception com.ibm.webdav.WebDAVException
744: */
745: protected MultiStatus lock(ActiveLock activeLock)
746: throws WebDAVException {
747: // get the locks on this resource
748: Enumeration locks = getLocks().elements();
749: while (locks.hasMoreElements()) {
750: ActiveLock lock = (ActiveLock) locks.nextElement();
751: if (lock.getScope().equals(ActiveLock.exclusive)) {
752: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
753: "Resource has an exclusive lock");
754: }
755: if (lock.getScope().equals(ActiveLock.shared)
756: && activeLock.getScope().equals(
757: ActiveLock.exclusive)) {
758: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
759: "Resource already has a shared lock");
760: }
761: if (lock.getScope().equals(ActiveLock.shared)
762: && lock.getPrincipal().equals(
763: activeLock.getPrincipal())) {
764: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
765: "The principal already has a lock on this resource");
766: }
767: }
768:
769: // first lock this collection
770: MultiStatus result = super .lock(activeLock);
771:
772: // now lock all the members if necessary
773: if (activeLock.getDepth().equals(Collection.deep)) {
774: Enumeration members = namespaceManager.getMembers()
775: .elements();
776: while (members.hasMoreElements()) {
777: ResourceImpl member = (ResourceImpl) members
778: .nextElement();
779: member.getRequestContext().precondition(
780: getRequestContext().precondition());
781: member.getRequestContext().authorization(
782: getRequestContext().authorization());
783: try {
784: MultiStatus memberResult = member.lock(activeLock);
785: result.mergeWith(memberResult);
786: } catch (WebDAVException exc) {
787: MethodResponse response = new MethodResponse(member
788: .getURL().toString(), exc.getStatusCode());
789: result.addResponse(response);
790: } catch (Exception e) {
791: e.printStackTrace();
792: throw new WebDAVException(
793: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
794: "unable to delete resource");
795: }
796: }
797: }
798:
799: return result;
800: }
801:
802: /** Lock this resource collection and potentially all its members
803: * based on the given parameters. This allows control of the lock
804: * scope (exclusive or shared) the lock type (write), owner information, etc.
805: *
806: * @param scope the scope of the lock, exclusive or shared
807: * @param type the type of the lock, currently only write
808: * @param timeout the number of seconds before the lock times out or
809: * 0 for infinite timeout.
810: * @param owner an XML element containing useful information that can be
811: * used to identify the owner of the lock. An href to a home page, an
812: * email address, phone number, etc. Can be null if no owner information
813: * is provided.
814: *
815: * @return a MultiStatus containing a lockdiscovery property indicating
816: * the results of the lock operation.
817: * @exception com.ibm.webdav.WebDAVException
818: */
819: public MultiStatus lock(ResourceContext context, String scope,
820: String type, int timeout, Element owner)
821: throws WebDAVException {
822: return lock(context, scope, type, timeout, owner,
823: Collection.deep);
824: }
825:
826: /** Lock this resource collection and potentially all its members
827: * based on the given parameters. This allows control of the lock
828: * scope (exclusive or shared) the lock type (write), owner information, etc.
829: *
830: * @param scope the scope of the lock, exclusive or shared
831: * @param type the type of the lock, currently only write
832: * @param timeout the number of seconds before the lock times out or
833: * 0 for infinite timeout.
834: * @param owner an XML element containing useful information that can be
835: * used to identify the owner of the lock. An href to a home page, an
836: * email address, phone number, etc. Can be null if no owner information
837: * is provided.
838: * @param depth
839: * <ul>
840: * <li>shallow lock only this resource</li>
841: * <li>deep lock this resource and all its children</li>
842: * </ul>
843: *
844: * @return a MultiStatus containing a lockdiscovery property indicating
845: * the results of the lock operation.
846: * @exception com.ibm.webdav.WebDAVException
847: */
848: public MultiStatus lock(ResourceContext context, String scope,
849: String type, int timeout, Element owner, String depth)
850: throws WebDAVException {
851: this .context = context;
852:
853: // check the depth parameter
854: if (!(depth.equals(Collection.shallow) || depth
855: .equals(Collection.deep))) {
856: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
857: "Invalid depth on copy");
858: }
859:
860: // lock the collection, and use the same lock token for all its members
861: ActiveLock activeLock = getActiveLockFor(scope, type, timeout,
862: owner);
863: activeLock.setDepth(depth);
864: MultiStatus result = lock(activeLock);
865:
866: // remove all granted locks if all the requests couldn't be satisfied
867: if (!result.isOK()) {
868: try {
869: unlock(context, activeLock.getLockToken());
870: } catch (Exception exc) {
871: }
872: // remove all the lockdiscovery elements from the result for the locks
873: // that were unlocked
874: result.removeOKResponses();
875: }
876:
877: // return the granted lock token in the lockToken response context
878: getResponseContext().lockToken(activeLock.getLockToken());
879: getResponseContext().contentType("text/xml");
880: return result;
881: }
882:
883: /** Refresh the lock on this resource collection and all its members locked
884: * by the same lock token by resetting the lock timeout.
885: * The context must contain the proper authorization for the requesting
886: * principal.
887: *
888: * @param lockToken the lock token identifying the lock.
889: * @param timeout the new timeout in seconds. -1 means infinite timeout.
890: * @return updated information about the lock status of this resource
891: * @exception com.ibm.webdav.WebDAVException
892: */
893: public MultiStatus refreshLock(ResourceContext context,
894: String lockToken, int timeout) throws WebDAVException {
895: this .context = context;
896:
897: // find all the locks identified by this lockToken, and refresh them.
898:
899: // first, is this the root parent collection locked by this lockToken
900: if (parentIsLockedWith(lockToken)) {
901: throw new WebDAVException(
902: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
903: "Must refresh depth lock from root collection having the lock.");
904: }
905:
906: // Refresh this lock
907: MultiStatus result = super .refreshLock(context, lockToken,
908: timeout);
909:
910: // get the new ActiveLock
911: ActiveLock lockToRefresh = null;
912: Enumeration activeLocks = getLocks().elements();
913: while (activeLocks.hasMoreElements()) {
914: ActiveLock activeLock = (ActiveLock) activeLocks
915: .nextElement();
916: if (activeLock.getLockToken().equals(lockToken)) {
917: lockToRefresh = activeLock;
918: break;
919: }
920: }
921:
922: // refresh the lock on this collection and then check all its
923: // members for a lock using the same lockToken.
924: if (lockToRefresh.getDepth().equals(Collection.deep)) {
925: Enumeration members = namespaceManager.getMembers()
926: .elements();
927: while (members.hasMoreElements()) {
928: Resource member = (Resource) members.nextElement();
929: member.getRequestContext().precondition(
930: getRequestContext().precondition());
931: member.getRequestContext().authorization(
932: getRequestContext().authorization());
933: try {
934: MultiStatus memberResult = member.refreshLock(
935: lockToken, timeout);
936: result.mergeWith(memberResult);
937: } catch (WebDAVException exc) {
938: MethodResponse response = new MethodResponse(member
939: .getURL().toString(), exc.getStatusCode());
940: result.addResponse(response);
941: } catch (Exception e) {
942: e.printStackTrace();
943: throw new WebDAVException(
944: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
945: "unable to delete resource");
946: }
947: }
948: }
949: getResponseContext().contentType("text/xml");
950: return result;
951: }
952:
953: /**
954: * Sets the ordering of the members of this collection
955: *
956: * @param context
957: * @param orderPatch
958: * @throws WebDAVException
959: */
960: public MultiStatus setOrdering(ResourceContext context,
961: Document orderPatch) throws WebDAVException {
962: // make sure the resource exists.
963: if (exists() == false) {
964: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
965: "Resource does not exist");
966: }
967:
968: if (isCollection() == false) {
969: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
970: "Resource is not collection");
971: }
972:
973: // check to see if the resource is locked by another user
974: if (isLocked() && isLockedByMe() == false) {
975: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
976: "Resource is locked by another user");
977: }
978:
979: MultiStatus result = new MultiStatus();
980:
981: try {
982: namespaceManager.setOrdering(orderPatch);
983: } catch (WebDAVException e) {
984: //TODO sort out proper error reporting
985: result
986: .addResponse(new MethodResponse(getURL().getPath(),
987: e));
988: }
989:
990: return result;
991: }
992: }
|