KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > webdav > protocol > http > ResourceHTTPStub


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

17 import com.ibm.webdav.protocol.http.WebDAVURLConnection;
18 import com.ibm.webdav.protocol.http.WebDAVAuthenticator;
19 import com.ibm.webdav.*;
20 import com.ibm.webdav.impl.*;
21 import com.ibm.webdav.ServerException;
22 import java.io.*;
23 import java.net.URL JavaDoc;
24 import org.w3c.dom.*;
25 import java.util.Vector JavaDoc;
26 import java.util.Properties JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import javax.xml.parsers.*;
29
30 /** Implements a client-side proxy stub of the Resource interface using HTTP plus WebDAV extensions
31  * as a remote procedure call protocol. It does this by creating a WebDAVURLConnection
32  * and dispatching the request to the servlet ResourceHTTPSkel which in turn dispatches
33  * to ResourceImpl. This is the place to see how the DAV4J client API is mapped to
34  * the WebDAV protocol.
35  */

36 public class ResourceHTTPStub implements IRResource {
37     protected URL JavaDoc url = null;
38
39     // contexts for communicating HTTP and WebDAV headers (method contol couples)
40
protected ResourceContext context = new ResourceContext();
41
42     static {
43
44         WebDAVURLConnection.setDefaultAuthenticator(new WebDAVAuthenticator());
45     }
46
47     protected WebDAVURLConnection connection = null;
48
49         // properties taken from the dav4j.properties file.
50
protected static Properties JavaDoc properties = ResourceFactory.properties;
51 /** The default constructor. Should be rarely used.
52  */

53 public ResourceHTTPStub() {
54     this.url = null;
55 }
56 /** Construct a ResourceHTTPStub with the given URL. The resource having
57  * the url may not exist as this constructor does not access the resource from
58  * the server. Use exists() or attmept to get the contents of the resource to
59  * see if it exists. Other constructors are provided using parameters for the
60  * various parts of the URL. See java.net.URLConnection for details.
61  *
62  * @param url the URL of the resource.
63  * @exception MalformedURLException
64  * @exception java.io.IOException
65  * @see URLConnection
66  * @see com.ibm.webdav.ResourceFactory
67  */

68 public ResourceHTTPStub(String JavaDoc url) throws java.io.IOException JavaDoc {
69     this(new URL JavaDoc(url), (TargetSelector)null);
70 }
71 /** Create a ResourceHTTPStub from the given URL components.
72  * @param protocol the protocol to use, http:, rmi:, or iiop:
73  * @param host the name or IP addres of the server host. Using the client host name,
74  * or 'localhost' without a port uses local access with no RPC or server required.
75  * @param port the TCP port to use. HTTP uses 80 by default.
76  * @param file the resource URL relative to the server including any query string, etc.
77  * @exception java.io.IOException
78  * @see URLConnection
79  * @see com.ibm.webdav.ResourceFactory
80  */

81 public ResourceHTTPStub(String JavaDoc protocol, String JavaDoc host, int port, String JavaDoc file) throws java.io.IOException JavaDoc {
82     this(new URL JavaDoc(protocol, host, port, file), (TargetSelector)null);
83 }
84 /** Create a ResourceHTTPStub from the given URL components. This constructor uses the default
85  * HTTP port.
86  * @param protocol the protocol to use, http:, rmi:, or iiop:
87  * @param host the name or IP addres of the server host. Using the client host name,
88  * or 'localhost' without a port uses local access with no RPC or server required.
89  * @param file the resource URL relative to the server including any query string, etc.
90  * @exception java.io.IOException
91  * @see URLConnection
92  * @see com.ibm.webdav.ResourceFactory
93  */

94 public ResourceHTTPStub(String JavaDoc protocol, String JavaDoc host, String JavaDoc file) throws java.io.IOException JavaDoc {
95     this(new URL JavaDoc(protocol, host, file), (TargetSelector)null);
96 }
97 /** Construct a ResourceHTTPStub with the given URL. The resource having
98  * the url may not exist as this constructor does not access the resource from
99  * the server. Use exists() or attmept to get the contents of the resource to
100  * see if it exists. Other constructors are provided using parameters for the
101  * various parts of the URL. See java.net.URLConnection for details.
102  *
103  * @param url the URL of the resource.
104  * @param targetSelector the revision target selector for this Collection
105  * @exception com.ibm.webdav.WebDAVException
106  * @see URLConnection
107  * @see com.ibm.webdav.ResourceFactory
108  */

109 public ResourceHTTPStub(URL JavaDoc url, TargetSelector targetSelector) throws WebDAVException {
110     this.url = url;
111 }
112 /** Construct a ResourceP with the given URL specification in the given context. The resource having
113  * the url may not exist as this constructor does not access the resource from
114  * the server. Use exists() or attmept to get the contents of the resource to
115  * see if it exists. Other constructors are provided using parameters for the
116  * various parts of the URL. See java.net.URLConnection for details.
117  *
118  * @param context a URL giving the context in which the spec is evaluated
119  * @param spec a URL whose missing parts are provided by the context
120  * @exception java.io.IOException
121  * @see URLConnection
122  * @see com.ibm.webdav.ResourceFactory
123  */

124 public ResourceHTTPStub(URL JavaDoc context, String JavaDoc spec) throws java.io.IOException JavaDoc {
125     this(new URL JavaDoc(context, spec), (TargetSelector)null);
126 }
127 /** This method must be called after the client has completed writing to the contents
128  * output stream that was obtained from <code>getContentsOutputStream()</code>.
129  * @exception com.ibm.webdav.WebDAVException
130  */

131 public void closeContentsOutputStream(ResourceContext context) throws WebDAVException {
132     this.closeContentsOutputStream(context, null);
133 }
134
135 public void closeContentsOutputStream(ResourceContext context,String JavaDoc sContentType) throws WebDAVException {
136     this.context = context;
137
138     getResults();
139 }
140 /** Copy this resource to the destination URL.
141  * Partial results are possible, check the returned status for details.
142  *
143  * @param destinationURL the destination
144  * @param overwrite true implies overrite the destination if it exists
145  * @param propertiesToCopy a collection of properties that must be copied or
146  * the method will fail. propertiesToCopy may have one of the following values:
147  * <ul>
148  * <li>null - ignore properties that cannot be copied</li>
149  * <li>empty collection - all properties must be copied or the method will fail</li>
150  * <li>a collection of URIs - a list of the properties that must be copied
151  * or the method will fail</li>
152  * </ul>
153  *
154  * @return the status of the copy operation for each resource copied
155  * @exception com.ibm.webdav.WebDAVException
156  */

157 public MultiStatus copy(ResourceContext context, String JavaDoc destinationURL, boolean overwrite, Vector JavaDoc propertiesToCopy) throws WebDAVException {
158     this.context = context;
159
160     context.getRequestContext().overwrite(overwrite ? "T" : "F");
161     context.getRequestContext().destination(destinationURL);
162
163     setupRequest("COPY");
164
165     return doCopyOrMove(propertiesToCopy);
166 }
167 /** Delete this resouce from the server. The actual effect of the delete operation is
168  * determined by the underlying repository manager. The visible effect to WebDAV
169  * is that the resource is no longer available.
170  *
171  * @return a MultiStatus containing the status of the delete method on each
172  * effected resource.
173  * @exception com.ibm.webdav.WebDAVException
174  */

175 public MultiStatus delete(ResourceContext context) throws WebDAVException {
176     this.context = context;
177
178     setupRequest("DELETE");
179     getResults();
180
181     return responseToMultiStatus();
182 }
183 /** Do the work involved in a remote procedure call for a copy or move
184 * operation.
185  * @param propertiesToCopy a collection of properties that must be copied or
186  * the method will fail. propertiesToCopy may have one of the following values:
187  * <ul>
188  * <li>null - ignore properties that cannot be copied</li>
189  * <li>empty collection - all properties must be copied or the method will fail</li>
190  * <li>a collection of URIs - a list of the properties that must be copied
191  * or the method will fail</li>
192  * </ul>
193  *
194  * @return the status of the copy operation for each resource copied
195 * @exception com.ibm.webdav.WebDAVException
196 */

197 private MultiStatus doCopyOrMove(Vector JavaDoc properties) throws WebDAVException {
198     context.getRequestContext().contentType("text/xml");
199
200     // Convert the propertiesToCopy to XML
201
Document document = null;
202         try {
203           document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
204     } catch(Exception JavaDoc e) {
205           throw new WebDAVException(WebDAVStatus.SC_PROCESSING,e.getMessage());
206         }
207         //document.setVersion(Resource.XMLVersion);
208
//document.setEncoding(Resource.defaultXMLEncoding);
209

210     Element propertybehavior = document.createElementNS("DAV:","D:propertybehavior");
211     propertybehavior.setAttribute("xmlns:D", "DAV:");
212     document.appendChild(propertybehavior);
213
214     if (properties == null) {
215         propertybehavior.appendChild(document.createElementNS("DAV:","D:omit"));
216     } else {
217         Element keepalive = document.createElementNS("DAV:","D:keepalive");
218         propertybehavior.appendChild(keepalive);
219         if (properties.isEmpty()) {
220             keepalive.appendChild(document.createTextNode("*"));
221         } else {
222             Enumeration JavaDoc props = properties.elements();
223             while (props.hasMoreElements()) {
224                 String JavaDoc uri = (String JavaDoc) props.nextElement();
225                 Element href = document.createElementNS("DAV:","D:href");
226                 href.appendChild(document.createTextNode(uri));
227                 keepalive.appendChild(href);
228             }
229         }
230     }
231
232     // output the properties to copy request entity
233
connection.setDoOutput(true);
234     try {
235         Writer writer = new OutputStreamWriter(connection.getOutputStream(), Resource.defaultCharEncoding);
236         PrintWriter pw = new PrintWriter(writer, false);
237         pw.print(XMLUtility.printNode(document.getDocumentElement()));
238                 //document.print(pw);
239
pw.flush();
240         getResults();
241     } catch (java.io.UnsupportedEncodingException JavaDoc exc) {
242         throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST, "Unsupported encoding requiested");
243     } catch (WebDAVException exc) {
244         throw exc;
245     } catch (java.io.IOException JavaDoc exc) {
246         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
247     }
248     return responseToMultiStatus();
249 }
250 /** Get an InputStream for accessing the contents of this resource. This method may provide
251  * more efficient access for resources that have large contents. Clients may want to create
252  * a Reader to perform appropriate character conversions on this stream.
253  *
254  * @return an InputStream on the contents
255  * @exception com.ibm.webdav.WebDAVException
256  */

