KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > webdav > impl > ResourceImpl


1 /*
2  * (C) Copyright IBM Corp. 2000 All rights reserved.
3  *
4  * The program is provided "AS IS" without any warranty express or
5  * implied, including the warranty of non-infringement and the implied
6  * warranties of merchantibility and fitness for a particular purpose.
7  * IBM will not be liable for any damages suffered by you as a result
8  * of using the Program. In no event will IBM be liable for any
9  * special, indirect or consequential damages or lost profits even if
10  * IBM has been advised of the possibility of their occurrence. IBM
11  * will not be liable for any third party claims against you.
12  *
13  * Portions Copyright (C) Simulacra Media Ltd, 2004.
14  */

15
16 package com.ibm.webdav.impl;
17
18 //import java.net.URLConnection;
19
import java.io.*;
20 import java.net.*;
21 import java.rmi.*;
22 import java.rmi.server.*;
23 import java.util.*;
24
25 import javax.xml.parsers.*;
26
27 import org.w3c.dom.*;
28
29 import com.ibm.webdav.*;
30 import com.ibm.webdav.Collection;
31 import com.ibm.webdav.protocol.http.*;
32
33 /** Implements the Resource interface and all the WebDAV semantics. ResourceImpl
34 * delegates certain low-level repository operations to managers provided for a
35 * particular repository implementation. There are three repository managers
36 * factoring the repository-specific behavior: NamesapceManager, PropertiesManager,
37 * and LockManager. ResourceImplFactory constructs the appropriate managers for
38 * this resource based on its URL. Mapping information from URL to repository
39 * manager is configured in the dav4j.properties file.
40 * <p>
41 * ResourceImpl is generally used by a server to implement the WebDAV protocol.
42 * However, it may also be used directly on the client if the resource URL is the localhost
43 * and in that case, there are no remote procedure calls, and no need for a
44 * server to run.
45 * @author Jim Amsden &lt;jamsden@us.ibm.com&gt;
46 * @see ResourceImplCollection
47 * @see ResourceHTTPSkel
48 */

