Package org.apache.slide.webdav.method

Source Code of org.apache.slide.webdav.method.LockMethod

/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LockMethod.java,v 1.69.2.4 2004/09/20 08:46:02 ozeigermann Exp $
* $Revision: 1.69.2.4 $
* $Date: 2004/09/20 08:46:02 $
*
* ====================================================================
*
* Copyright 1999-2002 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 org.apache.slide.webdav.method;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import javax.transaction.Transaction;

import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.NamespaceConfig;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.RevisionAlreadyExistException;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.event.VetoException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.lock.ObjectIsAlreadyLockedException;
import org.apache.slide.lock.ObjectLockedException;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.SubjectNode;
import org.apache.slide.transaction.ExternalTransactionContext;
import org.apache.slide.util.XMLValue;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.util.PropertyHelper;
import org.apache.slide.webdav.util.WebdavConstants;
import org.apache.slide.webdav.util.WebdavStatus;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.XMLOutputter;

/**
* LOCK method.
*
*/
public class LockMethod extends AbstractMultistatusResponseMethod implements
    WebdavConstants, WriteMethod {

  // -------------------------------------------------------------- Constants

  /**
   * Create a new lock.
   */
  private static final int LOCK_CREATION = 0;

  /**
   * Refresh lock.
   */
  private static final int LOCK_REFRESH = 1;

  /**
   * Maximum and default timeout.
   */
  private static final int MAX_TIMEOUT = Integer.MAX_VALUE;

  private static final int DEFAULT_TIMEOUT = MAX_TIMEOUT;

  /**
   * The default owner if not explicitely specified by the request.
   */
  public static final String DEFAULT_LOCK_OWNER = "";

  // ----------------------------------------------------- Instance Variables

  /**
   * Depth.
   */
  private int depth;

  /**
   * Type of the LOCK method ({@link #LOCK_CREATION}or {@link #LOCK_REFRESH}).
   */
  private int lockType;

  /**
   * Lock duration.
   */
  private int lockDuration = DEFAULT_TIMEOUT;

  /**
   * Lock scope.
   */
  private String lockInfo_lockScope;

  /*
   * Lock type.
   */
  private String lockInfo_lockType;

  /**
   * Lock owner.
   */
  private String lockInfo_lockOwner;

  /**
   * Lock subject.
   */
  private String lockInfo_lockSubject;

  /**
   * The PropertyHelper used by this instance.
   */
  protected PropertyHelper propertyHelper = null;

  // ----------------------------------------------------------- Constructors

  /**
   * Constructor.
   *
   * @param token
   *            the token for accessing the namespace
   * @param config
   *            configuration of the WebDAV servlet
   */
  public LockMethod(NamespaceAccessToken token, WebdavServletConfig config) {
    super(token, config);
  }

  // ------------------------------------------------------ Protected Methods

  /**
   * Parse request.
   *
   * @exception WebdavException
   *                Does not happen
   */
  protected void parseRequest() throws WebdavException {

    propertyHelper = PropertyHelper.getPropertyHelper(slideToken, token,
        getConfig());
    //        readRequestContent();

    // Loads the associated object from the store.
    lockInfo_lockSubject = requestUri;
    if (lockInfo_lockSubject == null) {
      lockInfo_lockSubject = "/";
    }

    depth = requestHeaders.getDepth(INFINITY);
    if (depth != 0 && depth != INFINITY) {
      int sc = WebdavStatus.SC_PRECONDITION_FAILED;
      sendError(sc, "Invalid header Depth: " + depth);
      throw new WebdavException(sc);
    }

    lockDuration = requestHeaders.getTimeout(MAX_TIMEOUT);

    if (req.getContentLength() > 0 || isRequestChunked()) {
      parseLockInfo();
    } else {
      lockType = LOCK_REFRESH;
    }

  }

  /**
   * Parses the <code>&lt;lockinfo&gt;</code> request content document.
   *
   * @throws WebdavException
   *             if parsing the request failed or if the request is not valid.
   */
  private void parseLockInfo() throws WebdavException {

    lockType = LOCK_CREATION;

    try {
      Iterator childrenIterator = parseRequestContent(E_LOCKINFO)
          .getChildren().iterator();
      while (childrenIterator.hasNext()) {
        Element currentElement = (Element) childrenIterator.next();
        if (E_LOCKSCOPE.equals(currentElement.getName())) {
          parseLockScope(currentElement);
        } else if (E_LOCKTYPE.equals(currentElement.getName())) {
          parseLockType(currentElement);
        } else if (E_OWNER.equals(currentElement.getName())) {
          parseOwner(currentElement);
        }
      }
    } catch (JDOMException e) {
      int statusCode = WebdavStatus.SC_BAD_REQUEST;
      sendError(statusCode, e);
      throw new WebdavException(statusCode);
    } catch (IOException e) {
      int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
      sendError(statusCode, e);
      throw new WebdavException(statusCode);
    }
  }

  /**
   * Parses the <code>&lt;lockscope&gt;</code> part of the request content
   * document.
   *
   * @param lockScopeElement
   *            the <code>&lt;lockscope&gt;</code> to parse.
   *
   * @throws JDOMException
   *             if parsing the request failed or if the request is not valid.
   */
  private void parseLockScope(Element lockScopeElement) throws JDOMException {
    if (lockScopeElement == null) {
      throw new JDOMException("Expected <" + E_LOCKSCOPE + "> element");
    }

    List children = lockScopeElement.getChildren();
    if (children.size() != 1) {
      throw new JDOMException("<" + E_LOCKSCOPE
          + "> must have exactly one child element");
    }

    lockInfo_lockScope = ((Element) children.get(0)).getName();
    if (!(E_EXCLUSIVE.equals(lockInfo_lockScope)
        || E_SHARED.equals(lockInfo_lockScope) || E_LOCAL
        .equals(lockInfo_lockScope))) {
      throw new JDOMException("<" + E_LOCKSCOPE
          + "> can only contain one of <" + E_EXCLUSIVE + "> or <"
          + E_SHARED + "> or <" + E_LOCAL + ">");
    }
  }

  /**
   * Parses the <code>&lt;locktype&gt;</code> part of the request content
   * document.
   *
   * @param lockTypeElement
   *            the <code>&lt;locktype&gt;</code> to parse.
   *
   * @throws JDOMException
   *             if parsing the request failed or if the request is not valid.
   */
  private void parseLockType(Element lockTypeElement) throws JDOMException {

    if (lockTypeElement == null) {
      throw new JDOMException("Expected <" + E_LOCKTYPE + "> element");
    }

    List children = lockTypeElement.getChildren();
    if (children.size() != 1) {
      throw new JDOMException("<" + E_LOCKTYPE
          + "> must have exactly one child element");
    }
    String lockTypeName = ((Element) children.get(0)).getName();
    if (!E_WRITE.equals(lockTypeName)
        && !E_TRANSACTION.equals(lockTypeName)) {
      throw new JDOMException(
          "Only write and transaction locks are supported");
    }
    lockInfo_lockType = ((Element) children.get(0)).getName();
  }

  /**
   * Parses the <code>&lt;owner&gt;</code> part of the request content
   * document.
   *
   * @param ownerElement
   *            the <code>&lt;owner&gt;</code> to parse.
   *
   * @throws JDOMException
   *             if parsing the request failed or if the request is not valid.
   */
  private void parseOwner(Element ownerElement) throws JDOMException {

    if (ownerElement == null) {
      lockInfo_lockOwner = DEFAULT_LOCK_OWNER;
      return;
      //          throw new JDOMException("Expected <"+E_OWNER+"> element");
    }

    StringWriter stringWriter = new StringWriter();
    XMLOutputter xmlOutputter = new XMLOutputter();
    try {
      xmlOutputter.outputElementContent(ownerElement, stringWriter);
    } catch (IOException e) {
      // this should not happen since we do no "real" I/O but
      // only print to a PrintWriter
      e.printStackTrace();
    }
    lockInfo_lockOwner = stringWriter.toString();

    if (lockInfo_lockOwner.length() == 0) {
      lockInfo_lockOwner = DEFAULT_LOCK_OWNER;
      //throw new JDOMException("<"+E_OWNER+"> element must not be
      // empty");
    }
  }

  /**
   * Execute request.
   *
   * @exception WebdavException
   *                Unrecoverable error while renewing lock
   */
  protected void executeRequest() throws WebdavException {

    // Prevent dirty reads
    slideToken.setForceStoreEnlistment(true);

    SubjectNode toLockSubject = null;
    boolean isCollection = isCollection(lockInfo_lockSubject);
    boolean inheritance = false;
    Date lockDate = null;

       
    switch (lockType) {

    case LOCK_CREATION:
      if (lockInfo_lockType.equals(E_TRANSACTION)) {
        try {
          NamespaceConfig namespaceConfig = token
          .getNamespaceConfig();
                    toLockSubject = getToLockSubject();
                    if (lockDate == null)
                        lockDate = new Date((new Date()).getTime()
                                + ((long) lockDuration * 1000L));
          NodeLock lockToken = new NodeLock(toLockSubject.getUri(),((SubjectNode)security.getPrincipal(slideToken)).getUri(),
              namespaceConfig.getCreateObjectAction().getUri(), lockDate,
              inheritance, NodeLock.LOCAL, lockInfo_lockOwner);
                    token.setTransactionTimeout(lockDuration * 1000);
          Transaction transaction = token.getTransactionManager().suspend();
                    //String txId = lockToken.getLockId();
                    String fullTxId = "<" + S_LOCK_TOKEN + lockToken.getLockId() + ">";
                    ExternalTransactionContext.registerContext(fullTxId, transaction);
                    slideToken.setExternalTx();
                    resp.setHeader("Lock-Token", fullTxId);
                    showLockDiscoveryInfo(lockToken);
        } catch (Exception e) {
          int statusCode = getErrorCode(e);
          sendError(statusCode, e);
          throw new WebdavException(statusCode);
        }
      } else if (lockInfo_lockType.equals(E_WRITE)) {
        try {
                   
                if (!checkIfHeaders()) {
                    return;
                }
                     
          NamespaceConfig namespaceConfig = token
              .getNamespaceConfig();
                    toLockSubject = getToLockSubject();
          NodeLock lockToken = null;

          inheritance = (depth != 0);
          boolean exclusive = !(lockInfo_lockScope.equals(E_SHARED));

          if (lockDate == null)
            lockDate = new Date((new Date()).getTime()
                + ((long) lockDuration * 1000L));

          lockToken = new NodeLock(toLockSubject,
              (SubjectNode) security.getPrincipal(slideToken),
              namespaceConfig.getCreateObjectAction(), lockDate,
              inheritance, exclusive, lockInfo_lockOwner);
          lock.lock(slideToken, lockToken);

          // Set the lock-token header
          // [RFC 2518, 9.5] " The Lock-Token response header is used
          // with the LOCK method to indicate the lock token created
          // as
          // a result of a successful LOCK request to create a new
          // lock."
          resp.setHeader("Lock-Token", "<" + S_LOCK_TOKEN
              + lockToken.getLockId() + ">");

          resp.setStatus(WebdavStatus.SC_OK);

          // The lock token on which the DAV module will have the info

          showLockDiscoveryInfo(lockToken);
        } catch (ObjectIsAlreadyLockedException e) {
          if (inheritance
              && generateMultiStatusResponse(isCollection, e,
                  requestUri)) {
            // error is on the resource which we attempted to lock
            String errorMessage = generateErrorMessage(e);
            // Write it on the servlet writer
            resp.setContentType(TEXT_XML_UTF_8);
            resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
            try {
              resp.getWriter().write(errorMessage);
            } catch (IOException ex) {
              // Critical error ... Servlet container is dead or
              // something
              int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
              sendError(statusCode, e);
              throw new WebdavException(statusCode);
            }
          } else {
            // Returning 207 on non-collection requests is generally
            // considered bad. So let's not do it, since this way
            // makes clients generally behave better.
            resp.setStatus(WebdavStatus.SC_LOCKED);
          }
          //
          // make sure the transaction is aborted
          // throw any WebDAV exception to indicate the transaction
          // wants to be aborted
          //
          throw new WebdavException(WebdavStatus.SC_ACCEPTED, false);
        } catch (Exception e) {
          int statusCode = getErrorCode(e);
          sendError(statusCode, e);
          throw new WebdavException(statusCode);
        }
      }
      break;

    case LOCK_REFRESH:

      try {

        Enumeration lockTokens = lock.enumerateLocks(slideToken,
            lockInfo_lockSubject, false);

        NodeLock currentLockToken = null;
        Date newExpirationDate = new Date((new Date()).getTime()
            + ((long) lockDuration * 1000L));
        while (lockTokens.hasMoreElements()) {
          currentLockToken = (NodeLock) lockTokens.nextElement();
          lock.renew(slideToken, currentLockToken, newExpirationDate);
        }

        showLockDiscoveryInfo(currentLockToken);

      } catch (SlideException e) {
        int statusCode = WebdavStatus.SC_PRECONDITION_FAILED;
        sendError(statusCode, e);
        throw new WebdavException(statusCode);
      }

      break;

    }

  }

    protected SubjectNode getToLockSubject() throws ObjectAlreadyExistsException, ObjectNotFoundException,
            AccessDeniedException, RevisionAlreadyExistException, LinkedObjectNotFoundException, ObjectLockedException,
            ServiceAccessException, VetoException {
       
        SubjectNode toLockSubject;
        try {
            toLockSubject = (SubjectNode) structure.retrieve(slideToken, lockInfo_lockSubject);
        } catch (ObjectNotFoundException ex) {

            // Creating a lock null resource
            toLockSubject = new SubjectNode();

            // Creating new subject
            structure.create(slideToken, toLockSubject, lockInfo_lockSubject);

            NodeRevisionDescriptor revisionDescriptor = new NodeRevisionDescriptor(0);

            // Resource type
            XMLValue lockNull = new XMLValue(new Element(E_LOCKNULL, DNSP));
            revisionDescriptor.setResourceType(lockNull.toString());

            NodeRevisionContent nrc = new NodeRevisionContent();
            nrc.setContent(new byte[0]);

            // Creating the revision descriptor
            content.create(slideToken, lockInfo_lockSubject, revisionDescriptor, nrc);
        }
        return toLockSubject;
    }
   
  /**
     * Get return status based on exception type.
     */
  protected int getErrorCode(Exception ex) {
    try {
      throw ex;
    } catch (ObjectNotFoundException e) {
      return WebdavStatus.SC_PRECONDITION_FAILED;
    } catch (Exception e) {
      return super.getErrorCode(e);
    }
  }

  /**
   * Show lockdiscovery info.
   *
   * @exception WebdavException
   *                Something is wrong with the servlet container
   */
  protected void showLockDiscoveryInfo(NodeLock token) throws WebdavException {

    // Generating XML response
    org.jdom.Element prop = new org.jdom.Element(E_PROP, DNSP);
    org.jdom.Element lockdiscovery = new org.jdom.Element(E_LOCKDISCOVERY,
        DNSP);
    prop.addContent(lockdiscovery);
    XMLValue xmlValue = propertyHelper.computeLockDiscovery(token,
        getSlideContextPath());
    Iterator iterator = xmlValue.iterator();
    while (iterator.hasNext()) {
      lockdiscovery.addContent((org.jdom.Element) iterator.next());
    }

    try {
      //System.out.println("Query result");
      //System.out.println(generatedXML.toString());
      resp.setContentType(TEXT_XML_UTF_8);
      Writer writer = resp.getWriter();
      org.jdom.output.Format format = org.jdom.output.Format
          .getPrettyFormat();
      format.setIndent(XML_RESPONSE_INDENT);
      new org.jdom.output.XMLOutputter(format).output(
          new org.jdom.Document(prop), writer);
      writer.flush();
    } catch (Exception e) {
      int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
      sendError(statusCode, e);
      throw new WebdavException(statusCode);
    }

  }
   
   private boolean checkIfHeaders() throws AccessDeniedException, LinkedObjectNotFoundException, ServiceAccessException, ObjectLockedException, VetoException, IOException
   {
       try {
           NodeRevisionDescriptors revisionDescriptors =
                      content.retrieve(slideToken, this.requestUri);
           // Retrieve latest revision descriptor
           NodeRevisionDescriptor revisionDescriptor =
                      content.retrieve(slideToken, revisionDescriptors);
           if (revisionDescriptor != null) {
               ResourceInfo resourceInfo =
                     new ResourceInfo(this.requestUri, revisionDescriptor);
               return checkIfHeaders(req, resp, resourceInfo);
           } else {
               return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri));
           }
       }
       catch (RevisionDescriptorNotFoundException e) {
           return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri));
       }
       catch (ObjectNotFoundException e) {
           return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri));
       }
   }
}
TOP

Related Classes of org.apache.slide.webdav.method.LockMethod

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.