257 public InputStream getContentsInputStream(ResourceContext context) throws WebDAVException {
258     this.context = context;
259          
260     setupRequest("GET");
261     getResults();
262     InputStream stream = null;
263     try {
264         stream = connection.getInputStream();
265     } catch (WebDAVException exc) {
266                 System.err.println("ResourceHTTPStub.getContentsInputStream: Exception -");
267         exc.printStackTrace(System.err);
268                 throw exc;
269     } catch (java.io.IOException JavaDoc exc) {
270         System.err.println("ResourceHTTPStub.getContentsInputStream: Exception -");
271         exc.printStackTrace(System.err);
272                 throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
273     }
274     return stream;
275 }
276 /** Get an OutputStream for setting the contents of this resource. This method may provide
277  * more efficient access for resources that have large contents. Remember to call
278  * closeContentsOutputStream() when all the data has been written.
279  *
280  * @return an OutputStream to set the contents
281  * @exception com.ibm.webdav.WebDAVException
282  */

283 public OutputStream getContentsOutputStream(ResourceContext context) throws WebDAVException {
284     this.context = context;
285     HTTPHeaders requestContext = context.getRequestContext();
286     if (requestContext.contentType() == null) {
287         requestContext.contentType("text/plain");
288     }
289
290     setupRequest("PUT");
291     connection.setDoOutput(true);
292     OutputStream stream = null;
293     try {
294         stream = connection.getOutputStream();
295     } catch (WebDAVException exc) {
296         throw exc;
297     } catch (java.io.IOException JavaDoc exc) {
298         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
299     }
300     return stream;
301 }
302 /** This method can be used for obtaining meta-information about this resource without
303  * actually reading the resource contents. This meta-information is maintained by the server
304  * in addition to the resource properties. The meta-information is obtained from an
305  * HTTP HEAD method.</p>
306  * <p>
307  * After this call, the resource context has been updated and
308  * <code>getStatusCode()</code>, <code>getStatusMessage()</code>, and <code>getResponseContext()</code>
309  * as well as all the ResourceContext methods return updated values based on the current
310  * state of the resource.</p>
311  * <p>This methods corresponds to the HTTP HEAD method.</p>
312  * <p>
313  * Do a getContentsInputStream() to set the response context,
314  * then just don't return the stream.
315  * @exception com.ibm.webdav.WebDAVException
316  */

