I was wondering how we could better code this method.  As it stands it is 
unusable for the following reason:

If one attempts to create a WebdavResource object for a resource that does not 
exist, the WebdavResource constructor will throw an exception and hence one can 
never even call exists().  So the if one can successfully call exists() it 
implies the resource DOES exist making the method of limited use.

Why is this happening?  It is due to the a) the way WebdavResource objects are 
constructed, and b) the WebDAV specification itself.  First off, almost all of 
WebdavResources constructors call setHttpURL at some point.  setHttpURL in turn 
calls setProperties.  setProperties (by virtue of one of the methods called in 
its switch statement) ends up calling setNamedProp, which in turn calls the 
propFindMethod.

propFindMethod queries the WebDAV server as to what properties the requested 
resource has.  It does so by generating a WebDAV PROPFIND request.  Now 
according to the WebDAV spec:

"If there is an error retrieving a property then a proper error result MUST be 
included in the response. A request to retrieve the value of a property which 
does not exist is an error and MUST be noted, if the response uses a 
multistatus XML element, with a response XML element which contains a 404 (Not 
Found) status value." [1]

[1] 8.1 PROPFIND 
http://www.webdav.org/specs/rfc2518.html#http.methods.for.distributed.authoring

So what's happening is that WebdavResource is using PROPFIND to get properties 
for a resource that does not exist which--according to the Webdav spec--is an 
error.  Hence a correct WebDAV server must return a 404 (Not Found) response. 
The code in propFindMethod (see snippet below) checks the response status and 
throws an exception if it doesn't recieve an XML multistatus response or an 
HTTP 200 (OK) response.

        if (status != HttpStatus.SC_MULTI_STATUS
            && status != HttpStatus.SC_OK) {
            HttpException ex = new HttpException();
            ex.setReasonCode(status);
            throw ex;
        }
        
Now while this behaviour may be ok when one checks properties on an 
already-instantiated object, its less clear whether it makes sense to do this 
in WebdavResource's constructor.  One would assume (principal of least 
astonishment) that a WebdavResource object would behave more like a standard 
java File object, in that many of java.io.File's properties are lazy-loaded at 
method-call time vs instantiation time. But this would require the 
propFindMethod know whether the caller was a constructor or not.  (For a some 
potential solutions, see the end of this post).

In lieu of a fix, one can get around this issue (in an albeit kludgey way), by 
using the following static method to determine whether a resource exists:

public class WebdavResourceUtils
{
        public static WebdavResource getResource(HttpURL url)
        throws IOException, HttpException
        {  
                WebdavResource wdr = null;
                try {
  
                        wdr = new WebdavResource(url);

                } catch(HttpException httpe) {
  
                        if (httpe.getReasonCode() == HttpStatus.SC_NOT_FOUND)
                                return null; // failed because resource does 
not exist
                        else
                                throw httpe; // failed for some other reason
  
                }
  
                return wdr;
        }
}


But this is both redundant and requires a strange 'util' class.

---



///////// POSSIBLE SOLUTION #1 ///////////


Here is one I thought of.  We simply add the following to this conditional:

        if (status != HttpStatus.SC_MULTI_STATUS
            && status != HttpStatus.SC_OK
            
            && status != HttpStatus.SC_NOT_FOUND // <---
            
            ) {
            HttpException ex = new HttpException();
            ex.setReasonCode(status);
            throw ex;
        }

What this essentially says is "if the property does not exist, we simply won't 
add it to the Enumeration of properties, but we won't throw an exception unless 
there is a server error".  So if the user loops through the Enumeration without 
finding the requested property, the client must assume it doesn't exist.

** However, I haven't looked into this enough to determine whether it will 
cause any strange side-effects. **




///////// POSSIBLE SOLUTION #2 ///////////

See http://issues.apache.org/bugzilla/show_bug.cgi?id=16642 for another 
possible solution to this issue.




Cheers!

Michael N. Christoff
[EMAIL PROTECTED]



Michael N. Christoff
Site Administrator
Continuing Professional Education Online
Centre for Addiction and Mental Health
33 Russell Street
Toronto, Ontario M5S 2S1

Phone: (416) 535-8501 x6655
Fax:     (416) 595-6617
e-mail:  [EMAIL PROTECTED]

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to