49 public class ResourceImpl implements IRResource {
50     /** Setting debug to true causes debug information to be printed to System.err for
51     * each method. This value can be changed by setting its value in
52     * the dav4j.properties file and restarting the server.
53     */

54     public static boolean debug = false;
55     public static java.util.Properties JavaDoc webdavProperties =
56         new java.util.Properties JavaDoc();
57     // properties taken from dav4j.properties.
58
private static Vector liveProperties = new Vector();
59     // the generic live properties
60

61     static {
62         // Find the dav4j.properties file in the classpath
63
String JavaDoc classpath = System.getProperty("java.class.path");
64         StringTokenizer paths = new StringTokenizer(classpath, ";");
65         File propertiesFile = null;
66         boolean found = false;
67
68         while (!found && paths.hasMoreTokens()) {
69             String JavaDoc path = paths.nextToken();
70             propertiesFile = new File(path, "dav4j.properties");
71             found = propertiesFile.exists();
72         }
73
74         if (found) {
75             try {
76                 webdavProperties.load(new FileInputStream(propertiesFile));
77             } catch (Exception JavaDoc exc) {
78                 exc.printStackTrace();
79             }
80         }
81
82         String JavaDoc debugString = webdavProperties.getProperty("debug");
83         debug = (debugString != null) && debugString.equals("true");
84
85         // create the live properties
86
liveProperties.addElement(new LockDiscovery());
87     }
88
89     // contexts for communicating HTTP and WebDAV headers (method contol couples)
90
protected ResourceContext context = new ResourceContext();
91
92     //------------------------------------------------------------------------------------
93
protected String JavaDoc fileName = null;
94     protected URL url = null;
95     protected NamespaceManager namespaceManager = null;
96     protected PropertiesManager propertiesManager = null;
97     protected LockManager lockManager = null;
98     static protected SearchManager searchManager = null;
99     static protected UserAuthenticator authenticator = null;
100
101     public ResourceImpl() {
102         this.url = null;
103         this.fileName = null;
104     }
105
106     /** Construct a ResourceImpl for the given URL.
107     *
108     * @param url the URL of the resource
109     * @param localName a translation of the URL (filePortion) into
110     * a name that has local meaning to a server.
111     * @exception com.ibm.webdav.WebDAVException
112     */

113     public ResourceImpl(URL url, String JavaDoc localName) throws WebDAVException {
114         this.url = url;
115         this.fileName = localName;
116
117         if (url.getProtocol().equals("rmi")) {
118             try {
119                 UnicastRemoteObject.exportObject(this);
120             } catch (java.rmi.RemoteException JavaDoc exc) {
121                 throw new WebDAVException(
122                     WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
123                     "Unable to export rmi object");
124             }
125         }
126
127         // TODO: get the Namespace to use from the dav4j.properties file
128
// need to use a factory to do this
129
namespaceManager = ResourceImplFactory.createNamespaceManager(this);
130         propertiesManager =
131             ResourceImplFactory.createPropertiesManager(this, namespaceManager);
132         lockManager =
133             ResourceImplFactory.createLockManager(
134                 this,
135                 namespaceManager,
136                 propertiesManager);
137         
138         if(searchManager == null) {
139             searchManager = ResourceImplFactory.createSearchManager(this);
140         }
141         
142         if(authenticator == null) {
143             authenticator = ResourceImplFactory.getAuthenticator(this);
144         }
145         
146
147         // Set some default response context
148
// Don't let proxy servers cache contents or properties
149
getResponseContext().put("Cache-Control", "No-Cache");
150         getResponseContext().put("Pragma", "No-Cache");
151
152         // identify ourselves
153
getResponseContext().put("Server", "IBM DAV4J Server/1.0");
154     }
155
156     /** Construct a ResourceImpl for the given URL.
157     *
158     * @param url the URL of the resource
159     * @param localName a translation of the URL (filePortion) into
160     * a name that has local meaning to a server.
161     * @param targetSelector the revision target selector for this Collection
162     * @exception com.ibm.webdav.WebDAVException
163     */

164     public ResourceImpl(
165         URL url,
166         String JavaDoc localName,
167         TargetSelector targetSelector)
168         throws WebDAVException {
169         this.url = url;
170         this.fileName = localName;
171
172         if (url.getProtocol().equals("rmi")) {
173             try {
174                 UnicastRemoteObject.exportObject(this);
175             } catch (java.rmi.RemoteException JavaDoc exc) {
176                 throw new WebDAVException(
177                     WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
178                     "Unable to export rmi object");
179             }
180         }
181
182         // TODO: get the Namespace to use from the dav4j.properties file
183
// need to use a factory to do this
184
namespaceManager = ResourceImplFactory.createNamespaceManager(this);
185         propertiesManager =
186             ResourceImplFactory.createPropertiesManager(this, namespaceManager);
187         lockManager =
188             ResourceImplFactory.createLockManager(
189                 this,
190                 namespaceManager,
191                 propertiesManager);
192         if(searchManager == null) {
193             searchManager = ResourceImplFactory.createSearchManager(this);
194         }
195     
196         if(authenticator == null) {
197             authenticator = ResourceImplFactory.getAuthenticator(this);
198         }
199
200         // Set some default response context
201
// Don't let proxy servers cache contents or properties
202
getResponseContext().put("Cache-Control", "No-Cache");
203         getResponseContext().put("Pragma", "No-Cache");
204
205         // identify ourselves
206
getResponseContext().put("Server", "IBM DAV4J Server/1.0");
207     }
208
209     /** This method must be called after the client has completed writing to the contents
210      * output stream that was obtained from <code>getContentsOutputStream()</code>.
211      * @exception com.ibm.webdav.WebDAVException
212      */

213     public void closeContentsOutputStream(ResourceContext context)
214         throws WebDAVException {
215             closeContentsOutputStream(context,null);
216     }
217
218     /** Copy this resource to the destination URL.
219      * Partial results are possible, check the returned status for details.
220      *
221      * @param destinationURL the destination
222      * @param overwrite true implies overrite the destination if it exists
223      * @param propertiesToCopy a collection of properties that must be copied or
224      * the method will fail. propertiesToCopy may have one of the following values:
225      * <ul>
226      * <li>null - ignore properties that cannot be copied</li>
227      * <li>empty collection - all properties must be copied or the method will fail</li>
228      * <li>a collection of URIs - a list of the properties that must be copied
229      * or the method will fail</li>
230      * </ul>
231      *
232      * @return the status of the copy operation for each resource copied
233      * @exception com.ibm.webdav.WebDAVException
234      */

235     public MultiStatus atomicMove(
236         ResourceContext context,
237         String JavaDoc destinationURL,
238         boolean overwrite)
239         throws WebDAVException {
240         this.context = context;
241
242         setStatusCode(WebDAVStatus.SC_CREATED);
243
244         // create a MultiStatus to hold the results
245
MultiStatus multiStatus = new MultiStatus();
246
247         try {
248             // validate the uri
249
if (!hasValidURI()) {
250                 throw new WebDAVException(
251                     WebDAVStatus.SC_BAD_REQUEST,
252                     "Invalid URI");
253             }
254
255             // make sure the resource exists
256
if (!exists()) {
257                 throw new WebDAVException(
258                     WebDAVStatus.SC_NOT_FOUND,
259                     "Cannot copy a lock-null resource");
260             }
261
262             // the destination may be a relative URL
263
URL destURL = new URL(this.url, destinationURL);
264             Resource destination = new Resource(destURL.toString());
265
266             // are the source and destination the same?
267
if (this.equals(destination)) {
268                 throw new WebDAVException(
269                     WebDAVStatus.SC_FORBIDDEN,
270                     "Can't copy source on top of itself");
271             }
272
273             // is the destination locked?
274
destination.getRequestContext().precondition(
275                 getRequestContext().precondition());
276             destination.getRequestContext().authorization(
277                 getRequestContext().authorization());
278
279             if (destination.exists()) {
280                 if (destination.isLocked()) {
281                     if (!destination.isLockedByMe()) {
282                         throw new WebDAVException(
283                             WebDAVStatus.SC_LOCKED,
284                             "Destination resource is locked");
285                     }
286                 }
287             }
288
289             // check to see if the destination exists and its OK to overwrite it
290
if (destination.exists()) {
291                 if (!overwrite) {
292                     throw new WebDAVException(
293                         WebDAVStatus.SC_PRECONDITION_FAILED,
294                         "Destination exists and overwrite not specified");
295                 } else {
296                     setStatusCode(WebDAVStatus.SC_NO_CONTENT);
297                 }
298             }
299
300             this.namespaceManager.move(
301                 URLDecoder.decode(ResourceFactory.getRealPath(destURL)));
302
303             // everything must have gone OK, there
304
// is no response for a successful delete
305
getResponseContext().contentType("text/xml");
306         } catch (WebDAVException exc) {
307             throw exc;
308         } catch (java.net.MalformedURLException JavaDoc exc) {
309             throw new WebDAVException(
310                 WebDAVStatus.SC_BAD_REQUEST,
311                 "Malformed URL");
312         } catch (java.io.IOException JavaDoc exc) {
313             throw new WebDAVException(
314                 WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
315                 "IO Error");
316         }
317
318         return multiStatus;
319     }
320
321     /** Copy this resource to the destination URL.
322      * Partial results are possible, check the returned status for details.
323      *
324      * @param destinationURL the destination
325      * @param overwrite true implies overrite the destination if it exists
326      * @param propertiesToCopy a collection of properties that must be copied or
327      * the method will fail. propertiesToCopy may have one of the following values:
328      * <ul>
329      * <li>null - ignore properties that cannot be copied</li>
330      * <li>empty collection - all properties must be copied or the method will fail</li>
331      * <li>a collection of URIs - a list of the properties that must be copied
332      * or the method will fail</li>
333      * </ul>
334      *
335      * @return the status of the copy operation for each resource copied
336      * @exception com.ibm.webdav.WebDAVException
337      */

338     public MultiStatus copy(
339         ResourceContext context,
340         String JavaDoc destinationURL,
341         boolean overwrite,
342         Vector propertiesToCopy)
343         throws WebDAVException {
344         this.context = context;
345
346         setStatusCode(WebDAVStatus.SC_CREATED);
347
348         // create a MultiStatus to hold the results
349
MultiStatus multiStatus = new MultiStatus();
350
351         try {
352             // validate the uri
353
if (!hasValidURI()) {
354                 throw new WebDAVException(
355                     WebDAVStatus.SC_BAD_REQUEST,
356                     "Invalid URI");
357             }
358
359             // make sure the resource exists
360
if (!exists()) {
361                 throw new WebDAVException(
362                     WebDAVStatus.SC_NOT_FOUND,
363                     "Cannot copy a lock-null resource");
364             }
365
366             // the destination may be a relative URL
367
URL destURL = new URL(this.url, destinationURL);
368             Resource destination = new Resource(destURL.toString());
369             
370             String JavaDoc sContentType = namespaceManager.getContentType();
371
372             // are the source and destination the same?
373
if (this.equals(destination)) {
374                 throw new WebDAVException(
375                     WebDAVStatus.SC_FORBIDDEN,
376                     "Can't copy source on top of itself");
377             }
378
379             // is the destination locked?
380
destination.getRequestContext().precondition(
381                 getRequestContext().precondition());
382             destination.getRequestContext().authorization(
383                 getRequestContext().authorization());
384
385             if (destination.exists()) {
386                 if (destination.isLocked()) {
387                     if (!destination.isLockedByMe()) {
388                         throw new WebDAVException(
389                             WebDAVStatus.SC_LOCKED,
390                             "Destination resource is locked");
391                     }
392                 }
393             }
394
395             // check to see if the destination exists and its OK to overwrite it
396
if (destination.exists()) {
397                 if (!overwrite) {
398                     throw new WebDAVException(
399                         WebDAVStatus.SC_PRECONDITION_FAILED,
400                         "Destination exists and overwrite not specified");
401                 } else {
402                     setStatusCode(WebDAVStatus.SC_NO_CONTENT);
403                 }
404             }
405
406             InputStream is = getContentsInputStream(context);
407             
408             
409             OutputStream os = destination.getContentsOutputStream();
410             if(is != null) {
411                 byte[] buf = new byte[8192];
412                 int numRead = 0;
413     
414                 while ((numRead = is.read(buf, 0, buf.length)) != -1) {
415                     os.write(buf, 0, numRead);
416                 }
417                 is.close();
418             }
419     
420             destination.closeContentsOutputStream(sContentType);
421
422             // copy the properties
423
WebDAVStatus savedStatusCode = getStatusCode();
424             MultiStatus ms2 = copyProperties(destination, propertiesToCopy);
425
426             if (!ms2.isOK()) {
427                 // todo: add code here to back out this partial copy. That might require
428
// restoring the resource that used to be at the destination. For now, we'll throw
429
// an exception.
430
throw new WebDAVException(
431                     WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
432                     "problem copying properties");
433             }
434
435             setStatusCode(savedStatusCode);
436
437             // remove all locks on the destination. Copy doesn't copy locks
438
// become super-user for this operation
439
String JavaDoc authorization = getRequestContext().authorization();
440             destination.getRequestContext().setBasicAuthorization("root", "");
441
442             Enumeration locks = destination.getLocks().elements();
443
444             while (locks.hasMoreElements()) {
445                 ActiveLock lock = (ActiveLock) locks.nextElement();
446
447                 // ignore exceptions, the unlock should work
448
try {
449                     destination.unlock(lock.getLockToken());
450                 } catch (Exception JavaDoc exc) {
451                 }
452             }
453
454             destination.getRequestContext().authorization(authorization);
455
456             // everything must have gone OK, there
457
// is no response for a successful delete
458
getResponseContext().contentType("text/xml");
459         } catch (WebDAVException exc) {
460             throw exc;
461         } catch (java.net.MalformedURLException JavaDoc exc) {
462             throw new WebDAVException(
463                 WebDAVStatus.SC_BAD_REQUEST,
464                 "Malformed URL");
465         } catch (java.io.IOException JavaDoc exc) {
466             throw new WebDAVException(
467                 WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
468                 "IO Error");
469         }
470
471         return multiStatus;
472     }
473
474     /** Copy the properties of this resource to the destination resource.
475     * Follow any keepalive instructions in the propertiesToCopy vector.
476     * @param destination the destination resource
477     * @param propertiesToCopy properties that must be kept alive at the destination
478      * <ul>
479      * <li>null - ignore properties that cannot be copied</li>
480      * <li>empty collection - all properties must be copied or the method will fail</li>
481      * <li>a collection of URIs - a list of the properties that must be copied
482      * or the method will fail</li>
483      * </ul>
484     * @return a MultiStatus indicating the result of the copy operation
485     * @exception com.ibm.webdav.WebDAVException
486     */

487     protected MultiStatus copyProperties(
488         Resource destination,
489         Vector propertiesToCopy)
490         throws WebDAVException {
491         MultiStatus result = getProperties(context);
492         boolean bOnlySomeProperties =
493             ((propertiesToCopy != null) && (propertiesToCopy.size() > 0));
494
495         // create a property update document
496
Document document = null;
497
498         try {
499             DocumentBuilderFactory factory =
500                 DocumentBuilderFactory.newInstance();
501             factory.setNamespaceAware(true);
502
503             DocumentBuilder docbuilder = factory.newDocumentBuilder();
504             document = docbuilder.newDocument();
505         } catch (Exception JavaDoc e) {
506             throw new WebDAVException(
507                 WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
508                 e.getMessage());
509         }
510
511         //document.setVersion(Resource.XMLVersion);
512
//document.setEncoding(Resource.defaultXMLEncoding);
513
Element propertyUpdate =
514             document.createElementNS("DAV:", "D:propertyupdate");
515
516         propertyUpdate.setAttribute("xmlns:D", "DAV:");
517         document.appendChild(propertyUpdate);
518
519         Element set = document.createElementNS("DAV:", "D:set");
520
521         propertyUpdate.appendChild(set);
522
523         Element prop = document.createElementNS("DAV:", "D:prop");
524
525         set.appendChild(prop);
526
527         Hashtable PropsWillCopy = new java.util.Hashtable JavaDoc();
528
529         // fill in the properties from the source
530
PropertyResponse response =
531             (PropertyResponse) result.getResponses().nextElement();
532         Enumeration propertyNames = response.getPropertyNamesPN();
533
534         while (propertyNames.hasMoreElements()) {
535             PropertyName name = (PropertyName) propertyNames.nextElement();
536             PropertyValue value = response.getProperty(name);
537             Node node = document.importNode(value.value, true);
538             PropsWillCopy.put(name, node);
539             prop.appendChild((Element) node);
540         }
541
542         // attempt to update all the properties at the destination
543
MultiStatus msRc = destination.setProperties(document);
544
545         // now look at what happened, and adjust based on the propertiesToCopy
546
Enumeration resources = msRc.getResponses();
547
548         while (resources.hasMoreElements()) {
549             Response resmember = (Response) resources.nextElement();
550             PropertyResponse propresponse = resmember.toPropertyResponse();
551             Dictionary htProperties =
552                 (Hashtable) propresponse.getPropertiesByPropName();
553             Enumeration propertynames = htProperties.keys();
554
555             while (propertynames.hasMoreElements()) {
556                 PropertyName propname =
557                     (PropertyName) propertynames.nextElement();
558                 PropertyValue pv = (PropertyValue) htProperties.get(propname);
559                 int stat = pv.getStatus();
560
561                 if ((stat != WebDAVStatus.SC_OK)
562                     && (stat != WebDAVStatus.SC_FAILED_DEPENDENCY)) {
563                     Node node = (Node) PropsWillCopy.get(propname);
564
565                     if ((propertiesToCopy == null)
566                         || (propertiesToCopy.size() > 0
567                             && !propertiesToCopy.contains(propname))) {
568                         prop.removeChild(node); // don't need to copy this one
569
}
570                 }
571             }
572         }
573
574         // attempt to update the remaining properties again
575
// after removing the ones that can be allowed to fail.
576
// This has to be a two step process because there's no
577
// way to determine what properties are live on anoter
578
// server. We're trying to get a propertyupdate element
579
// on PROPPATCH too so this extra step can be avoided.
580
return destination.setProperties(document);
581     }
582
583     /** Create a instance of a ResourceImpl with the given URL and localName.
584     *
585     * @param url the URL of the resource to create
586     * @param localName the name of the resource on the server machine
587     * @return a ResourceImpl or one of its subclasses.
588     * @exception com.ibm.webdav.WebDAVException
589     */

590     public static ResourceImpl create(URL url, String JavaDoc localName)
591         throws WebDAVException {
592         ResourceImpl resource = new ResourceImpl(url, localName);
593
594         if (resource.isCollection()) {
595             resource = new CollectionImpl(url, localName, null);
596         }
597
598         return resource;
599     }
600
601     /** Build a multistatus property response that returns the error specified
602     by the given exception. It should return this error for every property provided
603     in the specified document which should represent the XML of a PROPPATCH
604     request.
605      *
606      * @param exc an exception that describes the error to be placed in the MultiStatus created.
607      * @param updates an XML Document containing DAV:propertyupdate elements
608      * describing the edits that were request orginally requested and
609      * apparently generated the given exception.
610      * @return a MultiStatus indicating the status of the updates
611      * @exception com.ibm.webdav.WebDAVException
612      */

613     public MultiStatus createPropPatchMultiStatus(
614         WebDAVException exc,
615         Document updates)
616         throws WebDAVException {
617         MultiStatus ms2 = new MultiStatus();
618         Element el0 = updates.getDocumentElement();
619         Element txel0 = (Element) el0;
620         NodeList nl = txel0.getElementsByTagNameNS("DAV:", "prop");
621
622         /*Element na[] = txel0.searchDescendantsAll( Match.NSLOCAL, //Match.QNAME,
623         "DAV:", "prop" );*/

624         int nllen = nl.getLength();
625         int idx = 0;
626         String JavaDoc lxx = "xx";
627
628         if (nllen <= 0) {
629             throw exc;
630         }
631
632         while (idx < nllen) {
633             Element txelProp = (Element) nl.item(idx);
634             Node node2 = txelProp.getFirstChild();
635             Element txel2 = null;
636
637             try {
638                 txel2 = (Element) node2;
639             } catch (Exception JavaDoc exc2) {
640                 throw exc;
641             }
642
643             {
644                 // todo: add code to handle the responsedescription in the exception and
645
// include it in the multistatus response.
646
PropertyName pn = new PropertyName(txel2);
647                 PropertyResponse response =
648                     new PropertyResponse(getURL().toString());
649                 response.addProperty(
650                     pn,
651                     (Element) txel2.cloneNode(false),
652                     exc.getStatusCode());
653                 ms2.addResponse(response);
654             }
655
656             idx++;
657         }
658
659         return ms2;
660     }
661
662     /** Delete this resouce from the server. The actual effect of the delete operation is
663      * determined by the underlying repository manager. The visible effect to WebDAV
664      * is that the resource is no longer available.
665      *
666      * @return a MultiStatus containing the status of the delete method on each
667      * effected resource.
668      * @exception com.ibm.webdav.WebDAVException
669      */

670     public MultiStatus delete(ResourceContext context) throws WebDAVException {
671         this.context = context;
672
673         setStatusCode(WebDAVStatus.SC_NO_CONTENT);
674
675         MultiStatus result = new MultiStatus();
676
677         // validate the uri
678
if (!hasValidURI()) {
679             throw new WebDAVException(
680                 WebDAVStatus.SC_BAD_REQUEST,
681                 "Invalid URI");
682         }
683
684         // make sure the parent collection exists
685
CollectionImpl parent = (CollectionImpl) getParentCollection();
686
687         if ((parent != null) && !parent.exists()) {
688             throw new WebDAVException(
689                 WebDAVStatus.SC_CONFLICT,
690                 "Parent collection does not exist");
691         }
692         
693             // TODO support shared locks here or wherever needs it
694
/*
695            *
696      
697            QUICK FIX
698      
699            Commenting this out to allow addition of members to locked collections
700      
701            Will have to implement the shared lock thing eventually to support this
702      
703
704         // make sure the parent collection is not locked, or is locked by this user
705         if (parent != null) {
706             parent.getRequestContext().precondition(
707                 getRequestContext().precondition());
708             parent.getRequestContext().authorization(
709                 getRequestContext().authorization());
710
711             if (parent.isLocked() && !parent.isLockedByMe()) {
712                 throw new WebDAVException(
713                     WebDAVStatus.SC_LOCKED,
714                     "Parent collection is locked by another user");
715             }
716         }
717         */

718
719         if (!exists()) {
720             throw new WebDAVException(
721                 WebDAVStatus.SC_NOT_FOUND,
722                 "Resource does not exist");
723         }
724
725         // check to see if the resource is locked by another user
726
if (isLocked() && !isLockedByMe()) {
727             throw new WebDAVException(
728                 WebDAVStatus.SC_LOCKED,
729                 "Resource is locked by another user");
730         }
731
732         // reset statusCode because isLocked has a side effect of changing it
733
// to 207 multistatus.
734
setStatusCode(WebDAVStatus.SC_NO_CONTENT);
735
736         // Attempt to delete this resource
737
namespaceManager.delete();
738         propertiesManager.deleteProperties();
739         getResponseContext().contentType("text/xml");
740
741         return result;
742     }
743
744     /** Unlock the lock identified by the lockToken on this resource. This method
745      * is used internally to unlock resources copied or moved as well as unlocked.
746      *
747      * @param lockToken the lock token obtained from the ActiveLock of a previous <code>lock() </code>
748      * or <code>getLocks()</code>.
749      *
750      * @return a MultiStatus containing any responses on resources that could not
751      * be unlocked.
752      * @exception com.ibm.webdav.WebDAVException
753      */

754     protected MultiStatus doUnlock(String JavaDoc lockToken) throws WebDAVException {
755         String JavaDoc principal = getRequestContext().getAuthorizationId();
756
757         // get the locks on this resource
758
Enumeration locks = getLocks().elements();
759
760         // find the lock to unlock
761
ActiveLock lockToRemove = null;
762
763         while (locks.hasMoreElements()) {
764             ActiveLock activeLock = (ActiveLock) locks.nextElement();
765             
766             if (activeLock.getLockToken().equals(lockToken)
767                 && (activeLock.getPrincipal().equals(principal)
768                     || principal.equals("root")
769                     || authenticator.isSuperUser(this) == true)) {
770                 lockToRemove = activeLock;
771
772                 break;
773             }
774         }
775
776         if (lockToRemove == null) {
777             throw new WebDAVException(
778                 WebDAVStatus.SC_PRECONDITION_FAILED,
779                 "resource is not locked by this principal");
780         }
781
782         MultiStatus result = lockManager.unlock(lockToRemove);
783
784         // delete a lock-null resource that has no remaining activelocks
785
locks = getLocks().elements();
786
787         if (!locks.hasMoreElements() && namespaceManager.isLockNull()) {
788             propertiesManager.deleteProperties();
789         }
790
791         getResponseContext().contentType("text/xml");
792
793         return result;
794     }
795
796     /** See if the contents of this resource exists. A resource exists
797      * if it has contents or state maintained by a server.
798      *
799      * @return true if the contents exists, false otherwise
800      * @exception com.ibm.webdav.WebDAVException
801      */

802     public boolean exists() throws WebDAVException {
803         return namespaceManager.exists();
804     }
805
806     public boolean authenticateUser(String JavaDoc user, String JavaDoc pwd)
807         throws WebDAVException {
808         boolean bIsAuthenticated = true;
809
810         if (authenticator != null) {
811             bIsAuthenticated = authenticator.authenticate(user, pwd);
812         }
813
814         return bIsAuthenticated;
815     }
816
817     /** Get the active lock on this resource owned by the given principal if any.
818      * NOTE: this method cannot be reliably implemented based on version 10 of
819      * the WebDAV spec as an activelock element in a lockdiscovery does not contain
820      * the authorization credentials of the owner of the lock. For now, this method
821      * relies on an additional principal element in the activelock that contains
822      * the required id. This is an IBM EXTENSTION. When WebDAV ACLs are introduced,
823      * the principal will likely be added to the activelock element.
824      *
825      * @param principal the authorization id of the requesting principal
826      *
827      * @return the active lock owned by that principal or null if the resource is
828      * not locked by that principal.
829      * @exception com.ibm.webdav.WebDAVException
830      */

831     protected ActiveLock getActiveLockFor(
832         String JavaDoc scope,
833         String JavaDoc type,
834         int timeout,
835         Element owner)
836         throws WebDAVException {
837         String JavaDoc principal = getRequestContext().getAuthorizationId();
838
839         if (principal == null) {
840             throw new WebDAVException(
841                 WebDAVStatus.SC_UNAUTHORIZED,
842                 "missing authorization identification");
843         }
844
845         // check all the parameters
846
if ((scope == null)
847             || (!scope.equals(ActiveLock.exclusive)
848                 && !scope.equals(ActiveLock.shared))) {
849             throw new WebDAVException(
850                 WebDAVStatus.SC_BAD_REQUEST,
851                 "unsupported or missing lock scope: " + scope);
852         }
853
854         if ((type == null) || !type.equals(ActiveLock.writeLock)) {
855             throw new WebDAVException(
856                 WebDAVStatus.SC_BAD_REQUEST,
857                 "unsupported or missing lock type: " + type);
858         }
859
860         // handle locking non-existant resources
861
if (!exists()) {
862             namespaceManager.createLockNullResource();
863         }
864
865         // We extend ActiveLock to include the principal and expiration date
866
ActiveLock activeLock = new ActiveLock();
867         activeLock.setScope(scope);
868         activeLock.setLockType(type);
869         activeLock.setDepth(Collection.shallow);
870
871         if (owner != null) {
872             activeLock.setOwner(owner);
873         }
874
875         if (timeout < 0) {
876             activeLock.setTimeout("Infinite");
877         } else {
878             activeLock.setTimeout("Second-" + timeout);
879         }
880
881         String JavaDoc lockToken = "opaquelocktoken:" + new UUID();
882         activeLock.setLockToken(lockToken);
883         activeLock.setPrincipal(principal);
884
885         return activeLock;
886     }
887
888     /** Get an InputStream for accessing the contents of this resource. This method may provide
889      * more efficient access for resources that have large contents. Clients may want to create
890      * a Reader to perform appropriate character conversions on this stream.
891      *
892      * @return an InputStream on the contents
893      * @exception com.ibm.webdav.WebDAVException
894      */

895     public InputStream getContentsInputStream(ResourceContext context)
896         throws WebDAVException {
897         this.context = context;
898
899         // validate the uri
900
if (!hasValidURI()) {
901             throw new WebDAVException(
902                 WebDAVStatus.SC_BAD_REQUEST,
903                 "Invalid URI");
904         }
905
906         InputStream is = namespaceManager.getContentsInputStream();
907
908         return is;
909     }
910
911     /** Get an OutputStream for setting the contents of this resource. This method may provide
912      * more efficient access for resources that have large contents. Remember to call
913      * closeContentsOutputStream() when all the data has been written.
914      *
915      * @return an OutputStream to set the contents
916      * @exception com.ibm.webdav.WebDAVException
917      */

918     public OutputStream getContentsOutputStream(ResourceContext context)
919         throws WebDAVException {
920         this.context = context;
921
922         // validate the uri
923
if (!hasValidURI()) {
924             throw new WebDAVException(
925                 WebDAVStatus.SC_BAD_REQUEST,
926                 "Invalid URI");
927         }
928
929         // make sure the parent collection exists
930
CollectionImpl parent = (CollectionImpl) getParentCollection();
931
932         if ((parent != null) && !parent.exists()) {
933             throw new WebDAVException(
934                 WebDAVStatus.SC_CONFLICT,
935                 "Parent collection does not exist");
936         }
937
938         //TODO support shared locks here or wherever needs it
939
/*
940          *
941          
942          QUICK FIX
943          
944          Commenting this out to allow addition of members to locked collections
945          
946          Will have to implement the shared lock thing eventually to support this
947          
948          
949         // make sure the parent collection is not locked, or is locked by this user
950         if (parent != null) {
951             // use this resource's precondition, it should contain the
952             // parent locktoken if needed
953             parent.getRequestContext().precondition(
954                 getRequestContext().precondition());
955             parent.getRequestContext().authorization(
956                 getRequestContext().authorization());
957
958             if (parent.isLocked() && !parent.isLockedByMe()) {
959                 throw new WebDAVException(
960                     WebDAVStatus.SC_LOCKED,
961                     "Parent collection is locked by another user");
962             }
963         }*/

964
965         // check to see if the resource is locked by another user
966
if (exists() && isLocked() && !isLockedByMe()) {
967             throw new WebDAVException(
968                 WebDAVStatus.SC_LOCKED,
969                 "Resource is locked by another user");
970         }
971
972         // Resources that already exist are overwritten
973
return namespaceManager.getContentsOutputStream();
974     }
975
976     /**
977      * Insert the method's description here.
978      * Creation date: (4/14/2000 4:14:55 PM)
979      * @return com.ibm.webdav.ResourceContext
980      */

981     public com.ibm.webdav.ResourceContext getContext() {
982         return context;
983     }
984
985     /** Return lock manager for this resource
986     */

987     public LockManager getLockManager() {
988         return lockManager;
989     }
990
991     /**Return authenticator for this resource
992      *
993      */

994     public UserAuthenticator getUserAuthenticator() {
995         return ResourceImpl.authenticator;
996     }
997
998     /** Get the locks that exist on this resource.
999      *
1000     * @return a Vector of ActiveLock objects
1001     * @exception com.ibm.webdav.WebDAVException
1002     */

1003    public Vector getLocks() throws WebDAVException {
1004        return lockManager.getLocks();
1005    }
1006
1007    /** This method can be used for obtaining meta-information about this resource without
1008     * actually reading the resource contents. This meta-information is maintained by the server
1009     * in addition to the resource properties.</p>
1010     * <p>
1011     * After this call, the resource context has been updated and
1012     * <code>getStatusCode()</code>, <code>getStatusMessage()</code>, and <code>getResponseContext()</code>
1013     * as well as all the ResourceContext methods return updated values based on the current
1014     * state of the resource.</p>
1015     * <p>This methods corresponds to the HTTP HEAD method.</p>
1016     * <p>
1017     * Do a getContentsInputStream() to set the response context,
1018     * then just don't return the stream.
1019     * @exception com.ibm.webdav.WebDAVException
1020     */

1021    public void getMetaInformation(ResourceContext context)
1022        throws WebDAVException {
1023        this.context = context;
1024
1025        InputStream is = getContentsInputStream(context);
1026
1027        try {
1028            is.close();
1029        } catch (WebDAVException exc) {
1030            throw exc;
1031        } catch (java.io.IOException JavaDoc exc) {
1032        }
1033    }
1034
1035    /** Return the local name of the resource. What this name actually is
1036    * depends on the interpretation of the resource URL by the namespace
1037    * manager servicing it. Repository implementations are free to translate
1038    * the URL any way they want for their own purposes. For example, the
1039    * file system implementation uses the doc.root property to translate
1040    * the file part of the URL into a full pathname.
1041    * @return the repository specific name for this resource
1042    * @exception com.ibm.webdav.WebDAVException
1043    */

1044    public String JavaDoc getName() throws WebDAVException {
1045        if ((fileName == null) && (url != null)) {
1046            fileName = ResourceFactory.getRealPath(url);
1047        }
1048
1049        String JavaDoc sDecoded = null;
1050        try {
1051            sDecoded = URLDecoder.decode(fileName, "UTF-8");
1052        } catch (UnsupportedEncodingException e) {
1053            throw new WebDAVException(
1054                WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
1055                e.getLocalizedMessage());
1056        }
1057
1058        return sDecoded;
1059    }
1060
1061    /** Get the collection containing this resource.
1062    *
1063    * @return the parent collection
1064    * @exception com.ibm.webdav.WebDAVException
1065    */

1066    public IRCollection getParentCollection() throws WebDAVException {
1067        String JavaDoc parentURL = getURL().toString();
1068        String JavaDoc parentLocalName = getName();
1069        int delimiterPosition = 0;
1070        
1071        if(namespaceManager instanceof VersionedNamespaceManager) {
1072            if(((VersionedNamespaceManager)namespaceManager).isVersionURL(parentURL) == true) {
1073                parentURL = ((VersionedNamespaceManager)namespaceManager).getResourceURL();
1074                try {
1075                    parentLocalName = ResourceFactory.getRealPath(new URL(url,parentURL));
1076                } catch (MalformedURLException e) {
1077                    throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR,e.getLocalizedMessage());
1078                }
1079            }
1080        }
1081        
1082
1083        if (parentURL.endsWith("/")) {
1084            delimiterPosition =
1085                parentURL.substring(0, parentURL.length() - 1).lastIndexOf("/");
1086        } else {
1087            delimiterPosition = parentURL.lastIndexOf("/");
1088        }
1089
1090        parentURL = parentURL.substring(0, delimiterPosition + 1);
1091
1092        if (parentLocalName.endsWith(File.separator)) {
1093            delimiterPosition =
1094                parentLocalName.substring(
1095                    0,
1096                    parentLocalName.length() - 1).lastIndexOf(
1097                    File.separator);
1098        } else {
1099            delimiterPosition = parentLocalName.lastIndexOf(File.separator);
1100        }
1101
1102        parentLocalName = parentLocalName.substring(0, delimiterPosition + 1);
1103
1104        CollectionImpl parent = null;
1105
1106        try {
1107            URL url = new URL(getURL(),parentURL);
1108            parent = new CollectionImpl(url, parentLocalName, null);
1109        } catch (java.net.MalformedURLException JavaDoc exc) {
1110            exc.printStackTrace();
1111        }
1112        
1113        return parent;
1114    }
1115
1116    /** Get the URL of the collection containing this resource.
1117    *
1118    * @return the parent collection URL, always ending in a separator
1119    * @exception com.ibm.webdav.WebDAVException
1120    */

