You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2005/06/06 19:36:13 UTC

svn commit: r180346 [5/9] - in /incubator/jackrabbit/trunk/contrib/jcr-server: ./ client/ client/src/java/org/apache/jackrabbit/client/ client/src/java/org/apache/jackrabbit/webdav/client/methods/ commons/ commons/src/ commons/src/java/ commons/src/java/org/ commons/src/java/org/apache/ commons/src/java/org/apache/jackrabbit/ commons/src/java/org/apache/jackrabbit/nodetype/ commons/src/java/org/apache/jackrabbit/nodetype/xml/ commons/src/java/org/apache/jackrabbit/util/ commons/src/java/org/apache/jackrabbit/util/uuid/ commons/src/java/org/apache/jackrabbit/value/ server/ server/src/java/org/apache/jackrabbit/server/ server/src/java/org/apache/jackrabbit/server/io/ server/src/java/org/apache/jackrabbit/server/jcr/ server/src/java/org/apache/jackrabbit/server/simple/ server/src/java/org/apache/jackrabbit/webdav/jcr/ server/src/java/org/apache/jackrabbit/webdav/jcr/lock/ server/src/java/org/apache/jackrabbit/webdav/jcr/nodetype/ server/src/java/org/apache/jackrabbit/webdav/jcr/observation/ server/src/java/org/apache/jackrabbit/webdav/jcr/property/ server/src/java/org/apache/jackrabbit/webdav/jcr/search/ server/src/java/org/apache/jackrabbit/webdav/jcr/transaction/ server/src/java/org/apache/jackrabbit/webdav/jcr/version/ server/src/java/org/apache/jackrabbit/webdav/jcr/version/report/ server/src/java/org/apache/jackrabbit/webdav/simple/ webapp/ webapp/src/java/ webapp/src/java/org/ webapp/src/java/org/apache/ webapp/src/java/org/apache/jackrabbit/ webapp/src/java/org/apache/jackrabbit/j2ee/ webapp/src/webapp/ webapp/src/webapp/WEB-INF/ webdav/ webdav/src/java/org/apache/jackrabbit/webdav/ webdav/src/java/org/apache/jackrabbit/webdav/jcr/ webdav/src/java/org/apache/jackrabbit/webdav/lock/ webdav/src/java/org/apache/jackrabbit/webdav/property/ webdav/src/java/org/apache/jackrabbit/webdav/util/ webdav/src/java/org/apache/jackrabbit/webdav/version/report/

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java?rev=180346&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java Mon Jun  6 10:36:09 2005
@@ -0,0 +1,671 @@
+/*
+ * 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.webdav.jcr;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.search.SearchResource;
+import org.apache.jackrabbit.webdav.search.QueryGrammerSet;
+import org.apache.jackrabbit.webdav.search.SearchInfo;
+import org.apache.jackrabbit.webdav.transaction.TransactionResource;
+import org.apache.jackrabbit.webdav.transaction.TransactionInfo;
+import org.apache.jackrabbit.webdav.transaction.TransactionConstants;
+import org.apache.jackrabbit.webdav.transaction.TxLockManager;
+import org.apache.jackrabbit.webdav.jcr.transaction.TxLockManagerImpl;
+import org.apache.jackrabbit.webdav.jcr.search.SearchResourceImpl;
+import org.apache.jackrabbit.webdav.observation.*;
+import org.apache.jackrabbit.webdav.version.*;
+import org.apache.jackrabbit.webdav.version.report.Report;
+import org.apache.jackrabbit.webdav.version.report.ReportInfo;
+import org.apache.jackrabbit.webdav.version.report.ReportType;
+import org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty;
+import org.apache.jackrabbit.webdav.lock.*;
+import org.apache.jackrabbit.webdav.property.*;
+import org.apache.jackrabbit.webdav.property.ResourceType;
+import org.apache.jackrabbit.util.Text;
+
+import javax.jcr.Session;
+import javax.jcr.RepositoryException;
+import java.io.InputStream;
+import java.util.*;
+
+/**
+ * <code>AbstractResource</code> provides functionality common to all
+ * resources.
+ */
+abstract class AbstractResource implements DavResource, ObservationResource,
+        TransactionResource, DeltaVResource, SearchResource {
+
+    private static Logger log = Logger.getLogger(AbstractResource.class);
+
+    private final DavResourceLocator locator;
+    private final DavSession session;
+    private final DavResourceFactory factory;
+
+    private SubscriptionManager subsMgr;
+    private TxLockManagerImpl txMgr;
+    private String transactionId;
+
+    private long modificationTime = DavResource.UNDEFINED_MODIFICATIONTIME;
+
+    protected boolean initedProps;
+    protected DavPropertySet properties = new DavPropertySet();
+    protected SupportedLock supportedLock = new SupportedLock();
+    protected SupportedReportSetProperty supportedReports = new SupportedReportSetProperty();
+
+    /**
+     * Create a new <code>AbstractResource</code>
+     *
+     * @param locator
+     * @param session
+     */
+    AbstractResource(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
+        if (session == null) {
+            throw new IllegalArgumentException("Creating AbstractItemResource: DavSession must not be null.");
+        }
+
+        this.locator = locator;
+        this.session = session;
+        this.factory = factory;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getLocator()
+     */
+    public DavResourceLocator getLocator() {
+        return locator;
+    }
+
+    /**
+     * Returns the path of the underlaying repository item or the item to
+     * be created (PUT/MKCOL). If the resource exists but does not represent
+     * a repository item <code>null</code> is returned.
+     *
+     * @return path of the underlaying repository item.
+     * @see DavResource#getResourcePath()
+     * @see org.apache.jackrabbit.webdav.DavResourceLocator#getResourcePath()
+     */
+    public String getResourcePath() {
+        return locator.getResourcePath();
+    }
+
+    /**
+     * @see DavResource#getHref()
+     * @see DavResourceLocator#getHref(boolean)
+     */
+    public String getHref() {
+        return locator.getHref(isCollection());
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getModificationTime()
+     */
+    public long getModificationTime() {
+        return modificationTime;
+    }
+
+    /**
+     * Set the modificationTime field and adds the {@link DavPropertyName.GETLASTMODIFIED}
+     * property to the set of properties.
+     * @param modificationTime
+     */
+    void setModificationTime(long modificationTime) {
+        this.modificationTime = modificationTime;
+        if (this.modificationTime >= 0) {
+            properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED,
+                    DavConstants.modificationDateFormat.format(new Date(modificationTime))));
+        }
+    }
+
+    /**
+     * Returns <code>null</code>
+     *
+     * @return Always returns <code>null</code>
+     * @see org.apache.jackrabbit.webdav.DavResource#getStream()
+     */
+    public InputStream getStream() {
+        return null;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getPropertyNames()
+     */
+    public DavPropertyName[] getPropertyNames() {
+        return getProperties().getPropertyNames();
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
+     */
+    public DavProperty getProperty(DavPropertyName name) {
+        return getProperties().get(name);
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getProperties()
+     */
+    public DavPropertySet getProperties() {
+        if (!initedProps) {
+            initProperties();
+        }
+        return properties;
+    }
+
+    /**
+     * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     *
+     * @param property
+     * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     * @see org.apache.jackrabbit.webdav.DavResource#setProperty(org.apache.jackrabbit.webdav.property.DavProperty)
+     */
+    public void setProperty(DavProperty property) throws DavException {
+        throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+    }
+
+    /**
+     * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     *
+     * @param propertyName
+     * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     * @see org.apache.jackrabbit.webdav.DavResource#removeProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
+     */
+    public void removeProperty(DavPropertyName propertyName) throws DavException {
+        throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+    }
+
+    /**
+     * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     *
+     * @param destination
+     * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     * @see DavResource#move(org.apache.jackrabbit.webdav.DavResource)
+     */
+    public void move(DavResource destination) throws DavException {
+        throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+    }
+
+    /**
+     * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     *
+     * @param destination
+     * @param shallow
+     * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     * @see DavResource#copy(org.apache.jackrabbit.webdav.DavResource, boolean)
+     */
+    public void copy(DavResource destination, boolean shallow) throws DavException {
+        throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+    }
+
+
+    /**
+     * Returns true, if the {@link SupportedLock} property contains an entry
+     * with the given type and scope. By default resources allow for {@link org.apache.jackrabbit.webdav.transaction.TransactionConstants.XML_TRANSACTION
+     * transaction} lock only.
+     *
+     * @param type
+     * @param scope
+     * @return true if this resource may be locked by the given type and scope.
+     * @see DavResource#isLockable(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
+     */
+    public boolean isLockable(Type type, Scope scope) {
+        return supportedLock.isSupportedLock(type, scope);
+    }
+
+    /**
+     * Returns true if this resource has a lock applied with the given type and scope.
+     *
+     * @param type
+     * @param scope
+     * @return true if this resource has a lock applied with the given type and scope.
+     * @see DavResource#hasLock(Type, Scope)
+     */
+    public boolean hasLock(Type type, Scope scope) {
+        return getLock(type, scope) != null;
+    }
+
+    /**
+     * @see DavResource#getLock(Type, Scope)
+     */
+    public ActiveLock getLock(Type type, Scope scope) {
+        ActiveLock lock = null;
+        if (TransactionConstants.TRANSACTION.equals(type)) {
+            lock = txMgr.getLock(type, scope, this);
+        }
+        return lock;
+    }
+
+    /**
+     * @see DavResource#getLocks()
+     * todo improve....
+     */
+    public ActiveLock[] getLocks() {
+        List locks = new ArrayList();
+        // tx locks
+        ActiveLock l = getLock(TransactionConstants.TRANSACTION, TransactionConstants.LOCAL);
+        if (l != null) {
+            locks.add(l);
+        }
+        l = getLock(TransactionConstants.TRANSACTION, TransactionConstants.GLOBAL);
+        if (l != null) {
+            locks.add(l);
+        }
+        // write lock (either exclusive or session-scoped).
+        l = getLock(Type.WRITE, Scope.EXCLUSIVE);
+        if (l != null) {
+            locks.add(l);
+        } else {
+            l = getLock(Type.WRITE, ItemResourceConstants.EXCLUSIVE_SESSION);
+            if (l != null) {
+                locks.add(l);
+            }
+        }
+        return (ActiveLock[]) locks.toArray(new ActiveLock[locks.size()]);
+    }
+
+    /**
+     * @see DavResource#lock(org.apache.jackrabbit.webdav.lock.LockInfo)
+     */
+    public ActiveLock lock(LockInfo reqLockInfo) throws DavException {
+        if (isLockable(reqLockInfo.getType(), reqLockInfo.getScope())) {
+            return txMgr.createLock(reqLockInfo, this);
+        } else {
+            throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
+        }
+    }
+
+    /**
+     * Only transaction lock may be available on this resource.
+     *
+     * @param info
+     * @param lockToken
+     * @throws DavException
+     * @see DavResource#refreshLock(org.apache.jackrabbit.webdav.lock.LockInfo, String)
+     */
+    public ActiveLock refreshLock(LockInfo info, String lockToken) throws DavException {
+        return txMgr.refreshLock(info, lockToken, this);        
+    }
+
+    /**
+     * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED} since only transaction
+     * locks may be present on this resource, that need to be released by calling
+     * {@link TransactionResource#unlock(String, org.apache.jackrabbit.webdav.transaction.TransactionInfo)}.
+     *
+     * @param lockToken
+     * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     */
+    public void unlock(String lockToken) throws DavException {
+        throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
+    }
+
+    /**
+     * @see DavResource#addLockManager(org.apache.jackrabbit.webdav.lock.LockManager)
+     */
+    public void addLockManager(LockManager lockMgr) {
+        if (lockMgr instanceof TxLockManagerImpl) {
+            txMgr = (TxLockManagerImpl) lockMgr;
+        }
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getFactory()
+     */
+    public DavResourceFactory getFactory() {
+        return factory;
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * @see org.apache.jackrabbit.webdav.transaction.TransactionResource#getSession()
+     * @see org.apache.jackrabbit.webdav.observation.ObservationResource#getSession()
+     */
+    public DavSession getSession() {
+        return session;
+    }
+
+    //--------------------------------------< ObservationResource interface >---
+    /**
+     * @see ObservationResource#init(SubscriptionManager)
+     */
+    public void init(SubscriptionManager subsMgr) {
+        this.subsMgr = subsMgr;
+    }
+
+    /**
+     * @see ObservationResource#subscribe(org.apache.jackrabbit.webdav.observation.SubscriptionInfo, String)
+     * @see SubscriptionManager#subscribe(org.apache.jackrabbit.webdav.observation.SubscriptionInfo, String, org.apache.jackrabbit.webdav.observation.ObservationResource)
+     */
+    public Subscription subscribe(SubscriptionInfo info, String subscriptionId)
+            throws DavException {
+        return subsMgr.subscribe(info, subscriptionId, this);
+    }
+
+    /**
+     * @see ObservationResource#unsubscribe(String)
+     * @see SubscriptionManager#unsubscribe(String, org.apache.jackrabbit.webdav.observation.ObservationResource)
+     */
+    public void unsubscribe(String subscriptionId) throws DavException {
+        subsMgr.unsubscribe(subscriptionId, this);
+    }
+
+    /**
+     * @see ObservationResource#poll(String)
+     * @see SubscriptionManager#poll(String, org.apache.jackrabbit.webdav.observation.ObservationResource)
+     */
+    public EventDiscovery poll(String subscriptionId) throws DavException {
+        return subsMgr.poll(subscriptionId, this);
+    }
+
+    //--------------------------------------< TransactionResource interface >---
+    /**
+     * @see TransactionResource#init(TxLockManager, String)
+     */
+    public void init(TxLockManager txMgr, String transactionId) {
+        this.txMgr = (TxLockManagerImpl) txMgr;
+        this.transactionId = transactionId;
+    }
+
+    /**
+     * @see TransactionResource#unlock(String, org.apache.jackrabbit.webdav.transaction.TransactionInfo)
+     */
+    public void unlock(String lockToken, TransactionInfo tInfo) throws DavException {
+        txMgr.releaseLock(tInfo, lockToken, this);
+    }
+
+    /**
+     * @see TransactionResource#getTransactionId()
+     */
+    public String getTransactionId() {
+        return transactionId;
+    }
+
+    //-------------------------------------------< DeltaVResource interface >---
+    /**
+     * @param optionsInfo
+     * @return object to be used in the OPTIONS response body or <code>null</code>
+     * @see DeltaVResource#getOptionResponse(org.apache.jackrabbit.webdav.version.OptionsInfo)
+     */
+    public OptionsResponse getOptionResponse(OptionsInfo optionsInfo) {
+        OptionsResponse oR = null;
+        if (optionsInfo != null) {
+            oR = new OptionsResponse();
+            // currently on DAV:version-history-collection-set and
+            // DAV:workspace-collection-set is supported.
+            if (optionsInfo.containsElement(DeltaVConstants.XML_VH_COLLECTION_SET, DeltaVConstants.NAMESPACE)) {
+                String[] hrefs = new String[] { getLocatorFromResourcePath(ItemResourceConstants.VERSIONSTORAGE_PATH).getHref(true)};
+                oR.addEntry(DeltaVConstants.XML_VH_COLLECTION_SET, DeltaVConstants.NAMESPACE, hrefs);
+            } else if (optionsInfo.containsElement(DeltaVConstants.XML_WSP_COLLECTION_SET, DeltaVConstants.NAMESPACE)) {
+                // workspaces cannot be created anywhere.
+                oR.addEntry(DeltaVConstants.XML_WSP_COLLECTION_SET, DeltaVConstants.NAMESPACE, new String[0]);
+            }
+        }
+        return oR;
+    }
+
+    /**
+     * @param reportInfo
+     * @return the requested report
+     * @throws DavException
+     * @see DeltaVResource#getReport(org.apache.jackrabbit.webdav.version.report.ReportInfo)
+     */
+    public Report getReport(ReportInfo reportInfo) throws DavException {
+        if (reportInfo == null) {
+            throw new DavException(DavServletResponse.SC_BAD_REQUEST, "A REPORT request must provide a valid XML request body.");
+        }
+        if (!exists()) {
+            throw new DavException(DavServletResponse.SC_NOT_FOUND);
+        }
+
+        if (supportedReports.isSupportedReport(reportInfo)) {
+            try {
+                Report report = ReportType.getType(reportInfo).createReport();
+                report.setInfo(reportInfo);
+                report.setResource(this);
+                return report;
+            } catch (IllegalArgumentException e) {
+                // should never occur.
+                throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+            }
+        } else {
+            throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENTITY, "Unkown report "+ reportInfo.getReportElement().getNamespacePrefix() + reportInfo.getReportElement().getName() +"requested.");
+        }
+    }
+
+    /**
+     * The JCR api does not provide methods to create new workspaces. Calling
+     * <code>addWorkspace</code> on this resource will always fail.
+     *
+     * @param workspace
+     * @throws DavException Always throws.
+     * @see DeltaVResource#addWorkspace(org.apache.jackrabbit.webdav.DavResource)
+     */
+    public void addWorkspace(DavResource workspace) throws DavException {
+        throw new DavException(DavServletResponse.SC_FORBIDDEN);
+    }
+
+    /**
+     * Return an array of <code>DavResource</code> objects that are referenced
+     * by the property with the specified name.
+     *
+     * @param hrefPropertyName
+     * @return array of <code>DavResource</code>s
+     * @throws DavException
+     * @see DeltaVResource#getReferenceResources(org.apache.jackrabbit.webdav.property.DavPropertyName)
+     */
+    public DavResource[] getReferenceResources(DavPropertyName hrefPropertyName) throws DavException {
+        DavProperty prop = getProperty(hrefPropertyName);
+        if (prop == null || !(prop instanceof HrefProperty)) {
+            throw new DavException(DavServletResponse.SC_CONFLICT, "Unknown Href-Property '"+hrefPropertyName+"' on resource "+getResourcePath());
+        }
+
+        List hrefs = ((HrefProperty)prop).getHrefs();
+        DavResource[] refResources = new DavResource[hrefs.size()];
+        Iterator hrefIter = hrefs.iterator();
+        int i = 0;
+        while (hrefIter.hasNext()) {
+            refResources[i] = getResourceFromHref((String)hrefIter.next());
+            i++;
+        }
+        return refResources;
+    }
+
+    /**
+     * Retrieve the <code>DavResource</code> object that is represented by
+     * the given href String.
+     *
+     * @param href
+     * @return <code>DavResource</code> object
+     */
+    private DavResource getResourceFromHref(String href) throws DavException {
+        // build a new locator: remove trailing prefix
+        DavResourceLocator locator = getLocator();
+        String prefix = locator.getPrefix();
+        if (href.startsWith(prefix)) {
+            href = href.substring(prefix.length());
+        }
+        DavResourceLocator loc = locator.getFactory().createResourceLocator(prefix, href);
+
+        // create a new resource object
+        try {
+            DavResource res;
+            if (getRepositorySession().itemExists(loc.getResourcePath())) {
+                res = createResourceFromLocator(loc);
+            } else {
+                throw new DavException(DavServletResponse.SC_NOT_FOUND);
+            }
+            return res;
+        } catch (RepositoryException e) {
+            throw new JcrDavException(e);
+        }
+    }
+
+    //-------------------------------------------< SearchResource interface >---
+    /**
+     * @return
+     * @see org.apache.jackrabbit.webdav.search.SearchResource#getQueryGrammerSet()
+     */
+    public QueryGrammerSet getQueryGrammerSet() {
+        return new SearchResourceImpl(getLocator(), getSession()).getQueryGrammerSet();
+    }
+
+    /**
+     * @param sInfo
+     * @return
+     * @throws DavException
+     * @see SearchResource#search(org.apache.jackrabbit.webdav.search.SearchInfo)
+     */
+    public MultiStatus search(SearchInfo sInfo) throws DavException {
+        return new SearchResourceImpl(getLocator(), getSession()).search(sInfo);
+    }
+    //--------------------------------------------------------------------------
+    /**
+     * Fill the set of default properties
+     */
+    protected void initProperties() {
+        if (getDisplayName() != null) {
+            properties.add(new DefaultDavProperty(DavPropertyName.DISPLAYNAME, getDisplayName()));
+        }
+        if (isCollection()) {
+            properties.add(new ResourceType(ResourceType.COLLECTION));
+            // Windows XP support
+            properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "1"));
+        } else {
+            properties.add(new ResourceType(ResourceType.DEFAULT_RESOURCE));
+            // Windows XP support
+            properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "0"));
+        }
+        // todo: add etag
+
+        // default last modified
+        setModificationTime(new Date().getTime());
+        // default creation time
+        properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, DavConstants.creationDateFormat.format(new Date(0))));
+
+        // supported lock property
+        properties.add(supportedLock);
+
+        // set current lock information. If no lock is applied to this resource,
+        // an empty lockdiscovery will be returned in the response.
+        properties.add(new LockDiscovery(getLocks()));
+
+        // observation resource
+        SubscriptionDiscovery subsDiscovery = subsMgr.getSubscriptionDiscovery(this);
+        properties.add(subsDiscovery);
+
+        properties.add(new SupportedMethodSetProperty(getSupportedMethods().split(",\\s")));
+
+	// DeltaV properties
+	properties.add(supportedReports);
+	// creator-displayname, comment: not value available from jcr
+	properties.add(new DefaultDavProperty(DeltaVConstants.CREATOR_DISPLAYNAME, null, true));
+	properties.add(new DefaultDavProperty(DeltaVConstants.COMMENT, null, true));
+
+	// 'workspace' property as defined by RFC 3253
+	String workspaceHref = getWorkspaceHref();
+	if (workspaceHref != null) {
+	    properties.add(new HrefProperty(DeltaVConstants.WORKSPACE, workspaceHref, true));
+	}
+	// TODO: required supported-live-property-set
+    }
+
+    /**
+     * Create a new <code>DavResource</code> from the given locator.
+     * @param loc
+     * @return new <code>DavResource</code>
+     */
+    protected DavResource createResourceFromLocator(DavResourceLocator loc)
+            throws DavException {
+        DavResource res = factory.createResource(loc, session);
+        if (res instanceof AbstractResource) {
+            ((AbstractResource)res).transactionId = this.transactionId;
+        }
+        return res;
+    }
+
+    /**
+     * Build a <code>DavResourceLocator</code> from the given resource path.
+     *
+     * @param resourcePath
+     * @return a new <code>DavResourceLocator</code>
+     * @see DavLocatorFactory#createResourceLocator(String, String, String)
+     */
+    protected DavResourceLocator getLocatorFromResourcePath(String resourcePath) {
+        DavResourceLocator loc = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), resourcePath);
+        return loc;
+    }
+
+    /**
+     * Retrieve the name/label of a repository item from the given href by
+     * splitting of the part after the last slash. If the removeIndex
+     * flag is set to true, any trailing index (e.g. '[1]') will be removed.
+     *
+     * @param resourceHref
+     * @param removeIndex
+     * @return the name of the item
+     */
+    protected static String getResourceName(String resourceHref, boolean removeIndex) {
+        if (resourceHref == null) {
+            return resourceHref;
+        }
+
+        // cut the extension
+        int pos = resourceHref.lastIndexOf('.');
+        if (pos > 0) {
+            resourceHref = resourceHref.substring(pos+1);
+        } else if (resourceHref.endsWith("/")) {
+            resourceHref = resourceHref.substring(0, resourceHref.length()-1);
+        }
+
+        // retrieve the last part of the path
+        String name = Text.getLabel(resourceHref);
+        // remove index
+        if (removeIndex) {
+            if (name.endsWith("]")) {
+                name = name.substring(0, name.lastIndexOf('['));
+            }
+        }
+        return name;
+    }
+
+    /**
+     * Shortcut for <code>getSession().getRepositorySession()</code>
+     *
+     * @return repository session present in the {@link #session}.
+     */
+    protected Session getRepositorySession() {
+        return getSession().getRepositorySession();
+    }
+
+    /**
+     * Define the set of locks supported by this resource.
+     *
+     * @see org.apache.jackrabbit.webdav.lock.SupportedLock
+     */
+    abstract protected void initLockSupport();
+
+    /**
+     * Define the set of reports supported by this resource.
+     *
+     * @see org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty
+     */
+    abstract protected void initSupportedReports();
+
+    /**
+     * Retrieve the href of the workspace the current session belongs to.
+     *
+     * @return href of the workspace
+     */
+    abstract protected String getWorkspaceHref();
+}
\ No newline at end of file

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

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

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavLocatorFactoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavLocatorFactoryImpl.java?rev=180346&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavLocatorFactoryImpl.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavLocatorFactoryImpl.java Mon Jun  6 10:36:09 2005
@@ -0,0 +1,305 @@
+/*
+ * 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.webdav.jcr;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+
+/**
+ * <code>DavLocatorFactoryImpl</code>...
+ */
+public class DavLocatorFactoryImpl implements DavLocatorFactory {
+
+    private static Logger log = Logger.getLogger(DavLocatorFactoryImpl.class);
+
+    private final String pathPrefix;
+
+    /**
+     * Create a new factory
+     *
+     * @param pathPrefix Prefix, that needs to be removed in order to retrieve
+     * the path of the repository item from a given <code>DavResourceLocator</code>.
+     */
+    public DavLocatorFactoryImpl(String pathPrefix) {
+	this.pathPrefix = pathPrefix;
+    }
+
+    /**
+     * Create a new <code>DavResourceLocator</code>. Any leading
+     * path-prefix (as defined with the constructor) and trailing '/' with
+     * the request handle is removed. The first label of the remaining handle is
+     * treated as workspace name. The remaining part of the given request handle
+     * is said to be the resource handle ("/" if an empty string remains).
+     * If the request handle does neither provide workspace name nor resource
+     * handle both values are set to <code>null</code>; the path object then
+     * represents the root resource that has no corresponding item in the JCR
+     * repository.
+     *
+     * @param prefix
+     * @param requestHandle
+     * @return a new <code>DavResourceLocator</code>
+     * @throws IllegalArgumentException if the request handle is <code>null</code>
+     */
+    public DavResourceLocator createResourceLocator(String prefix, String requestHandle) {
+	if (requestHandle == null) {
+	    throw new IllegalArgumentException("Request handle must not be null.");
+	}
+
+	StringBuffer b = new StringBuffer("");
+	if (prefix != null) {
+	    b.append(prefix);
+	    if (pathPrefix != null && !prefix.endsWith(pathPrefix)) {
+		b.append(pathPrefix);
+	    }
+	}
+	String rlPrefix = b.toString();
+
+	// remove path-prefix defined with the servlet that may preceed the
+	// the requestHandle
+	if (pathPrefix != null && requestHandle.startsWith(pathPrefix)) {
+	    requestHandle = requestHandle.substring(pathPrefix.length());
+	}
+
+	// remove trailing "/" that is present with collections
+	if (requestHandle.endsWith("/")) {
+	    requestHandle = requestHandle.substring(0, requestHandle.length()-1);
+	}
+
+	String resourcePath;
+	String workspacePath;
+
+	// an empty requestHandle (after removal of the "/") signifies a request
+	// to the root that does not represent a repository item.
+	if ("".equals(requestHandle)) {
+	    resourcePath = null;
+	    workspacePath = null;
+	} else {
+	    // look for the first slash ignoring the leading one
+	    int pos = requestHandle.indexOf('/', 1);
+	    if (pos == -1) {
+		// request to a 'workspace' resource that in the same time
+		// represent the root node of the repository.
+		workspacePath = requestHandle;
+		resourcePath = ItemResourceConstants.ROOT_ITEM_PATH;
+	    } else {
+		// separate the workspace name from the path of the repository
+		// item.
+		workspacePath = requestHandle.substring(0, pos);
+		resourcePath = requestHandle.substring(pos);
+	    }
+	}
+
+	return new DavResourceLocatorImpl(rlPrefix, workspacePath, resourcePath, this);
+    }
+
+    /**
+     * Create a new <code>DavResourceLocator</code> from the specified prefix,
+     * workspace path and resource path, whithout modifying the specified Strings.
+     *
+     * @param prefix
+     * @param workspacePath
+     * @param resourcePath
+     * @return a new <code>DavResourceLocator</code>
+     * @see DavLocatorFactory#createResourceLocator(String, String, String)
+     */
+    public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
+	return new DavResourceLocatorImpl(prefix, workspacePath, resourcePath, this);
+    }
+
+    /**
+     * Private inner class <code>DavResourceLocatorImpl</code> implementing
+     * the <code>DavResourceLocator</code> interface.
+     */
+    private class DavResourceLocatorImpl implements DavResourceLocator {
+
+	private final String prefix;
+	private final String workspacePath;
+	private final String resourcePath;
+	private final DavLocatorFactory factory;
+
+	/**
+	 * Create a new <code>DavResourceLocatorImpl</code>.
+	 *
+	 * @param prefix
+	 * @param workspacePath
+	 * @param resourcePath
+	 */
+	DavResourceLocatorImpl(String prefix, String workspacePath, String resourcePath, DavLocatorFactory factory) {
+	    this.prefix = prefix;
+	    this.workspacePath = workspacePath;
+	    this.resourcePath = resourcePath;
+	    this.factory = factory;
+	}
+
+	/**
+	 * Return the prefix used to build the href String. This includes the initial
+	 * hrefPrefix as well a the path prefix.
+	 *
+	 * @return prefix String used to build the href.
+	 */
+	public String getPrefix() {
+	    return prefix;
+	}
+
+	/**
+	 * Return the resource path of <code>null</code> if this locator object
+	 * represents the '/' request handle. To a request handle specifying a
+	 * workspace name only the '/' resource path is assigned, which represents
+	 * the root node of the repository.
+	 *
+	 * @return resource path or <code>null</code>
+	 * @see org.apache.jackrabbit.webdav.DavResourceLocator#getResourcePath()
+	 */
+	public String getResourcePath() {
+	    return resourcePath;
+	}
+
+	/**
+	 * Return the workspace path or <code>null</code> if this locator object
+	 * represents the '/' request handle.
+	 *
+	 * @return workspace path or <code>null</code>
+	 * @see org.apache.jackrabbit.webdav.DavResourceLocator#getWorkspacePath()
+	 */
+	public String getWorkspacePath() {
+	    return workspacePath;
+	}
+
+	/**
+	 * Return the workspace name or <code>null</code> if this locator object
+	 * represents the '/' request handle.
+	 *
+	 * @return workspace name or <code>null</code>
+	 * @see org.apache.jackrabbit.webdav.DavResourceLocator#getWorkspaceName()
+	 */
+	public String getWorkspaceName() {
+	    if (workspacePath != null) {
+		return workspacePath.substring(1);
+	    }
+	    return null;
+	}
+
+	/**
+	 * Returns true if the specified locator object refers to a resource within
+	 * the same workspace.
+	 *
+	 * @param locator
+	 * @return true if the workspace name is equal to this workspace name.
+	 * @see DavResourceLocator#isSameWorkspace(org.apache.jackrabbit.webdav.DavResourceLocator)
+	 */
+	public boolean isSameWorkspace(DavResourceLocator locator) {
+	    return (locator == null) ? false : isSameWorkspace(locator.getWorkspaceName());
+	}
+
+	/**
+	 * Returns true if the specified string equals to this workspace name or
+	 * if this workspace name is null.
+	 *
+	 * @param workspaceName
+	 * @return true if the workspace name is equal to this workspace name.
+	 * @see DavResourceLocator#isSameWorkspace(String)
+	 */
+	public boolean isSameWorkspace(String workspaceName) {
+	    if (getWorkspaceName() == null) {
+		return true;
+	    } else {
+		return getWorkspaceName().equals(workspaceName);
+	    }
+	}
+
+	/**
+	 * Builds the 'href' from the prefix, the workspace name and the
+	 * resource path present and assures a trailing '/' in case the href
+	 * is used for collection.
+	 *
+	 * @param isCollection
+	 * @return href String representing the text of the href element
+	 * @see org.apache.jackrabbit.webdav.DavConstants#XML_HREF
+	 * @see DavResourceLocator#getHref(boolean)
+	 */
+	public String getHref(boolean isCollection) {
+	    StringBuffer href = new StringBuffer(prefix);
+	    if (workspacePath != null) {
+		href.append(workspacePath);
+	    }
+	    if (resourcePath != null) {
+		href.append(resourcePath);
+	    }
+	    if (isCollection && href.charAt(href.length()-1) != '/') {
+		href.append("/");
+	    }
+	    return href.toString();
+	}
+
+	/**
+	 * Returns true if the 'workspaceName' field is <code>null</code>.
+	 *
+	 * @return true if the 'workspaceName' field is <code>null</code>.
+	 * @see org.apache.jackrabbit.webdav.DavResourceLocator#isRootLocation()
+	 */
+	public boolean isRootLocation() {
+	    return workspacePath == null;
+	}
+
+	/**
+	 * Return the factory that created this locator.
+	 *
+	 * @return factory
+	 * @see org.apache.jackrabbit.webdav.DavResourceLocator#getFactory()
+	 */
+	public DavLocatorFactory getFactory() {
+	    return factory;
+	}
+
+	/**
+	 * Computes the hash code using the prefix, the workspace name and the
+	 * resource path.
+	 *
+	 * @return the hash code
+	 */
+	public int hashCode() {
+	    int hashCode = prefix.hashCode();
+	    if (workspacePath != null) {
+		hashCode += workspacePath.hashCode();
+	    }
+	    if (resourcePath != null) {
+		hashCode += resourcePath.hashCode();
+	    }
+	    return hashCode % Integer.MAX_VALUE;
+	}
+
+	/**
+	 * Equality of locators is achieved if prefix and resource path
+	 * are equal.
+	 *
+	 * @param obj the object to compare to
+	 * @return <code>true</code> if the 2 objects are equal;
+	 *         <code>false</code> otherwise
+	 */
+	public boolean equals(Object obj) {
+	    if (obj instanceof DavResourceLocatorImpl) {
+		DavResourceLocatorImpl locator = (DavResourceLocatorImpl) obj;
+		boolean equalWsName = (workspacePath == null) ? locator.workspacePath == null : workspacePath.equals(locator.workspacePath);
+		boolean equalRPath = (resourcePath == null) ? locator.resourcePath == null : resourcePath.equals(locator.resourcePath);
+
+		return prefix.equals(locator.prefix) && equalWsName && equalRPath;
+	    }
+	    return false;
+	}
+    }
+}
+

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

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

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavResourceFactoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavResourceFactoryImpl.java?rev=180346&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavResourceFactoryImpl.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DavResourceFactoryImpl.java Mon Jun  6 10:36:09 2005
@@ -0,0 +1,196 @@
+/*
+ * 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.webdav.jcr;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.transaction.TransactionResource;
+import org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest;
+import org.apache.jackrabbit.webdav.observation.SubscriptionManager;
+import org.apache.jackrabbit.webdav.observation.ObservationResource;
+import org.apache.jackrabbit.webdav.version.DeltaVServletRequest;
+import org.apache.jackrabbit.webdav.version.VersionControlledResource;
+import org.apache.jackrabbit.webdav.jcr.version.VersionItemCollection;
+import org.apache.jackrabbit.webdav.jcr.version.VersionHistoryItemCollection;
+import org.apache.jackrabbit.webdav.jcr.transaction.TxLockManagerImpl;
+
+import javax.jcr.*;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+
+/**
+ * <code>DavResourceFactoryImpl</code>...
+ */
+public class DavResourceFactoryImpl implements DavResourceFactory {
+
+    private static Logger log = Logger.getLogger(DavResourceFactoryImpl.class);
+
+    private final TxLockManagerImpl txMgr;
+    private final SubscriptionManager subsMgr;
+
+    /**
+     * Create a new <code>DavResourceFactoryImpl</code>.
+     *
+     * @param txMgr
+     * @param subsMgr
+     */
+    public DavResourceFactoryImpl(TxLockManagerImpl txMgr, SubscriptionManager subsMgr) {
+        this.txMgr = txMgr;
+        this.subsMgr = subsMgr;
+    }
+
+    /**
+     * Create a new <code>DavResource</code> from the specified locator and request
+     * objects. Note, that in contrast to
+     * {@link #createResource(DavResourceLocator, DavSession)} the locator may
+     * point to a non-existing resource.
+     * <p/>
+     * If the request contains a {@link org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getLabel()
+     * Label header}, the resource is build from the indicated
+     * {@link org.apache.jackrabbit.webdav.version.VersionResource version} instead.
+     *
+     * @param locator
+     * @param request
+     * @param response
+     * @return
+     * @see DavResourceFactory#createResource(org.apache.jackrabbit.webdav.DavResourceLocator, org.apache.jackrabbit.webdav.DavServletRequest, org.apache.jackrabbit.webdav.DavServletResponse)
+     */
+    public DavResource createResource(DavResourceLocator locator,
+                                      DavServletRequest request,
+                                      DavServletResponse response) throws DavException {
+
+        DavSession session = request.getDavSession();
+
+        DavResource resource;
+        if (locator.isRootLocation()) {
+            resource = new RootCollection(locator, session, this);
+        } else {
+            try {
+                resource = createResourceForItem(locator, session);
+
+                /* if the created resource is version-controlled and the request
+                contains a Label header, the corresponding Version must be used
+                instead.*/
+                if (request instanceof DeltaVServletRequest && isVersionControlled(resource)) {
+                    String labelHeader = ((DeltaVServletRequest)request).getLabel();
+                    if (labelHeader != null && DavMethods.isMethodAffectedByLabel(request.getMethod())) {
+                        Item item = session.getRepositorySession().getItem(locator.getResourcePath());
+                        Version v = ((Node)item).getVersionHistory().getVersionByLabel(labelHeader);
+                        DavResourceLocator vloc = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), v.getPath());
+                        resource =  new VersionItemCollection(vloc, session, this, v);
+                    }
+                }
+            } catch (PathNotFoundException e) {
+                /* item does not exist yet: create the default resources
+                Note: MKCOL request forces a collection-resource even if there already
+                exists a repository-property with the given path. the MKCOL will
+                in that particular case fail with a 405 (method not allowed).*/
+                if (DavMethods.getMethodCode(request.getMethod()) == DavMethods.DAV_MKCOL) {
+                    resource = new VersionControlledItemCollection(locator, session, this, null);
+                } else {
+                    resource = new DefaultItemResource(locator, session, this, null);
+                }
+            } catch (RepositoryException e) {
+                log.error("Failed to build resource from item '"+ locator.getResourcePath() + "'");
+                throw new JcrDavException(e);
+            }
+        }
+
+        ((TransactionResource)resource).init(txMgr, ((TransactionDavServletRequest)request).getTransactionId());
+        ((ObservationResource)resource).init(subsMgr);
+        return resource;
+    }
+
+    /**
+     * Create a new <code>DavResource</code> from the given locator and session.
+     *
+     * @param locator
+     * @param session
+     * @return DavResource representing either a repository item or the {@link RootCollection}.
+     * @throws DavException if the given locator does neither refer to a repository item
+     * nor does represent the {@link org.apache.jackrabbit.webdav.DavResourceLocator#isRootLocation()
+     * root location}.
+     */
+    public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException {
+        DavResource resource;
+        try {
+            resource = createResourceForItem(locator, session);
+        } catch (RepositoryException e) {
+            log.info("Creating resource for non-existing repository item ...");
+            if (locator.isRootLocation()) {
+                resource =  new RootCollection(locator, session, this);
+            } else {
+		// todo: is this correct?
+		resource = new VersionControlledItemCollection(locator, session, this, null);
+            }
+        }
+
+        // todo: currently transactionId is set manually after creation > to be improved.
+        resource.addLockManager(txMgr);
+        ((ObservationResource)resource).init(subsMgr);
+        return resource;
+    }
+
+    /**
+     * Tries to retrieve the repository item defined by the locator's resource
+     * path and build the corresponding WebDAV resource. The following distinction
+     * is made between items: Version nodes, VersionHistory nodes, root node,
+     * unspecified nodes and finally property items.
+     *
+     * @param locator
+     * @param session
+     * @return DavResource representing a repository item.
+     * @throws RepositoryException if {@link Session#getItem(String)} fails.
+     */
+    private DavResource createResourceForItem(DavResourceLocator locator, DavSession session) throws RepositoryException {
+        DavResource resource;
+        Item item = session.getRepositorySession().getItem(locator.getResourcePath());
+        if (item.isNode()) {
+            // create special resources for Version and VersionHistory
+            if (item instanceof Version) {
+                resource = new VersionItemCollection(locator, session, this, item);
+            } else if (item instanceof VersionHistory) {
+                resource = new VersionHistoryItemCollection(locator, session, this, item);
+            } else if (ItemResourceConstants.ROOT_ITEM_PATH.equals(locator.getResourcePath())) {
+                resource =  new RootItemCollection(locator, session, this, item);
+            }  else{
+                resource = new VersionControlledItemCollection(locator, session, this, item);
+            }
+        } else {
+            resource = new DefaultItemResource(locator, session, this, item);
+        }
+        return resource;
+    }
+
+    /**
+     * Returns true, if the specified resource is a {@link VersionControlledResource}
+     * and has a version history.
+     *
+     * @param resource
+     * @return true if the specified resource is version-controlled.
+     */
+    private boolean isVersionControlled(DavResource resource) {
+        boolean vc = false;
+        if (resource instanceof VersionControlledResource) {
+            try {
+                vc = ((VersionControlledResource)resource).getVersionHistory() != null;
+            } catch (DavException e) {
+                log.debug("Resource '" + resource.getHref() + "' is not version-controlled.");
+            }
+        }
+        return vc;
+    }
+}
\ No newline at end of file

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

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

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java?rev=180346&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java Mon Jun  6 10:36:09 2005
@@ -0,0 +1,746 @@
+/*
+ * 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.webdav.jcr;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.property.*;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.jcr.nodetype.NodeTypeProperty;
+import org.apache.jackrabbit.webdav.jcr.lock.JcrActiveLock;
+import org.apache.jackrabbit.webdav.ordering.*;
+import org.apache.jackrabbit.webdav.lock.*;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.util.Text;
+
+import javax.jcr.*;
+import javax.jcr.lock.Lock;
+import javax.jcr.nodetype.NodeType;
+import java.util.*;
+import java.io.*;
+
+/**
+ * <code>DefaultItemCollection</code> represents a JCR node item.
+ */
+public class DefaultItemCollection extends AbstractItemResource
+        implements OrderingResource {
+
+    private static Logger log = Logger.getLogger(DefaultItemCollection.class);
+
+    private InputStream in;
+
+    /**
+     * Create a new <code>DefaultItemCollection</code>.
+     *
+     * @param locator
+     * @param session
+     */
+    protected DefaultItemCollection(DavResourceLocator locator, DavSession session,
+                                    DavResourceFactory factory, Item item) {
+        super(locator, session, factory, item);
+        if (exists() && !(item instanceof Node)) {
+            throw new IllegalArgumentException("A collection resource can not be constructed from a Property item.");
+        }
+    }
+
+    //----------------------------------------------< DavResource interface >---
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getComplianceClass()
+     */
+    public String getComplianceClass() {
+        StringBuffer sb = new StringBuffer(super.getComplianceClass());
+        sb.append(", ").append(OrderingResource.COMPLIANCE_CLASS);
+        return sb.toString();
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
+     */
+    public String getSupportedMethods() {
+        StringBuffer sb = new StringBuffer(super.getSupportedMethods());
+        // Ordering
+        if (isOrderable()) {
+           sb.append(", ").append(OrderingResource.METHODS);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Always returns true
+     *
+     * @return true
+     * @see org.apache.jackrabbit.webdav.DavResource#isCollection()
+     */
+    public boolean isCollection() {
+        return true;
+    }
+
+
+    /**
+     * Returns an {@link java.io.InputStream} to the content of this collection.
+     *
+     * @return
+     * @see org.apache.jackrabbit.webdav.DavResource#getStream()
+     */
+    public InputStream getStream() {
+        initProperties();
+        return in;
+    }
+
+    /**
+     * This implementation of the <code>DavResource</code> does only allow
+     * to set the jcr:mixinnodetypes property. Please note that the existing list of
+     * mixin nodetypes will be completely replaces.<br>
+     * In order to add / set any other repository property on the underlaying
+     * {@link javax.jcr.Node} use <code>addMember(DavResource)</code> or
+     * <code>addMember(DavResource, InputStream)</code> or modify the value
+     * of the corresponding resource.
+     *
+     * @param property
+     * @throws org.apache.jackrabbit.webdav.DavException
+     * @see org.apache.jackrabbit.webdav.DavResource#setProperty(org.apache.jackrabbit.webdav.property.DavProperty)
+     * @see #JCR_MIXINNODETYPES
+     * @todo undo incomplete modifications...
+     */
+    public void setProperty(DavProperty property) throws DavException {
+        if (!exists()) {
+            throw new DavException(DavServletResponse.SC_NOT_FOUND);
+        }
+        if (property.getName().equals(JCR_MIXINNODETYPES)) {
+            try {
+                Node n = (Node)item;
+                NodeType[] existingMixin = n.getMixinNodeTypes();
+                NodeTypeProperty mix = new NodeTypeProperty(property);
+                Set mixins = mix.getNodeTypeNames();
+
+                for (int i = 0; i < existingMixin.length; i++) {
+                    String name = existingMixin[i].getName();
+                    if (mixins.contains(name)){
+                        // do not add existing mixins
+                        mixins.remove(name);
+                    } else {
+                        // remove mixin that are not contained in the new list
+                        n.removeMixin(name);
+                    }
+                }
+
+                // add the remaining mixing types that are not yet set
+                Iterator it = mixins.iterator();
+                while (it.hasNext()) {
+                    n.addMixin((String)it.next());
+                }
+                complete();
+
+            } catch (RepositoryException e) {
+                throw new JcrDavException(e);
+            }
+        } else {
+            // all props except for mixinnodetypes are read-only
+            throw new DavException(DavServletResponse.SC_CONFLICT);
+        }
+    }
+
+    /**
+     * This implementation of the <code>DavResource</code> does only allow
+     * to remove the jcr:mixinnodetypes property.
+     *
+     * @param propertyName
+     * @throws org.apache.jackrabbit.webdav.DavException
+     * @see org.apache.jackrabbit.webdav.DavResource#removeProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
+     * @see #JCR_MIXINNODETYPES
+     * @todo undo incomplete modifications...
+     */
+    public void removeProperty(DavPropertyName propertyName) throws DavException {
+        if (!exists()) {
+            throw new DavException(DavServletResponse.SC_NOT_FOUND);
+        }
+        if (JCR_MIXINNODETYPES.equals(propertyName)) {
+            // remove all mixin nodetypes
+            try {
+                Node n = (Node)item;
+                NodeType[] mixins = n.getMixinNodeTypes();
+                for (int i = 0; i < mixins.length; i++) {
+                    n.removeMixin(mixins[i].getName());
+                }
+                complete();
+
+            } catch (RepositoryException e) {
+                // NoSuchNodeTypeException, ConstraintViolationException should never occur...
+                throw new JcrDavException(e);
+            }
+        } else {
+            // all props except for mixinnodetypes are read-only
+            throw new DavException(DavServletResponse.SC_CONFLICT);
+        }
+    }
+
+    /**
+     * If the specified resource represents a collection, a new node is {@link Node#addNode(String)
+     * added} to the item represented by this resource. If an input stream is specified
+     * together with a collection resource {@link Session#importXML(String, java.io.InputStream, int)}
+     * is called instead and this resource path is used as <code>parentAbsPath</code> argument.
+     * <p/>
+     * However, if the specified resource is not of resource type collection a
+     * new {@link Property} is set or an existing one is changed by modifying its
+     * value.<br>
+     * NOTE: with the current implementation it is not possible to create or
+     * modify multivalue JCR properties.<br>
+     * NOTE: if the JCR property represented by the specified resource has an
+     * {@link PropertyType#UNDEFINED undefined} resource type, its value will be
+     * changed/set to type {@link PropertyType#BINARY binary}.
+     *
+     * @param resource
+     * @param in
+     * @throws org.apache.jackrabbit.webdav.DavException
+     * @see org.apache.jackrabbit.webdav.DavResource#addMember(org.apache.jackrabbit.webdav.DavResource, java.io.InputStream)
+     * @see Node#addNode(String)
+     * @see Node#setProperty(String, java.io.InputStream)
+     */
+    public void addMember(DavResource resource, InputStream in)
+            throws DavException {
+
+        /* RFC 2815 states that all 'parents' must exist in order all addition of members */
+        if (!exists()) {
+            throw new DavException(DavServletResponse.SC_CONFLICT);
+        }
+
+        try {
+            Node n = (Node) item;
+            if (resource.isCollection()) {
+                if (in == null) {
+                    // MKCOL without a request body, try if a default-primary-type is defined.
+                    n.addNode(resource.getDisplayName());
+                } else {
+                    // MKCOL, which is not allowed for existing resources
+                    if (getTransactionId() == null) {
+                        // if not part of a transaction directely import on workspace
+                        // since changes would be explicitely saved in the
+                        // complete-call.
+                        getRepositorySession().getWorkspace().importXML(getResourcePath(), in, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
+                    } else {
+                        // changes will not be persisted unless the tx is completed.
+                        getRepositorySession().importXML(getResourcePath(), in, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
+                    }
+                }
+            } else {
+                if (in == null) {
+                    // PUT: not possible
+                    throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Cannot create a new non-collection resource without request body.");
+                } else {
+                    // TODO: find a way to create non-binary and multivalue properties
+                    // PUT : create new or overwrite existing property.
+                    // NOTE: will fail for multivalue properties.
+                    n.setProperty(getResourceName(resource.getResourcePath(), true), in);
+                }
+            }
+            complete();
+        } catch (ItemExistsException e) {
+            // according to RFC 2518: MKCOL only possible on non-existing/deleted resource
+            throw new JcrDavException(e, DavServletResponse.SC_METHOD_NOT_ALLOWED);
+        } catch (RepositoryException e) {
+            throw new JcrDavException(e);
+        } catch (IOException e) {
+            throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENTITY, e.getMessage());
+        }
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#addMember(org.apache.jackrabbit.webdav.DavResource)
+     */
+    public void addMember(DavResource resource) throws DavException {
+        addMember(resource, resource.getStream());
+    }
+
+    /**
+     * @see org.apache.jackrabbit.webdav.DavResource#getMembers()
+     */
+    public DavResourceIterator getMembers() {
+        ArrayList memberList = new ArrayList();
+	if (exists()) {
+	    try {
+                Node n = (Node)item;
+                // add all node members
+		NodeIterator it = n.getNodes();
+		while (it.hasNext()) {
+                    Node node = it.nextNode();
+                    DavResourceLocator loc = getLocatorFromItem(node);
+		    memberList.add(createResourceFromLocator(loc));
+		}
+                // add all property members
+                PropertyIterator propIt = n.getProperties();
+                while (propIt.hasNext()) {
+                    Property prop = propIt.nextProperty();
+                    DavResourceLocator loc = getLocatorFromItem(prop);
+                    memberList.add(createResourceFromLocator(loc));
+                }
+	    } catch (RepositoryException e) {
+		// ignore
+                log.error(e.getMessage());
+	    } catch (DavException e) {
+                // should never occur.
+                log.error(e.getMessage());
+            }
+	}
+	return new DavResourceIteratorImpl(memberList);
+    }
+
+    /**
+     * Removes the repository item represented by the specified member
+     * resource.
+     *
+     * @throws DavException if this resource does not exist or if an error occurs
+     * while deleting the underlaying item.
+     * @see DavResource#removeMember(DavResource)
+     * @see javax.jcr.Item#remove()
+     */
+    public void removeMember(DavResource member) throws DavException {
+        Session session = getRepositorySession();
+        try {
+            if (!exists() || !session.itemExists(member.getResourcePath())) {
+                throw new DavException(DavServletResponse.SC_NOT_FOUND);
+            }
+            if (!getResourcePath().equals(Text.getRelativeParent(member.getResourcePath(), 1))) {
+                throw new DavException(DavServletResponse.SC_CONFLICT, member.getResourcePath() + "is not member of this resource (" + getResourcePath() + ")");
+            }
+            session.getItem(member.getResourcePath()).remove();
+            complete();
+        } catch (RepositoryException e) {
+            log.error("Unexpected error: " + e.getMessage());
+            throw new JcrDavException(e);
+        }
+    }
+
+    /**
+     * @param type
+     * @param scope
+     * @return true if a lock with the specified type and scope is present on
+     * this resource, false otherwise. If retrieving the corresponding information
+     * fails, false is returned.
+     * @see org.apache.jackrabbit.webdav.DavResource#hasLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
+     */
+    public boolean hasLock(Type type, Scope scope) {
+        if (isLockable(type, scope)) {
+            if (Type.WRITE.equals(type)) {
+                try {
+                    return ((Node) item).isLocked();
+                } catch (RepositoryException e) {
+                    log.error(e.getMessage());
+                }
+            } else {
+                return super.hasLock(type, scope);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Retrieve the lock with the specified type and scope.
+     *
+     * @param type
+     * @param scope
+     * @return lock with the specified type and scope is present on this
+     * resource or <code>null</code>. NOTE: If retrieving the write lock present
+     * on the underlaying repository item fails, <code>null</code> is return.
+     * @see org.apache.jackrabbit.webdav.DavResource#getLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
+     * @see javax.jcr.Node#getLock() for the write locks.
+     */
+    public ActiveLock getLock(Type type, Scope scope) {
+        ActiveLock lock = null;
+        if (isLockable(type, scope)) {
+            if (Type.WRITE.equals(type)) {
+                try {
+                    if (!exists()) {
+                        log.warn("Unable to retrieve lock: no item found at '" + getResourcePath() + "'");
+                    } else if (((Node) item).isLocked()) {
+                        Lock jcrLock = ((Node) item).getLock();
+                        // TODO: find out whether this lock is session-scoped or not!
+                        lock = new JcrActiveLock(jcrLock);
+                    }
+                } catch (AccessDeniedException e) {
+                    log.error("Error while accessing resource lock: "+e.getMessage());
+                } catch (UnsupportedRepositoryOperationException e) {
+                    log.error("Error while accessing resource lock: "+e.getMessage());
+                } catch (RepositoryException e) {
+                    log.error("Error while accessing resource lock: "+e.getMessage());
+                }
+            } else {
+                lock = super.getLock(type, scope);
+            }
+        }
+        return lock;
+    }
+
+    /**
+     * Creates a lock on this resource by locking the underlaying
+     * {@link javax.jcr.Node node}. Except for the {@link org.apache.jackrabbit.webdav.lock.LockInfo#isDeep()} }
+     * all information included in the <code>LockInfo</code> object is ignored.
+     * Lock timeout is defined by JCR implementation.
+     *
+     * @param reqLockInfo
+     * @return lock object representing the lock created on this resource.
+     * @throws org.apache.jackrabbit.webdav.DavException
+     * @see org.apache.jackrabbit.webdav.DavResource#lock(org.apache.jackrabbit.webdav.lock.LockInfo)
+     * @see Node#lock(boolean, boolean)
+     */
+    public ActiveLock lock(LockInfo reqLockInfo) throws DavException {
+
+        if (!isLockable(reqLockInfo.getType(), reqLockInfo.getScope())) {
+            throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
+        }
+
+        if (Type.WRITE.equals(reqLockInfo.getType())) {
+            if (!exists()) {
+                log.warn("Cannot create a write lock for non-existing JCR node (" + getResourcePath() + ")");
+                throw new DavException(DavServletResponse.SC_NOT_FOUND);
+            }
+            try {
+                boolean sessionScoped = EXCLUSIVE_SESSION.equals(reqLockInfo.getScope());
+                Lock jcrLock = ((Node)item).lock(reqLockInfo.isDeep(), sessionScoped);
+                return new JcrActiveLock(jcrLock, sessionScoped);
+
+            } catch (RepositoryException e) {
+                // UnsupportedRepositoryOperationException should not occur...
+                throw new JcrDavException(e);
+            }
+        } else {
+            return super.lock(reqLockInfo);
+        }
+    }
+
+    /**
+     * Refreshes the lock on this resource. With this implementation the
+     * {@link javax.jcr.lock lock} present on the underlaying {@link javax.jcr.Node node}
+     * is refreshed. The timeout indicated by the <code>LockInfo</code>
+     * object is ignored.
+     *
+     * @param reqLockInfo LockInfo as build from the request.
+     * @param lockToken
+     * @return the updated lock info object.
+     * @throws org.apache.jackrabbit.webdav.DavException in case the lock could not be refreshed.
+     * @see org.apache.jackrabbit.webdav.DavResource#refreshLock(org.apache.jackrabbit.webdav.lock.LockInfo, String)
+     * @see javax.jcr.lock.Lock#refresh()
+     */
+    public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken)
+            throws DavException {
+
+        if (lockToken == null) {
+            throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
+        }
+
+        ActiveLock lock = getLock(reqLockInfo.getType(), reqLockInfo.getScope());
+        if (lock == null) {
+            throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "No lock with the given scope/type present on this resource.");
+        }
+
+        if (Type.WRITE.equals(lock.getType())) {
+            try {
+                Lock jcrLock = ((Node) item).getLock();
+                jcrLock.refresh();
+                return new JcrActiveLock(jcrLock, EXCLUSIVE_SESSION.equals(lock.getScope()));
+            } catch (RepositoryException e) {
+                /*
+                  NOTE: LockException is only thrown by Lock.refresh()
+                        the lock exception thrown by Node.getLock() was circumvented
+                        by the init test if there is a lock applied...
+                  NOTE: UnsupportedRepositoryOperationException should not occur
+                */
+                throw new JcrDavException(e);
+            }
+        } else {
+            return super.refreshLock(reqLockInfo, lockToken);
+        }
+    }
+
+    /**
+     * Remove the write lock from this resource by unlocking the underlaying
+     * {@link javax.jcr.Node node}.
+     *
+     * @param lockToken
+     * @throws org.apache.jackrabbit.webdav.DavException
+     * @see org.apache.jackrabbit.webdav.DavResource#unlock(String)
+     * @see javax.jcr.Node#unlock()
+     */
+    public void unlock(String lockToken) throws DavException {
+        ActiveLock lock = getWriteLock();
+        if (lock != null && lockToken.equals(lock.getToken())) {
+            try {
+                ((Node) item).unlock();
+            } catch (RepositoryException e) {
+                throw new JcrDavException(e);
+            }
+        } else {
+            super.unlock(lockToken);
+        }
+    }
+
+    /**
+     * Returns the write lock present on this resource or <code>null</code> if
+     * no write lock exists. NOTE: that the scope of a write lock may either
+     * be {@link org.apache.jackrabbit.webdav.lock.Scope#EXCLUSIVE} or {@link #EXCLUSIVE_SESSION}.
+     *
+     * @return write lock or <code>null</code>
+     * @throws DavException if this resource does not represent a repository item.
+     */
+    private ActiveLock getWriteLock() throws DavException {
+        if (!exists()) {
+            throw new DavException(DavServletResponse.SC_NOT_FOUND, "Unable to retrieve write lock for non existing repository item (" + getResourcePath() + ")");
+        }
+        ActiveLock writeLock = getLock(Type.WRITE, Scope.EXCLUSIVE);
+        if (writeLock == null) {
+            writeLock = getLock(Type.WRITE, EXCLUSIVE_SESSION);
+        }
+        return writeLock;
+    }
+
+    //-----------------------------------------< OrderingResource interface >---
+    /**
+     * Returns true if this resource exists and the nodetype defining the
+     * underlaying repository node allow to reorder this nodes children.
+     *
+     * @return true if {@link #orderMembers(OrderPatch)} can be called on this
+     * resource.
+     * @see org.apache.jackrabbit.webdav.ordering.OrderingResource#isOrderable()
+     * @see javax.jcr.nodetype.NodeType#hasOrderableChildNodes()
+     */
+    public boolean isOrderable() {
+        boolean orderable = false;
+        if (exists()) {
+            try {
+                orderable = ((Node) item).getPrimaryNodeType().hasOrderableChildNodes();
+            } catch (RepositoryException e) {
+                log.warn(e.getMessage());
+            }
+        }
+        return orderable;
+    }
+
+    /**
+     * Reorder the child nodes of the repository item represented by this
+     * resource as indicated by the specified {@link OrderPatch} object.
+     *
+     * @param orderPatch
+     * @throws org.apache.jackrabbit.webdav.DavException
+     * @see org.apache.jackrabbit.webdav.ordering.OrderingResource#orderMembers(org.apache.jackrabbit.webdav.ordering.OrderPatch)
+     * @see Node#orderBefore(String, String)
+     */
+    public void orderMembers(OrderPatch orderPatch) throws DavException {
+        if (!isOrderable()) {
+            throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
+        }
+        // only custom ordering is allowed
+        if (!OrderingConstants.ORDERING_TYPE_CUSTOM.equalsIgnoreCase(orderPatch.getOrderingType())) {
+            throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENTITY,"Only DAV:custom ordering type supported.");
+        }
+
+        OrderPatch.Member[] instructions = orderPatch.getOrderInstructions();
+        Node n = (Node)item;
+        try {
+            for (int i = 0; i < instructions.length; i++) {
+                String srcRelPath = getResourceName(n.getPath() + instructions[i].getMemberHandle(), false);
+                Position pos = instructions[i].getPosition();
+                String destRelPath = getRelDestinationPath(pos, n.getNodes());
+
+                n.orderBefore(srcRelPath, destRelPath);
+            }
+        } catch (RepositoryException e) {
+            // UnsupportedRepositoryException should not occur
+            throw new JcrDavException(e);
+        }
+    }
+
+    /**
+     * Retrieve the relative path of the child node that acts as destination.
+     * A <code>null</code> destination path is used to place the child node indicated
+     * by the source path at the end of the list.
+     *
+     * @param position
+     * @param childNodes
+     * @return the relative path of the child node used as destination or <code>null</code>
+     * if the source node should be placed at the last position.
+     * @throws javax.jcr.RepositoryException
+     */
+    private String getRelDestinationPath(Position position, NodeIterator childNodes)
+            throws RepositoryException {
+
+        String destRelPath = null;
+        if (position.getType() == Position.TYPE_FIRST) {
+            while (childNodes.hasNext()) {
+                Node firstChild = childNodes.nextNode();
+                destRelPath = firstChild.getPath();
+            }
+            // no child nodes available > reordering to 'first' position fails.
+            if (destRelPath == null) {
+                throw new ItemNotFoundException("No 'first' item found for reordering.");
+            }
+        } else if (position.getType() == Position.TYPE_AFTER) {
+            String afterRelPath = getResourceName(position.getSegment(), false);
+            boolean found = false;
+            while (childNodes.hasNext() && destRelPath == null) {
+                String childPath = childNodes.nextNode().getPath();
+                if (found) {
+                    destRelPath = childPath;
+                } else {
+                    found = afterRelPath.equals(Text.getLabel(childPath));
+                }
+            }
+        } else {
+            destRelPath = position.getSegment();
+        }
+
+        if (destRelPath != null) {
+            destRelPath = getResourceName(destRelPath, false);
+        }
+
+        return destRelPath;
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Extend the general {@link #supportedLock} field by lock entries specific for this
+     * resource: write locks (exclusive or exclusive session-scoped) in case the underlaying
+     * node has the node type mix:lockable.
+     *
+     * @see org.apache.jackrabbit.JcrConstants#MIX_LOCKABLE
+     */
+    protected void initLockSupport() {
+        super.initLockSupport();
+        // add exclusive write lock if allowed for the given node
+        try {
+            if (exists() && ((Node)item).isNodeType(JcrConstants.MIX_LOCKABLE)) {
+                supportedLock.addEntry(Type.WRITE, Scope.EXCLUSIVE);
+                // TODO: do session-scoped lock properly (including session caching and proper scope discovery)
+                //supportedLock.addEntry(new SessionScopedLockEntry());
+            }
+        } catch (RepositoryException e) {
+            log.warn(e.getMessage());
+        }
+    }
+
+    /**
+     * Fill the property set for this resource.
+     */
+    protected void initProperties() {
+        super.initProperties();
+        if (exists()) {
+            try {
+                String prefix = "_tmp_" + item.getName();
+                // create tmpFile in default system-tmp directory
+                File tmpfile = File.createTempFile(prefix, null, null);
+                tmpfile.deleteOnExit();
+                FileOutputStream out = new FileOutputStream(tmpfile);
+                getSession().getRepositorySession().exportSystemView(item.getPath(), out, false, true);
+                out.close();
+                in = new FileInputStream(tmpfile);
+
+                properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, new Long(tmpfile.length())));
+                properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, "text/xml"));
+
+            } catch (IOException e) {
+                log.error("Error while property initialization: "+e.getMessage());
+            } catch (RepositoryException e) {
+                log.error("Error while property initialization: "+e.getMessage());
+            }
+
+            Node n = (Node)item;
+            // overwrite the default modificationtime if possible
+            try {
+		if (n.hasProperty(JcrConstants.JCR_LASTMODIFIED)) {
+                    setModificationTime(n.getProperty(JcrConstants.JCR_LASTMODIFIED).getLong());
+		}
+	    } catch (RepositoryException e) {
+		log.warn("Error while accessing jcr:lastModified property");
+	    }
+            // overwrite the default creation date if possible
+            try {
+                if (n.hasProperty(JcrConstants.JCR_CREATED)) {
+                    long creationTime = n.getProperty(JcrConstants.JCR_CREATED).getValue().getLong();
+                    properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE,
+                            DavConstants.creationDateFormat.format(new Date(creationTime))));
+                }
+            } catch (RepositoryException e) {
+                log.warn("Error while accessing jcr:created property");
+            }
+
+            // add node-specific resource properties
+	    try {
+                properties.add(new NodeTypeProperty(JCR_PRIMARYNODETYPE, n.getPrimaryNodeType(), false));
+                properties.add(new NodeTypeProperty(JCR_MIXINNODETYPES, n.getMixinNodeTypes(), false));
+                properties.add(new DefaultDavProperty(JCR_INDEX, new Integer(n.getIndex())));
+		addHrefProperty(JCR_REFERENCES, n.getReferences(), false);
+                if (n.isNodeType(JcrConstants.MIX_REFERENCEABLE)) {
+                    properties.add(new DefaultDavProperty(JCR_UUID, n.getUUID()));
+                }
+            } catch (RepositoryException e) {
+                log.error("Failed to retrieve primary nodetype property: " + e.getMessage());
+            }
+            try {
+                Item primaryItem = n.getPrimaryItem();
+                addHrefProperty(JCR_PRIMARYITEM, new Item[] {primaryItem}, false);
+            } catch (ItemNotFoundException e) {
+                log.info("No primary item present on this node '" + getResourcePath() + "'");
+            } catch (RepositoryException e) {
+                log.error("Error while retrieving primary item: " + e.getMessage());
+            }
+
+            // property defined by RFC 3648: this resource always has custom ordering!
+            if (isOrderable()) {
+                properties.add(new OrderingType(OrderingConstants.ORDERING_TYPE_CUSTOM));
+            }
+        }
+    }
+
+    /**
+     * Add a {@link org.apache.jackrabbit.webdav.property.HrefProperty} with the
+     * specified property name and values. Each item present in the specified
+     * values array is referenced in the resulting property.
+     *
+     * @param name
+     * @param values
+     * @param isProtected
+     */
+    protected void addHrefProperty(DavPropertyName name, Item[] values, boolean isProtected) {
+        if (values == null) {
+            return;
+        }
+        try {
+            String[] pHref = new String[values.length];
+            for (int i = 0; i < values.length; i++) {
+                pHref[i] = this.getLocatorFromResourcePath(values[i].getPath()).getHref(true);
+            }
+            properties.add(new HrefProperty(name, pHref, isProtected));
+        } catch (RepositoryException e) {
+            e.getMessage();
+        }
+    }
+
+    /**
+     * Add a new {@link HrefProperty href property} to the property set, where
+     * all items present in the specifed iterator are referenced in the
+     * resulting property.
+     *
+     * @param name
+     * @param itemIterator
+     * @param isProtected
+     * @see #addHrefProperty(DavPropertyName, Item[], boolean)
+     */
+    protected void addHrefProperty(DavPropertyName name, Iterator itemIterator,
+                                   boolean isProtected) {
+        ArrayList l = new ArrayList();
+        while (itemIterator.hasNext()) {
+            l.add(itemIterator.next());
+        }
+        addHrefProperty(name, (Item[]) l.toArray(new Item[l.size()]), isProtected);
+    }
+}
\ No newline at end of file

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

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