jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tri...@apache.org
Subject svn commit: r156314 [2/15] - in incubator/jackrabbit/trunk/contrib/jcr-server: ./ client/ client/src/ client/src/java/ client/src/java/org/ client/src/java/org/apache/ client/src/java/org/apache/jackrabbit/ client/src/java/org/apache/jackrabbit/client/ server/ server/src/ server/src/java/ server/src/java/org/ server/src/java/org/apache/ server/src/java/org/apache/jackrabbit/ server/src/java/org/apache/jackrabbit/server/ server/src/java/org/apache/jackrabbit/server/simple/ server/src/java/org/apache/jackrabbit/server/simple/dav/ server/src/java/org/apache/jackrabbit/server/simple/dav/lock/ server/src/java/org/apache/jackrabbit/webdav/ server/src/java/org/apache/jackrabbit/webdav/spi/ server/src/java/org/apache/jackrabbit/webdav/spi/lock/ server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/ server/src/java/org/apache/jackrabbit/webdav/spi/observation/ server/src/java/org/apache/jackrabbit/webdav/spi/search/ server/src/java/org/apache/jackrabbit/webdav/spi/transaction/ server/src/java/org/apache/jackrabbit/webdav/spi/version/ server/src/java/org/apache/jackrabbit/webdav/spi/version/report/ webapp/ webapp/src/ webapp/src/webapp/ webapp/src/webapp/WEB-INF/ webapp/src/webapp/WEB-INF/repository/ webdav/ webdav/src/ webdav/src/java/ webdav/src/java/org/ webdav/src/java/org/apache/ webdav/src/java/org/apache/jackrabbit/ webdav/src/java/org/apache/jackrabbit/webdav/ webdav/src/java/org/apache/jackrabbit/webdav/lock/ webdav/src/java/org/apache/jackrabbit/webdav/observation/ webdav/src/java/org/apache/jackrabbit/webdav/ordering/ webdav/src/java/org/apache/jackrabbit/webdav/property/ webdav/src/java/org/apache/jackrabbit/webdav/search/ webdav/src/java/org/apache/jackrabbit/webdav/transaction/ webdav/src/java/org/apache/jackrabbit/webdav/util/ webdav/src/java/org/apache/jackrabbit/webdav/version/ webdav/src/java/org/apache/jackrabbit/webdav/version/report/
Date Sun, 06 Mar 2005 14:03:09 GMT
Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,823 @@
+/*
+ * Copyright 2005 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.jackrabbit.server;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.observation.ObservationResource;
+import org.apache.jackrabbit.webdav.observation.SubscriptionInfo;
+import org.apache.jackrabbit.webdav.observation.Subscription;
+import org.apache.jackrabbit.webdav.observation.EventDiscovery;
+import org.apache.jackrabbit.webdav.ordering.OrderingResource;
+import org.apache.jackrabbit.webdav.ordering.OrderPatch;
+import org.apache.jackrabbit.webdav.transaction.TransactionInfo;
+import org.apache.jackrabbit.webdav.transaction.TransactionResource;
+import org.apache.jackrabbit.webdav.lock.LockInfo;
+import org.apache.jackrabbit.webdav.lock.ActiveLock;
+import org.apache.jackrabbit.webdav.version.*;
+import org.apache.jackrabbit.webdav.version.report.ReportInfo;
+import org.apache.jackrabbit.webdav.version.report.Report;
+import org.apache.jackrabbit.webdav.property.*;
+import org.apache.jackrabbit.webdav.search.SearchResource;
+import org.apache.jackrabbit.webdav.search.SearchConstants;
+import org.apache.jackrabbit.webdav.search.SearchRequest;
+
+import org.jdom.Document;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * <code>AbstractWebdavServlet</code>
+ *
+ * todo respect Position header 
+ */
+abstract public class AbstractWebdavServlet extends HttpServlet implements DavConstants {
+
+    /** default logger */
+    private static Logger log = Logger.getLogger(AbstractWebdavServlet.class);
+
+    /**
+     * Create a new <code>DavResource</code>
+     *
+     * @param locator
+     * @param request
+     * @param response
+     * @return resource for the given locator
+     * @throws DavException
+     */
+    abstract protected DavResource createResource(DavResourceLocator locator,
+                                                  WebdavRequest request,
+                                                  WebdavResponse response) throws DavException;
+
+    /**
+     * The OPTION method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     */
+    protected void doOptions(WebdavRequest request, WebdavResponse response,
+                             DavResource resource) throws IOException {
+        response.addHeader(DavConstants.HEADER_DAV, resource.getComplianceClass());
+        response.addHeader("Allow", resource.getSupportedMethods());
+        response.addHeader("MS-Author-Via", DavConstants.HEADER_DAV);
+        if (resource instanceof SearchResource) {
+            String[] langs = ((SearchResource)resource).getQueryGrammerSet().getQueryLanguages();
+            for (int i = 0; i < langs.length; i++) {
+                response.addHeader(SearchConstants.HEADER_DASL, "<" + langs[i] + ">");
+            }
+        }
+        // with DeltaV the OPTIONS request may contain a Xml body.
+        OptionsResponse oR = null;
+        OptionsInfo oInfo = request.getOptionsInfo();
+        if (oInfo != null && resource instanceof DeltaVResource) {
+            oR = ((DeltaVResource)resource).getOptionResponse(oInfo);
+        }
+        if (oR == null) {
+            response.setStatus(DavServletResponse.SC_OK);
+        } else {
+            response.sendXmlResponse(oR.toXml(), DavServletResponse.SC_OK);
+        }
+    }
+
+    /**
+     * The HEAD method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws java.io.IOException
+     */
+    protected void doHead(WebdavRequest request, WebdavResponse response,
+                          DavResource resource) throws IOException {
+        spoolResource(request, response, resource, false);
+    }
+
+    /**
+     * The GET method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     */
+    protected void doGet(WebdavRequest request, WebdavResponse response,
+                         DavResource resource) throws IOException {
+        spoolResource(request, response, resource, true);
+    }
+
+    /**
+     * @param request
+     * @param response
+     * @param resource
+     * @param sendContent
+     * @throws IOException
+     */
+    private void spoolResource(WebdavRequest request, WebdavResponse response,
+                               DavResource resource, boolean sendContent)
+            throws IOException {
+
+        if (!resource.exists()) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+
+        long modTime = resource.getModificationTime();
+        if (modTime != DavResource.UNDEFINED_MODIFICATIONTIME && modTime <= request.getDateHeader("If-Modified-Since")) {
+            // resource has not been modified since the time indicated in the
+            // 'If-Modified-Since' header.
+            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+            return;
+        }
+
+        DavProperty lastMod = resource.getProperty(DavPropertyName.GETLASTMODIFIED);
+        if (lastMod != null) {
+            response.setHeader("Last-Modified", String.valueOf(lastMod.getValue()));
+        }
+
+        DavProperty etag = resource.getProperty(DavPropertyName.GETETAG);
+        if (etag != null) {
+            response.setHeader("ETag", String.valueOf(etag.getValue()));
+        }
+
+        DavProperty contentType = resource.getProperty(DavPropertyName.GETCONTENTTYPE);
+        if (contentType != null) {
+            response.setHeader("Content-Type", String.valueOf(contentType.getValue()));
+        }
+
+        DavProperty contentLength = resource.getProperty(DavPropertyName.GETCONTENTLENGTH);
+        if (contentLength != null) {
+            try {
+                int length = Integer.parseInt(contentLength.getValue()+"");
+                if (length > 0) {
+                    response.setIntHeader("Content-Length", length);
+                }
+            } catch (NumberFormatException e) {
+                log.error("Could not build content length from property value '" + contentLength.getValue() + "'");
+            }
+        }
+
+        // spool content in case of 'GET' request
+        if (sendContent) {
+            InputStream in = resource.getStream();
+            if (in != null) {
+                OutputStream out = response.getOutputStream();
+                byte[] buffer = new byte[8192];
+                int read;
+                while ((read = in.read(buffer)) >= 0 ) {
+                    out.write(buffer, 0, read);
+                }
+                in.close();
+            }
+        }
+        response.flushBuffer();
+    }
+
+    /**
+     * The PROPFIND method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     */
+    protected void doPropFind(WebdavRequest request, WebdavResponse response,
+                              DavResource resource) throws IOException {
+
+        if (!resource.exists()) {
+            response.sendError(DavServletResponse.SC_NOT_FOUND);
+            return;
+        }
+
+        int depth = request.getDepth(DEPTH_INFINITY);
+        DavPropertyNameSet requestProperties = request.getPropFindProperties();
+        int propfindType = request.getPropFindType();
+
+        MultiStatus mstatus = new MultiStatus();
+        mstatus.addResourceProperties(resource, requestProperties, propfindType, depth);
+        response.sendMultiStatusResponse(mstatus);
+    }
+
+    /**
+     * The PROPPATCH method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     */
+    protected void doPropPatch(WebdavRequest request, WebdavResponse response,
+                               DavResource resource)
+            throws IOException, DavException {
+
+        DavPropertySet setProperties = request.getPropPatchSetProperties();
+        DavPropertyNameSet removeProperties = request.getPropPatchRemoveProperties();
+        if (setProperties.isEmpty() && removeProperties.isEmpty()) {
+            response.sendError(DavServletResponse.SC_BAD_REQUEST);
+            return;
+        }
+
+        // first resolve merge conflicts
+        // TODO: not correct resolution of merge conflicts are immediately perstisted
+        // TODO: rfc 2518 requires, that no changes must only be persisted if the complete proppatch-req succeeds
+        if (resource instanceof VersionControlledResource) {
+            ((VersionControlledResource)resource).resolveMergeConflict(setProperties, removeProperties);
+        }
+
+        // complete any other property setting or removing
+        DavPropertyIterator setIter = setProperties.iterator();
+        while (setIter.hasNext()) {
+            DavProperty prop = setIter.nextProperty();
+            resource.setProperty(prop);
+        }
+        Iterator remNameIter = removeProperties.iterator();
+        while (remNameIter.hasNext()) {
+            DavPropertyName propName = (DavPropertyName) remNameIter.next();
+            resource.removeProperty(propName);
+        }
+        response.setStatus(DavServletResponse.SC_OK);
+
+        // todo return multistatus response in case of failure
+    }
+
+    /**
+     * The PUT method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doPut(WebdavRequest request, WebdavResponse response,
+                         DavResource resource) throws IOException, DavException {
+
+        DavResource parentResource = resource.getCollection();
+        if (parentResource == null || !parentResource.exists()) {
+            // parent does not exist
+            response.sendError(DavServletResponse.SC_CONFLICT);
+            return;
+        }
+
+        int status;
+        // test if resource already exists
+        if (resource.exists()){
+            status = DavServletResponse.SC_NO_CONTENT;
+        } else {
+            status = DavServletResponse.SC_CREATED;
+        }
+
+        parentResource.addMember(resource, request.getInputStream());
+        response.setStatus(status);
+    }
+
+    /**
+     * The MKCOL method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doMkCol(WebdavRequest request, WebdavResponse response,
+                           DavResource resource) throws IOException, DavException {
+
+        DavResource parentResource = resource.getCollection();
+        if (parentResource == null || !parentResource.exists() || !parentResource.isCollection()) {
+            // parent does not exist or is not a collection
+            response.sendError(DavServletResponse.SC_CONFLICT);
+            return;
+        }
+
+        if (request.getContentLength() > 0 || request.getHeader("Transfer-Encoding") != null) {
+            parentResource.addMember(resource, request.getInputStream());
+        } else {
+            parentResource.addMember(resource);
+        }
+        response.setStatus(DavServletResponse.SC_CREATED);
+    }
+
+    /**
+     * The DELETE method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doDelete(WebdavRequest request, WebdavResponse response,
+                            DavResource resource) throws IOException, DavException {
+        DavResource parent = resource.getCollection();
+        if (parent != null) {
+            parent.removeMember(resource);
+            response.setStatus(DavServletResponse.SC_NO_CONTENT);
+        } else {
+            response.sendError(DavServletResponse.SC_FORBIDDEN, "Cannot remove the root resource.");
+        }
+    }
+
+    /**
+     * The COPY method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doCopy(WebdavRequest request, WebdavResponse response,
+                          DavResource resource) throws IOException, DavException {
+
+        // only depth 0 and infinity is allowed
+        int depth = request.getDepth(DEPTH_INFINITY);
+        if (!(depth == DEPTH_0 || depth == DEPTH_INFINITY)) {
+            response.sendError(DavServletResponse.SC_BAD_REQUEST);
+            return;
+        }
+
+        DavResource destResource = createResource(request.getDestinationLocator(), request, response);
+        int status = validateDestination(destResource, request);
+        if (status > DavServletResponse.SC_NO_CONTENT) {
+            response.sendError(status);
+            return;
+        }
+
+        resource.copy(destResource, depth == DEPTH_0);
+        response.setStatus(status);
+    }
+
+    /**
+     * The MOVE method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doMove(WebdavRequest request, WebdavResponse response,
+                          DavResource resource) throws IOException, DavException {
+
+        DavResource destResource = createResource(request.getDestinationLocator(), request, response);
+        int status = validateDestination(destResource, request);
+        if (status > DavServletResponse.SC_NO_CONTENT) {
+            response.sendError(status);
+            return;
+        }
+
+        resource.move(destResource);
+        response.setStatus(status);
+    }
+    
+    /**
+     * Validate the given destination resource and return the proper status
+     * code: Any return value greater/equal than {@link DavServletResponse#SC_NO_CONTENT}
+     * indicates an error.
+     *
+     * @param destResource destination resource to be validated.
+     * @param request
+     * @return status code indicating whether the destination is valid.
+     */
+    private int validateDestination(DavResource destResource, WebdavRequest request) {
+
+        String destHeader = request.getHeader(HEADER_DESTINATION);
+        if (destHeader == null || "".equals(destHeader)){
+            return DavServletResponse.SC_BAD_REQUEST;
+        }
+        if (destResource.getLocator().equals(request.getRequestLocator())) {
+            return DavServletResponse.SC_FORBIDDEN;
+        }
+
+        int status;
+        if (destResource.exists()) {
+            if (request.isOverwrite()) {
+                // matching if-header required for existing resources
+                if (!request.matchesIfHeader(destResource)) {
+                    return DavServletResponse.SC_PRECONDITION_FAILED;
+                } else {
+                    // overwrite existing resource: its up to the webdavresource
+                    // object to deal with any delete prior to the copy/move
+                    status = DavServletResponse.SC_NO_CONTENT;
+                }
+            } else {
+                // cannot copy/move to an existing item, if overwrite is not forced
+                return DavServletResponse.SC_PRECONDITION_FAILED;
+            }
+        } else {
+            // destination does not exist >> copy/move can be performed
+            status = DavServletResponse.SC_CREATED;
+        }
+        return status;
+    }
+
+    /**
+     * The LOCK method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doLock(WebdavRequest request, WebdavResponse response,
+                          DavResource resource) throws IOException, DavException {
+
+        LockInfo lockInfo = request.getLockInfo();
+        if (lockInfo.isRefreshLock()) {
+            // refresh any matching existing locks
+            ActiveLock[] activeLocks = resource.getLocks();
+            List lList = new ArrayList();
+            for (int i = 0; i < activeLocks.length; i++) {
+                if (request.matchesIfHeader(resource.getHref(), activeLocks[i].getToken(), "")) {
+                    lList.add(resource.refreshLock(lockInfo, activeLocks[i].getToken()));
+                }
+            }
+            if (lList.isEmpty()) {
+                throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
+            }
+            ActiveLock[] refreshedLocks = (ActiveLock[]) lList.toArray(new ActiveLock[lList.size()]);
+            response.sendRefreshLockResponse(refreshedLocks);
+        } else {
+            // create a new lock
+            ActiveLock lock = resource.lock(lockInfo);
+            response.sendLockResponse(lock);
+        }
+
+        // TODO multistatus in case of failure...
+        // NOTE: spec says 409 status, but example says 207 (multistatus)
+    }
+
+    /**
+     * The UNLOCK method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     */
+    protected void doUnlock(WebdavRequest request, WebdavResponse response,
+                            DavResource resource) throws DavException {
+        // get lock token from header
+        String lockToken = request.getLockToken();
+        TransactionInfo tInfo = request.getTransactionInfo();
+        if (tInfo != null) {
+            ((TransactionResource)resource).unlock(lockToken, tInfo);
+        } else {
+            resource.unlock(lockToken);
+        }
+        response.setStatus(DavServletResponse.SC_NO_CONTENT);
+    }
+
+    /**
+     * The ORDERPATCH method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws java.io.IOException
+     * @throws DavException
+     */
+    protected void doOrderPatch(WebdavRequest request,
+                                WebdavResponse response,
+                                DavResource resource)
+            throws IOException, DavException {
+
+        if (!(resource instanceof OrderingResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+
+        OrderPatch op = request.getOrderPatch();
+        if (op == null) {
+            response.sendError(DavServletResponse.SC_BAD_REQUEST);
+            return;
+        }
+        // perform reordering of internal members
+        ((OrderingResource)resource).orderMembers(op);
+        response.setStatus(DavServletResponse.SC_OK);
+
+        //TODO: in case of failure Multistatus is required...
+    }
+
+    /**
+     * The SUBSCRIBE method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doSubscribe(WebdavRequest request,
+                               WebdavResponse response,
+                               DavResource resource)
+            throws IOException, DavException {
+
+        if (!(resource instanceof ObservationResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+
+        SubscriptionInfo info = request.getSubscriptionInfo();
+        if (info == null) {
+            response.sendError(DavServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+            return;
+        }
+        Subscription subs = ((ObservationResource)resource).subscribe(info, request.getSubscriptionId());
+        response.sendSubscriptionResponse(subs);
+    }
+
+    /**
+     * The UNSUBSCRIBE method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doUnsubscribe(WebdavRequest request,
+                                 WebdavResponse response,
+                                 DavResource resource)
+            throws IOException, DavException {
+
+        if (!(resource instanceof ObservationResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        ((ObservationResource)resource).unsubscribe(request.getSubscriptionId());
+        response.setStatus(DavServletResponse.SC_NO_CONTENT);
+    }
+
+    /**
+     * The POLL method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws IOException
+     * @throws DavException
+     */
+    protected void doPoll(WebdavRequest request,
+                          WebdavResponse response,
+                          DavResource resource)
+            throws IOException, DavException {
+
+        if (!(resource instanceof ObservationResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        EventDiscovery ed = ((ObservationResource)resource).poll(request.getSubscriptionId());
+        response.sendPollResponse(ed);
+    }
+
+    /**
+     * The VERSION-CONTROL method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doVersionControl(WebdavRequest request, WebdavResponse response,
+                                    DavResource resource)
+            throws DavException, IOException {
+        if (!(resource instanceof VersionableResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        ((VersionableResource)resource).addVersionControl();
+    }
+
+    /**
+     * The LABEL method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doLabel(WebdavRequest request, WebdavResponse response,
+                           DavResource resource)
+            throws DavException, IOException {
+
+        LabelInfo labelInfo = request.getLabelInfo();
+        if (resource instanceof VersionResource) {
+           ((VersionResource)resource).label(labelInfo);
+        } else if (resource instanceof VersionControlledResource) {
+           ((VersionControlledResource)resource).label(labelInfo);
+        } else {
+            // any other resource type that does not support a LABEL request
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+        }
+    }
+
+    /**
+     * The REPORT method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doReport(WebdavRequest request, WebdavResponse response,
+                            DavResource resource)
+            throws DavException, IOException {
+        if (!(resource instanceof DeltaVResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        ReportInfo info = request.getReportInfo();
+        Report report = ((DeltaVResource)resource).getReport(info);
+        response.sendXmlResponse(report.toXml(), DavServletResponse.SC_OK);
+    }
+
+    /**
+     * The CHECKIN method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doCheckin(WebdavRequest request, WebdavResponse response,
+                             DavResource resource)
+            throws DavException, IOException {
+
+        if (!(resource instanceof VersionControlledResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        String versionHref = ((VersionControlledResource)resource).checkin();
+        response.setHeader(DeltaVConstants.HEADER_LOCATION, versionHref);
+    }
+
+    /**
+     * The CHECKOUT method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doCheckout(WebdavRequest request, WebdavResponse response,
+                              DavResource resource)
+            throws DavException, IOException {
+        if (!(resource instanceof VersionControlledResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        ((VersionControlledResource)resource).checkout();
+    }
+
+    /**
+     * The UNCHECKOUT method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doUncheckout(WebdavRequest request, WebdavResponse response,
+                              DavResource resource)
+            throws DavException, IOException {
+        if (!(resource instanceof VersionControlledResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        ((VersionControlledResource)resource).uncheckout();
+    }
+
+    /**
+     * The MERGE method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doMerge(WebdavRequest request, WebdavResponse response,
+                           DavResource resource) throws DavException, IOException {
+
+         if (!(resource instanceof VersionControlledResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        MergeInfo info = request.getMergeInfo();
+        MultiStatus ms = ((VersionControlledResource)resource).merge(info);
+        response.sendMultiStatusResponse(ms);
+    }
+
+    /**
+     * The UPDATE method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doUpdate(WebdavRequest request, WebdavResponse response,
+                            DavResource resource) throws DavException, IOException {
+
+        if (!(resource instanceof VersionControlledResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        UpdateInfo info = request.getUpdateInfo();
+        MultiStatus ms = ((VersionControlledResource)resource).update(info);
+        response.sendMultiStatusResponse(ms);
+    }
+
+    /**
+     * The MKWORKSPACE method
+     *
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doMkWorkspace(WebdavRequest request, WebdavResponse response,
+                               DavResource resource) throws DavException, IOException {
+        if (resource.exists()) {
+            log.warn("Cannot create a new workspace. Resource already exists.");
+            response.sendError(DavServletResponse.SC_FORBIDDEN);
+            return;
+        }
+
+        DavResource parentResource = resource.getCollection();
+        if (parentResource == null || !parentResource.exists() || !parentResource.isCollection()) {
+            // parent does not exist or is not a collection
+            response.sendError(DavServletResponse.SC_CONFLICT);
+            return;
+        }
+        if (!(parentResource instanceof DeltaVResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        ((DeltaVResource)parentResource).addWorkspace(resource);
+        response.setStatus(DavServletResponse.SC_CREATED);
+    }
+
+    /**
+     * The SEARCH method
+     * 
+     * @param request
+     * @param response
+     * @param resource
+     * @throws DavException
+     * @throws IOException
+     */
+    protected void doSearch(WebdavRequest request, WebdavResponse response,
+                            DavResource resource) throws DavException, IOException {
+
+        if (!(resource instanceof SearchResource)) {
+            response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+        try {
+            Document doc = request.getRequestDocument();
+            if (doc != null) {
+                SearchRequest sR = new SearchRequest(doc);
+                response.sendMultiStatusResponse(((SearchResource)resource).search(sR));
+            } else {
+                // request without request body is valid if requested resource
+                // is a 'query' resource.
+                response.sendMultiStatusResponse(((SearchResource)resource).search(null));
+            }
+        } catch (IllegalArgumentException e) {
+            response.sendError(DavServletResponse.SC_BAD_REQUEST);
+            return;
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java
------------------------------------------------------------------------------
    svn = 

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2005 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.jackrabbit.server;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.spi.JcrDavException;
+import org.apache.jackrabbit.client.RepositoryAccessServlet;
+
+import javax.jcr.*;
+import javax.servlet.ServletException;
+import java.util.HashMap;
+import java.util.HashSet;
+/**
+ * <code>JCRWebdavServer</code>...
+ */
+public class JCRWebdavServer {
+
+    /** the default logger */
+    private static Logger log = Logger.getLogger(JCRWebdavServer.class);
+
+    /** the session cache */
+    private final SessionCache cache = new SessionCache();
+
+    /** the jcr repository */
+    private final Repository repository;
+
+    /**
+     * Creates a new JCRWebdavServer that operates on the given repository.
+     *
+     * @param repository
+     */
+    public JCRWebdavServer(Repository repository) {
+	this.repository = repository;
+    }
+
+    /**
+     * Acquires a DavSession either from the session cache or creates a new
+     * one by login to the repository.
+     * Upon success, the WebdavRequest will reference that session.
+     *
+     * @param request
+     * @throws DavException if no session could be obtained.
+     */
+    public void acquireSession(WebdavRequest request)
+            throws DavException {
+        DavSession session = cache.get(request);
+	request.setDavSession(session);
+    }
+
+    /**
+     * Releases the reference from the request to the session. If no further
+     * references to the session exist, the session will be removed from the
+     * cache.
+     *
+     * @param request
+     */
+    public void releaseSession(WebdavRequest request) {
+	DavSession session = request.getDavSession();
+	if (session != null) {
+	    session.removeReference(request);
+	}
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Private inner class implementing the <code>DavSession</code> interface.
+     */
+    private class DavSessionImpl implements DavSession {
+
+	/** the underlaying jcr session */
+        private final Session session;
+
+        /**
+         * Private constructor.
+         *
+         * @param request
+         * @throws DavException in case a {@link javax.jcr.LoginException} or {@link javax.jcr.RepositoryException} occurs.
+         */
+        private DavSessionImpl(DavServletRequest request) throws DavException {
+            try {
+                String workspaceName = request.getRequestLocator().getWorkspaceName();
+		Credentials creds = RepositoryAccessServlet.getCredentialsFromHeader(request.getHeader(DavConstants.HEADER_AUTHORIZATION));
+                session = repository.login(creds, workspaceName);
+            } catch (RepositoryException e) {
+                // LoginException, RepositoryException both result in FORBIDDEN
+                throw new JcrDavException(e);
+            } catch (ServletException e) {
+		throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+	    }
+        }
+
+        /**
+         * Add a reference to this <code>DavSession</code>.
+         *
+         * @see DavSession#addReference(Object)
+         */
+        public void addReference(Object reference) {
+            cache.addReference(this, reference);
+        }
+
+        /**
+         * Removes the reference from this <code>DavSession</code>. If no
+         * more references are present, this <code>DavSession</code> is removed
+         * from the internal cache and the underlaying session is released by calling
+         * {@link javax.jcr.Session#logout()}.
+         *
+         * @see DavSession#removeReference(Object)
+         */
+        public void removeReference(Object reference) {
+            cache.removeReference(this, reference);
+        }
+
+        /**
+         * @see DavSession#getRepositorySession()
+         */
+        public Session getRepositorySession() {
+            return session;
+        }
+
+	/**
+	 * @see DavSession#addLockToken(String)
+	 */
+	public void addLockToken(String token) {
+	    session.addLockToken(token);
+	}
+
+	/**
+	 * @see DavSession#getLockTokens()
+	 */
+	public String[] getLockTokens() {
+	    return session.getLockTokens();
+	}
+
+	/**
+	 * @see DavSession#removeLockToken(String)
+	 */
+	public void removeLockToken(String token) {
+	    session.removeLockToken(token);
+	}
+    }
+
+    /**
+     * Private inner class providing a cache for referenced session objects.
+     */
+    private class SessionCache {
+
+        private SessionMap sessionMap = new SessionMap();
+        private HashMap referenceToSessionMap = new HashMap();
+
+        /**
+         * Try to retrieve <code>DavSession</code> if a TransactionId or
+         * SubscriptionId is present in the request header. If no cached session
+         * was found <code>null</code> is returned.
+         *
+         * @param request
+         * @return a cached <code>DavSession</code> or <code>null</code>.
+         * @throws DavException
+         */
+        private DavSession get(WebdavRequest request)
+                throws DavException {
+            String txId = request.getTransactionId();
+            String subscriptionId = request.getSubscriptionId();
+            String lockToken = request.getLockToken();
+
+            if ((lockToken != null || txId != null) && subscriptionId != null) {
+                throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Ambiguous headers: either TransactionId/Lock-Token or SubscriptionId can be present, not both.");
+            }
+
+            DavSession session = null;
+            // try to retrieve a cached session
+            if (lockToken != null && containsReference(lockToken)) {
+                session = getSessionByReference(lockToken);
+            } else if (txId != null && containsReference(txId)) {
+                session = getSessionByReference(txId);
+            } else if (subscriptionId != null && containsReference(subscriptionId)) {
+                session = getSessionByReference(subscriptionId);
+            }
+            // no cached session present -> create new one.
+            if (session == null) {
+                session = new DavSessionImpl(request);
+                sessionMap.put(session, new HashSet());
+                log.info("login: User '" + session.getRepositorySession().getUserId() + "' logged in.");
+            } else {
+                log.info("login: Retrieved cached session for user '" + session.getRepositorySession().getUserId() + "'");
+            }
+            addReference(session, request);
+            return session;
+        }
+
+        /**
+         * Add a references to the specified <code>DavSession</code>.
+         *
+         * @param session
+         * @param reference
+         */
+        private void addReference(DavSession session, Object reference) {
+            HashSet referenceSet = sessionMap.get(session);
+            if (referenceSet != null) {
+                referenceSet.add(reference);
+                referenceToSessionMap.put(reference, session);
+            } else {
+                log.error("Failed to add reference to session. No entry in cache found.");
+            }
+        }
+
+        /**
+         * Remove the given reference from the specified <code>DavSession</code>.
+         *
+         * @param session
+         * @param reference
+         */
+        private void removeReference(DavSession session, Object reference) {
+            HashSet referenceSet = sessionMap.get(session);
+            if (referenceSet != null) {
+                if (referenceSet.remove(reference)) {
+                    log.info("Removed reference " + reference + " to session " + session);
+                    referenceToSessionMap.remove(reference);
+                } else {
+                    log.warn("Failed to remove reference " + reference + " to session " + session);
+                }
+                if (referenceSet.isEmpty()) {
+                    log.info("No more references present on webdav session -> clean up.");
+                    sessionMap.remove(session);
+                    log.info("Login: User '" + session.getRepositorySession().getUserId() + "' logged out");
+                    session.getRepositorySession().logout();
+                } else {
+                    log.debug(referenceSet.size() + " references remaining on webdav session " + session);
+                }
+            } else {
+                log.error("Failed to remove reference from session. No entry in cache found.");
+            }
+        }
+
+        /**
+         * Returns true, if there exists a <code>DavSession</code> in the cache
+         * that is referenced by the specified object.
+         *
+         * @param reference
+         * @return true if a <code>DavSession</code> is referenced by the given
+         * object.
+         */
+        private boolean containsReference(Object reference) {
+            return referenceToSessionMap.containsKey(reference);
+        }
+
+        /**
+         * Returns the <code>DavSession</code> that is referenced by the
+         * specified reference object.
+         *
+         * @param reference
+         * @return <code>DavSession</code> that is referenced by this reference
+         * object.
+         * @see #containsReference(Object)
+         */
+        private DavSession getSessionByReference(Object reference) {
+            return (DavSession) referenceToSessionMap.get(reference);
+        }
+    }
+
+    /**
+     * Simple inner class extending the {@link HashMap}.
+     */
+    private static class SessionMap extends HashMap {
+
+        public HashSet get(DavSession key) {
+            return (HashSet) super.get(key);
+        }
+
+        public HashSet put(DavSession key, HashSet value) {
+            return (HashSet) super.put(key, value);
+        }
+
+        public HashSet remove(DavSession key) {
+            return (HashSet) super.remove(key);
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java
------------------------------------------------------------------------------
    svn = 

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2005 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.jackrabbit.server;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.WebdavRequestImpl;
+import org.apache.jackrabbit.webdav.observation.*;
+import org.apache.jackrabbit.webdav.spi.*;
+import org.apache.jackrabbit.webdav.spi.observation.SubscriptionManagerImpl;
+import org.apache.jackrabbit.webdav.spi.transaction.TxLockManagerImpl;
+import org.apache.jackrabbit.client.RepositoryAccessServlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.*;
+import javax.jcr.Repository;
+import java.io.IOException;
+
+/**
+ * JCRWebdavServerServlet provides request/response handling for the JCRWebdavServer.
+ */
+public class JCRWebdavServerServlet extends AbstractWebdavServlet implements DavConstants {
+
+    /** the default logger */
+    private static Logger log = Logger.getLogger(JCRWebdavServerServlet.class);
+
+    /** Init parameter specifying the prefix used with the resource path. */
+    public static final String INIT_PARAM_PREFIX = "resource-path-prefix";
+    private static String pathPrefix;
+
+    private JCRWebdavServer server;
+    private DavResourceFactory resourceFactory;
+    private DavLocatorFactory locatorFactory;
+    private TxLockManagerImpl txMgr;
+    private SubscriptionManager subscriptionMgr;
+
+    /**
+     * Initializes the servlet set reads the following parameter from the
+     * servlet configuration:
+     * <ul>
+     * <li>resource-path-prefix: optional prefix for all resources.</li>
+     * </ul>
+     *
+     * @throws ServletException
+     */
+    public void init() throws ServletException {
+        super.init();
+
+	// set resource path prefix
+	pathPrefix = getInitParameter(INIT_PARAM_PREFIX);
+	log.debug(INIT_PARAM_PREFIX + " = " + pathPrefix);
+
+	Repository repository = RepositoryAccessServlet.getRepository();
+	if (repository == null) {
+	    throw new ServletException("Repository could not be retrieved. Check config of 'RepositoryServlet'.");
+	}
+	server = new JCRWebdavServer(repository);
+        txMgr = new TxLockManagerImpl();
+        subscriptionMgr = new SubscriptionManagerImpl();
+
+        // todo: ev. make configurable
+        resourceFactory = new DavResourceFactoryImpl(txMgr, subscriptionMgr);
+        locatorFactory = new DavLocatorFactoryImpl(pathPrefix);
+    }
+
+    /**
+     * Returns the path prefix
+     *
+     * @return pathPrefix
+     * @see #INIT_PARAM_PREFIX
+     */
+    public static String getPathPrefix() {
+	return pathPrefix;
+    }
+
+    /**
+     * Service the request.
+     *
+     * @param request
+     * @param response
+     * @throws javax.servlet.ServletException
+     * @throws java.io.IOException
+     * @see HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+     */
+    protected void service(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+
+        WebdavRequest webdavRequest = new WebdavRequestImpl(request, locatorFactory);
+        WebdavResponse webdavResponse = new WebdavResponseImpl(response);
+        try {
+            // login to the server
+            server.acquireSession(webdavRequest);
+
+            // create the resource and perform initial precondition tests
+            DavResource resource = createResource(webdavRequest.getRequestLocator(), webdavRequest, webdavResponse);
+            if (preconditionFailed(webdavRequest, resource)) {
+                webdavResponse.sendError(DavServletResponse.SC_PRECONDITION_FAILED);
+                return;
+            }
+
+            // execute the requested method
+            int methodCode = DavMethods.getMethodCode(webdavRequest.getMethod());
+            execute(webdavRequest, webdavResponse, methodCode, resource);
+        } catch (DavException e) {
+            webdavResponse.sendErrorResponse(e);
+        } finally {
+            // logout
+	    server.releaseSession(webdavRequest);
+        }
+    }
+
+    /**
+     *
+     * @param locator
+     * @param request
+     * @param response
+     * @return
+     */
+    protected DavResource createResource(DavResourceLocator locator, WebdavRequest request,
+                               WebdavResponse response) throws DavException {
+        return resourceFactory.createResource(locator, request, response);
+    }
+
+    /**
+     *
+     * @param request
+     * @param resource
+     * @return
+     */
+    private boolean preconditionFailed(WebdavRequest request, DavResource resource) {
+        // first check matching If header
+        if (!request.matchesIfHeader(resource)) {
+            return true;
+        }
+
+        // test if the requested path matches to the existing session
+        // this may occur if the session was retrieved from the cache.
+        String wsName = request.getDavSession().getRepositorySession().getWorkspace().getName();
+        boolean failed = !resource.getLocator().isSameWorkspace(wsName);
+        if (!failed) {
+            // make sure, the TransactionId header is valid
+            String txId = request.getTransactionId();
+            if (txId != null && !txMgr.hasLock(txId, resource)) {
+               failed = true;
+            }
+        }
+        return failed;
+    }
+
+    /**
+     * @param request
+     * @param response
+     * @param method
+     * @param resource
+     * @throws ServletException
+     * @throws IOException
+     * @throws DavException
+     */
+    private void execute(WebdavRequest request, WebdavResponse response,
+                 int method, DavResource resource)
+            throws ServletException, IOException, DavException {
+
+        switch (method) {
+            case DavMethods.DAV_GET:
+                doGet(request, response, resource);
+                break;
+            case DavMethods.DAV_HEAD:
+                doHead(request, response, resource);
+                break;
+            case DavMethods.DAV_PROPFIND:
+                doPropFind(request, response, resource);
+                break;
+            case DavMethods.DAV_PROPPATCH:
+                doPropPatch(request, response, resource);
+                break;
+            case DavMethods.DAV_POST:
+            case DavMethods.DAV_PUT:
+                doPut(request, response, resource);
+                break;
+            case DavMethods.DAV_DELETE:
+                doDelete(request, response, resource);
+                break;
+            case DavMethods.DAV_COPY:
+                doCopy(request, response, resource);
+                break;
+            case DavMethods.DAV_MOVE:
+                doMove(request, response, resource);
+                break;
+            case DavMethods.DAV_MKCOL:
+                doMkCol(request, response, resource);
+                break;
+            case DavMethods.DAV_OPTIONS:
+                doOptions(request, response, resource);
+                break;
+            case DavMethods.DAV_LOCK:
+                doLock(request, response, resource);
+                break;
+            case DavMethods.DAV_UNLOCK:
+                doUnlock(request, response, resource);
+                break;
+            case DavMethods.DAV_ORDERPATCH:
+                doOrderPatch(request, response, resource);
+                break;
+            case DavMethods.DAV_SUBSCRIBE:
+                doSubscribe(request, response, resource);
+                break;
+            case DavMethods.DAV_UNSUBSCRIBE:
+                doUnsubscribe(request, response, resource);
+                break;
+            case DavMethods.DAV_POLL:
+                doPoll(request, response, resource);
+                break;
+            case DavMethods.DAV_SEARCH:
+                doSearch(request, response, resource);
+                break;
+            case DavMethods.DAV_VERSION_CONTROL:
+                doVersionControl(request, response, resource);
+                break;
+            case DavMethods.DAV_LABEL:
+                doLabel(request, response, resource);
+                break;
+            case DavMethods.DAV_REPORT:
+                doReport(request, response, resource);
+                break;
+            case DavMethods.DAV_CHECKIN:
+                doCheckin(request, response, resource);
+                break;
+            case DavMethods.DAV_CHECKOUT:
+                doCheckout(request, response, resource);
+                break;
+            case DavMethods.DAV_UNCHECKOUT:
+                doUncheckout(request, response, resource);
+                break;
+            case DavMethods.DAV_MERGE:
+                doMerge(request, response, resource);
+                break;
+            case DavMethods.DAV_UPDATE:
+                doUpdate(request, response, resource);
+                break;
+            case DavMethods.DAV_MKWORKSPACE:
+                doMkWorkspace(request, response, resource);
+                break;
+            default:
+                // any other method
+                super.service(request, response);
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java
------------------------------------------------------------------------------
    svn = 

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2005 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.jackrabbit.server;
+
+import org.apache.log4j.PropertyConfigurator;
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.rmi.server.ServerAdapterFactory;
+import org.xml.sax.InputSource;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.ServletException;
+import javax.jcr.*;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.*;
+import java.util.Properties;
+import java.util.Enumeration;
+import java.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.Naming;
+import java.rmi.RemoteException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.Remote;
+import java.net.MalformedURLException;
+
+/**
+ * The RepositoryStartupServlet starts a jackrabbit repository and registers it
+ * to the JNDI environment and optional to the RMI registry.
+ */
+public class RepositoryStartupServlet extends HttpServlet {
+
+    /** the default logger */
+    private static Logger log;
+
+    /** initial param name for the repository config location */
+    public final static String INIT_PARAM_REPOSITORY_CONFIG = "repository-config";
+
+    /** initial param name for the repository home directory */
+    public final static String INIT_PARAM_REPOSITORY_HOME = "repository-home";
+
+    /** initial param name for the repository name */
+    public final static String INIT_PARAM_REPOSITORY_NAME = "repository-name";
+
+    /** initial param name for the rmi port */
+    public final static String INIT_PARAM_RMI_PORT = "rmi-port";
+
+    /** initial param name for the log4j config properties */
+    public final static String INIT_PARAM_LOG4J_CONFIG = "log4j-config";
+
+    /** the registered repository */
+    private static RepositoryImpl repository;
+
+    /** the name of the repository as configured */
+    private static String repositoryName;
+
+    /** the jndi context, created base on configuration */
+    private static InitialContext jndiContext;
+
+    /** the rmi uri, in the form of  '//:${rmi-port}/${repository-name}' */
+    private static String rmiURI;
+
+    /**
+     * Initializes the servlet
+     * @throws ServletException
+     */
+    public void init() throws ServletException {
+	super.init();
+	initLog4J();
+	log.info("RepositoryStartupServlet initializing...");
+	initRepository();
+	registerJNDI();
+	registerRMI();
+	log.info("RepositoryStartupServlet initialized.");
+    }
+
+    /**
+     * destroy the servlet
+     */
+    public void destroy() {
+	super.destroy();
+	if (log == null) {
+	    log("RepositoryStartupServlet shutting down...");
+	} else {
+	    log.info("RepositoryStartupServlet shutting down...");
+	}
+	unregisterRMI();
+	unregisterJNDI();
+	log("RepositoryStartupServlet shut down.");
+    }
+
+    /**
+     * Initializes Log4J
+     * @throws ServletException
+     */
+    private void initLog4J() throws ServletException {
+	// setup log4j
+	String log4jConfig = getServletConfig().getInitParameter(INIT_PARAM_LOG4J_CONFIG);
+	InputStream in =getServletContext().getResourceAsStream(log4jConfig);
+	if (in==null) {
+	    // try normal init
+	    PropertyConfigurator.configure(log4jConfig);
+	} else {
+	    try {
+		Properties log4jProperties = new Properties();
+		log4jProperties.load(in);
+		in.close();
+		PropertyConfigurator.configure(log4jProperties);
+	    } catch (IOException e) {
+		throw new ServletException("Unable to load log4jProperties: " + e.toString());
+	    }
+	}
+	log = Logger.getLogger(RepositoryStartupServlet.class);
+    }
+
+    /**
+     * Creates a new Repository based on configuration
+     * @throws ServletException
+     */
+    private void initRepository() throws ServletException {
+	// setup home directory
+	String repHome = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_HOME);
+	if (repHome==null) {
+	    log.error(INIT_PARAM_REPOSITORY_HOME + " missing.");
+	    throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " missing.");
+	}
+	File repositoryHome;
+	try {
+	    repositoryHome = new File(repHome).getCanonicalFile();
+	} catch (IOException e) {
+	    log.error(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
+	    throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
+	}
+	log.info("  repository-home = " + repositoryHome.getPath());
+
+	// get repository config
+	String repConfig = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_CONFIG);
+	if (repConfig==null) {
+	    log.error(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
+	    throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
+	}
+	log.info("  repository-config = " + repConfig);
+
+	InputStream in = getServletContext().getResourceAsStream(repConfig);
+	if (in==null) {
+	    try {
+		in = new FileInputStream(new File(repositoryHome, repConfig));
+	    } catch (FileNotFoundException e) {
+		log.error(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
+		throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
+	    }
+	}
+
+	// get repository name
+	repositoryName = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_NAME);
+	if (repositoryName==null) {
+	    repositoryName="default";
+	}
+	log.info("  repository-name = " + repositoryName);
+
+	try {
+	    InputSource is = new InputSource(in);
+	    RepositoryConfig config = RepositoryConfig.create(is, repositoryHome.getAbsolutePath());
+	    repository = RepositoryImpl.create(config);
+	} catch (RepositoryException e) {
+	    throw new ServletException("Error while creating repository", e);
+	}
+    }
+
+    /**
+     * Registers the repository in the JNDI context
+     * @throws ServletException
+     */
+    private void registerJNDI() throws ServletException {
+	// registering via jndi
+	Properties env = new Properties();
+	Enumeration names = getServletConfig().getInitParameterNames();
+	while (names.hasMoreElements()) {
+	    String name = (String) names.nextElement();
+	    if (name.startsWith("java.naming.")) {
+		env.put(name, getServletConfig().getInitParameter(name));
+		log.info("  adding property to JNDI environment: " + name + "=" + env.getProperty(name));
+	    }
+	}
+	try {
+	    jndiContext = new InitialContext(env);
+	    jndiContext.bind(repositoryName, repository);
+	} catch (NamingException e) {
+	    throw new ServletException(e);
+	}
+	log.info("Repository bound to JNDI with name: " + repositoryName);
+    }
+
+    /**
+     * Unregisters the repository from the JNDI context
+     */
+    private void unregisterJNDI() {
+	if (jndiContext != null) {
+	    try {
+		jndiContext.unbind(repositoryName);
+	    } catch (NamingException e) {
+		log("Error while unbinding repository from JNDI: " + e);
+	    }
+	}
+    }
+
+    /**
+     * Registers the repositroy to the RMI registry
+     * @throws ServletException
+     */
+    private void registerRMI() throws ServletException {
+	// check registering via RMI
+	String rmiPortStr = getServletConfig().getInitParameter(INIT_PARAM_RMI_PORT);
+	if (rmiPortStr != null) {
+	    int rmiPort = 0;
+	    try {
+		rmiPort = Integer.parseInt(rmiPortStr);
+	    } catch (NumberFormatException e) {
+		log.warn("Invalid port in rmi-port param: " + e);
+	    }
+	    if (rmiPort == 0) {
+		rmiPort = Registry.REGISTRY_PORT;
+	    }
+
+	    // try to create remote repository
+	    Remote remote = null;
+	    try {
+		Class clazz = Class.forName("org.apache.jackrabbit.server.RMIRemoteFactoryDelegater");
+		RemoteFactoryDelegater rmf = (RemoteFactoryDelegater) clazz.newInstance();
+		remote = rmf.createRemoteRepository(repository);
+	    } catch (RemoteException e) {
+		throw new ServletException("Unable to create remote repository: " + e.toString(), e);
+	    } catch (NoClassDefFoundError e) {
+		log.warn("Unable to create RMI repository. jcr-rmi.jar might be missing.: " + e.toString());
+		return;
+	    } catch (Exception e) {
+		log.warn("Unable to create RMI repository. jcr-rmi.jar might be missing.: " + e.toString());
+		return;
+	    }
+
+	    try {
+		System.setProperty("java.rmi.server.useCodebaseOnly", "true");
+		try {
+		    // start registry
+		    LocateRegistry.createRegistry(rmiPort);
+		} catch (RemoteException e) {
+		    // ignore
+		}
+		rmiURI = "//:" + rmiPort + "/" + repositoryName;
+		Naming.bind(rmiURI, remote);
+
+		log.info("Repository bound via RMI with name: " + rmiURI);
+	    } catch (MalformedURLException e) {
+		throw new ServletException("Unable to bind repository via RMI: " + e.toString(), e);
+	    } catch (RemoteException e) {
+		throw new ServletException("Unable to bind repository via RMI: " + e.toString(), e);
+	    } catch (AlreadyBoundException e) {
+		throw new ServletException("Unable to bind repository via RMI: " + e.toString(), e);
+	    }
+	}
+    }
+
+    /**
+     * Unregisters the repository from the RMI registry
+     */
+    private void unregisterRMI() {
+	if (rmiURI != null) {
+	    try {
+		Naming.unbind(rmiURI);
+	    } catch (Exception e) {
+		log("Error while unbinding repository from JNDI: " + e);
+	    }
+	}
+    }
+
+}
+
+/**
+ * optional class for RMI, will only be used, if RMI server is present
+ */
+abstract class RemoteFactoryDelegater {
+
+    public abstract Remote createRemoteRepository(Repository repository)
+	    throws RemoteException;
+}
+/**
+ * optional class for RMI, will only be used, if RMI server is present
+ */
+class RMIRemoteFactoryDelegater extends RemoteFactoryDelegater {
+
+    // only used to enforce linking upon Class.forName()
+    static String FactoryClassName = ServerAdapterFactory.class.getName();
+
+    public Remote createRemoteRepository(Repository repository)
+	    throws RemoteException {
+	return new ServerAdapterFactory().getRemoteRepository(repository);
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java
------------------------------------------------------------------------------
    svn = 

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2005 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.jackrabbit.server.simple;
+
+import org.apache.jackrabbit.server.simple.dav.lock.SimpleLockManager;
+import org.apache.jackrabbit.server.simple.dav.ResourceFactoryImpl;
+import org.apache.jackrabbit.server.simple.dav.LocatorFactoryImpl;
+
+import javax.servlet.http.*;
+import javax.servlet.*;
+import javax.jcr.*;
+import java.io.*;
+import java.util.HashSet;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.server.AbstractWebdavServlet;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.spi.JcrDavException;
+import org.apache.jackrabbit.client.RepositoryAccessServlet;
+
+/**
+ * WebdavServlet provides webdav support (level 1 and 2 complient) for repository
+ * resources.
+ */
+public class WebdavServlet extends AbstractWebdavServlet {
+
+    /** the default logger */
+    private static final Logger log = Logger.getLogger(WebdavServlet.class);
+
+    /** init param name of the repository prefix */
+    public static final String INIT_PARAM_RESOURCE_PATH_PREFIX = "resource-path-prefix";
+
+    /**
+     * Map used to remember any webdav lock created without being reflected
+     * in the underlaying repository.
+     * This is needed because some clients rely on a successful locking
+     * mechanism in order to perform properly (e.g. mac OSX built-in dav client)
+     */
+    private SimpleLockManager lockManager;
+
+    /** the resource factory */
+    private DavResourceFactory resourceFactory;
+
+    /** the locator factory */
+    private DavLocatorFactory locatorFactory;
+
+    /** the repository prefix retrieved from config */
+    private static String resourcePathPrefix;
+
+    /**
+     * Init this servlet
+     *
+     * @throws ServletException
+     */
+    public void init() throws ServletException {
+        super.init();
+
+	resourcePathPrefix = getInitParameter(INIT_PARAM_RESOURCE_PATH_PREFIX);
+	log.info(INIT_PARAM_RESOURCE_PATH_PREFIX + " = " + resourcePathPrefix);
+
+	lockManager = new SimpleLockManager();
+        resourceFactory = new ResourceFactoryImpl(lockManager);
+        locatorFactory = new LocatorFactoryImpl(resourcePathPrefix);
+    }
+
+    /**
+     * Returns the configured path prefix
+     *
+     * @return resourcePathPrefix
+     * @see #INIT_PARAM_RESOURCE_PATH_PREFIX
+     */
+    public static String getPathPrefix() {
+	return resourcePathPrefix;
+    }
+
+    /**
+     * Service the given request.
+     *
+     * @param request
+     * @param response
+     * @throws ServletException
+     * @throws IOException
+     */
+    protected void service(HttpServletRequest request, HttpServletResponse response)
+	throws ServletException, IOException {
+
+	try {
+            WebdavRequest webdavRequest = new WebdavRequestImpl(request, locatorFactory);
+            WebdavResponse webdavResponse = new WebdavResponseImpl(response);
+
+            // make sure there is a authenticated user
+	    DavSession session = getSession(webdavRequest);
+	    if (session == null) {
+		return;
+	    }
+
+	    // check matching if=header for lock-token relevant operations
+	    DavResource resource = createResource(webdavRequest.getRequestLocator(), webdavRequest, webdavResponse);
+	    if (resource.exists() && !webdavRequest.matchesIfHeader(resource)) {
+		webdavResponse.sendError(DavServletResponse.SC_PRECONDITION_FAILED);
+		return;
+	    }
+
+	    /* set cache control headers in order to deal with non-dav complient
+	     * http1.1 or http1.0 proxies. >> see RFC2518 9.4.5 */
+	    webdavResponse.addHeader("Pragma", "No-cache");  // http1.0
+	    webdavResponse.addHeader("Cache-Control", "no-cache"); // http1.1
+
+	    int methodCode = DavMethods.getMethodCode(webdavRequest.getMethod());
+	    switch (methodCode) {
+		case DavMethods.DAV_HEAD:
+		case DavMethods.DAV_GET:
+		    doGet(webdavRequest, webdavResponse, resource);
+                case DavMethods.DAV_OPTIONS:
+                    doOptions(webdavRequest, webdavResponse, resource);
+                    break;
+		case DavMethods.DAV_PROPFIND:
+		    doPropFind(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_PROPPATCH:
+		    doPropPatch(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_PUT:
+		case DavMethods.DAV_POST:
+		    doPut(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_DELETE:
+		    doDelete(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_COPY:
+		    doCopy(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_MOVE:
+		    doMove(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_MKCOL:
+		    doMkCol(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_LOCK:
+		    doLock(webdavRequest, webdavResponse, resource);
+		    break;
+		case DavMethods.DAV_UNLOCK:
+		    doUnlock(webdavRequest, webdavResponse, resource);
+		    break;
+		default:
+		    // GET, HEAD, TRACE......
+		    super.service(request, response);
+	    }
+	} catch (DavException e) {
+	    response.sendError(e.getErrorCode());
+	}
+    }
+
+    /**
+     * The MKCOL method
+     *
+     * @throws IOException
+     */
+    protected void doMkCol(WebdavRequest request, WebdavResponse response,
+                           DavResource resource) throws IOException, DavException {
+        // mkcol request with request.body is not supported.
+        if (request.getContentLength()>0 || request.getHeader("Transfer-Encoding") != null) {
+            response.sendError(DavServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+            return;
+        }
+        super.doMkCol(request, response, resource);
+    }
+
+    /**
+     * Build a <code>DavResource</code> from the given path.<br>
+     * Please note, that the resource may not have a corresponding element in
+     * the repository in which case, {@link DavResource#exists()} will return
+     * false.
+     *
+     * @see AbstractWebdavServlet#createResource(org.apache.jackrabbit.webdav.DavResourceLocator, org.apache.jackrabbit.webdav.WebdavRequest, org.apache.jackrabbit.webdav.WebdavResponse)
+     */
+    protected DavResource createResource(DavResourceLocator locator, WebdavRequest request, WebdavResponse response)
+            throws DavException {
+        return resourceFactory.createResource(locator, request, response);
+    }
+
+    /**
+     * Retrieve the repository session for the given request object and force a header
+     * authentication if necessary.
+     *
+     * @param request
+     * @return a repository session for the given request or <code>null</code> if the
+     * authentication is missing. In the latter case the authentication is
+     * forces by the response code.
+     * @throws DavException
+     */
+    private DavSession getSession(WebdavRequest request) throws DavException {
+        try {
+	    Credentials creds = RepositoryAccessServlet.getCredentialsFromHeader(request.getHeader(DavConstants.HEADER_AUTHORIZATION));
+	    if (creds == null) {
+		// generate anonymous login to gain write access
+		creds = new SimpleCredentials("anonymous", "anonymous".toCharArray());
+	    }
+            Session repSession = RepositoryAccessServlet.getRepository().login(creds);
+	    DavSession ds = new DavSessionImpl(repSession);
+	    request.setDavSession(ds);
+	    return ds;
+        } catch (RepositoryException e) {
+	    throw new JcrDavException(e);
+	} catch (ServletException e) {
+	    throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+	}
+    }
+
+    /**
+     * Inner class implementing the DavSession interface
+     */
+    private class DavSessionImpl implements DavSession {
+
+	/** the underlaying jcr session */
+        private final Session session;
+
+	/** the lock tokens of this session */
+	private final HashSet lockTokens = new HashSet();
+
+	/**
+	 * Creates a new DavSession based on a jcr session
+	 * @param session
+	 */
+        private DavSessionImpl(Session session) {
+            this.session = session;
+        }
+
+	/**
+	 * @see DavSession#addReference(Object)
+	 */
+        public void addReference(Object reference) {
+            throw new UnsupportedOperationException("No yet implemented.");
+        }
+
+	/**
+	 * @see DavSession#removeReference(Object)
+	 */
+        public void removeReference(Object reference) {
+            throw new UnsupportedOperationException("No yet implemented.");
+        }
+
+	/**
+	 * @see DavSession#getRepositorySession()
+	 */
+        public Session getRepositorySession() {
+            return session;
+        }
+
+	/**
+	 * @see DavSession#addLockToken(String)
+	 */
+	public void addLockToken(String token) {
+	    lockTokens.add(token);
+	}
+
+	/**
+	 * @see DavSession#getLockTokens()
+	 */
+	public String[] getLockTokens() {
+	    return (String[]) lockTokens.toArray(new String[lockTokens.size()]);
+	}
+
+	/**
+	 * @see DavSession#removeLockToken(String)
+	 */
+	public void removeLockToken(String token) {
+	    lockTokens.remove(token);
+	}
+    }
+}

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java
------------------------------------------------------------------------------
    svn = 

Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message