1121    public URL getParentURL() throws WebDAVException {
1122        String JavaDoc uri = getURL().getFile();
1123        int delimiterPosition = 0;
1124
1125        if (uri.endsWith("/")) {
1126            delimiterPosition =
1127                uri.substring(0, uri.length() - 1).lastIndexOf("/");
1128        } else {
1129            delimiterPosition = uri.lastIndexOf("/");
1130        }
1131
1132        URL parentURL = null;
1133
1134        try {
1135            parentURL =
1136                new URL(getURL(), uri.substring(0, delimiterPosition + 1));
1137        } catch (java.net.MalformedURLException JavaDoc exc) {
1138            throw new WebDAVException(
1139                WebDAVStatus.SC_BAD_REQUEST,
1140                "Malformed URL");
1141        }
1142
1143        return parentURL;
1144    }
1145
1146    public MultiStatus getSearchSchema(
1147        ResourceContext context,
1148        SearchRequest searchReq)
1149        throws WebDAVException {
1150        this.context = context;
1151
1152        // create a MultiStatus to hold the results
1153
MultiStatus results = new MultiStatus();
1154
1155        // create a document
1156
Document document = null;
1157
1158        try {
1159            DocumentBuilderFactory factory =
1160                DocumentBuilderFactory.newInstance();
1161            factory.setNamespaceAware(true);
1162
1163            DocumentBuilder docbuilder = factory.newDocumentBuilder();
1164            document = docbuilder.newDocument();
1165        } catch (Exception JavaDoc e) {
1166            e.printStackTrace(System.err);
1167            throw new WebDAVException(
1168                WebDAVStatus.SC_PROCESSING,
1169                e.getMessage());
1170        }
1171
1172        SearchSchema schema = searchManager.getSearchSchema(searchReq);
1173
1174        SchemaResponse response =
1175            new SchemaResponse(document, schema, searchReq.getScopeURI());
1176
1177        results.addResponse(response);
1178
1179        return results;
1180    }
1181
1182    public MultiStatus executeSearch(
1183        ResourceContext context,
1184        SearchRequest searchReq)
1185        throws WebDAVException {
1186        this.context = context;
1187
1188        // create a MultiStatus to hold the results
1189
MultiStatus result = new MultiStatus();
1190
1191        if (searchManager.validate(searchReq)) {
1192            Vector resources = searchManager.executeSearch(searchReq, this);
1193
1194            // now get the properties of the members if necessary
1195
Enumeration members = resources.elements();
1196
1197            while (members.hasMoreElements()) {
1198                ResourceImpl member = (ResourceImpl) members.nextElement();
1199
1200                try {
1201                    MultiStatus memberResult = null;
1202
1203                    if (member.isCollection()) {
1204                        if (searchReq.isAllSelectProperties()) {
1205                            memberResult =
1206                                ((CollectionImpl) member).getProperties(
1207                                    context,
1208                                    Collection.thisResource);
1209                        } else {
1210                            memberResult =
1211                                ((CollectionImpl) member).getProperties(
1212                                    context,
1213                                    (PropertyName[]) searchReq
1214                                        .getSelectProperties()
1215                                        .toArray(
1216                                        new PropertyName[0]),
1217                                    Collection.thisResource);
1218                        }
1219                    } else {
1220                        if (searchReq.isAllSelectProperties()) {
1221                            memberResult = member.getProperties(context);
1222                        } else {
1223                            memberResult =
1224                                member.getProperties(
1225                                    context,
1226                                    (PropertyName[]) searchReq
1227                                        .getSelectProperties()
1228                                        .toArray(
1229                                        new PropertyName[0]));
1230                        }
1231                    }
1232
1233                    result.mergeWith(memberResult);
1234                } catch (WebDAVException exc) {
1235                    MethodResponse response =
1236                        new MethodResponse(
1237                            member.getURL().toString(),
1238                            exc.getStatusCode());
1239                    result.addResponse(response);
1240                } catch (Exception JavaDoc e) {
1241                    e.printStackTrace();
1242                    throw new WebDAVException(
1243                        WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
1244                        "unable to get properties");
1245                }
1246            }
1247        } else {
1248            throw new WebDAVException(
1249                WebDAVStatus.SC_BAD_REQUEST,
1250                "Invalid query");
1251        }
1252
1253        getResponseContext().contentType("text/xml");
1254
1255        return result;
1256    }
1257
1258    /** Get all the properties of this resource.
1259     *
1260     * @return a MultiStatus of PropertyResponses. It should contain only one
1261     * response element.
1262     * @see com.ibm.webdav.MultiStatus
1263     * @see com.ibm.webdav.PropertyResponse
1264     * @exception com.ibm.webdav.WebDAVException
1265     */

