You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@continuum.apache.org by ct...@apache.org on 2010/07/19 09:13:29 UTC

svn commit: r965372 [1/2] - in /continuum/trunk: ./ continuum-buildagent/ continuum-buildagent/continuum-buildagent-webapp/ continuum-buildagent/continuum-buildagent-webapp/src/main/webapp/WEB-INF/ continuum-buildagent/continuum-buildagent-webdav/ cont...

Author: ctan
Date: Mon Jul 19 07:13:27 2010
New Revision: 965372

URL: http://svn.apache.org/viewvc?rev=965372&view=rev
Log:
[CONTINUUM-2545] added WebDAV interface to continuum build agent for displaying working copies

Added:
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/pom.xml
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavLocatorFactory.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResource.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactory.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocator.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSession.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProvider.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/WorkingCopyServlet.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/IndexWriter.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WebdavMethodUtil.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WorkingCopyPathUtil.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactoryTest.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocatorTest.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProviderTest.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionTest.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/MockContinuumBuildAgentDavResourceFactory.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/WorkingCopyServletTest.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/util/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/util/WorkingCopyPathUtilTest.java
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/WEB-INF/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/WEB-INF/web.xml
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/org/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/org/apache/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/org/apache/continuum/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/org/apache/continuum/webdav/
    continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/resources/org/apache/continuum/webdav/WorkingCopyServletTest.xml
Modified:
    continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/pom.xml
    continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/src/main/webapp/WEB-INF/web.xml
    continuum/trunk/continuum-buildagent/pom.xml
    continuum/trunk/pom.xml

Modified: continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/pom.xml
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/pom.xml?rev=965372&r1=965371&r2=965372&view=diff
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/pom.xml (original)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/pom.xml Mon Jul 19 07:13:27 2010
@@ -44,6 +44,11 @@
       <scope>runtime</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.continuum</groupId>
+      <artifactId>continuum-buildagent-webdav</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
       <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-taskqueue</artifactId>
     </dependency>
@@ -72,7 +77,6 @@
     <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
-      <version>2.4</version>
       <scope>provided</scope>
     </dependency>
     <dependency>

Modified: continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/src/main/webapp/WEB-INF/web.xml?rev=965372&r1=965371&r2=965372&view=diff
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/src/main/webapp/WEB-INF/web.xml (original)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webapp/src/main/webapp/WEB-INF/web.xml Mon Jul 19 07:13:27 2010
@@ -64,8 +64,22 @@
     <load-on-startup>1</load-on-startup>
   </servlet>
   
+  <servlet>
+    <servlet-name>WorkingCopyServlet</servlet-name>
+    <servlet-class>
+      org.apache.continuum.webdav.WorkingCopyServlet
+    </servlet-class>
+    <!-- Loading this on startup so as to take advantage of configuration listeners -->
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
   <servlet-mapping>
     <servlet-name>SlaveXmlRpcServlet</servlet-name>
     <url-pattern>/xmlrpc</url-pattern>
   </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>WorkingCopyServlet</servlet-name>
