From: James William Dumay Date: Fri, 30 May 2008 04:01:37 +0000 (+0000) Subject: MRM-781 - Removal of Archiva-Webdav implementation in favor of Jackrabbit-webdav X-Git-Tag: archiva-r676265~96 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=721f552dfa13c7585d2aaf43994de21a6db67b7a;p=archiva.git MRM-781 - Removal of Archiva-Webdav implementation in favor of Jackrabbit-webdav * Adding LockManager to DavResourceFactory * Adding locking support to DavResource * General cleanup inside of the dav resource * Adding DavSession attachement inside of DavSessionProvider * Tests NOTE: We should have a complete Class 2 locking implementation (Exclusive only) so OS X dav client should work git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@661563 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java index f98940ea4..7d0efa9f4 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java @@ -56,23 +56,27 @@ public class ArchivaDavResource private final String logicalResource; - private static final String METHODS = - "OPTIONS, GET, HEAD, POST, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, PUT, DELETE, MOVE"; - - private static final String COMPLIANCE_CLASS = "1"; - private DavPropertySet properties; private boolean propsInitialized = false; - - public ArchivaDavResource( String localResource, String logicalResource, MimeTypes mimeTypes, - ArchivaDavResourceLocator locator, DavResourceFactory factory ) + + private LockManager lockManager; + + private final DavSession session; + + public ArchivaDavResource( String localResource, + String logicalResource, + MimeTypes mimeTypes, + DavSession session, + ArchivaDavResourceLocator locator, + DavResourceFactory factory ) { this.mimeTypes = mimeTypes; this.localResource = new File( localResource ); this.logicalResource = logicalResource; this.locator = locator; this.factory = factory; + this.session = session; this.properties = new DavPropertySet(); } @@ -218,7 +222,7 @@ public class ArchivaDavResource DavResourceLocator parentloc = locator.getFactory().createResourceLocator( locator.getPrefix(), parentPath ); try { - parent = factory.createResource( parentloc, null ); + parent = factory.createResource( parentloc, session ); } catch ( DavException e ) { @@ -285,7 +289,7 @@ public class ArchivaDavResource String path = locator.getResourcePath() + '/' + item; DavResourceLocator resourceLocator = locator.getFactory().createResourceLocator( locator.getPrefix(), path ); - DavResource resource = factory.createResource( resourceLocator, null ); + DavResource resource = factory.createResource( resourceLocator, session ); if ( resource != null ) list.add( resource ); } @@ -302,20 +306,20 @@ public class ArchivaDavResource public void removeMember( DavResource member ) throws DavException { - File localResource = checkDavResourceIsArchivaDavResource( member ).getLocalResource(); + File resource = checkDavResourceIsArchivaDavResource( member ).getLocalResource(); - if ( !localResource.exists() ) + if ( !resource.exists() ) { throw new DavException( HttpServletResponse.SC_NOT_FOUND, member.getResourcePath() ); } boolean suceeded = false; - if ( localResource.isDirectory() ) + if ( resource.isDirectory() ) { try { - FileUtils.deleteDirectory( localResource ); + FileUtils.deleteDirectory( resource ); suceeded = true; } catch ( IOException e ) @@ -324,9 +328,9 @@ public class ArchivaDavResource } } - if ( !suceeded && localResource.isFile() ) + if ( !suceeded && resource.isFile() ) { - suceeded = localResource.delete(); + suceeded = resource.delete(); } if ( !suceeded ) @@ -346,14 +350,14 @@ public class ArchivaDavResource try { - ArchivaDavResource localResource = checkDavResourceIsArchivaDavResource( destination ); + ArchivaDavResource resource = checkDavResourceIsArchivaDavResource( destination ); if ( isCollection() ) { - FileUtils.moveDirectory( getLocalResource(), localResource.getLocalResource() ); + FileUtils.moveDirectory( getLocalResource(), resource.getLocalResource() ); } else { - FileUtils.moveFile( getLocalResource(), localResource.getLocalResource() ); + FileUtils.moveFile( getLocalResource(), resource.getLocalResource() ); } } catch ( IOException e ) @@ -377,14 +381,14 @@ public class ArchivaDavResource try { - ArchivaDavResource localResource = checkDavResourceIsArchivaDavResource( destination ); + ArchivaDavResource resource = checkDavResourceIsArchivaDavResource( destination ); if ( isCollection() ) { - FileUtils.copyDirectory( getLocalResource(), localResource.getLocalResource() ); + FileUtils.copyDirectory( getLocalResource(), resource.getLocalResource() ); } else { - FileUtils.copyFile( getLocalResource(), localResource.getLocalResource() ); + FileUtils.copyFile( getLocalResource(), resource.getLocalResource() ); } } catch ( IOException e ) @@ -395,43 +399,82 @@ public class ArchivaDavResource public boolean isLockable( Type type, Scope scope ) { - return false; + return Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope); } public boolean hasLock( Type type, Scope scope ) { - return false; + return getLock(type, scope) != null; } public ActiveLock getLock( Type type, Scope scope ) { - return null; + ActiveLock lock = null; + if (exists() && Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope)) + { + lock = lockManager.getLock(type, scope, this); + } + return lock; } public ActiveLock[] getLocks() { - return new ActiveLock[0]; + ActiveLock writeLock = getLock(Type.WRITE, Scope.EXCLUSIVE); + return (writeLock != null) ? new ActiveLock[]{writeLock} : new ActiveLock[0]; } - public ActiveLock lock( LockInfo reqLockInfo ) + public ActiveLock lock( LockInfo lockInfo ) throws DavException { - return null; + ActiveLock lock = null; + if (isLockable(lockInfo.getType(), lockInfo.getScope())) + { + lock = lockManager.createLock(lockInfo, this); + } + else + { + throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Unsupported lock type or scope."); + } + return lock; } - public ActiveLock refreshLock( LockInfo reqLockInfo, String lockToken ) + public ActiveLock refreshLock( LockInfo lockInfo, String lockToken ) throws DavException { - return null; + if (!exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + ActiveLock lock = getLock(lockInfo.getType(), lockInfo.getScope()); + if (lock == null) { + throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "No lock with the given type/scope present on resource " + getResourcePath()); + } + + lock = lockManager.refreshLock(lockInfo, lockToken, this); + + return lock; } public void unlock( String lockToken ) throws DavException { + ActiveLock lock = getLock(Type.WRITE, Scope.EXCLUSIVE); + if (lock == null) + { + throw new DavException(HttpServletResponse.SC_PRECONDITION_FAILED); + } + else if (lock.isLockedByToken(lockToken)) + { + lockManager.releaseLock(lockToken, this); + } + else + { + throw new DavException(DavServletResponse.SC_LOCKED); + } } - public void addLockManager( LockManager lockmgr ) + public void addLockManager( LockManager lockManager ) { + this.lockManager = lockManager; } public DavResourceFactory getFactory() @@ -441,7 +484,7 @@ public class ArchivaDavResource public DavSession getSession() { - return null; + return session; } /** diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java index 8e67ff68c..71ae2c27c 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java @@ -68,6 +68,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.io.*; +import org.apache.jackrabbit.webdav.lock.LockManager; +import org.apache.jackrabbit.webdav.lock.SimpleLockManager; /** * @author James William Dumay @@ -123,6 +125,12 @@ public class ArchivaDavResourceFactory */ private HttpAuthenticator httpAuth; + + /** + * Lock Manager - use simple implementation from JackRabbit + */ + private final LockManager lockManager = new SimpleLockManager(); + public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request, final DavServletResponse response ) throws DavException @@ -216,7 +224,7 @@ public class ArchivaDavResourceFactory { throw new BrowserRedirectException( resource.getHref() ); } - + resource.addLockManager(lockManager); return resource; } } @@ -243,9 +251,10 @@ public class ArchivaDavResourceFactory String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ); File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource ); resource = - new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource, mimeTypes, archivaLocator, + new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource, mimeTypes, davSession, archivaLocator, this ); } + resource.addLockManager(lockManager); return resource; } @@ -255,7 +264,7 @@ public class ArchivaDavResourceFactory { File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() ); ArchivaDavResource resource = - new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, locator, this ); + new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, request.getDavSession(), locator, this ); if ( !resource.isCollection() ) { @@ -289,7 +298,7 @@ public class ArchivaDavResourceFactory resourceFile, " (proxied)" ); } resource = - new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, locator, + new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, request.getDavSession(), locator, this ); if ( !resourceFile.exists() ) @@ -326,7 +335,7 @@ public class ArchivaDavResourceFactory processAuditEvents( request, locator.getRepositoryId(), logicalResource.getPath(), previouslyExisted, resourceFile, null ); - return new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, locator, + return new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, request.getDavSession(), locator, this ); } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceLocator.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceLocator.java index ba1e3316b..b712adbb5 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceLocator.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceLocator.java @@ -46,6 +46,11 @@ public class ArchivaDavResourceLocator this.repositoryId = repositoryId; this.davLocatorFactory = davLocatorFactory; this.resourcePath = resourcePath; + + if (!resourcePath.startsWith("/")) + { + this.resourcePath = "/" + resourcePath; + } String escapedPath = Text.escapePath( resourcePath ); String hrefPrefix = prefix; diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java index d5265323f..b2200aac6 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java @@ -65,6 +65,9 @@ public class ArchivaDavSessionProvider { AuthenticationResult result = httpAuth.getAuthenticationResult( request, null ); + //Create a dav session + request.setDavSession(new ArchivaDavSession()); + return servletAuth.isAuthenticated( request, result ); } catch ( AuthenticationException e ) @@ -81,9 +84,13 @@ public class ArchivaDavSessionProvider } } - public void releaseSession( WebdavRequest webdavRequest ) + public void releaseSession( WebdavRequest request ) { - + //Remove DavSession + if (request.getDavSession() != null) + { + request.setDavSession(null); + } } private String removeContextPath( final DavServletRequest request ) diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/DavResourceTest.java b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/DavResourceTest.java new file mode 100644 index 000000000..9291601e7 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/DavResourceTest.java @@ -0,0 +1,238 @@ +package org.apache.maven.archiva.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.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.DavResource; +import org.apache.jackrabbit.webdav.DavServletResponse; +import org.apache.jackrabbit.webdav.DavSession; +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.SimpleLockManager; +import org.apache.jackrabbit.webdav.lock.Type; +import org.apache.maven.archiva.webdav.util.MimeTypes; +import org.codehaus.plexus.spring.PlexusInSpringTestCase; +import org.codehaus.plexus.spring.PlexusToSpringUtils; +import quicktime.std.qtcomponents.SCInfo; + + +public class DavResourceTest extends PlexusInSpringTestCase +{ + private DavSession session; + + private MimeTypes mimeTypes; + + private ArchivaDavResourceLocator resourceLocator; + + private ArchivaDavResourceFactory factory; + + private File baseDir; + + private final String REPOPATH = "/myresource.jar"; + + private final File myResource = new File(baseDir, REPOPATH); + + private DavResource resource; + + private LockManager lockManager; + + @Override + protected void setUp() + throws Exception + { + super.setUp(); + session = new ArchivaDavSession(); + mimeTypes = (MimeTypes)getApplicationContext().getBean(PlexusToSpringUtils.buildSpringId(MimeTypes.class)); + baseDir = new File("target/DavResourceTest"); + baseDir.mkdirs(); + myResource.createNewFile(); + resourceLocator = (ArchivaDavResourceLocator)new ArchivaDavLocatorFactory().createResourceLocator("/", REPOPATH); + resource = getDavResource(REPOPATH, myResource); + lockManager = new SimpleLockManager(); + resource.addLockManager(lockManager); + } + + @Override + protected void tearDown() + throws Exception + { + super.tearDown(); + release(mimeTypes); + FileUtils.deleteDirectory(baseDir); + } + + private DavResource getDavResource(String logicalPath, File file) + { + return new ArchivaDavResource(logicalPath, file.getAbsolutePath(), mimeTypes, session, resourceLocator, null); + } + + public void testIsLockable() + { + assertTrue(resource.isLockable(Type.WRITE, Scope.EXCLUSIVE)); + assertFalse(resource.isLockable(Type.WRITE, Scope.SHARED)); + } + + public void testLock() + throws Exception + { + assertEquals(0, resource.getLocks().length); + + LockInfo info = new LockInfo(Scope.EXCLUSIVE, Type.WRITE, "/", 0, false); + lockManager.createLock(info, resource); + + assertEquals(1, resource.getLocks().length); + } + + public void testLockIfResourceUnlockable() + throws Exception + { + assertEquals(0, resource.getLocks().length); + + LockInfo info = new LockInfo(Scope.SHARED, Type.WRITE, "/", 0, false); + try + { + lockManager.createLock(info, resource); + fail("Did not throw dav exception"); + } + catch (Exception e) + { + //Simple lock manager will die + } + assertEquals(0, resource.getLocks().length); + } + + public void testGetLock() + throws Exception + { + LockInfo info = new LockInfo(Scope.EXCLUSIVE, Type.WRITE, "/", 0, false); + lockManager.createLock(info, resource); + + assertEquals(1, resource.getLocks().length); + + //Lock should exist + assertNotNull(resource.getLock(Type.WRITE, Scope.EXCLUSIVE)); + + //Lock should not exist + assertNull(resource.getLock(Type.WRITE, Scope.SHARED)); + } + + + public void testRefreshLockThrowsExceptionIfNoLockIsPresent() + throws Exception + { + LockInfo info = new LockInfo(Scope.EXCLUSIVE, Type.WRITE, "/", 0, false); + + assertEquals(0, resource.getLocks().length); + + try + { + lockManager.refreshLock(info, "notoken", resource); + fail("Did not throw dav exception"); + } + catch (DavException e) + { + assertEquals(DavServletResponse.SC_PRECONDITION_FAILED, e.getErrorCode()); + } + + assertEquals(0, resource.getLocks().length); + } + + public void testRefreshLock() + throws Exception + { + LockInfo info = new LockInfo(Scope.EXCLUSIVE, Type.WRITE, "/", 0, false); + + assertEquals(0, resource.getLocks().length); + + lockManager.createLock(info, resource); + + assertEquals(1, resource.getLocks().length); + + ActiveLock lock = resource.getLocks()[0]; + + lockManager.refreshLock(info, lock.getToken(), resource); + + assertEquals(1, resource.getLocks().length); + } + + public void testUnlock() + throws Exception + { + LockInfo info = new LockInfo(Scope.EXCLUSIVE, Type.WRITE, "/", 0, false); + + assertEquals(0, resource.getLocks().length); + + lockManager.createLock(info, resource); + + assertEquals(1, resource.getLocks().length); + + ActiveLock lock = resource.getLocks()[0]; + + lockManager.releaseLock(lock.getToken(), resource); + + assertEquals(0, resource.getLocks().length); + } + + public void testUnlockThrowsDavExceptionIfNotLocked() + throws Exception + { + LockInfo info = new LockInfo(Scope.EXCLUSIVE, Type.WRITE, "/", 0, false); + + assertEquals(0, resource.getLocks().length); + + lockManager.createLock(info, resource); + + assertEquals(1, resource.getLocks().length); + + try + { + lockManager.releaseLock("BLAH", resource); + fail("Did not throw DavException"); + } + catch (DavException e) + { + assertEquals(DavServletResponse.SC_LOCKED, e.getErrorCode()); + } + + assertEquals(1, resource.getLocks().length); + } + + public void testUnlockThrowsDavExceptionIfResourceNotLocked() + throws Exception + { + assertEquals(0, resource.getLocks().length); + + try + { + lockManager.releaseLock("BLAH", resource); + fail("Did not throw DavException"); + } + catch (DavException e) + { + assertEquals(DavServletResponse.SC_PRECONDITION_FAILED, e.getErrorCode()); + } + + assertEquals(0, resource.getLocks().length); + } +}