1   /**
2    * Copyright (c) 2000-2007 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.webdav.methods;
24  
25  import com.liferay.portal.NoSuchGroupException;
26  import com.liferay.portal.kernel.util.GetterUtil;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.Validator;
29  import com.liferay.portal.model.Group;
30  import com.liferay.portal.service.GroupLocalServiceUtil;
31  import com.liferay.portal.webdav.BaseResourceImpl;
32  import com.liferay.portal.webdav.Resource;
33  import com.liferay.portal.webdav.WebDAVException;
34  import com.liferay.portal.webdav.WebDAVRequest;
35  import com.liferay.portal.webdav.WebDAVStorage;
36  import com.liferay.portal.webdav.WebDAVUtil;
37  import com.liferay.util.servlet.ServletResponseUtil;
38  import com.liferay.util.xml.DocUtil;
39  import com.liferay.util.xml.XMLFormatter;
40  
41  import java.io.StringReader;
42  
43  import java.text.DateFormat;
44  import java.text.SimpleDateFormat;
45  
46  import java.util.ArrayList;
47  import java.util.Iterator;
48  import java.util.List;
49  import java.util.Locale;
50  
51  import javax.servlet.http.HttpServletRequest;
52  import javax.servlet.http.HttpServletResponse;
53  
54  import org.apache.commons.logging.Log;
55  import org.apache.commons.logging.LogFactory;
56  
57  import org.dom4j.Document;
58  import org.dom4j.DocumentFactory;
59  import org.dom4j.Element;
60  import org.dom4j.Namespace;
61  import org.dom4j.QName;
62  import org.dom4j.io.SAXReader;
63  
64  /**
65   * <a href="PropfindMethodImpl.java.html"><b><i>View Source</i></b></a>
66   *
67   * @author Brian Wing Shun Chan
68   *
69   */
70  public class PropfindMethodImpl implements Method {
71  
72      public void process(WebDAVRequest webDavReq) throws WebDAVException {
73          try {
74              HttpServletResponse res = webDavReq.getHttpServletResponse();
75  
76              String xml = getResponseXML(webDavReq);
77  
78              res.setContentType("text/xml; charset=UTF-8");
79              res.setStatus(WebDAVUtil.SC_MULTI_STATUS);
80  
81              try {
82                  ServletResponseUtil.write(res, xml);
83              }
84              catch (Exception e) {
85                  if (_log.isWarnEnabled()) {
86                      _log.warn(e);
87                  }
88              }
89          }
90          catch (Exception e) {
91              throw new WebDAVException(e);
92          }
93      }
94  
95      protected void addResponse(
96              Resource resource, List props, Element multistatus,
97              DateFormat createDateFormat, DateFormat modifiedDateFormat)
98          throws Exception {
99  
100         Element response = multistatus.addElement("D:response");
101 
102         DocUtil.add(response, "D:href", resource.getHREF());
103 
104         Element propstat = response.addElement("D:propstat");
105 
106         Element prop = propstat.addElement("D:prop");
107 
108         DocUtil.add(prop, "D:displayname", resource.getDisplayName());
109         DocUtil.add(
110             prop, "D:creationdate",
111             createDateFormat.format(resource.getCreateDate()));
112         DocUtil.add(
113             prop, "D:getlastmodified",
114             modifiedDateFormat.format(resource.getModifiedDate()));
115 
116         if (resource.isFolder()) {
117             DocUtil.add(prop, "D:getcontenttype", "httpd/unix-directory");
118         }
119         else {
120             DocUtil.add(
121                 prop, "D:getcontentlength", String.valueOf(resource.getSize()));
122         }
123 
124         Element resourcetype = prop.addElement("D:resourcetype");
125 
126         if (resource.isFolder()) {
127             resourcetype.addElement("D:collection");
128         }
129 
130         if (props.size() == 0) {
131             DocUtil.add(prop, "D:getetag", "\"19504-0-a4075c30\"");
132 
133             Element supportedlock = prop.addElement("D:supportedlock");
134 
135             Element lockentry = supportedlock.addElement("D:lockentry");
136 
137             Element lockscope = lockentry.addElement("D:lockscope");
138 
139             lockscope.addElement("D:exclusive");
140 
141             Element locktype = lockentry.addElement("D:locktype");
142 
143             locktype.addElement("D:write");
144 
145             lockentry = supportedlock.addElement("D:lockentry");
146 
147             lockscope = lockentry.addElement("D:lockscope");
148 
149             lockscope.addElement("D:shared");
150 
151             locktype = lockentry.addElement("D:locktype");
152 
153             locktype.addElement("D:write");
154 
155             prop.addElement("D:lockdiscovery");
156         }
157 
158         DocUtil.add(propstat, "D:status", "HTTP/1.1 200 OK");
159 
160         if (props.size() > 0) {
161             propstat = response.addElement("D:propstat");
162 
163             prop = propstat.addElement("D:prop");
164 
165             for (int i = 0; i < props.size(); i++) {
166                 String propName = (String)props.get(i);
167 
168                 prop.addElement("D:" + propName);
169             }
170 
171             DocUtil.add(propstat, "D:status", "HTTP/1.1 404 Not Found");
172         }
173     }
174 
175     protected void addResponse(String href, Element multistatus)
176         throws Exception {
177 
178         Element response = multistatus.addElement("D:response");
179 
180         DocUtil.add(response, "D:href", href);
181 
182         Element propstat = response.addElement("D:propstat");
183 
184         DocUtil.add(propstat, "D:status", "HTTP/1.1 404 Not Found");
185     }
186 
187     protected int getDepth(WebDAVRequest webDavReq) {
188         HttpServletRequest req = webDavReq.getHttpServletRequest();
189 
190         String depth = req.getHeader("Depth");
191 
192         if (_log.isDebugEnabled()) {
193             _log.debug("Depth " + depth);
194         }
195 
196         return GetterUtil.getInteger(depth, 1);
197     }
198 
199     protected DateFormat getCreateDateFormat() {
200         return new SimpleDateFormat(_CREATE_DATE_FORMAT, Locale.US);
201     }
202 
203     protected DateFormat getModifiedDateFormat() {
204         return new SimpleDateFormat(_MODIFIED_DATE_FORMAT, Locale.US);
205     }
206 
207     protected List getProps(WebDAVRequest webDavReq) throws Exception {
208         HttpServletRequest req = webDavReq.getHttpServletRequest();
209 
210         List props = new ArrayList();
211 
212         String xml = WebDAVUtil.getRequestXML(req);
213 
214         if (Validator.isNull(xml)) {
215             return props;
216         }
217 
218         SAXReader reader = new SAXReader();
219 
220         Document doc = reader.read(new StringReader(xml));
221 
222         Element root = doc.getRootElement();
223 
224         Element prop = root.element("prop");
225 
226         Iterator itr = prop.elements().iterator();
227 
228         while (itr.hasNext()) {
229             Element el = (Element)itr.next();
230 
231             props.add(el.getName());
232         }
233 
234         return props;
235     }
236 
237     protected String getResponseXML(WebDAVRequest webDavReq) throws Exception {
238         WebDAVStorage storage = webDavReq.getWebDAVStorage();
239         long companyId = webDavReq.getCompanyId();
240         long groupId = webDavReq.getGroupId();
241         DateFormat createDateFormat = getCreateDateFormat();
242         DateFormat modifiedDateFormat = getModifiedDateFormat();
243 
244         List props = getProps(webDavReq);
245 
246         DocumentFactory docFactory = DocumentFactory.getInstance();
247 
248         Document doc = docFactory.createDocument();
249 
250         Element multistatus = docFactory.createElement(
251             new QName("multistatus", new Namespace("D", "DAV:")));
252 
253         doc.setRootElement(multistatus);
254 
255         if (companyId <= 0) {
256             return getResponseXML(doc);
257         }
258 
259         if (groupId == 0) {
260             addResponse(
261                 new BaseResourceImpl(
262                     storage.getRootPath() + StringPool.SLASH + companyId,
263                     String.valueOf(companyId), true),
264                 props, multistatus, createDateFormat, modifiedDateFormat);
265 
266             if (props.size() > 0) {
267                 Iterator itr = storage.getCommunities(webDavReq).iterator();
268 
269                 while (itr.hasNext()) {
270                     Resource resource = (Resource)itr.next();
271 
272                     addResponse(
273                         resource, props, multistatus, createDateFormat,
274                         modifiedDateFormat);
275                 }
276             }
277 
278             return getResponseXML(doc);
279         }
280 
281         Resource resource = storage.getResource(webDavReq);
282 
283         if ((resource == null) && !webDavReq.isGroupPath()) {
284             String href = storage.getRootPath() + webDavReq.getPath();
285 
286             if (_log.isWarnEnabled()) {
287                 _log.warn("No resource found for " + webDavReq.getPath());
288             }
289 
290             addResponse(href, multistatus);
291 
292             return getResponseXML(doc);
293         }
294 
295         if (resource != null) {
296             addResponse(
297                 resource, props, multistatus, createDateFormat,
298                 modifiedDateFormat);
299         }
300         else if (webDavReq.isGroupPath()) {
301             try {
302                 Group group = GroupLocalServiceUtil.getGroup(groupId);
303 
304                 addResponse(
305                     new BaseResourceImpl(
306                         storage.getRootPath() + StringPool.SLASH + companyId +
307                             StringPool.SLASH + groupId,
308                         group.getName(), true),
309                     props, multistatus, createDateFormat, modifiedDateFormat);
310             }
311             catch (NoSuchGroupException nsge) {
312                 String href = storage.getRootPath() + webDavReq.getPath();
313 
314                 if (_log.isWarnEnabled()) {
315                     _log.warn("No group found for " + href);
316                 }
317 
318                 addResponse(href, multistatus);
319             }
320         }
321 
322         Iterator itr = storage.getResources(webDavReq).iterator();
323 
324         while (itr.hasNext()) {
325             resource = (Resource)itr.next();
326 
327             addResponse(
328                 resource, props, multistatus, createDateFormat,
329                 modifiedDateFormat);
330         }
331 
332         return getResponseXML(doc);
333     }
334 
335     protected String getResponseXML(Document doc) throws Exception {
336         String xml = XMLFormatter.toString(doc, "    ");
337 
338         if (_log.isDebugEnabled()) {
339             _log.debug("Response XML\n" + xml);
340         }
341 
342         return xml;
343     }
344 
345     private static final String _CREATE_DATE_FORMAT =
346         "yyyy-MM-dd'T'HH:mm:ss'Z'";
347 
348     private static final String _MODIFIED_DATE_FORMAT =
349         "EEE, dd MMM yyyy HH:mm:ss zzz";
350 
351     private static Log _log = LogFactory.getLog(PropfindMethodImpl.class);
352 
353 }