317 public void getMetaInformation(ResourceContext context) throws WebDAVException {
318     this.context = context;
319
320     setupRequest("HEAD");
321     getResults();
322 }
323 /** Get all the properties for this resource and (potentially) its children.
324 *
325 * @param depth an indicator for immediate members or recursively all children.
326 * <ul>
327 * <li>thisResource: propeprties of this resource</li>
328 * <li>immediateMembers: propeprties of this resource and its immediate children</li>
329 * <li>allMembers: properties of this resource and recursively all its children</li>
330 * </ul>
331 *
332 * @return a MultiStatus of PropertyResponses
333 * @exception com.ibm.webdav.WebDAVException
334 */

335 public MultiStatus getProperties(ResourceContext context) throws WebDAVException {
336     this.context = context;
337     context.getRequestContext().contentType("text/xml");
338      // default is deep in WebDAV, but we don't want this behavior
339
if (context.getRequestContext().depth() == null) {
340         context.getRequestContext().depth(Collection.thisResource);
341     }
342
343     setupRequest("PROPFIND");
344
345     Document requestBody = null;
346         try {
347           requestBody = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
348     } catch(Exception JavaDoc e) {
349           throw new WebDAVException(WebDAVStatus.SC_PROCESSING,e.getMessage());
350         }
351     //requestBody.setVersion(Resource.XMLVersion);
352
//requestBody.setEncoding(Resource.defaultXMLEncoding);
353
Element propfind = requestBody.createElementNS("DAV:","D:propfind");
354     propfind.setAttribute("xmlns:D", "DAV:");
355     requestBody.appendChild(propfind);
356     propfind.appendChild(requestBody.createElementNS("DAV:","D:allprop"));
357
358     connection.setDoOutput(true);
359     try {
360         Writer writer = new OutputStreamWriter(connection.getOutputStream(), Resource.defaultCharEncoding);
361         PrintWriter pw = new PrintWriter(writer, false);
362         pw.print(XMLUtility.printNode(requestBody.getDocumentElement()));
363                 //requestBody.print(pw);
364
pw.flush();
365     } catch (WebDAVException exc) {
366         throw exc;
367     } catch (java.io.IOException JavaDoc exc) {
368         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO error or bad encoding");
369     }
370
371     getResults();
372
373     return responseToMultiStatus();
374 }
375 /** Get the named properties for this resource and (potentially) its children.
376 *
377 * @param names an arrary of property names to retrieve.
378 * @param depth an indicator for immediate members or recursively all children.
379 * <ul>
380 * <li>immediateMembers: propeprties of this resource and its immediate children</li>
381 * <li>allMembers: properties of this resource and recursively all its children</li>
382 * </ul>
383 *
384 * @return a MultiStatus of PropertyResponses
385 * @exception com.ibm.webdav.WebDAVException
386 */