1266    public MultiStatus getProperties(ResourceContext context)
1267        throws WebDAVException {
1268        this.context = context;
1269
1270        // make sure the resource exists.
1271
if (!(exists() || namespaceManager.isLockNull())) {
1272            
1273            throw new WebDAVException(
1274                WebDAVStatus.SC_NOT_FOUND,
1275                "Resource does not exist");
1276        }
1277
1278        setStatusCode(WebDAVStatus.SC_MULTI_STATUS);
1279        getResponseContext().contentType("text/xml");
1280
1281        return propertiesManager.getProperties();
1282    }
1283
1284    /** Get the named properties of this resource.
1285     *
1286     * @param names an arrary of property names to retrieve
1287     *
1288     * @return a MultiStatus of PropertyResponses
1289     * @exception com.ibm.webdav.WebDAVException
1290     * @see com.ibm.webdav.PropertyResponse
1291     */

1292    public MultiStatus getProperties(
1293        ResourceContext context,
1294        PropertyName[] names)
1295        throws WebDAVException {
1296        this.context = context;
1297
1298        // make sure the resource exists.
1299
if (!(exists() || namespaceManager.isLockNull())) {
1300            throw new WebDAVException(
1301                WebDAVStatus.SC_NOT_FOUND,
1302                "Resource does not exist");
1303        }
1304
1305        getResponseContext().contentType("text/xml");
1306
1307        return propertiesManager.getProperties(names);
1308    }
1309
1310    /** Get the value of the given property for this resource.
1311     *
1312     * @param name the name of the property to retrieve
1313     *
1314     * @return PropertyValue or null if the resource does not have the requested property
1315     * @exception com.ibm.webdav.WebDAVException
1316     */

