001: package com.ibm.webdav;
002:
003: /*
004: * (C) Copyright IBM Corp. 2000 All rights reserved.
005: *
006: * The program is provided "AS IS" without any warranty express or
007: * implied, including the warranty of non-infringement and the implied
008: * warranties of merchantibility and fitness for a particular purpose.
009: * IBM will not be liable for any damages suffered by you as a result
010: * of using the Program. In no event will IBM be liable for any
011: * special, indirect or consequential damages or lost profits even if
012: * IBM has been advised of the possibility of their occurrence. IBM
013: * will not be liable for any third party claims against you.
014: *
015: * Portions Copyright (C) Simulacra Media Ltd, 2004.
016: */
017:
018: import java.util.*;
019: import org.w3c.dom.*;
020: import javax.xml.parsers.*;
021: import java.io.*;
022:
023: /** A MultiStatus contains multiple Response instances resulting from the
024: * invocation of a method on a resource. There will generally be one Response for
025: * each resource effected by the method.
026: * @author Jim Amsden <jamsden@us.ibm.com>
027: * @see com.ibm.webdav.MethodResponse
028: * @see com.ibm.webdav.PropertyResponse
029: */
030: public class MultiStatus extends Object implements Serializable {
031: private Vector responses = new Vector();
032: private String description = null;
033:
034: /** Construct an empty MultiStatus.
035: *
036: */
037: public MultiStatus() throws ServerException {
038: }
039:
040: /** Construct a MultiStatus from an XML DOM Document.
041: *
042: * @param document the XML Document containing a DAV:multistatus element
043: * used to construct a MultiStatus object
044: *
045: */
046: public MultiStatus(Document document) throws ServerException {
047: init(document);
048: }
049:
050: /** Add a Response to this MultiStatus
051: *
052: * @param response the Response to add
053: */
054: public void addResponse(Response response) {
055: responses.addElement(response);
056: }
057:
058: /** Convert a MultiStatus into an XML DOM Document containing a
059: * DAV:multistatus element.
060: * @return an XML document containing a DAV:multistatus representing this MultiStatus
061: */
062: public Document asXML() {
063:
064: Document document = null;
065:
066: try {
067: document = DocumentBuilderFactory.newInstance()
068: .newDocumentBuilder().newDocument();
069: } catch (Exception e) {
070: e.printStackTrace(System.err);
071: throw new RuntimeException(e.getMessage());
072: }
073: //document.setVersion(Resource.XMLVersion);
074: //document.setEncoding(Resource.defaultXMLEncoding);
075:
076: Element multistatus = document.createElementNS("DAV:",
077: "D:multistatus");
078:
079: multistatus.setAttribute("xmlns:D", "DAV:");
080: document.appendChild(multistatus);
081: Enumeration responses = getResponses();
082: while (responses.hasMoreElements()) {
083: Response response = (Response) responses.nextElement();
084: response.setDocument(document);
085:
086: multistatus.appendChild(document.importNode(response
087: .asXML(), true));
088: }
089: if (getDescription() != null) {
090: Element description = document.createElementNS("DAV:",
091: "D:responsedescription");
092:
093: description.appendChild(document
094: .createTextNode(getDescription()));
095: multistatus.appendChild(description);
096: }
097:
098: //System.out.println(Response.printNode(multistatus));
099:
100: return document;
101: }
102:
103: /** Get the active lock on this resource owned by the given principal if any.
104: * This is a convenience method to get the active lock granted by a lock request
105: * from the returned MultiStatus. A WebDAVException is raised if the MultiStatus
106: * does not contain a PropertyResponse containing a DAV:lockdiscovery property.
107: * <p>
108: * NOTE: this method cannot be reliably implemented based on the version 10 of
109: * the WebDAV spec as an activelock element in a lockdiscovery does not contain
110: * the authorization credentials of the owner of the lock. For now, this method
111: * relies on an additional principal element in the activelock that contains
112: * the required id that is an IBM EXTENSION.
113: *
114: * @param principal the authorization id of the requesting principal
115: *
116: * @return the active lock owned by that principal or null if the resource is
117: * not locked by that principal.
118: * @exception com.ibm.webdav.WebDAVException raised if the MultiStatus doesn't contain a DAV:lockdiscovery property
119: */
120: public ActiveLock getActiveLockFor(String principal)
121: throws WebDAVException {
122: if (!isOK()) {
123: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
124: "Can't access lock information lock method failed");
125: }
126: if (!(responses.elementAt(0) instanceof PropertyResponse)) {
127: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
128: "MultiStatus doesn't contain a property response");
129: }
130: PropertyResponse response = (PropertyResponse) responses
131: .elementAt(0);
132: PropertyValue lockdiscovery = response
133: .getProperty(PropertyName.pnLockdiscovery);
134: if (lockdiscovery == null) {
135: throw new WebDAVException(
136: WebDAVStatus.SC_BAD_REQUEST,
137: "MultiStatus doesn't contain a property response containing a lockdiscovery property");
138: }
139:
140: // get the active locks from the lockdiscovery and see if one is owned
141: // by this principal. This relies on the principal element added to the
142: // activelock element to identify the owning principal
143: NodeList locks = ((Element) lockdiscovery.value)
144: .getElementsByTagNameNS("DAV:", "activelock");
145: Element lockElement = null;
146: ActiveLock ownedLock = null;
147: for (int i = 0; i < locks.getLength(); i++) {
148: lockElement = (Element) locks.item(i);
149: ActiveLock lock = new ActiveLock(lockElement);
150: if (lock.getPrincipal().equals(principal)) {
151: ownedLock = lock;
152: }
153: }
154: return ownedLock;
155: }
156:
157: /** Get the overall summary description for this MultiStatus.
158: *
159: * @return a synopsis of the responses in the MultiStatus
160: */
161: public String getDescription() {
162: return description;
163: }
164:
165: /** Get the responses in this MultiStatus
166: *
167: * @return Enumeration of Response instances
168: * @see com.ibm.webdav.MethodResponse
169: * @see com.ibm.webdav.PropertyResponse
170: */
171: public Enumeration getResponses() {
172: return responses.elements();
173: }
174:
175: /** Initialize a MultiStatus from an XML DOM Document.
176: *
177: * @param document an XML Document containing a DAV:multistatus element
178: * @exception com.ibm.webdav.ServerException
179: */
180: private void init(Document document) throws ServerException {
181: responses = new Vector();
182: Element multistatus = (Element) document.getDocumentElement();
183: NodeList responses = multistatus.getElementsByTagNameNS("DAV:",
184: "response");
185: Element response = null;
186: for (int i = 0; i < responses.getLength(); i++) {
187: response = (Element) responses.item(i);
188: Response aResponse = null;
189: if (response.getElementsByTagNameNS("DAV:", "propstat")
190: .item(0) != null) {
191: aResponse = new PropertyResponse((Document) document,
192: response);
193: } else {
194: aResponse = new MethodResponse((Document) document,
195: response);
196: }
197: this .responses.addElement(aResponse);
198: }
199: Element responseDescription = (Element) multistatus
200: .getElementsByTagNameNS("DAV:", "responsedescription");
201: if (responseDescription != null) {
202: setDescription(((Text) responseDescription.getFirstChild())
203: .getData());
204: }
205: }
206:
207: /** Check to see if all responses in this MultiStatus were successful.
208: *
209: * @return true if all method response status codes are successful, false otherwise.
210: */
211: public boolean isOK() {
212: boolean isok = true;
213: Enumeration responses = this .getResponses();
214: while (isok && responses.hasMoreElements()) {
215: Response response = (Response) responses.nextElement();
216: if (response instanceof MethodResponse) {
217: isok = isok && ((MethodResponse) response).isOK();
218: }
219: }
220: return isok;
221: }
222:
223: /** Merge the responses in childMultiStatus into this MultiStatus.
224: *
225: * @param childMultiStatus contains the responses to merge
226: */
227: public void mergeWith(MultiStatus childMultiStatus) {
228: Enumeration responses = childMultiStatus.getResponses();
229: while (responses.hasMoreElements()) {
230: Response response = (Response) responses.nextElement();
231: addResponse(response);
232: }
233: }
234:
235: /** De-serialize a MultiStatus as an XML document.
236: * @param in the stream to read from
237: */
238: private void readObject(java.io.ObjectInputStream in)
239: throws IOException, ClassNotFoundException {
240: int size = in.readInt();
241: byte[] buffer = new byte[size];
242: in.readFully(buffer);
243: ByteArrayInputStream is = new ByteArrayInputStream(buffer);
244:
245: // TODO: the parser closes the stream with it is done reading. This closes
246: // the rmi socket!
247: Document contents = null;
248:
249: try {
250: DocumentBuilderFactory factory = DocumentBuilderFactory
251: .newInstance();
252: factory.setNamespaceAware(true);
253: DocumentBuilder docbuilder = factory.newDocumentBuilder();
254: contents = docbuilder
255: .parse(new org.xml.sax.InputSource(is));
256: init(contents);
257: } catch (Exception exc) {
258: System.err.println(exc);
259: throw new IOException(exc.getMessage());
260: }
261: }
262:
263: /** Remove responses that are OK from this MultiStatus. This method is used
264: * for those situations where the MultiStatus may contain responses that are
265: * not necessary to return to a client.
266: */
267: public void removeOKResponses() {
268: for (int i = responses.size() - 1; i >= 0; i--) {
269: Response response = (Response) responses.elementAt(i);
270: if (response.isOK()) {
271: responses.removeElementAt(i);
272: }
273: }
274: }
275:
276: /** Remove a Response from this MultiStatus. Ignores errors if the response is
277: * not in the MultiStatus.
278: *
279: * @param response the Response to remove
280: */
281: public void removeResponse(Response response) {
282: try {
283: responses.removeElement(response);
284: } catch (Exception exc) {
285: }
286: }
287:
288: /** Set the overall summary description for this MultiStatus.
289: *
290: * @param value a synopsis of the responses in the MultiStatus
291: */
292: public void setDescription(String value) {
293: description = value;
294: }
295:
296: /** Convert this MultiStatus to a String representation (an XML document).
297: * The String is formatted, and will therefore contain ignorable whitespace.
298: * Use multiStatus.asXML().print(pout) if ignorable whitespace is not desired.
299: * @return a string representation of a MultiStatus as an XML document
300: *
301: */
302: public String toString() {
303: /*ByteArrayOutputStream os = new ByteArrayOutputStream();
304: PrintWriter pout = new PrintWriter(os);
305: TXDocument document = (TXDocument) asXML();
306: try {
307: document.printWithFormat(pout);
308: } catch (Exception exc) {
309: }
310: pout.close();
311: return os.toString();*/
312:
313: Document document = null;
314:
315: try {
316: document = DocumentBuilderFactory.newInstance()
317: .newDocumentBuilder().newDocument();
318: } catch (Exception e) {
319: e.printStackTrace(System.err);
320: }
321: //document.setVersion(Resource.XMLVersion);
322: //document.setEncoding(Resource.defaultXMLEncoding);
323:
324: Element multistatus = document.createElementNS("DAV:",
325: "D:multistatus");
326:
327: multistatus.setAttribute("xmlns:D", "DAV:");
328: document.appendChild(multistatus);
329: Enumeration responses = getResponses();
330: while (responses.hasMoreElements()) {
331: Response response = (Response) responses.nextElement();
332: response.setDocument(document);
333: //System.out.println(response.toString());
334: multistatus.appendChild(response.asXML());
335: }
336: if (getDescription() != null) {
337: Element description = document.createElementNS("DAV:",
338: "D:responsedescription");
339:
340: description.appendChild(document
341: .createTextNode(getDescription()));
342: multistatus.appendChild(description);
343: }
344:
345: return Response.printNode(multistatus);
346:
347: }
348:
349: /** Serialize a MultiStatus as an XML document.
350: * @param out the stream to write to
351: */
352: private void writeObject(java.io.ObjectOutputStream out)
353: throws IOException {
354: Document document = (Document) asXML();
355: ByteArrayOutputStream os = new ByteArrayOutputStream();
356: PrintWriter pw = new PrintWriter(os, false);
357: pw.print(XMLUtility.printNode(document.getDocumentElement()));
358: //document.print(pw);
359: out.writeInt(os.size());
360: out.write(os.toByteArray());
361: }
362: }
|