Package net.sf.webdav.methods

Source Code of net.sf.webdav.methods.DoPropfind

/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.webdav.methods;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Vector;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import net.sf.webdav.MimeTyper;
import net.sf.webdav.ResourceLocks;
import net.sf.webdav.WebdavStatus;
import net.sf.webdav.WebdavStore;
import net.sf.webdav.exceptions.AccessDeniedException;
import net.sf.webdav.exceptions.WebdavException;
import net.sf.webdav.fromcatalina.URLEncoder;
import net.sf.webdav.fromcatalina.XMLWriter;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class DoPropfind extends AbstractMethod {

    private static org.slf4j.Logger log = org.slf4j.LoggerFactory
      .getLogger("net.sf.webdav.methods");

    /**
     * Array containing the safe characters set.
     */
    protected static URLEncoder urlEncoder;

    /**
     * Simple date format for the creation date ISO representation (partial).
     */
    protected static final SimpleDateFormat creationDateFormat = new SimpleDateFormat(
      "yyyy-MM-dd'T'HH:mm:ss'Z'");

    /**
     * Default depth is infite.
     */
    private static final int INFINITY = 3;

    /**
     * PROPFIND - Specify a property mask.
     */
    private static final int FIND_BY_PROPERTY = 0;

    /**
     * PROPFIND - Display all properties.
     */
    private static final int FIND_ALL_PROP = 1;

    /**
     * PROPFIND - Return property names.
     */
    private static final int FIND_PROPERTY_NAMES = 2;

    private WebdavStore store;
    private ResourceLocks resLocks;
    private boolean readOnly;
    private MimeTyper mimeTyper;

    static {
  creationDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
  /**
   * GMT timezone - all HTTP dates are on GMT
   */
  urlEncoder = new URLEncoder();
  urlEncoder.addSafeCharacter('-');
  urlEncoder.addSafeCharacter('_');
  urlEncoder.addSafeCharacter('.');
  urlEncoder.addSafeCharacter('*');
  urlEncoder.addSafeCharacter('/');
    }

    public DoPropfind(WebdavStore store, ResourceLocks resLocks,
      boolean readOnly, MimeTyper mimeTyper) {
  this.store = store;
  this.resLocks = resLocks;
  this.readOnly = readOnly;
  this.mimeTyper = mimeTyper;
    }

    public void execute(HttpServletRequest req, HttpServletResponse resp)
      throws IOException {
  log.trace("-- " + this.getClass().getName());

  // Retrieve the resources
  String lockOwner = "doPropfind" + System.currentTimeMillis()
    + req.toString();
  String path = getCleanPath(getRelativePath(req));
  int depth = getDepth(req);
  if (resLocks.lock(path, lockOwner, false, depth)) {
      try {
    if (!store.objectExists(path)) {
        resp.sendError(HttpServletResponse.SC_NOT_FOUND, req
          .getRequestURI());
        return;
    }

    Vector properties = null;

    int propertyFindType = FIND_ALL_PROP;
    Node propNode = null;
    getPropertyNodeAndType(propNode, propertyFindType, req);

    if (propertyFindType == FIND_BY_PROPERTY) {
        properties = getPropertiesFromXML(propNode);
    }

    resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
    resp.setContentType("text/xml; charset=UTF-8");

    // Create multistatus object
    XMLWriter generatedXML = new XMLWriter(resp.getWriter());
    generatedXML.writeXMLHeader();
    generatedXML.writeElement(null, "multistatus xmlns=\"DAV:\"",
      XMLWriter.OPENING);
    if (depth == 0) {
        parseProperties(req, generatedXML, path, propertyFindType,
          properties, mimeTyper.getMimeType(path));
    } else {
        recursiveParseProperties(path, req, generatedXML,
          propertyFindType, properties, depth, mimeTyper
            .getMimeType(path));
    }
    generatedXML.writeElement(null, "multistatus",
      XMLWriter.CLOSING);
    generatedXML.sendData();
      } catch (AccessDeniedException e) {
    resp.sendError(WebdavStatus.SC_FORBIDDEN);
      } catch (WebdavException e) {
    log.warn("Sending internal error!");
    resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
      } catch (ServletException e) {
    e.printStackTrace(); // To change body of catch statement use
    // File | Settings | File Templates.
      } finally {
    resLocks.unlock(path, lockOwner);
      }
  } else {
      log.warn("Sending internal error!");
      resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  }
    }

    /**
     * reads the depth header from the request and returns it as a int
     *
     * @param req
     * @return the depth from the depth header
     */
    private int getDepth(HttpServletRequest req) {
  int depth = INFINITY;
  String depthStr = req.getHeader("Depth");
  if (depthStr != null) {
      if (depthStr.equals("0")) {
    depth = 0;
      } else if (depthStr.equals("1")) {
    depth = 1;
      } else if (depthStr.equals("infinity")) {
    depth = INFINITY;
      }
  }
  return depth;
    }

    /**
     * removes a / at the end of the path string, if present
     *
     * @param path
     *                the path
     * @return the path without trailing /
     */
    private String getCleanPath(String path) {

  if (path.endsWith("/") && path.length() > 1)
      path = path.substring(0, path.length() - 1);
  return path;
    }

    /**
     * overwrites propNode and type, parsed from xml input stream
     *
     * @param propNode
     * @param type
     * @param req
     *                HttpServletRequest
     * @throws javax.servlet.ServletException
     */
    private void getPropertyNodeAndType(Node propNode, int type,
      ServletRequest req) throws ServletException {
  if (req.getContentLength() != 0) {
      DocumentBuilder documentBuilder = getDocumentBuilder();
      try {
    Document document = documentBuilder.parse(new InputSource(req
      .getInputStream()));
    // Get the root element of the document
    Element rootElement = document.getDocumentElement();
    NodeList childList = rootElement.getChildNodes();

    for (int i = 0; i < childList.getLength(); i++) {
        Node currentNode = childList.item(i);
        switch (currentNode.getNodeType()) {
        case Node.TEXT_NODE:
      break;
        case Node.ELEMENT_NODE:
      if (currentNode.getNodeName().endsWith("prop")) {
          type = FIND_BY_PROPERTY;
          propNode = currentNode;
      }
      if (currentNode.getNodeName().endsWith("propname")) {
          type = FIND_PROPERTY_NAMES;
      }
      if (currentNode.getNodeName().endsWith("allprop")) {
          type = FIND_ALL_PROP;
      }
      break;
        }
    }
      } catch (Exception e) {

      }
  } else {
      // no content, which means it is a allprop request
      type = FIND_ALL_PROP;
  }
    }

    /**
     * Return JAXP document builder instance.
     */
    private DocumentBuilder getDocumentBuilder() throws ServletException {
  DocumentBuilder documentBuilder = null;
  DocumentBuilderFactory documentBuilderFactory = null;
  try {
      documentBuilderFactory = DocumentBuilderFactory.newInstance();
      documentBuilderFactory.setNamespaceAware(true);
      documentBuilder = documentBuilderFactory.newDocumentBuilder();
  } catch (ParserConfigurationException e) {
      throw new ServletException("jaxp failed");
  }
  return documentBuilder;
    }

    private Vector getPropertiesFromXML(Node propNode) {
  Vector properties;
  properties = new Vector();
  NodeList childList = propNode.getChildNodes();

  for (int i = 0; i < childList.getLength(); i++) {
      Node currentNode = childList.item(i);
      switch (currentNode.getNodeType()) {
      case Node.TEXT_NODE:
    break;
      case Node.ELEMENT_NODE:
    String nodeName = currentNode.getNodeName();
    String propertyName = null;
    if (nodeName.indexOf(':') != -1) {
        propertyName = nodeName
          .substring(nodeName.indexOf(':') + 1);
    } else {
        propertyName = nodeName;
    }
    // href is a live property which is handled differently
    properties.addElement(propertyName);
    break;
      }
  }
  return properties;
    }

    /**
     * goes recursive through all folders. used by propfind
     *
     * @param currentPath
     *                the current path
     * @param req
     *                HttpServletRequest
     * @param generatedXML
     * @param propertyFindType
     * @param properties
     * @param depth
     *                depth of the propfind
     * @throws IOException
     *                 if an error in the underlying store occurs
     */
    private void recursiveParseProperties(String currentPath,
      HttpServletRequest req, XMLWriter generatedXML,
      int propertyFindType, Vector properties, int depth, String mimeType)
      throws WebdavException {

  parseProperties(req, generatedXML, currentPath, propertyFindType,
    properties, mimeType);
  String[] names = store.getChildrenNames(currentPath);
  if ((names != null) && (depth > 0)) {

      for (int i = 0; i < names.length; i++) {
    String name = names[i];
    String newPath = currentPath;
    if (!(newPath.endsWith("/"))) {
        newPath += "/";
    }
    newPath += name;
    recursiveParseProperties(newPath, req, generatedXML,
      propertyFindType, properties, depth - 1, mimeType);
      }
  }
    }

    /**
     * Propfind helper method.
     *
     * @param req
     *                The servlet request
     * @param generatedXML
     *                XML response to the Propfind request
     * @param path
     *                Path of the current resource
     * @param type
     *                Propfind type
     * @param propertiesVector
     *                If the propfind type is find properties by name, then this
     *                Vector contains those properties
     */
    private void parseProperties(HttpServletRequest req,
      XMLWriter generatedXML, String path, int type,
      Vector propertiesVector, String mimeType) throws WebdavException {

  String creationdate = getISOCreationDate(store.getCreationDate(path)
    .getTime());
  boolean isFolder = store.isFolder(path);
  SimpleDateFormat formatter = new SimpleDateFormat(
    "EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
  formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
  String lastModified = formatter.format(store.getLastModified(path));
  String resourceLength = String.valueOf(store.getResourceLength(path));

  // ResourceInfo resourceInfo = new ResourceInfo(path, resources);

  generatedXML.writeElement(null, "response", XMLWriter.OPENING);
  String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
    + WebdavStatus.getStatusText(WebdavStatus.SC_OK));

  // Generating href element
  generatedXML.writeElement(null, "href", XMLWriter.OPENING);

  String href = req.getContextPath();
  String servletPath = req.getServletPath();
  if (servletPath != null) {
      if ((href.endsWith("/")) && (servletPath.startsWith("/")))
    href += servletPath.substring(1);
      else
    href += servletPath;
  }
  if ((href.endsWith("/")) && (path.startsWith("/")))
      href += path.substring(1);
  else
      href += path;
  if ((isFolder) && (!href.endsWith("/")))
      href += "/";

  generatedXML.writeText(rewriteUrl(href));

  generatedXML.writeElement(null, "href", XMLWriter.CLOSING);

  String resourceName = path;
  int lastSlash = path.lastIndexOf('/');
  if (lastSlash != -1)
      resourceName = resourceName.substring(lastSlash + 1);

  switch (type) {

  case FIND_ALL_PROP:

      generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
      generatedXML.writeElement(null, "prop", XMLWriter.OPENING);

      generatedXML.writeProperty(null, "creationdate", creationdate);
      generatedXML.writeElement(null, "displayname", XMLWriter.OPENING);
      generatedXML.writeData(resourceName);
      generatedXML.writeElement(null, "displayname", XMLWriter.CLOSING);
      if (!isFolder) {
    generatedXML.writeProperty(null, "getlastmodified",
      lastModified);
    generatedXML.writeProperty(null, "getcontentlength",
      resourceLength);
    String contentType = mimeType;
    if (contentType != null) {
        generatedXML.writeProperty(null, "getcontenttype",
          contentType);
    }
    generatedXML.writeProperty(null, "getetag", getETag(path,
      resourceLength, lastModified));
    generatedXML.writeElement(null, "resourcetype",
      XMLWriter.NO_CONTENT);
      } else {
    generatedXML.writeElement(null, "resourcetype",
      XMLWriter.OPENING);
    generatedXML.writeElement(null, "collection",
      XMLWriter.NO_CONTENT);
    generatedXML.writeElement(null, "resourcetype",
      XMLWriter.CLOSING);
      }

      generatedXML.writeProperty(null, "source", "");
      generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
      generatedXML.writeElement(null, "status", XMLWriter.OPENING);
      generatedXML.writeText(status);
      generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
      generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);

      break;

  case FIND_PROPERTY_NAMES:

      generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
      generatedXML.writeElement(null, "prop", XMLWriter.OPENING);

      generatedXML.writeElement(null, "creationdate",
        XMLWriter.NO_CONTENT);
      generatedXML
        .writeElement(null, "displayname", XMLWriter.NO_CONTENT);
      if (!isFolder) {
    generatedXML.writeElement(null, "getcontentlanguage",
      XMLWriter.NO_CONTENT);
    generatedXML.writeElement(null, "getcontentlength",
      XMLWriter.NO_CONTENT);
    generatedXML.writeElement(null, "getcontenttype",
      XMLWriter.NO_CONTENT);
    generatedXML
      .writeElement(null, "getetag", XMLWriter.NO_CONTENT);
    generatedXML.writeElement(null, "getlastmodified",
      XMLWriter.NO_CONTENT);
      }
      generatedXML.writeElement(null, "resourcetype",
        XMLWriter.NO_CONTENT);
      generatedXML.writeElement(null, "source", XMLWriter.NO_CONTENT);
      generatedXML.writeElement(null, "lockdiscovery",
        XMLWriter.NO_CONTENT);

      generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
      generatedXML.writeElement(null, "status", XMLWriter.OPENING);
      generatedXML.writeText(status);
      generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
      generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);

      break;

  case FIND_BY_PROPERTY:

      Vector propertiesNotFound = new Vector();

      // Parse the list of properties

      generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
      generatedXML.writeElement(null, "prop", XMLWriter.OPENING);

      Enumeration properties = propertiesVector.elements();

      while (properties.hasMoreElements()) {

    String property = (String) properties.nextElement();

    if (property.equals("creationdate")) {
        generatedXML.writeProperty(null, "creationdate",
          creationdate);
    } else if (property.equals("displayname")) {
        generatedXML.writeElement(null, "displayname",
          XMLWriter.OPENING);
        generatedXML.writeData(resourceName);
        generatedXML.writeElement(null, "displayname",
          XMLWriter.CLOSING);
    } else if (property.equals("getcontentlanguage")) {
        if (isFolder) {
      propertiesNotFound.addElement(property);
        } else {
      generatedXML.writeElement(null, "getcontentlanguage",
        XMLWriter.NO_CONTENT);
        }
    } else if (property.equals("getcontentlength")) {
        if (isFolder) {
      propertiesNotFound.addElement(property);
        } else {
      generatedXML.writeProperty(null, "getcontentlength",
        resourceLength);
        }
    } else if (property.equals("getcontenttype")) {
        if (isFolder) {
      propertiesNotFound.addElement(property);
        } else {
      generatedXML.writeProperty(null, "getcontenttype",
        mimeType);
        }
    } else if (property.equals("getetag")) {
        if (isFolder) {
      propertiesNotFound.addElement(property);
        } else {
      generatedXML.writeProperty(null, "getetag", getETag(
        path, resourceLength, lastModified));
        }
    } else if (property.equals("getlastmodified")) {
        if (isFolder) {
      propertiesNotFound.addElement(property);
        } else {
      generatedXML.writeProperty(null, "getlastmodified",
        lastModified);
        }
    } else if (property.equals("resourcetype")) {
        if (isFolder) {
      generatedXML.writeElement(null, "resourcetype",
        XMLWriter.OPENING);
      generatedXML.writeElement(null, "collection",
        XMLWriter.NO_CONTENT);
      generatedXML.writeElement(null, "resourcetype",
        XMLWriter.CLOSING);
        } else {
      generatedXML.writeElement(null, "resourcetype",
        XMLWriter.NO_CONTENT);
        }
    } else if (property.equals("source")) {
        generatedXML.writeProperty(null, "source", "");
    } else {
        propertiesNotFound.addElement(property);
    }

      }

      generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
      generatedXML.writeElement(null, "status", XMLWriter.OPENING);
      generatedXML.writeText(status);
      generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
      generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);

      Enumeration propertiesNotFoundList = propertiesNotFound.elements();

      if (propertiesNotFoundList.hasMoreElements()) {

    status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND
      + " "
      + WebdavStatus.getStatusText(WebdavStatus.SC_NOT_FOUND));

    generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
    generatedXML.writeElement(null, "prop", XMLWriter.OPENING);

    while (propertiesNotFoundList.hasMoreElements()) {
        generatedXML.writeElement(null,
          (String) propertiesNotFoundList.nextElement(),
          XMLWriter.NO_CONTENT);
    }

    generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
    generatedXML.writeElement(null, "status", XMLWriter.OPENING);
    generatedXML.writeText(status);
    generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
    generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);

      }

      break;

  }

  generatedXML.writeElement(null, "response", XMLWriter.CLOSING);

    }

    /**
     * Get creation date in ISO format.
     *
     * @param creationDate
     *                the date in milliseconds
     * @return the Date in ISO format
     */
    private String getISOCreationDate(long creationDate) {
  StringBuffer creationDateValue = new StringBuffer(creationDateFormat
    .format(new Date(creationDate)));
  /*
   * int offset = Calendar.getInstance().getTimeZone().getRawOffset() /
   * 3600000; // FIXME ? if (offset < 0) { creationDateValue.append("-");
   * offset = -offset; } else if (offset > 0) {
   * creationDateValue.append("+"); } if (offset != 0) { if (offset < 10)
   * creationDateValue.append("0"); creationDateValue.append(offset +
   * ":00"); } else { creationDateValue.append("Z"); }
   */
  return creationDateValue.toString();
    }

    /**
     * Get the ETag associated with a file.
     *
     * @param path
     *                path to the resource
     * @param resourceLength
     *                filesize
     * @param lastModified
     *                last-modified date
     * @return the ETag
     */
    protected String getETag(String path, String resourceLength,
      String lastModified) {
  // TODO create a real (?) ETag
  // parameter "path" is not used at the monent
  return "W/\"" + resourceLength + "-" + lastModified + "\"";

    }

    /**
     * URL rewriter.
     *
     * @param path
     *                Path which has to be rewiten
     * @return the rewritten path
     */
    protected String rewriteUrl(String path) {
  return urlEncoder.encode(path);
    }

}
TOP

Related Classes of net.sf.webdav.methods.DoPropfind

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.