1317    public PropertyValue getProperty(PropertyName name)
1318        throws WebDAVException {
1319        PropertyName[] names = new PropertyName[1];
1320        names[0] = name;
1321
1322        Enumeration responses = getProperties(context, names).getResponses();
1323        PropertyResponse response = (PropertyResponse) responses.nextElement();
1324        Dictionary properties = response.getPropertiesByPropName();
1325
1326        return (PropertyValue) properties.get(name);
1327    }
1328
1329    /** Get the names of all properties for this resource. The result is similar to
1330     * getProperties(), but the properties have no values.
1331     *
1332     * @return a MultiStatus of PropertyResponses
1333     * (PropertyValue.value is always null, PropertyValue.status contains the status)
1334     * @exception com.ibm.webdav.WebDAVException
1335     * @see com.ibm.webdav.PropertyResponse
1336     */

1337    public MultiStatus getPropertyNames(ResourceContext context)
1338        throws WebDAVException {
1339        this.context = context;
1340
1341        // make sure the resource exists.
1342
if (!(exists() || namespaceManager.isLockNull())) {
1343            throw new WebDAVException(
1344                WebDAVStatus.SC_NOT_FOUND,
1345                "Resource does not exist");
1346        }
1347
1348        getResponseContext().contentType("text/xml");
1349
1350        return propertiesManager.getPropertyNames();
1351    }
1352
1353    /** Get the request context for this resource. The context contains information
1354     * used by methods on a resource when the method is called.
1355     *
1356     * @return the HTTPHeaders providing information that controls
1357     * method execution.
1358     * @exception com.ibm.webdav.WebDAVException
1359     */

1360    public HTTPHeaders getRequestContext() throws WebDAVException {
1361        return context.getRequestContext();
1362    }
1363
1364    /** Get the response context for this resource. The context contains information
1365     * returned from invocations of methods on a resource.
1366     *
1367     * @return the HTTPHeaders providing information that
1368     * is returned by method execution.
1369     * @exception com.ibm.webdav.WebDAVException
1370     */

1371    public HTTPHeaders getResponseContext() throws WebDAVException {
1372        return context.getResponseContext();
1373    }
1374
1375    /**
1376     * Insert the method's description here.
1377     * Creation date: (4/13/2000 8:53:11 PM)
1378     * @return com.ibm.webdav.WebDAVStatus
1379     */

1380    public com.ibm.webdav.WebDAVStatus getStatusCode() {
1381        return context.getStatusCode();
1382    }
1383
1384    /** Get the name that identifies this resource.
1385     *
1386     * @return the URL for this resource
1387     * @exception com.ibm.webdav.WebDAVException
1388     */

1389    public URL getURL() throws WebDAVException {
1390        return url;
1391    }
1392
1393    /** Is this resource locked with the given lock token?
1394     * @param lockToken the lock token to check for
1395     * @exception com.ibm.webdav.WebDAVException
1396     */

1397    protected boolean hasLock(String JavaDoc lockToken) throws WebDAVException {
1398        boolean hasLock = false;
1399        Enumeration locks = getLocks().elements();
1400
1401        while (!hasLock && locks.hasMoreElements()) {
1402            ActiveLock lock = (ActiveLock) locks.nextElement();
1403            hasLock = lock.getLockToken().equals(lockToken);
1404        }
1405
1406        return hasLock;
1407    }
1408
1409    /** Check for a valid URI
1410    * @return true if this resource has a valid URI
1411    * @exception com.ibm.webdav.WebDAVException
1412    */

1413    public boolean hasValidURI() throws WebDAVException {
1414        return getName() != null;
1415    }
1416
1417    /** Inherit all deep locks on the parent of this resource.
1418    * @exception com.ibm.webdav.WebDAVException
1419    */

1420    protected void inheritParentDeepLocks() throws WebDAVException {
1421        CollectionImpl parent = (CollectionImpl) getParentCollection();
1422        
1423        Enumeration parentLocks = parent.getLocks().elements();
1424
1425        while (parentLocks.hasMoreElements()) {
1426            ActiveLock parentLock = (ActiveLock) parentLocks.nextElement();
1427
1428            if (parentLock.getDepth().equals(Collection.deep)) {
1429                if (!hasLock(parentLock.getLockToken())) {
1430                    lock(parentLock);
1431                }
1432            }
1433        }
1434    }
1435
1436    /** Returns true if this Resource is a collection. Returns false otherwise.
1437     *
1438     * @return true if this Resource is a collection.
1439     * @exception com.ibm.webdav.WebDAVException
1440     */

1441    public boolean isCollection() throws WebDAVException {
1442        return namespaceManager.isCollection();
1443    }
1444
1445    /** See if this resource is locked.
1446     *
1447     * @return true if this resource is locked, false otherwise.
1448     * @exception com.ibm.webdav.WebDAVException
1449     */

1450    public boolean isLocked() throws WebDAVException {
1451        // see if there are any active locks
1452
return !getLocks().isEmpty();
1453    }
1454
1455    /** Is this resource locked by the current authorized user? That is, does the
1456     * current user have sufficient locking access to modify this resource. The
1457     * method, like all methods that do modify the resource, must have a precondition
1458     * set in the context containing the lock token of the resource owned by this
1459     * user. The user is set in the request context using the authorization method.
1460     * @return true if this resource is locked by the principal in the context
1461     * sufficient to modify the resource.
1462     * @exception com.ibm.webdav.WebDAVException
1463     * @see com.ibm.webdav.ResourceContext#authorization
1464     */

1465    public boolean isLockedByMe() throws WebDAVException {
1466        String JavaDoc principal = getRequestContext().getAuthorizationId();
1467        Precondition precondition = getRequestContext().precondition();
1468
1469        if (precondition == null) {
1470            return false; // it is not locked by me, or the server doesn't know
1471

1472            //throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST, "Missing If header containing lock token");
1473
}
1474
1475        // get the locks on this resource
1476
Enumeration locks = getLocks().elements();
1477        boolean isLockedByMe = false;
1478
1479        // look for a matching lock
1480
while (locks.hasMoreElements()) {
1481            ActiveLock activeLock = (ActiveLock) locks.nextElement();
1482            Condition condition = new Condition(getURL().getFile());
1483            ConditionTerm term = new ConditionTerm();
1484            StateToken stateToken = new StateToken(activeLock.getLockToken());
1485            term.addConditionFactor(stateToken);
1486            condition.addConditionTerm(term);
1487
1488            
1489            if (precondition.matches(condition)
1490                && activeLock.getPrincipal().equals(principal)
1491                && activeLock.getLockType().equals(ActiveLock.writeLock)) {
1492                isLockedByMe = true;
1493
1494                break;
1495            }
1496        }
1497
1498        return isLockedByMe;
1499    }
1500
1501    /** See if the target URL has the same host and port (e.g., the same server)
1502    * as this resource. Matches on the host name, not its Internet address.
1503    *
1504    * @target the URL of the target resource
1505    *
1506    * @return true if the target is supported by the same server
1507    */

1508    public boolean isSameServerAs(URL target) {
1509        return target.getHost().equals(url.getHost())
1510            && (target.getPort() == url.getPort());
1511    }
1512
1513    /** Load properties from the properties manager and update live properties.
1514    *
1515    * @return an XML document containing a properties element.
1516    * @exception com.ibm.webdav.WebDAVException
1517    */

1518    public Document loadProperties() throws WebDAVException {
1519        Document propertiesDocument = propertiesManager.loadProperties();
1520        updateLiveProperties(propertiesDocument);
1521        if (propertiesManager instanceof VersionedPropertiesManager) {
1522            if (((VersionedNamespaceManager) namespaceManager).isVersioned()
1523                == true) {
1524                ((VersionedPropertiesManager) propertiesManager).updateVersionProperties(propertiesDocument);
1525            }
1526        }
1527
1528        return propertiesDocument;
1529    }
1530
1531    /** Lock this resource with the information contained in the given active lock.
1532    * @param activeLock information about the lock
1533    * @return a MultiStatus containing a lockdiscovery property indicating
1534    * @exception com.ibm.webdav.WebDAVException
1535    */

1536    protected MultiStatus lock(ActiveLock activeLock) throws WebDAVException {
1537        // get the locks on this resource
1538
Enumeration locks = getLocks().elements();
1539
1540        while (locks.hasMoreElements()) {
1541            ActiveLock lock = (ActiveLock) locks.nextElement();
1542
1543            if (lock.getScope().equals(ActiveLock.exclusive)) {
1544                throw new WebDAVException(
1545                    WebDAVStatus.SC_LOCKED,
1546                    "Resource has an exclusive lock");
1547            }
1548
1549            if (lock.getScope().equals(ActiveLock.shared)
1550                && activeLock.getScope().equals(ActiveLock.exclusive)) {
1551                throw new WebDAVException(
1552                    WebDAVStatus.SC_LOCKED,
1553                    "Resource already has a shared lock");
1554            }
1555
1556            if (lock.getScope().equals(ActiveLock.shared)
1557                && lock.getPrincipal().equals(activeLock.getPrincipal())) {
1558                throw new WebDAVException(
1559                    WebDAVStatus.SC_LOCKED,
1560                    "The principal already has a lock on this resource");
1561            }
1562        }
1563
1564        return lockManager.lock(activeLock);
1565    }
1566
1567    /** Lock this resource based on the given parameters. This allows control of
1568     * the lock scope (exclusive or shared) the lock type (write), owner information, etc.
1569     *
1570     * @param scope the scope of the lock, exclusive or shared
1571     * @param type the type of the lock, currently only write
1572     * @param timeout the number of seconds before the lock times out or
1573     * -1 for infinite timeout.
1574     * @param owner an XML element containing useful information that can be
1575     * used to identify the owner of the lock. An href to a home page, an
1576     * email address, phone number, etc. Can be null if no owner information
1577     * is provided.
1578     *
1579     * @return a MultiStatus containing a lockdiscovery property indicating
1580     * the results of the lock operation.
1581     * @exception com.ibm.webdav.WebDAVException
1582    */