387 public MultiStatus getProperties(ResourceContext context, PropertyName names[]) throws WebDAVException {
388     this.context = context;
389     context.getRequestContext().contentType("text/xml");
390      // default is deep in WebDAV, but we don't want this behavior
391
if (context.getRequestContext().depth() == null) {
392         context.getRequestContext().depth(Collection.thisResource);
393     }
394
395     setupRequest("PROPFIND");
396
397     Document requestBody = null;
398         try {
399           requestBody = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
400     } catch(Exception JavaDoc e) {
401           throw new WebDAVException(WebDAVStatus.SC_PROCESSING,e.getMessage());
402         }
403         //requestBody.setVersion(Resource.XMLVersion);
404
//requestBody.setEncoding(Resource.defaultXMLEncoding);
405
Element propfind = requestBody.createElementNS("DAV:","D:propfind");
406     propfind.setAttribute("xmlns:D", "DAV:");
407     requestBody.appendChild(propfind);
408     Element prop = requestBody.createElementNS("DAV:","D:prop");
409     propfind.appendChild( prop );
410     for (int i = 0; i < names.length; i++) {
411         // substitute the prefix for any namespace
412
// todo: has to iterate through all the namespaces
413
PropertyName name = names[i];
414         Element el = requestBody.createElementNS("DAV:","D:"+name.getLocal());
415         if (!name.getNamespace().equals("DAV:")) {
416             el.setAttribute( "xmlns:D", name.getNamespace());
417         }
418
419         prop.appendChild( el );
420     }
421
422     connection.setDoOutput(true);
423     try {
424         Writer writer = new OutputStreamWriter(connection.getOutputStream(), Resource.defaultCharEncoding);
425         PrintWriter pw = new PrintWriter(writer, false);
426         pw.print(XMLUtility.printNode(requestBody.getDocumentElement()));
427                 //requestBody.print(pw);
428
pw.flush();
429     } catch (WebDAVException exc) {
430         throw exc;
431     } catch (java.io.IOException JavaDoc exc) {
432         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO error or bad encoding");
433     }
434     getResults();
435
436     return responseToMultiStatus();
437 }
438 /** Get the names of all properties for this resource and (potentially) its children.
439 *
440 * @param depth an indicator for immediate members or recursively all children.
441 * <ul>
442 * <li>thisResource: propeprties of this resource</li>
443 * <li>immediateMembers: propeprties of this resource and its immediate children</li>
444 * <li>allMembers: properties of this resource and recursively all its children</li>
445 * </ul>
446 *
447 * @return a MultiStatus of PropertyResponses
448 * (PropertyValue.value is always null, PropertyValue.status contains the status)
449 * @exception com.ibm.webdav.WebDAVException
450 */

