Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 362   Methods: 14
NCLOC: 262   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Propfind.java 80.6% 94.5% 100% 90.5%
coverage coverage
 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    * $Id: Propfind.java 551440 2007-06-28 04:26:07Z vgritsenko $
 18    */
 19   
 20    package org.apache.xindice.webadmin.webdav.components;
 21   
 22    import java.io.IOException;
 23    import java.util.Set;
 24    import java.util.HashMap;
 25    import java.util.Iterator;
 26    import java.util.ArrayList;
 27    import java.util.HashSet;
 28   
 29    import javax.servlet.ServletException;
 30    import javax.servlet.http.HttpServletResponse;
 31   
 32    import org.apache.xindice.core.Collection;
 33    import org.apache.xindice.core.DBException;
 34    import org.apache.xindice.core.Database;
 35    import org.apache.xindice.core.data.Entry;
 36    import org.apache.xindice.webadmin.webdav.components.props.CreationDate;
 37    import org.apache.xindice.webadmin.webdav.components.props.DAVProperty;
 38    import org.apache.xindice.webadmin.webdav.components.props.LastModified;
 39    import org.apache.xindice.webadmin.webdav.components.props.DisplayName;
 40    import org.apache.xindice.webadmin.webdav.components.props.ResourceType;
 41    import org.apache.xindice.webadmin.webdav.components.props.ContentType;
 42    import org.apache.xindice.webadmin.webdav.WebdavStatus;
 43    import org.apache.xindice.webadmin.webdav.DAVRequest;
 44    import org.apache.xindice.webadmin.webdav.DAVResponse;
 45    import org.apache.xindice.webadmin.PartialResponse;
 46    import org.apache.xindice.webadmin.Location;
 47    import org.apache.commons.logging.Log;
 48    import org.apache.commons.logging.LogFactory;
 49    import org.w3c.dom.Document;
 50    import org.w3c.dom.Node;
 51    import org.w3c.dom.NodeList;
 52   
 53    /**
 54    * This class implements the Propfind command for WebDAV operations on
 55    * Xindice. <br>
 56    * <br>
 57    * PROPFIND command requests properties defined for resources or collections.
 58    * Request can have a body that contians XML document. It is possible
 59    * to request particular property values, all property values, or a
 60    * list of the names of the resource's properties. A client may choose not
 61    * to submit a request body. An empty PROPFIND request body is treated as a
 62    * request for the names and values of all properties.<br>
 63    * <br>
 64    * A client may submit a Depth header with a value of "0", "1", or "infinity"
 65    * with a PROPFIND on a collection. By default, the PROPFIND method without a
 66    * Depth header acts as if a "Depth: infinity" header was included.<br>
 67    * <br>
 68    * The default operation status code is 207 (Multi-Status).
 69    *
 70    * @author <a href="mailto:jmetzner@apache.org">Jan Metzner</a>
 71    * @author <a href="mailto:gianugo@apache.org">Gianugo Rabellino</a>
 72    * @version $Revision: 551440 $, $Date: 2007-06-27 21:26:07 -0700 (Wed, 27 Jun 2007) $
 73    */
 74    public class Propfind implements DAVComponent {
 75   
 76    public static final int FIND_BY_PROPERTY = 1;
 77    public static final int FIND_PROPERTY_NAMES = 2;
 78    public static final int FIND_ALL_PROP = 3;
 79   
 80    private static final HashMap PROPS_MAP = new HashMap();
 81    static {
 82  2 DAVProperty[] props = {
 83    new CreationDate(),
 84    new LastModified(),
 85    new DisplayName(),
 86    new ResourceType(),
 87    new ContentType()
 88    };
 89   
 90  2 for (int i = 0; i < props.length; i++) {
 91  10 PROPS_MAP.put(props[i].getName(), props[i]);
 92    }
 93    }
 94   
 95    private static final Log log = LogFactory.getLog(Propfind.class);
 96   
 97  6 public void execute(DAVRequest req, DAVResponse res, Location target) throws ServletException, IOException {
 98  6 if (!target.isRoot() && target.getCollection() == null) {
 99  1 res.setStatus(HttpServletResponse.SC_NOT_FOUND);
 100  1 return;
 101    }
 102   
 103  5 try {
 104  5 process(req, res, target.getCollection(), target.getName());
 105    } catch (DBException e) {
 106  0 log.error(e);
 107  0 throw new ServletException(e);
 108    }
 109    }
 110   
 111  5 private void process(DAVRequest req, DAVResponse res, Collection col, String name)
 112    throws DBException, IOException {
 113  5 res.setProtocol(req.getProtocol());
 114  5 Document requestDoc = req.getRequestDoc();
 115  5 int type = getPropFindType(requestDoc);
 116   
 117  5 Set requestedProps = null;
 118  5 if (type == FIND_BY_PROPERTY) {
 119  1 requestedProps = getRequestPropertyNames(requestDoc);
 120    }
 121   
 122  5 String contextPath = req.getContextPath();
 123  5 if (name == null) {
 124  4 int depth = req.getDepth();
 125  4 String requestPath = req.getPath();
 126   
 127  4 if (requestPath == null || requestPath.equals("/")) { // root
 128  0 col = null;
 129    }
 130   
 131  4 HashMap values = getProperties(col, null, requestedProps, type);
 132  4 addPropfindResponse(res, getLocation(contextPath, col), values);
 133   
 134  4 if (depth != 0) {
 135  3 processChildren(res, contextPath, col, requestedProps, type, depth);
 136    }
 137   
 138    } else {
 139  1 Entry entry = col.getEntry(name);
 140  1 if (entry == null) {
 141  1 res.setStatus(HttpServletResponse.SC_NOT_FOUND);
 142    } else {
 143  0 HashMap values = getProperties(col, entry, requestedProps, type);
 144  0 addPropfindResponse(res, getLocation(contextPath, col, name), values);
 145    }
 146    }
 147   
 148  5 res.closeMultistatusResponse();
 149    }
 150   
 151  6 private void processChildren(DAVResponse res, String contextPath, Collection col, Set requestedProps, int type, int depth)
 152    throws DBException, IOException {
 153  6 String[] children;
 154  6 if (col == null) {
 155  0 children = Database.listDatabases();
 156    } else {
 157  6 children = col.listCollections();
 158    }
 159   
 160  6 if (depth != 0) {
 161    // child resources
 162  5 if (col != null) {
 163  5 String[] childResources = col.listDocuments();
 164  5 for (int i = 0; i < childResources.length; i++) {
 165  5 HashMap values = getProperties(col, col.getEntry(childResources[i]), requestedProps, type);
 166  5 addPropfindResponse(res, getLocation(contextPath, col, childResources[i]), values);
 167    }
 168    }
 169   
 170    // child collections
 171  5 for (int i = 0; i < children.length; i++) {
 172  3 Collection childCol = col != null ?
 173    col.getCollection(children[i]) :
 174    Database.getDatabase(children[i]);
 175   
 176  3 HashMap values = getProperties(childCol, null, requestedProps, type);
 177  3 addPropfindResponse(res, getLocation(contextPath, childCol), values);
 178  3 processChildren(res, contextPath, childCol, requestedProps, type, depth - 1 );
 179    }
 180    }
 181    }
 182   
 183  12 private HashMap getProperties(Collection col, Entry entry, Set requestedProps, int type) {
 184  12 HashMap values = null;
 185  12 switch (type) {
 186  3 case FIND_PROPERTY_NAMES:
 187  3 values = getPropertyNames(col, entry);
 188  3 break;
 189  5 case FIND_ALL_PROP:
 190  5 values = getAllPropertiesValues(col, entry);
 191  5 break;
 192  4 case FIND_BY_PROPERTY:
 193  4 values = getPropertiesValues(col, entry, requestedProps);
 194  4 break;
 195    }
 196   
 197  12 return values;
 198    }
 199   
 200  3 private HashMap getPropertyNames(Collection col, Entry entry) {
 201  3 ArrayList values = new ArrayList();
 202   
 203  3 for (Iterator i = PROPS_MAP.keySet().iterator(); i.hasNext(); ) {
 204  15 String property = (String) i.next();
 205   
 206  15 if (getProperty(col, entry, property) != null) {
 207  13 values.add(new PartialResponse.Content(property));
 208    }
 209    }
 210   
 211  3 HashMap status = new HashMap();
 212  3 status.put(new Integer(WebdavStatus.SC_OK), values);
 213  3 return status;
 214    }
 215   
 216  4 private HashMap getPropertiesValues(Collection col, Entry entry, Set requestProps) {
 217  4 ArrayList values = new ArrayList();
 218  4 ArrayList notFound = new ArrayList();
 219   
 220  4 for (Iterator i = requestProps.iterator(); i.hasNext(); ) {
 221  16 String requestProp = (String) i.next();
 222  16 if (PROPS_MAP.containsKey(requestProp)) { // supported property
 223   
 224  12 PartialResponse.Content part = getProperty(col, entry, requestProp);
 225   
 226  12 if (part != null) {
 227  10 values.add(part);
 228    } else {
 229  2 notFound.add(new PartialResponse.Content(requestProp));
 230    }
 231    } else { // requested property not supported
 232  4 notFound.add(new PartialResponse.Content(requestProp));
 233    }
 234    }
 235   
 236  4 HashMap status = new HashMap();
 237  4 status.put(new Integer(WebdavStatus.SC_OK), values);
 238  4 status.put(new Integer(WebdavStatus.SC_NOT_FOUND), notFound);
 239  4 return status;
 240    }
 241   
 242  5 private HashMap getAllPropertiesValues(Collection col, Entry entry) {
 243  5 ArrayList values = new ArrayList();
 244   
 245  5 Set props = PROPS_MAP.keySet();
 246  5 for (Iterator i = props.iterator(); i.hasNext(); ) {
 247  25 String requestProp = (String) i.next();
 248   
 249  25 PartialResponse.Content part = getProperty(col, entry, requestProp);
 250   
 251  25 if (part != null) {
 252  22 values.add(part);
 253    }
 254    }
 255   
 256  5 HashMap status = new HashMap();
 257  5 status.put(new Integer(WebdavStatus.SC_OK), values);
 258  5 return status;
 259    }
 260   
 261  52 private PartialResponse.Content getProperty(Collection col, Entry entry, String propName) {
 262  52 DAVProperty prop = (DAVProperty) PROPS_MAP.get(propName);
 263   
 264  52 PartialResponse.Content part;
 265  52 if (entry != null) {
 266  21 part = prop.getProperty(entry);
 267  31 } else if (col != null) {
 268  31 part = prop.getProperty(col);
 269    } else {
 270  0 part = prop.getRootProperty();
 271    }
 272   
 273  52 return part;
 274    }
 275   
 276  1 private Set getRequestPropertyNames(Document doc) {
 277  1 NodeList nodes = doc.getDocumentElement().getElementsByTagNameNS("DAV:", "prop");
 278   
 279  1 HashSet properties = new HashSet();
 280  1 NodeList childList = nodes.item(0).getChildNodes();
 281  1 for (int i = 0; i < childList.getLength(); i++) {
 282  4 Node currentNode = childList.item(i);
 283  4 if (currentNode.getNodeType() == Node.ELEMENT_NODE && currentNode.getNamespaceURI().equals("DAV:")) {
 284  4 properties.add(currentNode.getLocalName());
 285    }
 286    }
 287  1 if (log.isDebugEnabled()) {
 288  0 log.debug("Requested properties: " + properties.toString());
 289    }
 290   
 291  1 return properties;
 292    }
 293   
 294  5 private int getPropFindType(Document doc) {
 295  5 if (doc == null) {
 296  1 return FIND_ALL_PROP;
 297    }
 298   
 299  4 int type = FIND_ALL_PROP;
 300  4 Node propfind = doc.getDocumentElement();
 301  4 if (propfind != null && isNodeNamed(propfind, "propfind")) {
 302  4 NodeList childList = propfind.getChildNodes();
 303   
 304  4 for (int i = 0; i < childList.getLength(); i++) {
 305  4 Node currentNode = childList.item(i);
 306  4 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
 307  4 if (isNodeNamed(currentNode, "prop")) {
 308  1 type = FIND_BY_PROPERTY;
 309  1 break;
 310  3 } else if (isNodeNamed(currentNode, "propname")) {
 311  1 type = FIND_PROPERTY_NAMES;
 312  1 break;
 313  2 } else if (isNodeNamed(currentNode, "allprop")) {
 314  2 type = FIND_ALL_PROP;
 315  2 break;
 316    }
 317    }
 318    }
 319    }
 320   
 321  4 return type;
 322    }
 323   
 324  13 private boolean isNodeNamed(Node node, String name) {
 325  13 return node.getNamespaceURI().equals("DAV:") && node.getLocalName().equals(name);
 326    }
 327   
 328  7 private String getLocation(String context, Collection col) {
 329  7 return context + (col != null ? col.getCanonicalName() : "") + "/";
 330    }
 331   
 332  5 private String getLocation(String context, Collection col, String resource) {
 333  5 return context + col.getCanonicalDocumentName(resource);
 334    }
 335   
 336  12 public void addPropfindResponse(DAVResponse res, String location, HashMap statusList) throws IOException {
 337  12 PartialResponse response = new PartialResponse(location);
 338   
 339  12 for (Iterator i = statusList.keySet().iterator(); i.hasNext(); ) {
 340  16 Integer status = (Integer) i.next();
 341  16 ArrayList props = (ArrayList) statusList.get(status);
 342   
 343  16 if (props != null && props.size() > 0) {
 344  16 PartialResponse.Content prop = new PartialResponse.Content("prop");
 345  16 for (Iterator j = props.iterator(); j.hasNext(); ) {
 346  51 prop.addChild((PartialResponse.Content) j.next());
 347    }
 348   
 349  16 PartialResponse.Content stat = new PartialResponse.Content("status");
 350  16 stat.setValue(res.getProtocol() + " " + status + " " + WebdavStatus.getStatusText(status.intValue()));
 351   
 352  16 PartialResponse.Content propstat = new PartialResponse.Content("propstat");
 353  16 propstat.addChild(prop);
 354  16 propstat.addChild(stat);
 355   
 356  16 response.addContent(propstat);
 357    }
 358    }
 359   
 360  12 res.sendMultiStatusResponse(response);
 361    }
 362    }