1583    public MultiStatus lock(
1584        ResourceContext context,
1585        String JavaDoc scope,
1586        String JavaDoc type,
1587        int timeout,
1588        Element owner)
1589        throws WebDAVException {
1590        this.context = context;
1591
1592        ActiveLock activeLock = getActiveLockFor(scope, type, timeout, owner);
1593        MultiStatus result = lock(activeLock);
1594
1595        // return the granted lock token in the lockToken response context
1596
getResponseContext().lockToken(activeLock.getLockToken());
1597        getResponseContext().contentType("text/xml");
1598
1599        return result;
1600    }
1601
1602    /** Startup an RMI server for a ResourceImpl. The URL would most likely be for
1603    * some root WebDAV collection corresponding to the doc.root of a typical web
1604    * server. The resource identified by the URL must exist.
1605    * @param args root URL, its local file pathname
1606    */

1607    public static void main(String JavaDoc[] args) {
1608        // get the URL of the resource to export
1609
if (args.length != 2) {
1610            System.err.println("Usage: java ResourceImpl url localName");
1611            System.exit(-1);
1612        }
1613
1614        // Create a ResourceImpl, export it, and bind it in the RMI Registry
1615
try {
1616            URL url = new URL(args[0]);
1617            String JavaDoc localName = args[1];
1618
1619            // Create and install a security manager
1620
System.setSecurityManager(new RMISecurityManager());
1621
1622            ResourceImpl resource = ResourceImpl.create(url, localName);
1623
1624            // strip the protocol off the URL for the registered name
1625
String JavaDoc name = url.toString();
1626            name = name.substring(name.indexOf(":") + 1);
1627            Naming.rebind(name, resource);
1628            
1629        } catch (Exception JavaDoc exc) {
1630            System.err.println("ResourceImpl error: " + exc.getMessage());
1631            exc.printStackTrace();
1632            System.exit(-1);
1633        }
1634    } // main
1635

1636    public MultiStatus createBinding(
1637        ResourceContext context,
1638        String JavaDoc bindName,String JavaDoc resourceURI)
1639        throws WebDAVException {
1640        this.context = context;
1641
1642        setStatusCode(WebDAVStatus.SC_CREATED);
1643
1644        MultiStatus result = new MultiStatus();
1645
1646        try {
1647            // validate the uri
1648
if (!hasValidURI()) {
1649                throw new WebDAVException(
1650                    WebDAVStatus.SC_BAD_REQUEST,
1651                    "Invalid URI");
1652            }
1653
1654            // make sure the resource exists
1655
if (!exists()) {
1656                throw new WebDAVException(
1657                    WebDAVStatus.SC_NOT_FOUND,
1658                    "Cannot copy a lock-null resource");
1659            }
1660            
1661            //make sure the resource is a collection
1662
if(isCollection() == false) {
1663                throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,"URI indentified in BIND request must be an existing collection");
1664            }
1665
1666            // the destination may be a relative URL
1667
StringBuffer JavaDoc strbuf = new StringBuffer JavaDoc();
1668            strbuf.append(url.toExternalForm());
1669            
1670            if(strbuf.toString().endsWith("/") == false) {
1671                strbuf.append("/");
1672            }
1673            strbuf.append(bindName);
1674            
1675            Resource destination = new Resource(strbuf.toString());
1676            
1677            Resource bindSource = new Resource(resourceURI);
1678
1679            // are the source and destination the same?
1680
if (bindSource.equals(destination)) {
1681                throw new WebDAVException(
1682                    WebDAVStatus.SC_FORBIDDEN,
1683                    "Can't copy source on top of itself");
1684            }
1685
1686            destination.getRequestContext().precondition(
1687                getRequestContext().precondition());
1688            destination.getRequestContext().authorization(
1689                getRequestContext().authorization());
1690
1691            if (destination.exists()) {
1692                throw new WebDAVException(
1693                    WebDAVStatus.SC_PRECONDITION_FAILED,
1694                    "Destination exists and overwrite not specified");
1695            }
1696
1697            this.namespaceManager.createBinding(bindName,new URL(resourceURI));
1698
1699            // everything must have gone OK, there
1700
// is no response for a successful delete
1701
getResponseContext().contentType("text/xml");
1702        } catch (WebDAVException exc) {
1703            throw exc;
1704        } catch (java.net.MalformedURLException JavaDoc exc) {
1705            throw new WebDAVException(
1706                WebDAVStatus.SC_BAD_REQUEST,
1707                "Malformed URL");
1708        } catch (java.io.IOException JavaDoc exc) {
1709            throw new WebDAVException(
1710                WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
1711                "IO Error");
1712        }
1713
1714        return result;
1715    }
1716
1717    /** Move this resource to the destination URL.
1718     * Partial results are possible, check the returned status for details
1719     *
1720     * @param destinationURL the destination
1721     * @param overwrite true implies overrite the destination if it exists
1722     * @param propertiesToMove a collection of properties that must be moved or
1723     * the method will fail. propertiesToMove may have one of the following values:
1724     * <ul>
1725     * <li>null - ignore properties that cannot be moved</li>
1726     * <li>empty collection - all properties must be moved or the method will fail</li>
1727     * <li>a collection of URIs - a list of the properties that must be moved
1728     * or the method will fail</li>
1729     * </ul>
1730     *
1731     * @return the status of the move operation for each resource moved
1732     * @exception com.ibm.webdav.WebDAVException
1733     */

1734    public MultiStatus move(
1735        ResourceContext context,
1736        String JavaDoc destinationURL,
1737        boolean overwrite,
1738        Vector propertiesToMove)
1739        throws WebDAVException {
1740        this.context = context;
1741
1742        MultiStatus result = new MultiStatus();
1743
1744        if (webdavProperties
1745            .getProperty("atomicmove")
1746            .equalsIgnoreCase("true")) {
1747            
1748            // check to see if the resource is locked by another user
1749
if (isLocked() && !isLockedByMe()) {
1750                throw new WebDAVException(
1751                    WebDAVStatus.SC_LOCKED,
1752                    "Resource is locked by another user");
1753            }
1754            
1755            result = atomicMove(context, destinationURL, overwrite);
1756
1757            Enumeration propertyNames = context.getResponseContext().keys();
1758        } else {
1759            // proceed with the move even if the source is locked by
1760
// another principal. Best effort will perform the copy but
1761
// not the delete.
1762
result = copy(context, destinationURL, overwrite, propertiesToMove);
1763
1764            ResourceContext copyContext = context;
1765            WebDAVStatus oldStatus = context.getStatusCode();
1766            result.mergeWith(delete(context));
1767
1768            if (getStatusCode().getStatusCode() == 204) {
1769                // it was a clean delete that doesn't affect the
1770
// final result code.
1771
context.setStatusCode(oldStatus);
1772            }
1773
1774            Enumeration propertyNames = copyContext.getResponseContext().keys();
1775
1776            while (propertyNames.hasMoreElements()) {
1777                String JavaDoc name = (String JavaDoc) propertyNames.nextElement();
1778                String JavaDoc value =
1779                    (String JavaDoc) copyContext.getResponseContext().get(name);
1780
1781                if (!context.getResponseContext().containsKey(name)) {
1782                    getResponseContext().put(name, value);
1783                }
1784            }
1785        }
1786
1787        getResponseContext().contentType("text/xml");
1788
1789        return result;
1790    }
1791
1792    /** Is the parent of this resource depth locked with the given lock token?
1793    * @param lockToken the lock token to check
1794    * @return true if the parant of this resource is locked with the lock token
1795    * @exception com.ibm.webdav.WebDAVException
1796    */

1797    public boolean parentIsLockedWith(String JavaDoc lockToken)
1798        throws WebDAVException {
1799        // get the locks on the parent of this resource
1800
boolean isLocked = false;
1801        CollectionImpl parent = null;
1802
1803        try {
1804            parent = (CollectionImpl) getParentCollection();
1805        } catch (Exception JavaDoc exc) {
1806        }
1807
1808        if (parent != null) {
1809            Enumeration locks = parent.getLocks().elements();
1810
1811            // look for a matching lock
1812
while (locks.hasMoreElements()) {
1813                ActiveLock activeLock = (ActiveLock) locks.nextElement();
1814
1815                if (activeLock.getLockToken().equals(lockToken)) {
1816                    isLocked = true;
1817
1818                    break;
1819                }
1820            }
1821        }
1822
1823        return isLocked;
1824    }
1825
1826    /** This method treats this resource as a method or service, and sends its parameter to
1827     * this resource where it is handled in a resource-specific way. For example,
1828     * sending data from an HTML form to a URL representing a Servlet or CGI script that processes
1829     * the form data to produce some result.
1830     *
1831     * @param args a string representing the arguments to the method represented by this URL. The
1832     * arguments are in the form ?parameterName1=value1&amp;parameterName2=value2... as specified
1833     * for URL queries.
1834     *
1835     * @return the results of sending the arguments to the URL
1836     * @exception com.ibm.webdav.WebDAVException
1837     */

1838    public byte[] performWith(ResourceContext context, String JavaDoc args)
1839        throws WebDAVException {
1840        this.context = context;
1841
1842        return namespaceManager.performWith(args);
1843    }
1844
1845    /** Refresh the lock on this resource by resetting the lock timeout.
1846     * The context must contain the proper authorization for the requesting
1847     * principal.
1848     *
1849     * @param lockToken the lock token identifying the lock.
1850     * @param timeout the new timeout in seconds. -1 means infinite timeout.
1851     *
1852     * @return updated information about the lock status of this resource
1853     * @exception com.ibm.webdav.WebDAVException
1854     */