451 public MultiStatus getPropertyNames(ResourceContext context) throws WebDAVException {
452     this.context = context;
453     context.getRequestContext().contentType("text/xml");
454      // default is deep in WebDAV, but we don't want this behavior
455
if (context.getRequestContext().depth() == null) {
456         context.getRequestContext().depth(Collection.thisResource);
457     }
458
459     setupRequest("PROPFIND");
460
461     Document requestBody = null;
462         try {
463           requestBody = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
464     } catch(Exception JavaDoc e) {
465           throw new WebDAVException(WebDAVStatus.SC_PROCESSING,e.getMessage());
466         }
467         //requestBody.setVersion(Resource.XMLVersion);
468
//requestBody.setEncoding(Resource.defaultXMLEncoding);
469
Element propfind = requestBody.createElementNS("DAV:","D:propfind");
470     propfind.setAttribute("xmlns:D", "DAV:");
471     requestBody.appendChild(propfind);
472     propfind.appendChild(requestBody.createElementNS("DAV:","D:propname"));
473     connection.setDoOutput(true);
474
475     try {
476         Writer writer = new OutputStreamWriter(connection.getOutputStream(), Resource.defaultCharEncoding);
477         PrintWriter pw = new PrintWriter(writer, false);
478         pw.print(XMLUtility.printNode(requestBody.getDocumentElement()));
479                 //requestBody.print(pw);
480
pw.flush();
481     } catch (WebDAVException exc) {
482         throw exc;
483     } catch (java.io.IOException JavaDoc exc) {
484         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO error or bad encoding");
485     }
486
487     getResults();
488
489     return responseToMultiStatus();
490 }
491 /** Get the response entity for the previous WebDAVURLConnection request.
492 * @return the response entity contents
493 * @exception com.ibm.webdav.WebDAVException
494 */

495 protected byte[] getResponseEntity() throws WebDAVException {
496     byte[] data = new byte[0];
497     try {
498         BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
499         int length = (int) context.getResponseContext().contentLength();
500         if (length != -1) {
501             int rcvd = 0;
502             int size = 0;
503             data = new byte[length];
504             do {
505                 size += rcvd;
506                 rcvd = is.read(data, size, length - size);
507             } while (size < length && rcvd != -1);
508             if (rcvd == -1)
509             // premature EOF
510
data = resizeArray(data, size);
511         } else {
512             data = new byte[0];
513             int inc = 8192;
514             int off = data.length;
515             int rcvd = 0;
516             do {
517                 off += rcvd;
518                 data = resizeArray(data, off + inc);
519                 rcvd = is.read(data, off, inc);
520             } while (rcvd != -1);
521             data = resizeArray(data, off);
522         }
523     } catch (WebDAVException exc) {
524         throw exc;
525     } catch (java.io.IOException JavaDoc exc) {
526         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
527     }
528     return data;
529 }
530 /** Cause a WebDAVURLConnection request to be sent and get the
531 * status code and message. After this method has been called,
532 * getResponseEntity() can be called.
533 * @exception com.ibm.webdav.WebDAVException
534 */

535 protected void getResults() throws WebDAVException {
536     // cause the request to be sent and raise any necessary exceptions
537
String JavaDoc statusMessage = null;
538     int responseCode = 0;
539     try {
540         responseCode = connection.getResponseCode();
541         context.getStatusCode().setStatusCode(responseCode);
542         statusMessage = connection.getResponseMessage();
543     } catch (WebDAVException exc) {
544         throw exc;
545     } catch (java.io.IOException JavaDoc exc) {
546         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
547     }
548
549     if (statusMessage == null || statusMessage.equals("Unknown")) {
550         statusMessage = context.getStatusCode().getStatusMessage();
551     }
552     // copy the response and contents headers into the response context
553
// Note the index starts at 1 not 0
554
int i = 1;
555     String JavaDoc name = null;
556     while ((name = connection.getHeaderFieldKey(i)) != null) {
557         name = name.toLowerCase();
558         String JavaDoc value = connection.getHeaderField(i);
559         context.getResponseContext().put(name, value);
560         i++;
561     }
562
563     if (responseCode >= 300 && responseCode <= 399) {
564         throw new RedirectionException(responseCode, statusMessage);
565     } else if (responseCode >= 400 && responseCode <= 499) {
566         throw new ClientException(responseCode, statusMessage);
567     } else if (responseCode >= 500 && responseCode <= 599) {
568         throw new ServerException(responseCode, statusMessage);
569     }
570 }
571 /** Lock this resource collection and potentially all its members
572 * based on the given parameters. This allows control of the lock
573 * scope (exclusive or shared) the lock type (write), owner information, etc.
574 *
575 * @param scope the scope of the lock, exclusive or shared
576 * @param type the type of the lock, currently only write
577 * @param timeout the number of seconds before the lock times out or
578 * 0 for infinite timeout.
579 * @param owner an XML element containing useful information that can be
580 * used to identify the owner of the lock. An href to a home page, an
581 * email address, phone number, etc. Can be null if no owner information
582 * is provided.
583 *
584 * @return a MultiStatus containing a lockdiscovery property indicating
585 * the results of the lock operation.
586 * @exception com.ibm.webdav.WebDAVException
587 */

