1 package org.apache.jackrabbit.webdav;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
23 import org.apache.jackrabbit.webdav.xml.DomUtil;
24 import org.apache.jackrabbit.webdav.xml.ElementIterator;
25 import org.apache.jackrabbit.webdav.xml.XmlSerializable;
26 import org.w3c.dom.Document;
27 import org.w3c.dom.Element;
28
29 import java.util.Map;
30 import java.util.LinkedHashMap;
31
32 /**
33 * MultiStatus representing the content of a multistatus response body and
34 * allows to retrieve the Xml representation.
35 */
36 public class MultiStatus
37 implements DavConstants, XmlSerializable
38 {
39
40 /**
41 * Map collecting the responses for this multistatus, where every href must
42 * only occur one single time.
43 */
44 private Map<String, MultiStatusResponse> responses = new LinkedHashMap<String, MultiStatusResponse>();
45
46 /**
47 * A general response description at the multistatus top level is used to
48 * provide a general message describing the overarching nature of the response.
49 * If this value is available an application may use it instead of
50 * presenting the individual response descriptions contained within the
51 * responses.
52 */
53 private String responseDescription;
54
55 /**
56 * Add response(s) to this multistatus, in order to build a multistatus for
57 * responding to a PROPFIND request.
58 *
59 * @param resource The resource to add property from
60 * @param propNameSet The requested property names of the PROPFIND request
61 * @param propFindType
62 * @param depth
63 */
64 public void addResourceProperties( DavResource resource, DavPropertyNameSet propNameSet, int propFindType,
65 int depth )
66 {
67 addResponse( new MultiStatusResponse( resource, propNameSet, propFindType ) );
68 if ( depth > 0 && resource.isCollection() )
69 {
70 DavResourceIterator iter = resource.getMembers();
71 while ( iter.hasNext() )
72 {
73 addResourceProperties( iter.nextResource(), propNameSet, propFindType, depth - 1 );
74 }
75 }
76 }
77
78 /**
79 * Add response(s) to this multistatus, in order to build a multistatus e.g.
80 * in order to respond to a PROPFIND request. Please note, that in terms
81 * of PROPFIND, this method would correspond to a
82 * {@link DavConstants#PROPFIND_BY_PROPERTY} propfind type.
83 *
84 * @param resource The resource to add property from
85 * @param propNameSet The requested property names of the PROPFIND request
86 * @param depth
87 * @see #addResourceProperties(DavResource, DavPropertyNameSet, int, int) for
88 * the corresponding method that allows to specify the type explicitly.
89 */
90 public void addResourceProperties( DavResource resource, DavPropertyNameSet propNameSet, int depth )
91 {
92 addResourceProperties( resource, propNameSet, PROPFIND_BY_PROPERTY, depth );
93 }
94
95 /**
96 * Add response(s) to this multistatus, in order to build a multistatus
97 * as returned for COPY, MOVE, LOCK or DELETE requests resulting in an error
98 * with a resource other than the resource identified in the Request-URI.
99 *
100 * @param resource
101 * @param status
102 * @param depth
103 */
104 public void addResourceStatus( DavResource resource, int status, int depth )
105 {
106 addResponse( new MultiStatusResponse( resource.getHref(), status ) );
107 if ( depth > 0 && resource.isCollection() )
108 {
109 DavResourceIterator iter = resource.getMembers();
110 while ( iter.hasNext() )
111 {
112 addResourceStatus( iter.nextResource(), status, depth - 1 );
113 }
114 }
115 }
116
117 /**
118 * Add a <code>MultiStatusResponse</code> element to this <code>MultiStatus</code>
119 *
120 * @param response
121 */
122 public void addResponse( MultiStatusResponse response )
123 {
124 responses.put( response.getHref(), response );
125 }
126
127 /**
128 * Returns the multistatus responses present as array.
129 *
130 * @return array of all {@link MultiStatusResponse responses} present in this
131 * multistatus.
132 */
133 public MultiStatusResponse[] getResponses()
134 {
135 return (MultiStatusResponse[]) responses.values().toArray( new MultiStatusResponse[responses.size()] );
136 }
137
138 /**
139 * Set the response description.
140 *
141 * @param responseDescription
142 */
143 public void setResponseDescription( String responseDescription )
144 {
145 this.responseDescription = responseDescription;
146 }
147
148 /**
149 * Returns the response description.
150 *
151 * @return responseDescription
152 */
153 public String getResponseDescription()
154 {
155 return responseDescription;
156 }
157
158 /**
159 * Return the Xml representation of this <code>MultiStatus</code>.
160 *
161 * @return Xml document
162 * @param document
163 */
164 public Element toXml( Document document )
165 {
166 Element multistatus = DomUtil.createElement( document, XML_MULTISTATUS, NAMESPACE );
167 for ( MultiStatusResponse response : responses.values() )
168 {
169 multistatus.appendChild( response.toXml( document ) );
170 }
171 if ( responseDescription != null )
172 {
173 Element respDesc =
174 DomUtil.createElement( document, XML_RESPONSEDESCRIPTION, NAMESPACE, responseDescription );
175 multistatus.appendChild( respDesc );
176 }
177 return multistatus;
178 }
179
180 /**
181 * Build a <code>MultiStatus</code> from the specified xml element.
182 *
183 * @param multistatusElement
184 * @return new <code>MultiStatus</code> instance.
185 * @throws IllegalArgumentException if the given document is <code>null</code>
186 * or does not provide the required element.
187 */
188 public static MultiStatus createFromXml( Element multistatusElement )
189 {
190 if ( !DomUtil.matches( multistatusElement, XML_MULTISTATUS, NAMESPACE ) )
191 {
192 throw new IllegalArgumentException( "DAV:multistatus element expected." );
193 }
194
195 MultiStatus multistatus = new MultiStatus();
196
197 ElementIterator it = DomUtil.getChildren( multistatusElement, XML_RESPONSE, NAMESPACE );
198 while ( it.hasNext() )
199 {
200 Element respElem = it.nextElement();
201 MultiStatusResponse response = MultiStatusResponse.createFromXml( respElem );
202 multistatus.addResponse( response );
203 }
204
205 // optional response description on the multistatus element
206 multistatus.setResponseDescription( DomUtil.getChildText( multistatusElement, XML_RESPONSEDESCRIPTION,
207 NAMESPACE ) );
208 return multistatus;
209 }
210 }