1855    public MultiStatus refreshLock(
1856        ResourceContext context,
1857        String JavaDoc lockToken,
1858        int timeout)
1859        throws WebDAVException {
1860        this.context = context;
1861
1862        String JavaDoc principal = getRequestContext().getAuthorizationId();
1863
1864        // find the lock
1865
ActiveLock lockToRefresh = null;
1866        Enumeration activeLocks = getLocks().elements();
1867
1868        while (activeLocks.hasMoreElements()) {
1869            ActiveLock activeLock = (ActiveLock) activeLocks.nextElement();
1870
1871            if (activeLock.getLockToken().equals(lockToken)
1872                && (activeLock.getPrincipal().equals(principal)
1873                    || principal.equals("root")
1874                    || ResourceImpl.authenticator.isSuperUser(this) == true)) {
1875                lockToRefresh = activeLock;
1876
1877                break;
1878            }
1879        }
1880
1881        if (lockToRefresh == null) {
1882            throw new WebDAVException(
1883                WebDAVStatus.SC_PRECONDITION_FAILED,
1884                "principal does not own a lock");
1885        }
1886
1887        // finally, reset the lock.
1888
lockToRefresh.setTimeout(timeout);
1889        getResponseContext().contentType("text/xml");
1890
1891        return lockManager.refreshLock(lockToRefresh);
1892    }
1893
1894    /** Remove the live DAV properties from the properties document. There is no
1895    * reason to save them as they are recalculated each time the properties are
1896    * loaded.
1897    * @param propertiesDocument an XML document containing the current resource properties
1898    */

1899    public void removeLiveProperties(Document propertiesDocument) {
1900        Element properties = (Element) propertiesDocument.getDocumentElement();
1901        Element p = null;
1902        p =
1903            (Element) ((Element) properties)
1904                .getElementsByTagNameNS("DAV:", "supportedlock")
1905                .item(0);
1906
1907        if (p != null) {
1908            properties.removeChild(p);
1909        }
1910
1911        // remove the live properties that are repository specific
1912
propertiesManager.removeLiveProperties(propertiesDocument);
1913    }
1914
1915    /** Save the properties after removing any live properties that don't need
1916    * to be saved.
1917    * @param propertiesDocument an XML document containing the resource's properties
1918    * @exception com.ibm.webdav.WebDAVException
1919    */

1920    public void saveProperties(Document propertiesDocument)
1921        throws WebDAVException {
1922        // don't save the live properties, they will be recalculated on each load
1923
removeLiveProperties(propertiesDocument);
1924        if (propertiesManager instanceof VersionedPropertiesManager) {
1925            // don't save versoined properties, they will be recalculated on each load
1926
(
1927                (
1928                    VersionedPropertiesManager) propertiesManager)
1929                        .removeVersionProperties(
1930                propertiesDocument);
1931        }
1932
1933        propertiesManager.saveProperties(propertiesDocument);
1934    }
1935
1936    /** Set the contents of this resource. This may create a new resource on the server,
1937     * or update the contents of an existing resource. Sufficient authorization is required
1938     * and administered by the target web server. For text/* MIME types, the caller should
1939     * be sure to convert Strings to byte codes using an acceptable charset, and to set
1940     * that charset in the request context so the server knows how to decode the byte
1941     * stream.
1942     *
1943     * @param value the new contents for the resource
1944     * @exception com.ibm.webdav.WebDAVException
1945     */

1946    public void setContents(byte[] value) throws WebDAVException {
1947        BufferedOutputStream os =
1948            (BufferedOutputStream) getContentsOutputStream(context);
1949
1950        for (int i = 0; i < value.length; i++) {
1951            try {
1952                os.write(value[i]);
1953            } catch (WebDAVException exc) {
1954                throw exc;
1955            } catch (java.io.IOException JavaDoc exc) {
1956                throw new WebDAVException(
1957                    WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
1958                    "IO Error");
1959            }
1960        }
1961
1962        closeContentsOutputStream(context);
1963    }
1964
1965    /**
1966     * Insert the method's description here.
1967     * Creation date: (4/14/2000 4:14:55 PM)
1968     * @param newContext com.ibm.webdav.ResourceContext
1969     */

1970    void setContext(com.ibm.webdav.ResourceContext newContext) {
1971        context = newContext;
1972    }
1973
1974    /** Edit the properties of a resource. The updates must refer to a Document containing a WebDAV
1975     * DAV:propertyupdates element as the document root.
1976     *
1977     * @param updates an XML Document containing DAV:propertyupdate elements
1978     * describing the edits to be made
1979     * @return a MultiStatus indicating the status of the updates
1980     * @exception com.ibm.webdav.WebDAVException
1981     */

1982    public MultiStatus setProperties(ResourceContext context, Document updates)
1983        throws WebDAVException {
1984        this.context = context;
1985
1986        // make sure the resource exists.
1987
if (!exists()) {
1988            throw new WebDAVException(
1989                WebDAVStatus.SC_NOT_FOUND,
1990                "Resource does not exist");
1991        }
1992
1993        // check to see if the resource is locked by another user
1994
if (isLocked() && !isLockedByMe()) {
1995            return createPropPatchMultiStatus(
1996                new WebDAVException(
1997                    WebDAVStatus.SC_LOCKED,
1998                    "Resource is locked by another user"),
1999                updates);
2000        }
2001
2002        getResponseContext().contentType("text/xml");
2003
2004        return propertiesManager.setProperties(updates);
2005    }
2006
2007    /**
2008     * Insert the method's description here.
2009     * Creation date: (4/13/2000 8:48:11 PM)
2010     * @param newRequestContext com.ibm.webdav.ResourceContext
2011     */

2012    public void setRequestContext(ResourceContext newRequestContext) {
2013        context.setRequestContext(newRequestContext.getRequestContext());
2014    }
2015
2016    /**
2017     * Insert the method's description here.
2018     * Creation date: (4/13/2000 8:48:11 PM)
2019     * @param newResponseContext com.ibm.webdav.ResourceContext
2020     */

2021    public void setResponseContext(
2022        com.ibm.webdav.ResourceContext newResponseContext) {
2023        context.setResponseContext(newResponseContext.getResponseContext());
2024    }
2025
2026    /**
2027     * Insert the method's description here.
2028     * Creation date: (4/13/2000 8:53:11 PM)
2029     * @param newStatusCode com.ibm.webdav.WebDAVStatus
2030     */

2031    void setStatusCode(int newStatusCode) {
2032        context.getStatusCode().setStatusCode(newStatusCode);
2033    }
2034
2035    /**
2036     * Insert the method's description here.
2037     * Creation date: (4/13/2000 8:53:11 PM)
2038     * @param newStatusCode com.ibm.webdav.WebDAVStatus
2039     */

2040    void setStatusCode(com.ibm.webdav.WebDAVStatus newStatusCode) {
2041        context.getStatusCode().setStatusCode(newStatusCode.getStatusCode());
2042    }
2043
2044    /** Translate the URI reference relative to this resource in order to obtain
2045    * the real path name if the URI references a resource on the same machine.
2046    *
2047    * @param target the URL of the path to translate
2048    *
2049    * @return the pathname to the file on this machine, or the URL if the file
2050    * is not on this machine
2051    * @exception com.ibm.webdav.WebDAVException
2052    */

2053    public String JavaDoc translatePathRelativeToMe(String JavaDoc target)
2054        throws WebDAVException {
2055        String JavaDoc result = target;
2056        URL targetURL = null;
2057
2058        try {
2059            targetURL = new URL(url, target);
2060        } catch (java.net.MalformedURLException JavaDoc exc) {
2061            throw new WebDAVException(
2062                WebDAVStatus.SC_BAD_REQUEST,
2063                "malformed target URL");
2064        }
2065
2066        if (targetURL.getHost().equals(url.getHost())) {
2067            // is on this machine, convert the target to a file on this machine
2068
result = targetURL.getFile().replace('/', File.separatorChar);
2069
2070            // append it to doc.root
2071
String JavaDoc uri = url.getFile();
2072            String JavaDoc docRoot =
2073                fileName.substring(0, fileName.length() - uri.length());
2074            result = docRoot + result;
2075        }
2076
2077        return result;
2078    }
2079
2080    /** Unlock the lock identified by the lockToken on this resource
2081     *
2082     * @param lockToken the lock token obtained from the ActiveLock of a previous <code>lock() </code>
2083     * or <code>getLocks()</code>.
2084     *
2085     * @return a MultiStatus containing any responses on resources that could not
2086     * be unlocked.
2087     * @exception com.ibm.webdav.WebDAVException
2088     */

2089    public MultiStatus unlock(ResourceContext context, String JavaDoc lockToken)
2090        throws WebDAVException {
2091        this.context = context;
2092
2093        // first, is this the root parent collection locked by this lockToken
2094
if (parentIsLockedWith(lockToken)) {
2095            throw new WebDAVException(
2096                WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2097                "Must unlock depth lock from root collection having the lock.");
2098        }
2099
2100        MultiStatus result = doUnlock(lockToken);
2101        setStatusCode(WebDAVStatus.SC_NO_CONTENT); // the default status code
2102

2103        return result;
2104    }
2105
2106    /** Update live properties that are supported by this server. This method
2107    * updates those that are not unique to any repository implementation.
2108    * This is mostly the live DAV properties as defined in the WebDAV spec.
2109    * @param document an XML document containing the resource properties
2110    * @exception com.ibm.webdav.WebDAVException
2111    */