588 public MultiStatus lock(ResourceContext context, String JavaDoc scope, String JavaDoc type, int timeout, Element owner) throws WebDAVException {
589     this.context = context;
590
591     context.getRequestContext().contentType("text/xml");
592     context.getRequestContext().setTimeout(timeout);
593     context.getRequestContext().precondition((String JavaDoc) null);
594      // default is deep in WebDAV, but we don't want this behavior
595
if (context.getRequestContext().depth() == null) {
596         context.getRequestContext().depth(Collection.thisResource);
597     }
598
599     setupRequest("LOCK");
600
601     // construct the request entity body
602
Document requestBody = null;
603         try {
604           requestBody = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
605     } catch(Exception JavaDoc e) {
606           throw new WebDAVException(WebDAVStatus.SC_PROCESSING,e.getMessage());
607         }
608         //requestBody.setVersion(Resource.XMLVersion);
609
//requestBody.setEncoding(Resource.defaultXMLEncoding);
610
Element lockinfo = requestBody.createElementNS("DAV:","D:lockinfo");
611     lockinfo.setAttribute("xmlns:D", "DAV:");
612     requestBody.appendChild(lockinfo);
613     Element lockscope = requestBody.createElementNS("DAV:","D:lockscope");
614     lockscope.appendChild(requestBody.createElementNS("DAV:","D:" + scope));
615     lockinfo.appendChild(lockscope);
616     Element locktype = requestBody.createElementNS("DAV:","D:locktype");
617     locktype.appendChild(requestBody.createElementNS("DAV:","D:" + type));
618     lockinfo.appendChild(locktype);
619     if (owner != null) {
620         lockinfo.appendChild((Element) owner);
621     }
622
623     // output the request entity body
624
connection.setDoOutput(true);
625     try {
626         PrintWriter pw = new PrintWriter(connection.getOutputStream(), false);
627         pw.print(XMLUtility.printNode(requestBody.getDocumentElement()));
628                 //requestBody.print(pw);
629
} catch (WebDAVException exc) {
630         throw exc;
631     } catch (java.io.IOException JavaDoc exc) {
632         System.err.println(exc);
633         exc.printStackTrace();
634         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
635     }
636
637     // either a prop containing a lockdiscovery, or a multistatus
638
getResults();
639
640     return lockResponseToMultiStatus();
641 }
642 /** Convert the response from a LOCK method (an XML multistatus with a prop element
643 * containing a lockdiscovery) into a MultiStatus.
644 * @return a MultiStatus created from the DAV:multistatus from a LOCK method
645 * @exception com.ibm.webdav.ServerException thrown if there is a syntax error in the XML DAV:multistatus
646 */

647 protected MultiStatus lockResponseToMultiStatus() throws WebDAVException {
648     // parse the response
649
WebDAVErrorHandler errorHandler = new WebDAVErrorHandler(url.toString());
650     Reader reader = null;
651         Document document = null;
652
653         /*Parser xmlParser = new Parser(url.toString(), errorListener, null);
654     xmlParser.setWarningNoDoctypeDecl(false);
655     xmlParser.setProcessNamespace(true);*/

656
657
658     try {
659                 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
660                 factory.setNamespaceAware(true);
661                 DocumentBuilder docbuilder = factory.newDocumentBuilder();
662                 docbuilder.setErrorHandler(errorHandler);
663         reader = new InputStreamReader(connection.getInputStream(), Resource.defaultCharEncoding);
664                 document = docbuilder.parse(new org.xml.sax.InputSource JavaDoc(reader));
665         } catch (WebDAVException exc) {
666         throw exc;
667     } catch (java.io.IOException JavaDoc exc) {
668         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
669     } catch (Exception JavaDoc exc) {
670           throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, exc.getMessage());
671         }
672
673
674     if (errorHandler.getErrorCount() > 0) {
675         context.getStatusCode().setStatusCode(WebDAVStatus.SC_INTERNAL_SERVER_ERROR);
676         throw new ServerException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "Syntax error in multistatus response entity body");
677     }
678
679     // see if it's a multistatus
680
if (context.getStatusCode().getStatusCode() != WebDAVStatus.SC_MULTI_STATUS) {
681         // it's a prop containing a lockdiscovery. Put the prop in a propstat in a
682
// response and then convert that to a MultiStatus
683
Element prop = document.getDocumentElement();
684         Element response = document.createElementNS("DAV:","D:response");
685
686         Element href = document.createElementNS("DAV:","D:href");
687         href.appendChild(document.createTextNode(url.toString()));
688
689         Element status = document.createElementNS("DAV:","D:status");
690         String JavaDoc statusText = Response.HTTPVersion + " " + context.getStatusCode().getStatusCode() + " " + context.getStatusCode().getStatusMessage();
691         status.appendChild(document.createTextNode(statusText));
692
693         Element propstat = document.createElementNS("DAV:","D:propstat");
694         propstat.appendChild((Element) ((Element) prop).cloneNode(true));
695         propstat.appendChild(status);
696         response.appendChild(href);
697         response.appendChild(propstat);
698
699         Element multistatus = document.createElementNS("DAV:","D:multistatus");
700         multistatus.setAttribute("xmlns:D", "DAV:");
701         multistatus.appendChild(response);
702         Document newDocument = null;
703                 try {
704                   newDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
705         } catch(Exception JavaDoc exc) {
706                   throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, exc.getMessage());
707                 }
708                 //newDocument.setVersion(Resource.XMLVersion);
709
//newDocument.appendChild(multistatus);
710
document = newDocument;
711     }
712     MultiStatus multiStatus = new MultiStatus(document);
713     return multiStatus;
714 }
715 /** Move this resource to the destination URL.
716  * Partial results are possible, check the returned status for details
717  *
718  * @param destinationURL the destination
719  * @param overwrite true implies overrite the destination if it exists
720  * @param propertiesToMove a collection of properties that must be moved or
721  * the method will fail. propertiesToMove may have one of the following values:
722  * <ul>
723  * <li>null - ignore properties that cannot be moved</li>
724  * <li>empty collection - all properties must be moved or the method will fail</li>
725  * <li>a collection of URIs - a list of the properties that must be moved
726  * or the method will fail</li>
727  * </ul>
728  *
729  * @return the status of the move operation for each resource moved
730  * @exception com.ibm.webdav.WebDAVException
731  */