+    <url-pattern>/workingcopy/*</url-pattern>
+  </servlet-mapping>
 </web-app>

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/pom.xml
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/pom.xml?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/pom.xml (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/pom.xml Mon Jul 19 07:13:27 2010
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.continuum</groupId>
+    <artifactId>continuum-buildagent</artifactId>
+    <version>1.4.1-SNAPSHOT</version>
+  </parent>
+  <artifactId>continuum-buildagent-webdav</artifactId>
+  <name>Continuum :: Distributed Build :: Build Agent :: Webdav</name>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.continuum</groupId>
+      <artifactId>continuum-buildagent-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-webdav</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>joda-time</groupId>
+      <artifactId>joda-time</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>httpunit</groupId>
+      <artifactId>httpunit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavLocatorFactory.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavLocatorFactory.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavLocatorFactory.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavLocatorFactory.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,69 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.continuum.webdav.util.WorkingCopyPathUtil;
+import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+
+public class ContinuumBuildAgentDavLocatorFactory
+    implements DavLocatorFactory
+{
+    public DavResourceLocator createResourceLocator( String prefix, String href )
+    {
+        // build prefix string and remove all prefixes from the given href.
+        StringBuilder b = new StringBuilder();
+        if ( prefix != null && prefix.length() > 0 )
+        {
+            b.append( prefix );
+            if ( !prefix.endsWith( "/" ) )
+            {
+                b.append( '/' );
+            }
+            if ( href.startsWith( prefix ) )
+            {
+                href = href.substring( prefix.length() );
+            }
+        }
+
+        // special treatment for root item, that has no name but '/' path.
+        if ( href == null || "".equals( href ) )
+        {
+            href = "/";
+        }
+
+        final int projectId = WorkingCopyPathUtil.getProjectId( href );
+        return new ContinuumBuildAgentDavResourceLocator( b.toString(), Text.unescape( href ), this, projectId );
+    }
+
+    public DavResourceLocator createResourceLocator( String prefix, String workspacePath, String resourcePath )
+    {
+        return createResourceLocator( prefix, workspacePath, resourcePath, true );
+    }
+
+    public DavResourceLocator createResourceLocator( String prefix, String workspacePath, String path,
+                                                     boolean isResourcePath )
+    {
+        final int projectId = WorkingCopyPathUtil.getProjectId( path );
+        return new ContinuumBuildAgentDavResourceLocator( prefix, path, this, projectId );
+    }
+
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResource.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResource.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResource.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResource.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,402 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.activation.MimetypesFileTypeMap;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.continuum.webdav.util.IndexWriter;
+import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavResource;
+import org.apache.jackrabbit.webdav.DavResourceFactory;
+import org.apache.jackrabbit.webdav.DavResourceIterator;
+import org.apache.jackrabbit.webdav.DavResourceIteratorImpl;
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+import org.apache.jackrabbit.webdav.DavSession;
+import org.apache.jackrabbit.webdav.MultiStatusResponse;
+import org.apache.jackrabbit.webdav.io.InputContext;
+import org.apache.jackrabbit.webdav.io.OutputContext;
+import org.apache.jackrabbit.webdav.lock.ActiveLock;
+import org.apache.jackrabbit.webdav.lock.LockInfo;
+import org.apache.jackrabbit.webdav.lock.LockManager;
+import org.apache.jackrabbit.webdav.lock.Scope;
+import org.apache.jackrabbit.webdav.lock.Type;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
+import org.apache.jackrabbit.webdav.property.ResourceType;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ContinuumBuildAgentDavResource
+    implements DavResource
+{
+    private static final Logger log = LoggerFactory.getLogger( ContinuumBuildAgentDavResource.class );
+
+    private final ContinuumBuildAgentDavResourceLocator locator;
+
+    private final DavResourceFactory factory;
+
+    private final File localResource;
+
+    private final String logicalResource;
+
+    private final DavSession session;
+
+    private final MimetypesFileTypeMap mimeTypes;
+
+    private DavPropertySet properties = null;
+
+    public static final String COMPLIANCE_CLASS = "1, 2";
+
+    public static final String HIDDEN_PATH_PREFIX = ".";
+
+    public static final String SUPPORTED_METHODS = "OPTIONS, GET, HEAD, TRACE, PROPFIND";
+
+    public ContinuumBuildAgentDavResource( String localResource, String logicalResource,
+                                           DavSession session, ContinuumBuildAgentDavResourceLocator locator,
+                                           DavResourceFactory factory, MimetypesFileTypeMap mimeTypes )
+    {
+        this.localResource = new File( localResource );
+        this.logicalResource = logicalResource;
+        this.locator = locator;
+        this.factory = factory;
+        this.session = session;
+        this.mimeTypes = mimeTypes;
+    }
+
+    public void addLockManager( LockManager lockManager )
+    {
+    }
+
+    public void addMember( DavResource davResource, InputContext arg1 )
+        throws DavException
+    {
+        throw new UnsupportedOperationException( "Not supported" );
+    }
+
+    public MultiStatusResponse alterProperties( List changeList )
+        throws DavException
+    {
+        return null;
+    }
+
+    public MultiStatusResponse alterProperties( DavPropertySet setProperties, DavPropertyNameSet removePropertyNames )
+        throws DavException
+    {
+        return null;
+    }
+
+    public void copy( DavResource destination, boolean shallow )
+        throws DavException
+    {
+        throw new UnsupportedOperationException( "Not supported" );
+    }
+
+    public boolean exists()
+    {
+        return localResource.exists();
+    }
+
+    public DavResource getCollection()
+    {
+        DavResource parent = null;
+        if ( getResourcePath() != null && !"/".equals( getResourcePath() ) )
+        {
+            String parentPath = Text.getRelativeParent( getResourcePath(), 1 );
+            if ( "".equals( parentPath ) )
+            {
+                parentPath = "/";
+            }
+
+            DavResourceLocator parentloc = locator.getFactory().createResourceLocator( locator.getPrefix(), 
+                                                                                       parentPath );
+
+            try
+            {
+                parent = factory.createResource( parentloc, session );
+            }
+            catch ( DavException e )
+            {
+                // should not occur
+            }
+        }
+        return parent;
+    }
+
+    public String getComplianceClass()
+    {
+        return COMPLIANCE_CLASS;
+    }
+
+    public String getDisplayName()
+    {
+        String resPath = getResourcePath();
+        return ( resPath != null ) ? Text.getName( resPath ) : resPath;
+    }
+
+    public DavResourceFactory getFactory()
+    {
+        return factory;
+    }
+
+    public String getHref()
+    {
+        return locator.getHref( isCollection() );
+    }
+
+    public File getLocalResource()
+    {
+        return localResource;
+    }
+
+    public DavResourceLocator getLocator()
+    {
+        return locator;
+    }
+
+    public ActiveLock getLock( Type type, Scope scope )
+    {
+        return null;
+    }
+
+    public ActiveLock[] getLocks()
+    {
+        return null;
+    }
+
+    public DavResourceIterator getMembers()
+    {
+        List<DavResource> list = new ArrayList<DavResource>();
+        if ( exists() && isCollection() )
+        {
+            for ( String item : localResource.list() )
+            {
+                try
+                {
+                    if ( !item.startsWith( HIDDEN_PATH_PREFIX ) )
+                    {
+                        String path = locator.getResourcePath() + '/' + item;
+                        DavResourceLocator resourceLocator = locator.getFactory().createResourceLocator(
+                            locator.getPrefix(), path );
+                        DavResource resource = factory.createResource( resourceLocator, session );
+
+                        if ( resource != null )
+                        {
+                            log.debug( "Retrieved resource: " + resource.getResourcePath() );
+                            list.add( resource );
+                        }
+                    }
+                }
+                catch ( DavException e )
+                {
+                    // should not occur
+                }
+            }
+        }
+
+        return new DavResourceIteratorImpl( list );
+    }
+
+    public long getModificationTime()
+    {
+        return localResource.lastModified();
+    }
+
+    public DavPropertySet getProperties()
+    {
+        return initProperties();
+    }
+
+    public DavProperty getProperty( DavPropertyName propertyName )
+    {
+        return getProperties().get( propertyName );
+    }
+
+    public DavPropertyName[] getPropertyNames()
+    {
+        return getProperties().getPropertyNames();
+    }
+
+    public String getResourcePath()
+    {
+        return locator.getResourcePath();
+    }
+
+    public DavSession getSession()
+    {
+        return session;
+    }
+
+    public String getSupportedMethods()
+    {
+        return SUPPORTED_METHODS;
+    }
+
+    public boolean hasLock( Type type, Scope scope )
+    {
+        return false;
+    }
+
+    public boolean isCollection()
+    {
+        return localResource.isDirectory();
+    }
+
+    public boolean isLockable( Type type, Scope scope )
+    {
+        return false;
+    }
+
+    public ActiveLock lock( LockInfo lockInfo )
+        throws DavException
+    {
+        return null;
+    }
+
+    public void move( DavResource destination )
+        throws DavException
+    {
+        throw new UnsupportedOperationException( "Not supported" );
+    }
+
+    public ActiveLock refreshLock( LockInfo lockInfo, String lockTocken )
+        throws DavException
+    {
+        return null;
+    }
+
+    public void removeMember( DavResource member )
+        throws DavException
+    {
+        throw new UnsupportedOperationException( "Not supported" );
+    }
+
+    public void removeProperty( DavPropertyName propertyName )
+        throws DavException
+    {
+        throw new UnsupportedOperationException( "Not supported" );
+    }
+
+    public void setProperty( DavProperty property )
+        throws DavException
+    {
+        throw new UnsupportedOperationException( "Not supported" );
+    }
+
+    public void spool( OutputContext outputContext )
+        throws IOException
+    {
+        if ( !isCollection() )
+        {
+            outputContext.setContentLength( localResource.length() );
+            outputContext.setContentType( mimeTypes.getContentType( localResource ) );
+        }
+
+        if ( !isCollection() && outputContext.hasStream() )
+        {
+            FileInputStream is = null;
+            try
+            {
+                // Write content to stream
+                is = new FileInputStream( localResource );
+                IOUtils.copy( is, outputContext.getOutputStream() );
+            }
+            finally
+            {
+                IOUtils.closeQuietly( is );
+            }
+        }
+        else if ( outputContext.hasStream() )
+        {
+            IndexWriter writer = new IndexWriter( this, localResource, logicalResource );
+            writer.write( outputContext );
+        }
+    }
+
+    public void unlock( String lockTocken )
+        throws DavException
+    {
+    }
+
+    /**
+     * Fill the set of properties
+     */
+    protected DavPropertySet initProperties()
+    {
+        if ( !exists() )
+        {
+            properties = new DavPropertySet();
+        }
+
+        if ( properties != null )
+        {
+            return properties;
+        }
+
+        DavPropertySet properties = new DavPropertySet();
+
+        // set (or reset) fundamental properties
+        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" ) );
+        }
+
+        // Need to get the ISO8601 date for properties
+        DateTime dt = new DateTime( localResource.lastModified() );
+        DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+        String modifiedDate = fmt.print( dt );
+
+        properties.add( new DefaultDavProperty( DavPropertyName.GETLASTMODIFIED, modifiedDate ) );
+
+        properties.add( new DefaultDavProperty( DavPropertyName.CREATIONDATE, modifiedDate ) );
+
+        properties.add( new DefaultDavProperty( DavPropertyName.GETCONTENTLENGTH, localResource.length() ) );
+
+        this.properties = properties;
+
+        return properties;
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactory.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactory.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactory.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactory.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,165 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.File;
+
+import javax.activation.MimetypesFileTypeMap;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.continuum.buildagent.configuration.BuildAgentConfigurationService;
+import org.apache.continuum.webdav.util.WebdavMethodUtil;
+import org.apache.continuum.webdav.util.WorkingCopyPathUtil;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavResource;
+import org.apache.jackrabbit.webdav.DavResourceFactory;
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+import org.apache.jackrabbit.webdav.DavServletRequest;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.DavSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ContinuumBuildAgentDavResourceFactory
+    implements DavResourceFactory
+{
+    private static final Logger log = LoggerFactory.getLogger( ContinuumBuildAgentDavResourceFactory.class );
+
+    private static final MimetypesFileTypeMap mimeTypes;
+
+    /**
+     * @plexus.requirement
+     */
+    private BuildAgentConfigurationService buildAgentConfigurationService;
+
+    static
+    {
+        mimeTypes = new MimetypesFileTypeMap();
+        mimeTypes.addMimeTypes( "application/java-archive jar war ear" );
+        mimeTypes.addMimeTypes( "application/java-class class" );
+        mimeTypes.addMimeTypes( "image/png png" );
+    }
+
+    public DavResource createResource( final DavResourceLocator locator, final DavSession davSession )
+        throws DavException
+    {
+        ContinuumBuildAgentDavResourceLocator continuumLocator = 
+            checkLocatorIsInstanceOfContinuumBuildAgentLocator( locator );
+
+        String logicalResource = WorkingCopyPathUtil.getLogicalResource( locator.getResourcePath() );
+        if ( logicalResource.startsWith( "/" ) )
+        {
+            logicalResource = logicalResource.substring( 1 );
+        }
+
+        File resourceFile = getResourceFile( continuumLocator.getProjectId(), logicalResource );
+
+        if ( !resourceFile.exists() || ( continuumLocator.getHref( false ).endsWith( "/" ) && !resourceFile.isDirectory() ) )
+        {
+            // force a resource not found
+            log.error( "Resource file '" + resourceFile.getAbsolutePath() + "' does not exist" );
+            throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" );
+        }
+        else
+        {
+            DavResource resource = new ContinuumBuildAgentDavResource( resourceFile.getAbsolutePath(), logicalResource,
+                                                                       davSession, continuumLocator, this, mimeTypes );
+            return resource;
+        }
+    }
+
+    public DavResource createResource( DavResourceLocator locator, DavServletRequest request, 
+                                       DavServletResponse response )
+        throws DavException
+    {
+        ContinuumBuildAgentDavResourceLocator continuumLocator = 
+            checkLocatorIsInstanceOfContinuumBuildAgentLocator( locator );
+
+        if ( !WebdavMethodUtil.isReadMethod( request.getMethod() ) )
+        {
+            throw new DavException( HttpServletResponse.SC_METHOD_NOT_ALLOWED,
+                                    "Write method not allowed in working copy" );
+        }
+
+        String logicalResource = WorkingCopyPathUtil.getLogicalResource( continuumLocator.getResourcePath() );
+        if ( logicalResource.startsWith( "/" ) )
+        {
+            logicalResource = logicalResource.substring( 1 );
+        }
+
+        File resourceFile = getResourceFile( continuumLocator.getProjectId(), logicalResource );
+
+        if ( !resourceFile.exists() || ( continuumLocator.getHref( false ).endsWith( "/" ) && !resourceFile.isDirectory() ) )
+        {
+            // force a resource not found
+            log.error( "Resource file '" + resourceFile.getAbsolutePath() + "' does not exist" );
+            throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" );
+        }
+        else
+        {
+            DavResource resource = new ContinuumBuildAgentDavResource( resourceFile.getAbsolutePath(), logicalResource,
+                                                                       request.getDavSession(), continuumLocator, this,
+                                                                       mimeTypes );
+            return resource;
+        }
+    }
+
+    public BuildAgentConfigurationService getBuildAgentConfigurationService()
+    {
+        return buildAgentConfigurationService;
+    }
+
+    public void setBuildAgentConfigurationService( BuildAgentConfigurationService buildAgentConfigurationService )
+    {
+        this.buildAgentConfigurationService = buildAgentConfigurationService;
+    }
+
+    private ContinuumBuildAgentDavResourceLocator checkLocatorIsInstanceOfContinuumBuildAgentLocator( DavResourceLocator locator )
+        throws DavException
+    {
+        if ( !( locator instanceof ContinuumBuildAgentDavResourceLocator ) )
+        {
+            throw new DavException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                                    "Locator does not implement ContinuumBuildAgentLocator" );
+        }
+
+        // Hidden paths
+        if ( locator.getResourcePath().startsWith( ContinuumBuildAgentDavResource.HIDDEN_PATH_PREFIX ) )
+        {
+            throw new DavException( HttpServletResponse.SC_NOT_FOUND );
+        }
+
+        ContinuumBuildAgentDavResourceLocator continuumLocator = (ContinuumBuildAgentDavResourceLocator) locator;
+        if ( continuumLocator.getProjectId() <= 0 )
+        {
+            log.error( "Invalid project id: " + continuumLocator.getProjectId() );
+            throw new DavException( HttpServletResponse.SC_NO_CONTENT );
+        }
+
+        return continuumLocator;
+    }
+
+    protected File getResourceFile( int projectId, String logicalResource )
+    {
+        File workingDir = buildAgentConfigurationService.getWorkingDirectory( projectId );
+
+        return new File( workingDir, logicalResource );
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocator.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocator.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocator.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocator.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,157 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+
+public class ContinuumBuildAgentDavResourceLocator
+    implements DavResourceLocator
+{
+    private final String prefix;
+
+    private final String resourcePath;
+
+    private final String href;
+
+    private final DavLocatorFactory davLocatorFactory;
+
+    private final int projectId;
+
+    public ContinuumBuildAgentDavResourceLocator( String prefix, String resourcePath, 
+                                                  DavLocatorFactory davLocatorFactory,
+                                                  int projectId )
+    {
+        this.prefix = prefix;
+        this.davLocatorFactory = davLocatorFactory;
+        this.projectId = projectId;
+
+        String escapedPath = Text.escapePath( resourcePath );
+        String hrefPrefix = prefix;
+
+        // Ensure no extra slashes when href is joined
+        if ( hrefPrefix.endsWith( "/" ) && escapedPath.startsWith( "/" ) )
+        {
+            hrefPrefix = hrefPrefix.substring( 0, hrefPrefix.length() - 1 );
+        }
+
+        href = hrefPrefix + escapedPath;
+
+        String path = resourcePath;
+
+        if ( !resourcePath.startsWith("/") )
+        {
+            path = "/" + resourcePath;
+        }
+
+        //Remove trailing slashes otherwise Text.getRelativeParent fails
+        if ( resourcePath.endsWith( "/" ) && resourcePath.length() > 1 )
+        {
+            path = resourcePath.substring( 0, resourcePath.length() - 1 );
+        }
+
+        this.resourcePath = path;
+    }
+
+    public DavLocatorFactory getFactory()
+    {
+        return davLocatorFactory;
+    }
+
+    public String getHref( boolean isCollection )
+    {
+        // avoid doubled trailing '/' for the root item
+        String suffix = ( isCollection && !isRootLocation() && !href.endsWith("/") ) ? "/" : "";
+        return href + suffix;
+    }
+
+    public String getPrefix()
+    {
+        return prefix;
+    }
+
+    public int getProjectId()
+    {
+        return projectId;
+    }
+
+    public String getRepositoryPath()
+    {
+        return getResourcePath();
+    }
+
+    public String getResourcePath()
+    {
+        return resourcePath;
+    }
+
+    public String getWorkspaceName()
+    {
+        return "";
+    }
+
+    public String getWorkspacePath()
+    {
+        return "";
+    }
+
+    /**
+     * Computes the hash code from the href, which is built using the final fields prefix and resourcePath.
+     * 
+     * @return the hash code
+     */
+    public int hashCode()
+    {
+        return href.hashCode();
+    }
+
+    public boolean isRootLocation()
+    {
+        return "/".equals( resourcePath );
+    }
+
+    public boolean isSameWorkspace( DavResourceLocator locator )
+    {
+        return isSameWorkspace( locator.getWorkspaceName() );
+    }
+
+    public boolean isSameWorkspace( String workspaceName )
+    {
+        return getWorkspaceName().equals( workspaceName );
+    }
+
+    /**
+     * Equality of path is achieved if the specified object is a <code>DavResourceLocator</code> object with the same
+     * hash code.
+     * 
+     * @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 DavResourceLocator )
+        {
+            DavResourceLocator other = (DavResourceLocator) obj;
+            return hashCode() == other.hashCode();
+        }
+        return false;
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSession.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSession.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSession.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSession.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,56 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.HashSet;
+
+import org.apache.jackrabbit.webdav.DavSession;
+
+public class ContinuumBuildAgentDavSession
+    implements DavSession
+{
+    private final HashSet<String> lockTokens = new HashSet<String>();
+
+    public void addLockToken( String token )
+    {
+        lockTokens.add( token );
+    }
+
+    public void addReference( Object reference )
+    {
+        throw new UnsupportedOperationException( "Not supported yet" );
+    }
+
+    public String[] getLockTokens()
+    {
+        return (String[]) lockTokens.toArray( new String[lockTokens.size()] );
+    }
+
+    public void removeLockToken( String token )
+    {
+        lockTokens.remove( token );
+    }
+
+    public void removeReference( Object reference )
+    {
+        throw new UnsupportedOperationException( "Not supported yet" );
+    }
+
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProvider.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProvider.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProvider.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProvider.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,43 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavSessionProvider;
+import org.apache.jackrabbit.webdav.WebdavRequest;
+
+public class ContinuumBuildAgentDavSessionProvider
+    implements DavSessionProvider
+{
+    public boolean attachSession( WebdavRequest request )
+        throws DavException
+    {
+        // TODO check if user is authorized
+
+        request.setDavSession( new ContinuumBuildAgentDavSession() );
+
+        return true;
+    }
+
+    public void releaseSession( WebdavRequest request )
+    {
+        request.setDavSession(null);
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/WorkingCopyServlet.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/WorkingCopyServlet.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/WorkingCopyServlet.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/WorkingCopyServlet.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,129 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+import org.apache.jackrabbit.webdav.DavResource;
+import org.apache.jackrabbit.webdav.DavResourceFactory;
+import org.apache.jackrabbit.webdav.DavSessionProvider;
+import org.apache.jackrabbit.webdav.WebdavRequest;
+import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
+import org.codehaus.plexus.spring.PlexusToSpringUtils;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+public class WorkingCopyServlet
+    extends AbstractWebdavServlet
+{
+    private DavLocatorFactory locatorFactory;
+
+    private DavResourceFactory resourceFactory;
+
+    private DavSessionProvider sessionProvider;
+
+    @Override
+    public void init( ServletConfig servletConfig )
+        throws ServletException
+    {
+        super.init( servletConfig );
+        initServers( servletConfig );
+    }
+
+    public synchronized void initServers( ServletConfig servletConfig )
+    {
+        WebApplicationContext wac =
+            WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
+
+        resourceFactory =
+            (DavResourceFactory) wac.getBean( PlexusToSpringUtils.
+                                              buildSpringId( ContinuumBuildAgentDavResourceFactory.class ) );
+        locatorFactory = new ContinuumBuildAgentDavLocatorFactory();
+        sessionProvider = new ContinuumBuildAgentDavSessionProvider();
+    }
+
+    @Override
+    public String getAuthenticateHeaderValue()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DavSessionProvider getDavSessionProvider()
+    {
+        return sessionProvider;
+    }
+
+    @Override
+    public DavLocatorFactory getLocatorFactory()
+    {
+        return locatorFactory;
+    }
+
+    @Override
+    public DavResourceFactory getResourceFactory()
+    {
+        return resourceFactory;
+    }
+
+    @Override
+    protected boolean isPreconditionValid( WebdavRequest request, DavResource resource )
+    {
+        // TODO Auto-generated method stub
+        return true;
+    }
+
+    @Override
+    public void setDavSessionProvider( final DavSessionProvider sessionProvider )
+    {
+        this.sessionProvider = sessionProvider;
+    }
+
+    @Override
+    public void setLocatorFactory( final DavLocatorFactory locatorFactory )
+    {
+        this.locatorFactory = locatorFactory;
+    }
+
+    @Override
+    public void setResourceFactory( DavResourceFactory resourceFactory )
+    {
+        this.resourceFactory = resourceFactory;
+    }
+
+    @Override
+    public void destroy()
+    {
+        resourceFactory = null;
+        locatorFactory = null;
+        sessionProvider = null;
+
+        WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
+
+        if ( wac instanceof ConfigurableApplicationContext )
+        {
+            ( (ConfigurableApplicationContext) wac ).close();
+        }
+        super.destroy();
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/IndexWriter.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/IndexWriter.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/IndexWriter.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/IndexWriter.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,128 @@
+package org.apache.continuum.webdav.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.jackrabbit.webdav.DavResource;
+import org.apache.jackrabbit.webdav.io.OutputContext;
+
+public class IndexWriter
+{
+    private final String logicalResource;
+    
+    private final List<File> localResources;
+
+    public IndexWriter( DavResource resource, File localResource, String logicalResource )
+    {
+        this.localResources = new ArrayList<File>();
+        this.localResources.add( localResource );
+        this.logicalResource = logicalResource;
+    }
+
+    public IndexWriter( DavResource resource, List<File> localResources, String logicalResource )
+    {
+        this.localResources = localResources;
+        this.logicalResource = logicalResource;
+    }
+
+    public void write( OutputContext outputContext )
+    {
+        outputContext.setModificationTime(new Date().getTime());
+        outputContext.setContentType("text/html");
+        outputContext.setETag("");
+        if ( outputContext.hasStream() )
+        {
+            PrintWriter writer = new PrintWriter( outputContext.getOutputStream() );
+            writeDocumentStart( writer );
+            writeHyperlinks(writer);
+            writeDocumentEnd(writer);
+            writer.flush();
+            writer.close();
+        }
+    }
+
+    private void writeDocumentStart( PrintWriter writer )
+    {
+        writer.println( "<html>" );
+        writer.println( "<head>" );
+        writer.println( "<title>Working Copy: /" + logicalResource + "</title>" );
+        writer.println( "</head>" );
+        writer.println( "<body>" );
+        writer.println( "<h3>Working Copy: /" + logicalResource + "</h3>" );
+
+        // Check if not root
+        if ( logicalResource.length() > 0 )
+        {
+            File file = new File( logicalResource );
+            String parentName = file.getParent() == null ? "/" : file.getParent();
+
+            //convert to unix path in case archiva is hosted on windows
+            parentName = StringUtils.replace( parentName, "\\", "/" );
+
+            writer.println( "<ul>" );
+            writer.println( "<li><a href=\"../\">" + parentName + "</a> <i><small>(Parent)</small></i></li>" );
+            writer.println( "</ul>" );
+        }
+        
+        writer.println( "</ul>" );
+    }
+
+    private void writeDocumentEnd( PrintWriter writer )
+    {
+        writer.println( "</ul>" );
+        writer.println( "</body>" );
+        writer.println( "</html>" );
+    }
+
+    private void writeHyperlinks( PrintWriter writer )
+    {
+        for ( File localResource : localResources )
+        {
+            List<File> files = new ArrayList<File>( Arrays.asList( localResource.listFiles() ) ); 
+            Collections.sort( files );
+            
+            for ( File file : files )
+            {
+                writeHyperlink( writer, file.getName(), file.isDirectory() );
+            }
+        }
+    }
+
+    private void writeHyperlink( PrintWriter writer, String resourceName, boolean directory )
+    {        
+        if ( directory && !"CVS".equals( resourceName ) && !".svn".equals( resourceName ) && !"SCCS".equals( resourceName ) )
+        {
+            writer.println( "<li><a href=\"" + resourceName + "/\">" + resourceName + "</a></li>" );
+        }
+        else if ( !directory && !".cvsignore".equals( resourceName ) && !"vssver.scc".equals( resourceName ) &&
+                !".DS_Store".equals( resourceName ) && !"release.properties".equals( resourceName ) )
+        {
+            writer.println( "<li><a href=\"" + resourceName + "\">" + resourceName + "</a></li>" );
+        }
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WebdavMethodUtil.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WebdavMethodUtil.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WebdavMethodUtil.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WebdavMethodUtil.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,50 @@
+package org.apache.continuum.webdav.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.lang.StringUtils;
+
+public class WebdavMethodUtil
+{
+    private static final List<String> READ_METHODS;
+
+    static
+    {
+        READ_METHODS = new ArrayList<String>();
+        READ_METHODS.add( "HEAD" );
+        READ_METHODS.add( "GET" );
+        READ_METHODS.add( "PROPFIND" );
+        READ_METHODS.add( "OPTIONS" );
+        READ_METHODS.add( "REPORT" );
+    }
+
+    public static boolean isReadMethod( String method )
+    {
+        if ( StringUtils.isBlank( method ) )
+        {
+            throw new IllegalArgumentException( "WebDAV method is empty" );
+        }
+        return READ_METHODS.contains( method.toUpperCase( Locale.US ) );
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WorkingCopyPathUtil.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WorkingCopyPathUtil.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WorkingCopyPathUtil.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/main/java/org/apache/continuum/webdav/util/WorkingCopyPathUtil.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,121 @@
+package org.apache.continuum.webdav.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+
+public class WorkingCopyPathUtil
+{
+    public static String getLogicalResource( final String href )
+    {
+        String logicalResource = null;
+        String requestPathInfo = StringUtils.defaultString( href );
+
+        //remove prefix ie /workingcopy/blah becomes /blah
+        requestPathInfo = removePrefix( requestPathInfo );
+
+        // Remove prefixing slash as the project id doesn't contain it;
+        if ( requestPathInfo.startsWith( "/" ) )
+        {
+            requestPathInfo = requestPathInfo.substring( 1 );
+        }        
+
+        int slash = requestPathInfo.indexOf( '/' );
+        if ( slash > 0 )
+        {   
+            logicalResource = requestPathInfo.substring( slash );
+         
+            if (logicalResource.endsWith( "/.." ) )
+            {
+                logicalResource += "/";
+            }
+            
+            if ( logicalResource != null && logicalResource.startsWith( "//" ) )
+            {
+                logicalResource = logicalResource.substring( 1 );
+            }
+            
+            if ( logicalResource == null )
+            {
+                logicalResource = "/";
+            }
+        }
+        else
+        {
+            logicalResource = "/";
+        }
+        return logicalResource;
+    }
+
+    public static int getProjectId( final String href )
+    {
+        String requestPathInfo = StringUtils.defaultString( href );
+
+        // Remove prefix ie /workingcopy/blah becomes /blah
+        requestPathInfo = removePrefix( requestPathInfo );
+
+        // Remove prefixing slash as the project id doesn't contain it;
+        if ( requestPathInfo.startsWith( "/" ) )
+        {
+            requestPathInfo = requestPathInfo.substring( 1 );
+        }
+
+        int projectId = 0;
+        
+        try
+        {
+            // Find first element, if slash exists.
+            int slash = requestPathInfo.indexOf( '/' );
+            if ( slash > 0 )
+            {
+                // Filtered: "1/src/main/java/" -> "1"
+                projectId = Integer.parseInt( requestPathInfo.substring( 0, slash ) );
+            }
+            else
+            {
+                projectId = Integer.parseInt( requestPathInfo );
+            }
+        }
+        catch ( NumberFormatException e )
+        {
+        }
+
+        return projectId;
+    }
+
+    private static String removePrefix( final String href )
+    {
+        String[] parts = StringUtils.split( href, '/' );
+        parts = (String[]) ArrayUtils.subarray( parts, 1, parts.length );
+        if ( parts == null || parts.length == 0 )
+        {
+            return "/";
+        }
+        
+        String joinedString = StringUtils.join( parts, '/' );        
+        if( href.endsWith( "/" ) )
+        {
+            joinedString = joinedString + "/";
+        }
+        
+        return joinedString;
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactoryTest.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactoryTest.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactoryTest.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceFactoryTest.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,155 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.File;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.continuum.buildagent.configuration.BuildAgentConfigurationService;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+import org.apache.jackrabbit.webdav.DavServletRequest;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.codehaus.plexus.spring.PlexusInSpringTestCase;
+import org.easymock.MockControl;
+
+public class ContinuumBuildAgentDavResourceFactoryTest
+    extends PlexusInSpringTestCase
+{
+    private MockControl requestControl;
+
+    private DavServletRequest request;
+
+    private MockControl responseControl;
+
+    private DavServletResponse response;
+
+    private MockControl buildAgentConfigurationServiceControl;
+
+    private BuildAgentConfigurationService buildAgentConfigurationService;
+
+    private ContinuumBuildAgentDavResourceFactory resourceFactory;
+
+    private File workingDirectory;
+
+    @Override
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        requestControl = MockControl.createControl( DavServletRequest.class );
+        request = (DavServletRequest) requestControl.getMock();
+
+        responseControl = MockControl.createControl( DavServletResponse.class );
+        response = (DavServletResponse) responseControl.getMock();
+        responseControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER );
+
+        buildAgentConfigurationServiceControl = MockControl.
+            createControl( BuildAgentConfigurationService.class );
+        buildAgentConfigurationService = 
+            (BuildAgentConfigurationService) buildAgentConfigurationServiceControl.getMock();
+
+        resourceFactory = new ContinuumBuildAgentDavResourceFactory();
+        resourceFactory.setBuildAgentConfigurationService( buildAgentConfigurationService );
+
+        String appserverBase = getTestFile( "target/appserver-base" ).getAbsolutePath();
+        System.setProperty( "appserver.base", appserverBase );
+
+        workingDirectory = new File( appserverBase, "data/working-directory" );
+
+        new File( workingDirectory, "1/target" ).mkdirs();
+        new File( workingDirectory, "1/target/continuum-artifact-1.0.jar" ).createNewFile();
+    }
+
+    @Override
+    public void tearDown()
+        throws Exception
+    {
+        if ( workingDirectory.exists() )
+        {
+            FileUtils.deleteDirectory( workingDirectory );
+        }
+
+        super.tearDown();
+    }
+
+    public void testRequestArtifact()
+        throws Exception
+    {
+        DavResourceLocator locator =
+            new ContinuumBuildAgentDavResourceLocator( "http://myhost/", "/workingcopy/1/target/continuum-artifact-1.0.jar", 
+                                                       new ContinuumBuildAgentDavLocatorFactory(), 1 );
+
+        try
+        {
+            requestControl.expectAndReturn( request.getMethod(), "GET" );
+            buildAgentConfigurationServiceControl.
+                expectAndReturn( buildAgentConfigurationService.getWorkingDirectory( 1 ), getWorkingDirectory( 1 ) );
+            requestControl.expectAndReturn( request.getDavSession(), new ContinuumBuildAgentDavSession() );
+
+            requestControl.replay();
+            buildAgentConfigurationServiceControl.replay();
+
+            resourceFactory.createResource( locator, request, response );
+
+            requestControl.verify();
+            buildAgentConfigurationServiceControl.verify();
+        }
+        catch ( DavException e )
+        {
+            fail( "A DavException should not have been thrown!" );
+        }
+    }
+
+    public void testRequestArtifactDoesNotExist()
+        throws Exception
+    {
+        DavResourceLocator locator =
+            new ContinuumBuildAgentDavResourceLocator( "http://myhost/", "/workingcopy/1/pom.xml", 
+                                                       new ContinuumBuildAgentDavLocatorFactory(), 1 );
+
+        try
+        {
+            requestControl.expectAndReturn( request.getMethod(), "GET", 1 );
+            buildAgentConfigurationServiceControl.
+                expectAndReturn( buildAgentConfigurationService.getWorkingDirectory( 1 ), getWorkingDirectory( 1 ) );
+
+            requestControl.replay();
+            buildAgentConfigurationServiceControl.replay();
+
+            resourceFactory.createResource( locator, request, response );
+
+            requestControl.verify();
+            buildAgentConfigurationServiceControl.verify();
+
+            fail( "A DavException with 404 error code should have been thrown." );
+        }
+        catch ( DavException e )
+        {
+            assertEquals( 404, e.getErrorCode() );
+        }
+    }
+
+    private File getWorkingDirectory( int projectId )
+    {
+        return new File( workingDirectory, String.valueOf( projectId ) );
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocatorTest.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocatorTest.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocatorTest.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavResourceLocatorTest.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,111 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import junit.framework.TestCase;
+
+public class ContinuumBuildAgentDavResourceLocatorTest
+    extends TestCase
+{
+    private ContinuumBuildAgentDavLocatorFactory factory;
+
+    private ContinuumBuildAgentDavResourceLocator locator;
+    
+    @Override
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+        factory = new ContinuumBuildAgentDavLocatorFactory();
+    }
+
+    public void testAvoidDoubleSlashInHref()
+        throws Exception
+    {
+        String prefix = "http://myhost/";
+        String href = "/workingcopy/1/";
+        locator = getLocator( prefix, href );
+
+        assertEquals( 1, locator.getProjectId() );
+        assertEquals( "", locator.getWorkspaceName() );
+        assertEquals( "", locator.getWorkspacePath() );
+        assertEquals( "http://myhost/", locator.getPrefix() );
+        assertEquals( "http://myhost/workingcopy/1/", locator.getHref( false ) );
+        assertEquals( "http://myhost/workingcopy/1/", locator.getHref( true ) );
+        assertEquals( "/workingcopy/1", locator.getResourcePath() );
+        assertEquals( "/workingcopy/1", locator.getRepositoryPath() );
+    }
+
+    public void testLocatorWithPrefixHref()
+        throws Exception
+    {
+        String prefix = "http://myhost/";
+        String href = "/workingcopy/1";
+        locator = getLocator( prefix, href );
+
+        assertEquals( 1, locator.getProjectId() );
+        assertEquals( "", locator.getWorkspaceName() );
+        assertEquals( "", locator.getWorkspacePath() );
+        assertEquals( "http://myhost/", locator.getPrefix() );
+        assertEquals( "http://myhost/workingcopy/1", locator.getHref( false ) );
+        assertEquals( "http://myhost/workingcopy/1/", locator.getHref( true ) );
+        assertEquals( "/workingcopy/1", locator.getResourcePath() );
+        assertEquals( "/workingcopy/1", locator.getRepositoryPath() );
+    }
+
+    public void testLocatorWithHrefThatContainsPrefix()
+        throws Exception
+    {
+        String prefix = "http://myhost/";
+        String href = "http://myhost/workingcopy/1";
+        locator = getLocator( prefix, href );
+
+        assertEquals( 1, locator.getProjectId() );
+        assertEquals( "", locator.getWorkspaceName() );
+        assertEquals( "", locator.getWorkspacePath() );
+        assertEquals( "http://myhost/", locator.getPrefix() );
+        assertEquals( "http://myhost/workingcopy/1", locator.getHref( false ) );
+        assertEquals( "http://myhost/workingcopy/1/", locator.getHref( true ) );
+        assertEquals( "/workingcopy/1", locator.getResourcePath() );
+        assertEquals( "/workingcopy/1", locator.getRepositoryPath() );
+    }
+
+    public void testLocatorWithRootHref()
+        throws Exception
+    {
+        String prefix = "http://myhost/";
+        String href = "/";
+        locator = getLocator( prefix, href );
+
+        assertEquals( 0, locator.getProjectId() );
+        assertEquals( "", locator.getWorkspaceName() );
+        assertEquals( "", locator.getWorkspacePath() );
+        assertEquals( "http://myhost/", locator.getPrefix() );
+        assertEquals( "http://myhost/", locator.getHref( false ) );
+        assertEquals( "http://myhost/", locator.getHref( true ) );
+        assertEquals( "/", locator.getResourcePath() );
+        assertEquals( "/", locator.getRepositoryPath() );
+    }
+
+    private ContinuumBuildAgentDavResourceLocator getLocator( String prefix, String href )
+    {
+        return (ContinuumBuildAgentDavResourceLocator) factory.createResourceLocator( prefix, href );
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProviderTest.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProviderTest.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProviderTest.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionProviderTest.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,343 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.jackrabbit.webdav.DavSessionProvider;
+import org.apache.jackrabbit.webdav.WebdavRequest;
+import org.apache.jackrabbit.webdav.WebdavRequestImpl;
+
+import junit.framework.TestCase;
+
+public class ContinuumBuildAgentDavSessionProviderTest
+    extends TestCase
+{
+    private DavSessionProvider sessionProvider;
+
+    private WebdavRequest request;
+
+    @Override
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+        sessionProvider = new ContinuumBuildAgentDavSessionProvider();
+        request = new WebdavRequestImpl( new HttpServletRequestMock(), null );
+    }
+
+    public void testAttachSession()
+        throws Exception
+    {
+        assertNull( request.getDavSession() );
+        sessionProvider.attachSession( request );
+        assertNotNull( request.getDavSession() );
+    }
+
+    public void testReleaseSession()
+        throws Exception
+    {
+        assertNull( request.getDavSession() );
+        sessionProvider.attachSession( request );
+        assertNotNull( request.getDavSession() );
+        
+        sessionProvider.releaseSession( request );
+        assertNull( request.getDavSession() );
+    }
+
+    @SuppressWarnings("unchecked")
+    private class HttpServletRequestMock implements HttpServletRequest
+    {
+        public Object getAttribute(String arg0) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Enumeration getAttributeNames() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getCharacterEncoding() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public int getContentLength() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getContentType() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public ServletInputStream getInputStream()
+            throws IOException
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getLocalAddr() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getLocalName() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public int getLocalPort() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Locale getLocale() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Enumeration getLocales()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getParameter(String arg0)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Map getParameterMap()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Enumeration getParameterNames()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String[] getParameterValues(String arg0)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getProtocol() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public BufferedReader getReader()
+            throws IOException 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getRealPath(String arg0)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getRemoteAddr()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getRemoteHost()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public int getRemotePort()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public RequestDispatcher getRequestDispatcher(String arg0)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getScheme()
+        {
+            return "";
+        }
+
+        public String getServerName()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public int getServerPort()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean isSecure()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public void removeAttribute(String arg0)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public void setAttribute(String arg0, Object arg1)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public void setCharacterEncoding(String arg0)
+            throws UnsupportedEncodingException
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+        
+
+        public String getAuthType()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getContextPath()
+        {
+            return "/";
+        }
+
+        public Cookie[] getCookies()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public long getDateHeader(String arg0) 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getHeader(String arg0) {
+            return "";
+        }
+
+        public Enumeration getHeaderNames()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Enumeration getHeaders(String arg0) 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public int getIntHeader(String arg0) 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getMethod()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getPathInfo()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getPathTranslated()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getQueryString()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getRemoteUser()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getRequestURI()
+        {
+            return "/";
+        }
+
+        public StringBuffer getRequestURL() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getRequestedSessionId() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public String getServletPath() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public HttpSession getSession(boolean arg0) 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public HttpSession getSession() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Principal getUserPrincipal() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean isRequestedSessionIdFromCookie() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean isRequestedSessionIdFromURL() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean isRequestedSessionIdFromUrl() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean isRequestedSessionIdValid() 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean isUserInRole(String arg0) 
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+}

Added: continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionTest.java
URL: http://svn.apache.org/viewvc/continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionTest.java?rev=965372&view=auto
==============================================================================
--- continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionTest.java (added)
+++ continuum/trunk/continuum-buildagent/continuum-buildagent-webdav/src/test/java/org/apache/continuum/webdav/ContinuumBuildAgentDavSessionTest.java Mon Jul 19 07:13:27 2010
@@ -0,0 +1,67 @@
+package org.apache.continuum.webdav;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import junit.framework.TestCase;
+
+public class ContinuumBuildAgentDavSessionTest
+    extends TestCase
+{
+    public void testTokens()
+    {
+        ContinuumBuildAgentDavSession session = new ContinuumBuildAgentDavSession();
+        final String myToken = "thisisadavtoken";
+        
+        session.addLockToken( myToken );
+        assertEquals( 1, session.getLockTokens().length );
+        assertEquals( myToken, session.getLockTokens()[0] );
+        
+        session.removeLockToken( myToken );
+        assertEquals( 0, session.getLockTokens().length );
+    }
+
+    public void testAddReferencesThrowsUnsupportedOperationException()
+    {
+        ContinuumBuildAgentDavSession session = new ContinuumBuildAgentDavSession();
+        try
+        {
+            session.addReference( new Object() );
+            fail( "Did not throw UnsupportedOperationException" );
+        }
+        catch ( UnsupportedOperationException e )
+        {
+            assertTrue( true );
+        } 
+    }
+    
+    public void testRemoveReferencesThrowsUnsupportedOperationException()
+    {
+        ContinuumBuildAgentDavSession session = new ContinuumBuildAgentDavSession();
+        try
+        {
+            session.removeReference( new Object() );
+            fail( "Did not throw UnsupportedOperationException" );
+        }
+        catch ( UnsupportedOperationException e )
+        {
+            assertTrue( true );
+        }
+    }
+}