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