732 public MultiStatus move(ResourceContext context, String JavaDoc destinationURL, boolean overwrite, Vector JavaDoc propertiesToMove) throws WebDAVException {
733     this.context = context;
734
735     context.getRequestContext().depth(Collection.deep); // (always deep for move, set it anyway)
736
context.getRequestContext().overwrite(overwrite ? "T" : "F");
737     context.getRequestContext().destination(destinationURL);
738
739     setupRequest("MOVE");
740
741     return doCopyOrMove(propertiesToMove);
742 }
743 /** This method treats this resource as a method or service, and sends its parameter to
744  * this resource where it is handled in a resource-specific way. For example,
745  * sending data from an HTML form to a URL representing a Servlet or CGI script that processes
746  * the form data to produce some result.
747  *
748  * @param args a string representing the arguments to the method represented by this URL. The
749  * arguments are in the form ?parameterName1=value1&amp;parameterName2=value2... as specified
750  * for URL queries.
751  *
752  * @return the results of sending the arguments to the URL
753  * @exception com.ibm.webdav.WebDAVException
754  */

755 public byte[] performWith(ResourceContext context, String JavaDoc args) throws WebDAVException {
756     this.context = context;
757
758     setupRequest("POST");
759     putRequestEntity(args.getBytes());
760     getResults();
761     return getResponseEntity();
762 }
763 /** Write the request entity body to the WebDAVURLConnection.
764 * @param value the request entity body to write
765 * @exception com.ibm.webdav.WebDAVException
766 */

767 protected void putRequestEntity(byte[] value) throws WebDAVException {
768     connection.setDoOutput(true);
769     try {
770         BufferedOutputStream outputStream = new BufferedOutputStream(connection.getOutputStream());
771         outputStream.write(value, 0, value.length);
772         outputStream.flush();
773     } catch (WebDAVException exc) {
774         throw exc;
775     } catch (java.io.IOException JavaDoc exc) {
776         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
777     }
778 }
779 /** Refresh the lock on this resource by resetting the lock timeout.
780  * The context must contain the proper authorization for the requesting
781  * principal.
782  *
783  * @param lockToken the lock token identifying the lock.
784  * @param timeout the new timeout in seconds. -1 means infinite timeout.
785  *
786  * @return updated information about the lock status of this resource
787  * @exception com.ibm.webdav.WebDAVException
788  */

789 public MultiStatus refreshLock(ResourceContext context, String JavaDoc lockToken, int timeout) throws WebDAVException {
790     this.context = context;
791
792     // on lock refresh, the precondition (If header) must contain the
793
// lock token
794
context.getRequestContext().precondition("(<" + lockToken + ">)");
795     context.getRequestContext().setTimeout(timeout);
796      // default is deep in WebDAV, but we don't want this behavior
797
context.getRequestContext().depth(Collection.thisResource);
798
799     // A lock refresh doesn't have a request entity body
800
setupRequest("LOCK");
801
802     // either a prop containing a lockdiscovery, or a multistatus
803
getResults();
804     return lockResponseToMultiStatus();
805 }
806 /** A utility to resize a byte array and copy its current contents.
807  * @param src the source array
808  * @param new_size the new size to make the array
809  * @param the newly sized array (may be smaller than src)
810  */

811 private final static byte[] resizeArray(byte[] src, int new_size) {
812     byte tmp[] = new byte[new_size];
813     System.arraycopy(src, 0, tmp, 0, (src.length < new_size ? src.length : new_size));
814     return tmp;
815 }
816 /** Convert the response (an XML multistatus or simple status code) into
817 * a MultiStatus.
818 * @return a MultiStatus constructed from a DAV:multistatus or response code
819 * @exception com.ibm.webdav.ServerException thrown if there is a syntax error in the DAV:multistatus
820 */