2112    public void updateLiveProperties(Document document)
2113        throws WebDAVException {
2114        Element properties = document.getDocumentElement();
2115
2116        // remove any live properties that need to be recalculated
2117
removeLiveProperties(document);
2118
2119        // now recalculate the live properties, the repository independent ones first
2120
Enumeration liveprops = liveProperties.elements();
2121
2122        while (liveprops.hasMoreElements()) {
2123            LiveProperty liveProperty = (LiveProperty) liveprops.nextElement();
2124            PropertyValue value = liveProperty.getValueFor(this);
2125            Element e =
2126                (Element) ((Element) properties)
2127                    .getElementsByTagNameNS(
2128                        liveProperty.getNSName(),
2129                        liveProperty.getNSLocalName())
2130                    .item(0);
2131
2132            if ((e != null) && (value != null) && (value.getValue() != null)) {
2133                properties.removeChild(e);
2134            }
2135
2136            if ((value != null) && (value.getValue() != null)) {
2137                properties.appendChild(value.getValue());
2138            } else {
2139                // put in an empty element
2140
e =
2141                    document.createElementNS(
2142                        liveProperty.getNSName(),
2143                        liveProperty.getPreferredPrefix()
2144                            + ":"
2145                            + liveProperty.getNSLocalName());
2146
2147                e.setAttribute(
2148                    "xmlns:" + liveProperty.getPreferredPrefix(),
2149                    liveProperty.getNSName());
2150                properties.appendChild(e);
2151            }
2152
2153            // TODO: missing status
2154
}
2155
2156        // lockdiscovery
2157

2158        /*
2159        Element lockdiscovery = (TXElement) lockManager.getLockDiscovery();
2160        Element l = ((TXElement) properties).getElementNamed("DAV:", "lockdiscovery");
2161        if (l != null && lockdiscovery != null) {
2162        properties.removeChild(l);
2163        }
2164        properties.appendChild(lockdiscovery);
2165        */

2166
2167        // creationdate
2168
Element creationDate =
2169            (Element) ((Element) properties)
2170                .getElementsByTagNameNS("DAV:", "creationdate")
2171                .item(0);
2172
2173        if (creationDate == null) {
2174            creationDate = document.createElementNS("DAV:", "D:creationdate");
2175
2176            String JavaDoc cdstring =
2177                new SimpleISO8601DateFormat().format(new java.util.Date JavaDoc());
2178            creationDate.appendChild(document.createTextNode(cdstring));
2179            properties.appendChild(creationDate);
2180        }
2181
2182        // displayname - set the default. Subclasses may want to override
2183
Element displayName =
2184            (Element) ((Element) properties)
2185                .getElementsByTagNameNS("DAV:", "displayname")
2186                .item(0);
2187
2188        if (displayName == null) {
2189            displayName = document.createElementNS("DAV:", "D:displayname");
2190
2191            displayName.appendChild(
2192                document.createTextNode(URLEncoder.encode(getName())));
2193            properties.appendChild(displayName);
2194        }
2195
2196        // get the supportedlock element from the lock manager
2197
properties.appendChild(
2198            document.importNode(lockManager.getSupportedLock(), true));
2199
2200        // do the ones that are repository specific
2201
propertiesManager.updateLiveProperties(document);
2202    }
2203
2204    /**
2205     * Checks in current resource
2206     *
2207     * @throws WebDAVException
2208     */

2209    public void checkin() throws WebDAVException {
2210        if (namespaceManager instanceof VersionedNamespaceManager) {
2211            // validate the uri
2212
if (hasValidURI() == false) {
2213                throw new WebDAVException(
2214                    WebDAVStatus.SC_BAD_REQUEST,
2215                    "Invalid URI");
2216            }
2217
2218            // make sure the resource exists
2219
if (exists() == false) {
2220                throw new WebDAVException(
2221                    WebDAVStatus.SC_NOT_FOUND,
2222                    "Cannot copy a lock-null resource");
2223            }
2224
2225            if (((VersionedNamespaceManager) namespaceManager)
2226                .isCheckedOutVersion()
2227                == false) {
2228                throw new WebDAVException(
2229                    WebDAVStatus.SC_BAD_REQUEST,
2230                    "Not checked out");
2231            }
2232
2233            // check to see if the resource is locked by another user
2234
if (isLocked() && !isLockedByMe()) {
2235                throw new WebDAVException(
2236                    WebDAVStatus.SC_LOCKED,
2237                    "Resource is locked by another user");
2238            }
2239            
2240            String JavaDoc sLoc =
2241                ((VersionedNamespaceManager) namespaceManager).checkin();
2242            context.getResponseContext().location(sLoc);
2243            setStatusCode(WebDAVStatus.SC_CREATED);
2244        } else {
2245            throw new WebDAVException(
2246                WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2247                "Repository does not support this method");
2248        }
2249    }
2250
2251    /**
2252     * Checks out the current resource
2253     *
2254     * @throws WebDAVException
2255     */

2256    public void checkout() throws WebDAVException {
2257        if (namespaceManager instanceof VersionedNamespaceManager) {
2258            // validate the uri
2259
if (hasValidURI() == false) {
2260                throw new WebDAVException(
2261                    WebDAVStatus.SC_BAD_REQUEST,
2262                    "Invalid URI");
2263            }
2264
2265            // make sure the resource exists
2266
if (exists() == false) {
2267                throw new WebDAVException(
2268                    WebDAVStatus.SC_NOT_FOUND,
2269                    "Cannot copy a lock-null resource");
2270            }
2271            
2272            // check to see if the resource is locked by another user
2273
if (isLocked() && !isLockedByMe()) {
2274                throw new WebDAVException(
2275                    WebDAVStatus.SC_LOCKED,
2276                    "Resource is locked by another user");
2277            }
2278
2279            ((VersionedNamespaceManager) namespaceManager).checkout();
2280            setStatusCode(WebDAVStatus.SC_OK);
2281        } else {
2282            throw new WebDAVException(
2283                WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2284                "Repository does not support this method");
2285        }
2286    }
2287
2288    /**
2289     * Get the named properties for all versions of this resource.
2290     *
2291     * @param context
2292     * @param names an array of PropertyNames to retrieve.
2293     *
2294     * @return
2295     * @throws WebDAVException
2296     */

2297    public MultiStatus getVersionTreeReport(
2298        ResourceContext context,
2299        PropertyName[] names)
2300        throws WebDAVException {
2301        this.context = context;
2302
2303        // check the depth parameter
2304
if (namespaceManager.isVersionable() == false) {
2305            throw new WebDAVException(
2306                WebDAVStatus.SC_BAD_REQUEST,
2307                "Invalid depth on copy");
2308        }
2309        MultiStatus result = new MultiStatus();
2310        // now get the properties of the versions if necessary
2311

2312        Iterator memberIter =
2313            ((VersionedNamespaceManager) namespaceManager)
2314                .getVersions()
2315                .iterator();
2316        while (memberIter.hasNext()) {
2317            ResourceImpl member = (ResourceImpl) memberIter.next();
2318            try {
2319                MultiStatus memberResult = member.getProperties(context, names);
2320
2321                result.mergeWith(memberResult);
2322            } catch (WebDAVException exc) {
2323                MethodResponse response =
2324                    new MethodResponse(
2325                        member.getURL().toString(),
2326                        exc.getStatusCode());
2327                result.addResponse(response);
2328            } catch (Exception JavaDoc e) {
2329                e.printStackTrace();
2330                throw new WebDAVException(
2331                    WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
2332                    "unable to delete resource");
2333            }
2334        }
2335
2336        getResponseContext().contentType("text/xml");
2337        return result;
2338
2339    }
2340
2341    /**
2342     * Get the properties for all versions of this resource.
2343     *
2344     * @param context
2345     * @return
2346     * @throws WebDAVException
2347     */

2348    public MultiStatus getVersionTreeReport(ResourceContext context)
2349        throws WebDAVException {
2350        this.context = context;
2351
2352        // check the depth parameter
2353
if (namespaceManager.isVersionable() == false) {
2354            throw new WebDAVException(
2355                WebDAVStatus.SC_BAD_REQUEST,
2356                "Invalid depth on copy");
2357        }
2358        MultiStatus result = new MultiStatus();
2359        // now get the properties of the versions if necessary
2360

2361        Iterator memberIter =
2362            ((VersionedNamespaceManager) namespaceManager)
2363                .getVersions()
2364                .iterator();
2365        while (memberIter.hasNext()) {
2366            ResourceImpl member = (ResourceImpl) memberIter.next();
2367            try {
2368                MultiStatus memberResult = member.getProperties(context);
2369
2370                result.mergeWith(memberResult);
2371            } catch (WebDAVException exc) {
2372                MethodResponse response =
2373                    new MethodResponse(
2374                        member.getURL().toString(),
2375                        exc.getStatusCode());
2376                result.addResponse(response);
2377            } catch (Exception JavaDoc e) {
2378                e.printStackTrace();
2379                throw new WebDAVException(
2380                    WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
2381                    "unable to delete resource");
2382            }
2383        }
2384
2385        getResponseContext().contentType("text/xml");
2386        return result;
2387
2388    }
2389
2390    /**
2391     *
2392     */

2393    public void uncheckout() throws WebDAVException {
2394        if (namespaceManager instanceof VersionedNamespaceManager) {
2395            // validate the uri
2396
if (hasValidURI() == false) {
2397                throw new WebDAVException(
2398                    WebDAVStatus.SC_BAD_REQUEST,
2399                    "Invalid URI");
2400            }
2401
2402            // make sure the resource exists
2403
if (exists() == false) {
2404                throw new WebDAVException(
2405                    WebDAVStatus.SC_NOT_FOUND,
2406                    "Cannot copy a lock-null resource");
2407            }
2408
2409            if (((VersionedNamespaceManager) namespaceManager)
2410                .isCheckedOutVersion()
2411                == false) {
2412                throw new WebDAVException(
2413                    WebDAVStatus.SC_BAD_REQUEST,
2414                    "Not checked out");
2415            }
2416
2417            ((VersionedNamespaceManager) namespaceManager).uncheckout();
2418            setStatusCode(WebDAVStatus.SC_OK);
2419        } else {
2420            throw new WebDAVException(
2421                WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2422                "Repository does not support this method");
2423        }
2424
2425    }
2426
2427    /**
2428     *
2429     */

2430    public void versionControl() throws WebDAVException {
2431        if (namespaceManager instanceof VersionedNamespaceManager) {
2432            // validate the uri
2433
if (hasValidURI() == false) {
2434                throw new WebDAVException(
2435                    WebDAVStatus.SC_BAD_REQUEST,
2436                    "Invalid URI");
2437            }
2438
2439            // make sure the resource exists
2440
if (exists() == false) {
2441                throw new WebDAVException(
2442                    WebDAVStatus.SC_NOT_FOUND,
2443                    "Cannot copy a lock-null resource");
2444            }
2445
2446            if (((VersionedNamespaceManager) namespaceManager).isVersioned()
2447                == true) {
2448                throw new WebDAVException(
2449                    WebDAVStatus.SC_BAD_REQUEST,
2450                    "Already versioned");
2451            }
2452
2453            ((VersionedNamespaceManager) namespaceManager).versionControl();
2454            setStatusCode(WebDAVStatus.SC_OK);
2455        } else {
2456            throw new WebDAVException(
2457                WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2458                "Repository does not support this method");
2459        }
2460
2461    }
2462
2463    /**
2464     * @return
2465     */

2466    public List getAllowedMethods() throws WebDAVException {
2467
2468        return namespaceManager.getAllowedMethods();
2469    }
2470
2471    /* (non-Javadoc)
2472     * @see com.ibm.webdav.impl.IRResource#closeContentsOutputStream(com.ibm.webdav.ResourceContext, java.lang.String)
2473     */

2474    public void closeContentsOutputStream(ResourceContext context, String JavaDoc sContentType) throws WebDAVException {
2475        this.context = context;
2476
2477        if(sContentType == null) {
2478            namespaceManager.closeContentsOutputStream();
2479        } else {
2480            namespaceManager.closeContentsOutputStream(sContentType);
2481        }
2482        
2483
2484        // update the live properties
2485
Document propertiesDocument = loadProperties();
2486        saveProperties(propertiesDocument);
2487
2488        // inherit any deep locks on the parent collection
2489
inheritParentDeepLocks();
2490        
2491    }
2492}
Popular Tags