jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tri...@apache.org
Subject svn commit: r156314 [4/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:10 GMT
Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractResource.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractResource.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractResource.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractResource.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,500 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.*;
+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.spi.transaction.TxLockManagerImpl;
+import org.apache.jackrabbit.webdav.observation.*;
+import org.apache.jackrabbit.webdav.util.Text;
+import org.apache.jackrabbit.webdav.property.HrefProperty;
+import org.apache.jackrabbit.webdav.version.DeltaVConstants;
+import org.apache.jackrabbit.webdav.version.SupportedMethodSetProperty;
+import org.apache.jackrabbit.webdav.lock.*;
+import org.apache.jackrabbit.webdav.property.*;
+
+import java.io.InputStream;
+import java.util.*;
+
+/**
+ * <code>AbstractResource</code> provides functionality common to all
+ * resources.
+ */
+abstract class AbstractResource implements DavResource, ObservationResource,
+        TransactionResource {
+
+    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();
+
+    /**
+     * 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(true);
+    }
+
+    /**
+     * @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;
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * 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);
+
+        // 'workspace' property as defined by RFC 3253
+        String workspaceHref = getWorkspaceHref();
+        if (workspaceHref != null) {
+           properties.add(new HrefProperty(DeltaVConstants.WORKSPACE, workspaceHref, true));
+        }
+        properties.add(new SupportedMethodSetProperty(getSupportedMethods().split(",\\s")));
+    }
+
+    /**
+     * @return href of the workspace or <code>null</code> if this resource
+     * does not represent a repository item.
+     */
+    private String getWorkspaceHref() {
+        String workspaceHref = null;
+        if (locator != null && locator.getWorkspaceName() != null) {
+            workspaceHref = locator.getHref(isCollection());
+            if (locator.getResourcePath() != null) {
+                workspaceHref = workspaceHref.substring(workspaceHref.indexOf(locator.getResourcePath()));
+            }
+        }
+        return workspaceHref;
+    }
+
+    /**
+     * 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;
+    }
+}
\ No newline at end of file

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

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

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavLocatorFactoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavLocatorFactoryImpl.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavLocatorFactoryImpl.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavLocatorFactoryImpl.java Sun Mar  6 06:02:39 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.spi;
+
+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/spi/DavLocatorFactoryImpl.java
------------------------------------------------------------------------------
    svn = 

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

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavResourceFactoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavResourceFactoryImpl.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavResourceFactoryImpl.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavResourceFactoryImpl.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,202 @@
+/*
+ * 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.spi;
+
+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.spi.version.VersionItemCollection;
+import org.apache.jackrabbit.webdav.spi.version.VersionHistoryItemCollection;
+import org.apache.jackrabbit.webdav.spi.version.VersionControlledItemCollection;
+import org.apache.jackrabbit.webdav.spi.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 {
+
+        DavResource resource = null;
+        DavSession session = request.getDavSession();
+
+        if (locator.isRootLocation()) {
+            resource = new RootCollection(locator, session, this);
+        }
+
+        if (resource == null) {
+            try {
+                resource = createResourceForItem(locator, session);
+            } catch (RepositoryException e) {
+                // create the default resources if no such item exists
+
+                // 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);
+                } else {
+                    resource = new DefaultItemResource(locator, session, this);
+                }
+            }
+
+            // 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())) {
+                    try {
+                        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);
+                    } catch (RepositoryException e) {
+                        log.error("Failed to build version resource from "+locator.getHref(true)+" and label "+labelHeader);
+                        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 {
+                throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to create resource for "+locator.getHref(false));
+            }
+        }
+
+        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);
+            } else if (item instanceof VersionHistory) {
+                resource = new VersionHistoryItemCollection(locator, session, this);
+            } else if (ItemResourceConstants.ROOT_ITEM_PATH.equals(locator.getResourcePath())) {
+                resource =  new RootItemCollection(locator, session, this);
+            }  else{
+                resource = new VersionControlledItemCollection(locator, session, this);
+            }
+        } else {
+            resource = new DefaultItemResource(locator, session, this);
+        }
+        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/spi/DavResourceFactoryImpl.java
------------------------------------------------------------------------------
    svn = 

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

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemCollection.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemCollection.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemCollection.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemCollection.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,731 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.property.*;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.spi.lock.JcrActiveLock;
+import org.apache.jackrabbit.webdav.spi.nodetype.NodeTypeProperty;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.ordering.*;
+import org.apache.jackrabbit.webdav.util.Text;
+import org.apache.jackrabbit.webdav.lock.*;
+
+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) {
+        super(locator, session, factory);
+        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);
+                List 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)}
+     * 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
+                    getRepositorySession().importXML(getResourcePath(), in);
+                }
+            } 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();
+        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() + ")");
+        }
+        try {
+            session.getItem(member.getResourcePath()).remove();
+            complete();
+        } catch (RepositoryException e) {
+            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 = getWriteLock();
+        if (lock != null && lockToken.equals(lock.getToken())) {
+            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 #MIX_LOCKABLE
+     */
+    protected void initLockSupport() {
+        super.initLockSupport();
+        // add exclusive write lock if allowed for the given node
+        try {
+            if (exists() && ((Node)item).isNodeType(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().exportSysView(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(PROP_LASTMODIFIED)) {
+                    setModificationTime(n.getProperty(PROP_LASTMODIFIED).getLong());
+		}
+	    } catch (RepositoryException e) {
+		log.warn("Error while accessing jcr:lastModified property");
+	    }
+            // overwrite the default creation date if possible
+            try {
+                if (n.hasProperty(PROP_CREATED)) {
+                    long creationTime = n.getProperty(PROP_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 jcr-specific resource properties: primary-nodetype and mixin-nodetypes
+            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);
+            } catch (RepositoryException e) {
+                log.error("Failed to retrieve primary nodetype property: " + e.getMessage());
+            }
+
+            // jcr-specific primaryitem property
+            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/spi/DefaultItemCollection.java
------------------------------------------------------------------------------
    svn = 

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

Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemResource.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemResource.java?view=auto&rev=156314
==============================================================================
--- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemResource.java (added)
+++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemResource.java Sun Mar  6 06:02:39 2005
@@ -0,0 +1,379 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.Logger;
+import org.apache.jackrabbit.webdav.property.*;
+import org.apache.jackrabbit.webdav.*;
+import org.apache.jackrabbit.webdav.DavResource;
+import org.apache.jackrabbit.webdav.DavResourceIterator;
+import org.apache.jackrabbit.webdav.DavResourceIteratorImpl;
+import org.apache.jackrabbit.webdav.lock.*;
+import org.apache.jackrabbit.core.util.ValueHelper;
+import org.jdom.Element;
+
+import javax.jcr.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * <code>DefaultItemResource</code> represents JCR property item.
+ *
+ * @see Property
+ */
+public class DefaultItemResource extends AbstractItemResource {
+
+    private static Logger log = Logger.getLogger(DefaultItemResource.class);
+
+    /**
+     * Create a new <code>DefaultItemResource</code>.
+     *
+     * @param locator
+     * @param session
+     */
+    public DefaultItemResource(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
+        super(locator, session, factory);
+    }
+
+    //----------------------------------------------< DavResource interface >---
+    /**
+     * Returns false.
+     *
+     * @return false
+     * @see DavResource#isCollection()
+     */
+    public boolean isCollection() {
+        return false;
+    }
+
+    /**
+     * In case an underlaying repository {@link Property property} exists the following
+     * logic is applyed to obtain the stream:<ul>
+     * <li>Property is not multivalue: Return the {@link javax.jcr.Value#getStream()
+     * stream representation} of the property value.</li>
+     * <li>Property is multivalue: Return stream that provides the system view of
+     * that item.</li>
+     * </ul>
+     *
+     * @return
+     * @see DavResource#getStream()
+     */
+    public InputStream getStream() {
+        InputStream in = null;
+        if (exists()) {
+            try {
+                // NOTE: stream cannot be obtained for multivalue properties
+                if (!isMultiple()) {
+                    in = ((Property)item).getStream();
+                }
+            } catch (ValueFormatException e) {
+                // should not occur
+                log.error("Cannot obtain stream from resource: " + e.getMessage());
+            } catch (RepositoryException e) {
+                log.error("Cannot obtain stream from resource: " + e.getMessage());
+            }
+        }
+        return in;
+    }
+
+    /**
+     * Sets the given property. Note, that {@link #JCR_VALUE} and {@link #JCR_VALUES}
+     * are the only resource properties that are allowed to be modified. Any other
+     * property is read-only and will throw an exception ('Conflict').
+     *
+     * @param property
+     * @throws DavException
+     * @see DavResource#setProperty(org.apache.jackrabbit.webdav.property.DavProperty)
+     * @todo undo incomplete modifications...
+     */
+    public void setProperty(DavProperty property) throws DavException {
+        if (!exists()) {
+            throw new DavException(DavServletResponse.SC_NOT_FOUND);
+        }
+        try {
+            Property prop = (Property) item;
+            int type = prop.getType();
+            if (property.getName().equals(JCR_VALUE)) {
+                Value val = ValueHelper.convert(String.valueOf(property.getValue()), type);
+                prop.setValue(val);
+            } else if (property.getName().equals(JCR_VALUES)) {
+                prop.setValue(new ValuesProperty(property).getValues());
+            } else {
+                throw new DavException(DavServletResponse.SC_CONFLICT);
+            }
+            complete();
+
+        } catch (IllegalArgumentException e) {
+            throw new DavException(DavServletResponse.SC_BAD_REQUEST, e.getMessage());
+        } catch (RepositoryException e) {
+            throw new JcrDavException(e);
+        }
+    }
+
+    /**
+     * Removing properties is not allowed, for a single-value JCR-property without
+     * a value does not exist. For multivalue properties an empty {@link Value values array}
+     * may be specified with by setting the {@link #JCR_VALUES 'values' webdav property}.
+     *
+     * @param propertyName
+     * @throws DavException
+     * @see org.apache.jackrabbit.webdav.DavResource#removeProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
+     */
+    public void removeProperty(DavPropertyName propertyName) throws DavException {
+        if (!exists()) {
+            throw new DavException(DavServletResponse.SC_NOT_FOUND);
+        }
+        throw new DavException(DavServletResponse.SC_FORBIDDEN);
+    }
+
+    /**
+     * Method is not allowed.
+     *
+     * @see org.apache.jackrabbit.webdav.DavResource#addMember(org.apache.jackrabbit.webdav.DavResource, InputStream)
+     */
+    public void addMember(DavResource resource, InputStream in) throws DavException {
+        throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED, "Cannot add members to a non-collection resource");
+    }
+
+    /**
+     * Method is not allowed.
+     *
+     * @see DavResource#addMember(DavResource)
+     */
+    public void addMember(DavResource resource) throws DavException {
+        throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED, "Cannot add members to a non-collection resource");
+    }
+
+    /**
+     * Always returns an empty iterator for a non-collection resource might
+     * not have internal members.
+     *
+     * @return an empty iterator
+     * @see DavResource#getMembers()
+     */
+    public DavResourceIterator getMembers() {
+        log.warn("A non-collection resource never has internal members.");
+        return new DavResourceIteratorImpl(new ArrayList(0));
+    }
+
+    /**
+     * Method is not allowed.
+     *
+     * @see DavResource#removeMember(DavResource)
+     */
+    public void removeMember(DavResource member) throws DavException {
+        throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED, "Cannot remove members from a non-collection resource");
+    }
+
+    /**
+     * {@link javax.jcr.Property JCR properties} are locked if their
+     * parent node is locked; thus this method will always return the
+     * {@link ActiveLock lock} object from the collection this resource is
+     * internal member of.
+     *
+     * @param type
+     * @param scope
+     * @return lock present on this resource or <code>null</code> if this resource
+     * has no lock.
+     * @see DavResource#getLock(Type, Scope)
+     */
+    public ActiveLock getLock(Type type, Scope scope) {
+        if (Type.WRITE.equals(type)) {
+            return getCollection().getLock(type, scope);
+        } else {
+            return super.getLock(type, scope);
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Add resource specific properties.
+     */
+    protected void initProperties() {
+        super.initProperties();
+        if (exists()) {
+            try {
+                Property prop = (Property)item;
+                int type = prop.getType();
+
+                // set the content type
+                String contentType;
+                if (!isMultiple()) {
+                    contentType = (type == PropertyType.BINARY) ? "application/octet-stream" : "text/plain";
+                    properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, contentType));
+                } // else: no contenttype for multivalue properties
+
+                // add jcr-specific resource properties
+                properties.add(new DefaultDavProperty(JCR_TYPE, PropertyType.nameFromValue(type)));
+                if (isMultiple()) {
+                    properties.add(new ValuesProperty(prop.getValues()));
+                    properties.add(new LengthsProperty(prop.getLengths()));
+                } else {
+                    properties.add(new DefaultDavProperty(JCR_VALUE, prop.getString()));
+                    properties.add(new DefaultDavProperty(JCR_LENGTH, String.valueOf(prop.getLength())));
+                }
+            } catch (RepositoryException e) {
+                log.error("Failed to retrieve resource properties: "+e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Returns true if the JCR Property represented by this resource is a multi
+     * value property. Note: if this resource does not exist or if the definition
+     * could not be retrieved false is returned.
+     *
+     * @return true if the underlaying resource is a multi value property.
+     */
+    private boolean isMultiple() {
+        try {
+            if (exists() && ((Property)item).getDefinition().isMultiple()) {
+                return true;
+            }
+        } catch (RepositoryException e) {
+            log.error("Error while retrieving property definition: " + e.getMessage());
+        }
+        return false;
+    }
+
+    //------------------------------------------------------< inner classes >---
+    /**
+     * <code>ValuesProperty</code> extends {@link DavProperty} providing
+     * utilities to handle the multiple values of the property item represented
+     * by this resource.
+     */
+    private class ValuesProperty extends AbstractDavProperty {
+
+        private final Element[] value;
+
+        /**
+         * Wrap the specified <code>DavProperty</code> in a new <code>ValuesProperty</code>.
+         *
+         * @param property
+         */
+        private ValuesProperty(DavProperty property) {
+            super(JCR_VALUES, false);
+
+            if (!JCR_VALUES.equals(property.getName())) {
+               throw new IllegalArgumentException("ValuesProperty may only be created with a property that has name="+JCR_VALUES.getName());
+            }
+
+            Element[] elems = new Element[0];
+            if (property.getValue() instanceof List) {
+                Iterator elemIt = ((List)property.getValue()).iterator();
+                ArrayList valueElements = new ArrayList();
+                while (elemIt.hasNext()) {
+                    Object el = elemIt.next();
+                    /* make sure, only Elements with name 'value' are used for
+                     * the 'value' field. any other content (other elements, text,
+                     * comment etc.) is ignored. NO bad-request/conflict error is
+                     * thrown.
+                     */
+                    if (el instanceof Element && "value".equals(((Element)el).getName())) {
+                        valueElements.add(el);
+                    }
+                }
+                /* fill the 'value' with the valid 'value' elements found before */
+                elems = (Element[])valueElements.toArray(new Element[valueElements.size()]);
+            } else {
+                new IllegalArgumentException("ValuesProperty may only be created with a property that has a list of 'value' elements as content.");
+            }
+            // finally set the value to the DavProperty
+            value = elems;
+        }
+
+        /**
+         * Create a new <code>ValuesProperty</code> from the given {@link Value Value
+         * array}.
+         *
+         * @param values Array of Value objects as obtained from the JCR property.
+         */
+        private ValuesProperty(Value[] values) throws ValueFormatException, RepositoryException {
+            super(JCR_VALUES, false);
+
+            Element[] propValue = new Element[values.length];
+            for (int i = 0; i < values.length; i++) {
+                propValue[i] = new Element(XML_VALUE, ItemResourceConstants.NAMESPACE);
+                propValue[i].addContent(values[i].getString());
+            }
+            // finally set the value to the DavProperty
+            value = propValue;
+        }
+
+        /**
+         * Converts the value of this property to a {@link javax.jcr.Value value array}.
+         * Please note, that the convertion is done by using the {@link ValueHelper}
+         * class that is not part of the JSR170 API.
+         *
+         * @return Array of Value objects
+         * @throws RepositoryException
+         */
+        private Value[] getValues() throws ValueFormatException, RepositoryException {
+            Element[] propValue = (Element[])getValue();
+            Value[] values = new Value[propValue.length];
+            for (int i = 0; i < propValue.length; i++) {
+                values[i] = ValueHelper.convert(propValue[i].getText(), ((Property)item).getType());
+            }
+            return values;
+        }
+
+        /**
+         * Returns an array of {@link Element}s representing the value of this
+         * property.
+         *
+         * @return an array of {@link Element}s
+         */
+        public Object getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * <code>LengthsProperty</code> extends {@link DavProperty} providing
+     * utilities to handle the multiple lengths of the property item represented
+     * by this resource.
+     */
+    private class LengthsProperty extends AbstractDavProperty {
+
+        private final Element[] value;
+
+        /**
+         * Create a new <code>LengthsProperty</code> from the given long array.
+         *
+         * @param lengths as retrieved from the JCR property
+         */
+        private LengthsProperty(long[] lengths) {
+            super(JCR_LENGTHS, false);
+
+            Element[] elems = new Element[lengths.length];
+            for (int i = 0; i < lengths.length; i++) {
+                elems[i] = new Element(XML_LENGTH, ItemResourceConstants.NAMESPACE);
+                elems[i].addContent(String.valueOf(lengths[i]));
+            }
+            this.value = elems;
+        }
+
+        /**
+         * Returns an array of {@link Element}s representing the value of this
+         * property.
+         *
+         * @return an array of {@link Element}s
+         */
+        public Object getValue() {
+            return value;
+        }
+    }
+}
\ No newline at end of file

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

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



Mime
View raw message