821 protected MultiStatus responseToMultiStatus() throws WebDAVException {
822     MultiStatus multiStatus = null;
823     if (context.getStatusCode().getStatusCode() == WebDAVStatus.SC_MULTI_STATUS) {
824         BufferedReader reader = null;
825                 Document document = null;
826                 //WebDAVErrorListener errorListener = new WebDAVErrorListener(url.toString());
827
WebDAVErrorHandler errorHandler = new WebDAVErrorHandler(url.toString());
828
829
830                 try {
831                 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
832                 factory.setNamespaceAware(true);
833                 DocumentBuilder docbuilder = factory.newDocumentBuilder();
834                 docbuilder.setErrorHandler(errorHandler);
835                 /*Parser xmlParser = new Parser(url.toString(), errorListener, null);
836         xmlParser.setWarningNoDoctypeDecl(false);
837         xmlParser.setProcessNamespace(true);*/

838
839
840             reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Resource.defaultCharEncoding));
841                 document = docbuilder.parse(new org.xml.sax.InputSource JavaDoc(reader));
842                 } catch (WebDAVException exc) {
843             throw exc;
844         } catch (java.io.IOException JavaDoc exc) {
845             throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error or bad encoding");
846         } catch (Exception JavaDoc exc) {
847             throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, exc.getMessage());
848         }
849
850         if (errorHandler.getErrorCount() > 0) {
851             context.getStatusCode().setStatusCode(WebDAVStatus.SC_INTERNAL_SERVER_ERROR);
852             throw new ServerException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "Syntax error in multistatus response entity body");
853         }
854         multiStatus = new MultiStatus(document);
855     } else {
856         multiStatus = new MultiStatus();
857         MethodResponse response = new MethodResponse(url.toString(), context.getStatusCode().getStatusCode());
858         response.setDescription(context.getStatusCode().getStatusMessage());
859         multiStatus.addResponse(response);
860     }
861     return multiStatus;
862 }
863 /** Edit the properties of a resource. The updates must refer to a Document containing a WebDAV
864  * DAV:propertyupdates element as the document root.
865  *
866  * @param updates an XML Document containing DAV:propertyupdate elements
867  * describing the edits to be made
868  * @return a MultiStatus indicating the status of the updates
869  * @exception com.ibm.webdav.WebDAVException
870  */

871 public MultiStatus setProperties(ResourceContext context, Document updates) throws WebDAVException {
872     this.context = context;
873     context.getRequestContext().contentType("text/xml");
874
875     setupRequest("PROPPATCH");
876
877     // output the request entity body
878
connection.setDoOutput(true);
879     try {
880         PrintWriter pw = new PrintWriter(connection.getOutputStream(), false);
881         pw.print(XMLUtility.printNode(updates.getDocumentElement()));
882
883                 //((Document) updates).print(pw);
884
} catch (WebDAVException exc) {
885         throw exc;
886     } catch (java.io.IOException JavaDoc exc) {
887         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
888     }
889
890     getResults();
891
892     return responseToMultiStatus();
893 }
894 /** Setup a WebDAVURLConnection by opening a connection and setting the
895 * method. This should be done before outputting any request entity body.
896 * @param method the HTTP/1.1 or WebDAV request method
897 * @exception com.ibm.webdav.WebDAVException
898 */

899 protected void setupRequest(String JavaDoc method) throws WebDAVException {
900     // open a connection
901
try {
902                 connection = new WebDAVURLConnection(url,"localhost",url.getPort());
903
904         //connection = (WebDAVURLConnection) url.openConnection();
905
connection.setRequestMethod(method);
906     } catch (java.net.ProtocolException JavaDoc exc) {
907         exc.printStackTrace();
908     } catch (WebDAVException exc) {
909         throw exc;
910     } catch (java.io.IOException JavaDoc exc) {
911         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
912     }
913
914     // put the context into the request headers
915
Enumeration JavaDoc propertyNames = context.getRequestContext().keys();
916     while (propertyNames.hasMoreElements()) {
917         String JavaDoc name = (String JavaDoc) propertyNames.nextElement();
918         String JavaDoc value = (String JavaDoc) context.getRequestContext().get(name);
919         connection.setRequestProperty(name, value);
920     }
921 }
922 /** Unlock the lock identified by the lockToken on this resource. The request context
923  * must contain the proper authorization.
924  *
925  * @param lockToken the lock token obtained from the ActiveLock of a previous <code>lock() </code>
926  * or <code>getLocks()</code>.
927  *
928  * @return a MultiStatus containing any responses on resources that could not
929  * be unlocked.
930  * @exception com.ibm.webdav.WebDAVException
931  */

932 public MultiStatus unlock(ResourceContext context, String JavaDoc lockToken) throws WebDAVException {
933     this.context = context;
934
935     context.getRequestContext().lockToken(lockToken);
936
937     setupRequest("UNLOCK");
938
939     // a status code or a multistatus if the unlock fails
940
getResults();
941
942     return responseToMultiStatus();
943 }
944 }
945
Popular Tags