From 39fad530229a092e94602f6bbfa72bc3b4538adc Mon Sep 17 00:00:00 2001 From: "Maria Odea B. Ching" Date: Tue, 20 May 2008 14:34:48 +0000 Subject: [PATCH] [MRM-694] -handle virtual repos in webdav browse -add new DavResource for virtual repos git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@658261 13f79535-47bb-0310-9956-ffa450edef68 --- .../RepositoryServletRepositoryGroupTest.java | 26 +- .../webdav/ArchivaDavResourceFactory.java | 62 +++- .../webdav/ArchivaVirtualDavResource.java | 348 ++++++++++++++++++ .../archiva/webdav/util/IndexWriter.java | 74 +++- .../webdav/util/RepositoryPathUtil.java | 18 +- .../webdav/util/RepositoryPathUtilTest.java | 3 + 6 files changed, 484 insertions(+), 47 deletions(-) create mode 100644 archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaVirtualDavResource.java diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletRepositoryGroupTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletRepositoryGroupTest.java index c3d98394c..ef80939c0 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletRepositoryGroupTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletRepositoryGroupTest.java @@ -125,20 +125,7 @@ public class RepositoryServletRepositoryGroupTest super.tearDown(); } - - - /* - * Test Case 1 - */ - public void testGetValidRepositoryGroupRootPathReturnBadRequest() - throws Exception - { - WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/" + REPO_GROUP_WITH_VALID_REPOS ); - WebResponse response = sc.getResponse( request ); - assertResponseBadRequest( response ); - } - /* * Test Case 3.c */ @@ -217,11 +204,20 @@ public class RepositoryServletRepositoryGroupTest WebRequest request = new PutMethodWebRequest( putUrl, is, "text/plain" ); WebResponse response = sc.getResponse( request ); - + assertResponseBadRequest( response ); } - + public void testBrowseRepositoryGroup() + throws Exception + { + WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/" + REPO_GROUP_WITH_VALID_REPOS ); + WebResponse response = sc.getResponse( request ); + + assertNotNull( "Should have received a response", response ); + assertResponseOK( response ); + } + protected void assertResponseBadRequest( WebResponse response ) { assertNotNull( "Should have recieved a response", response ); 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 efef673c0..f8f71dfbc 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 @@ -123,7 +123,7 @@ public class ArchivaDavResourceFactory public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request, final DavServletResponse response ) throws DavException - { + { checkLocatorIsInstanceOfRepositoryLocator( locator ); ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator; @@ -134,23 +134,21 @@ public class ArchivaDavResourceFactory boolean isGet = WebdavMethodUtil.isReadMethod( request.getMethod() ); boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() ); - + if ( repoGroupConfig != null ) - { - if ( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ).equals( "/" ) || - WebdavMethodUtil.isWriteMethod( request.getMethod() ) ) + { + if( WebdavMethodUtil.isWriteMethod( request.getMethod() ) ) { throw new DavException( HttpServletResponse.SC_BAD_REQUEST, "Bad request to repository group <" + repoGroupConfig.getId() + ">" ); } repositories.addAll( repoGroupConfig.getRepositories() ); - // do not allow write request for repo groups - if( isPut ) - { - throw new DavException( HttpServletResponse.SC_FORBIDDEN, "Write request is not allowed for <" + - repoGroupConfig.getId() + ">" ); - } + // handle browse requests for virtual repos + if ( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ).endsWith( "/" ) ) + { + return getResource( repositories, archivaLocator ); + } } else { @@ -231,7 +229,7 @@ public class ArchivaDavResourceFactory public DavResource createResource( final DavResourceLocator locator, final DavSession davSession ) throws DavException - { + { checkLocatorIsInstanceOfRepositoryLocator( locator ); ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator; @@ -666,4 +664,44 @@ public class ArchivaDavResourceFactory } } + private DavResource getResource( List repositories, ArchivaDavResourceLocator locator ) + throws DavException + { + List mergedRepositoryContents = new ArrayList(); + LogicalResource logicalResource = + new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) ); + + for( String repository : repositories ) + { + ManagedRepositoryContent managedRepository = null; + + try + { + managedRepository = getManagedRepository( repository ); + } + catch ( DavException de ) + { + throw new DavException( HttpServletResponse.SC_NOT_FOUND, "Invalid managed repository <" + + repository + ">" ); + } + + if ( !locator.getResourcePath().startsWith( ArchivaVirtualDavResource.HIDDEN_PATH_PREFIX ) ) + { + if( managedRepository != null ) + { + File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() ); + if( resourceFile.exists() ) + { + mergedRepositoryContents.add( resourceFile ); + } + } + } + } + + ArchivaVirtualDavResource resource = + new ArchivaVirtualDavResource( mergedRepositoryContents, logicalResource.getPath(), mimeTypes, locator, this ); + + return resource; + } + } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaVirtualDavResource.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaVirtualDavResource.java new file mode 100644 index 000000000..af671f587 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaVirtualDavResource.java @@ -0,0 +1,348 @@ +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 java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +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.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.apache.maven.archiva.webdav.util.IndexWriter; +import org.apache.maven.archiva.webdav.util.MimeTypes; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * DavResource for virtual repositories + * + * @author Maria Odea Ching + */ +public class ArchivaVirtualDavResource + implements DavResource +{ + public static final String HIDDEN_PATH_PREFIX = "."; + + private static final String COMPLIANCE_CLASS = "1"; + + private MimeTypes mimeTypes; + + private ArchivaDavResourceLocator locator; + + private DavResourceFactory factory; + + private String logicalResource; + + private DavPropertySet properties; + + private boolean propsInitialized = false; + + private static final String METHODS = "OPTIONS, GET, HEAD, POST, TRACE, PROPFIND, PROPPATCH, MKCOL"; + + private final List localResources; + + public ArchivaVirtualDavResource( List localResources, String logicalResource, MimeTypes mimeTypes, + ArchivaDavResourceLocator locator, DavResourceFactory factory ) + { + this.localResources = localResources; + this.logicalResource = logicalResource; + this.mimeTypes = mimeTypes; + this.locator = locator; + this.factory = factory; + this.properties = new DavPropertySet(); + } + + public void spool( OutputContext outputContext ) + throws IOException + { + Collections.sort( localResources ); + List localResourceFiles = new ArrayList(); + + for ( File resourceFile : localResources ) + { + if ( resourceFile.exists() ) + { + localResourceFiles.add( resourceFile ); + } + } + + IndexWriter writer = new IndexWriter( this, localResourceFiles, logicalResource ); + writer.write( outputContext ); + } + + public void addLockManager( LockManager arg0 ) + { + + } + + public void addMember( DavResource arg0, InputContext arg1 ) + throws DavException + { + + } + + public MultiStatusResponse alterProperties( List arg0 ) + throws DavException + { + return null; + } + + public MultiStatusResponse alterProperties( DavPropertySet arg0, DavPropertyNameSet arg1 ) + throws DavException + { + return null; + } + + public void copy( DavResource arg0, boolean arg1 ) + throws DavException + { + + } + + public boolean exists() + { + // localResources are already filtered (all files in the list are already existing) + return true; + } + + public ActiveLock getLock( Type arg0, Scope arg1 ) + { + return null; + } + + public ActiveLock[] getLocks() + { + return null; + } + + public DavResourceIterator getMembers() + { + return null; + } + + public String getSupportedMethods() + { + return METHODS; + } + + public long getModificationTime() + { + return 0; + } + + public boolean hasLock( Type arg0, Scope arg1 ) + { + return false; + } + + public boolean isCollection() + { + return true; + } + + public boolean isLockable( Type arg0, Scope arg1 ) + { + return false; + } + + public ActiveLock lock( LockInfo arg0 ) + throws DavException + { + return null; + } + + public void move( DavResource arg0 ) + throws DavException + { + + } + + public ActiveLock refreshLock( LockInfo arg0, String arg1 ) + throws DavException + { + return null; + } + + public void removeMember( DavResource arg0 ) + throws DavException + { + + } + + public void unlock( String arg0 ) + throws DavException + { + + } + + public String getComplianceClass() + { + return COMPLIANCE_CLASS; + } + + public DavResourceLocator getLocator() + { + return locator; + } + + public String getResourcePath() + { + return locator.getResourcePath(); + } + + public String getHref() + { + return locator.getHref( isCollection() ); + } + + public DavResourceFactory getFactory() + { + return factory; + } + + public String getDisplayName() + { + String resPath = getResourcePath(); + + return ( resPath != null ) ? Text.getName( resPath ) : resPath; + } + + public DavSession getSession() + { + return null; + } + + public DavPropertyName[] getPropertyNames() + { + return getProperties().getPropertyNames(); + } + + public DavProperty getProperty( DavPropertyName name ) + { + initProperties(); + return properties.get( name ); + } + + public DavPropertySet getProperties() + { + initProperties(); + return properties; + } + + public void setProperty( DavProperty property ) + throws DavException + { + } + + public void removeProperty( DavPropertyName propertyName ) + throws DavException + { + } + + public DavResource getCollection() + { + DavResource parent = null; + if ( getResourcePath() != null && !getResourcePath().equals( "/" ) ) + { + String parentPath = Text.getRelativeParent( getResourcePath(), 1 ); + if ( parentPath.equals( "" ) ) + { + parentPath = "/"; + } + DavResourceLocator parentloc = locator.getFactory().createResourceLocator( locator.getPrefix(), parentPath ); + try + { + // go back to ArchivaDavResourceFactory! + parent = factory.createResource( parentloc, null ); + } + catch ( DavException e ) + { + // should not occur + } + } + return parent; + } + + /** + * Fill the set of properties + */ + protected void initProperties() + { + if ( !exists() || propsInitialized ) + { + return; + } + + // 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( 0 ); + 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, 0 ) ); + + propsInitialized = true; + } + +} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/IndexWriter.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/IndexWriter.java index 4c41a6ee9..3c6b07f20 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/IndexWriter.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/IndexWriter.java @@ -26,7 +26,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.io.PrintWriter; import java.io.File; @@ -37,19 +39,31 @@ public class IndexWriter { private final DavResource resource; - private final File localResource; - private final String logicalResource; - + + private final List localResources; + + private final boolean isVirtual; + public IndexWriter(DavResource resource, File localResource, String logicalResource) { this.resource = resource; - this.localResource = localResource; + this.localResources = new ArrayList(); + this.localResources.add( localResource ); + this.logicalResource = logicalResource; + this.isVirtual = false; + } + + public IndexWriter( DavResource resource, List localResources, String logicalResource ) + { + this.resource = resource; this.logicalResource = logicalResource; + this.localResources = localResources; + this.isVirtual = true; } public void write(OutputContext outputContext) - { + { outputContext.setModificationTime(new Date().getTime()); outputContext.setContentType("text/html"); outputContext.setETag(""); @@ -94,18 +108,50 @@ public class IndexWriter } private void writeHyperlinks(PrintWriter writer) - { - List files = new ArrayList( Arrays.asList( localResource.listFiles() ) ); - Collections.sort( files ); - - for ( File file : files ) + { + if( !isVirtual ) { - writeHyperlink(writer, file.getName(), file.isDirectory()); + for( File localResource : localResources ) + { + List files = new ArrayList( Arrays.asList( localResource.listFiles() ) ); + Collections.sort( files ); + + for ( File file : files ) + { + writeHyperlink( writer, file.getName(), file.isDirectory(), false ); + } + } + } + else + { + // virtual repository - filter unique directories + Map uniqueChildFiles = new HashMap(); + for( File resource : localResources ) + { + List files = new ArrayList( Arrays.asList( resource.listFiles() ) ); + Collections.sort( files ); + + for ( File file : files ) + { + if( uniqueChildFiles.get( file.getName() ) == null ) + { + uniqueChildFiles.put( file.getName(), file ); + } + } + } + + List uniqueChildFilesInList = new ArrayList(); + uniqueChildFilesInList.addAll( uniqueChildFiles.values() ); + + for ( File file : uniqueChildFilesInList ) + { + writeHyperlink( writer, file.getName(), file.isDirectory(), true ); + } } } - private void writeHyperlink(PrintWriter writer, String resourceName, boolean directory) - { + private void writeHyperlink(PrintWriter writer, String resourceName, boolean directory, boolean isBrowse ) + { if (directory) { writer.println("
  • " + resourceName + "
  • "); @@ -114,5 +160,5 @@ public class IndexWriter { writer.println("
  • " + resourceName + "
  • "); } - } + } } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtil.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtil.java index 368e1a1d7..5071dc3da 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtil.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtil.java @@ -21,7 +21,6 @@ package org.apache.maven.archiva.webdav.util; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.io.FilenameUtils; /** * @author James William Dumay @@ -44,19 +43,19 @@ public class RepositoryPathUtil 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 = "/"; @@ -100,6 +99,13 @@ public class RepositoryPathUtil { return "/"; } - return StringUtils.join(parts, '/'); + + String joinedString = StringUtils.join(parts, '/'); + if( href.endsWith( "/" ) ) + { + joinedString = joinedString + "/"; + } + + return joinedString; } } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtilTest.java b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtilTest.java index 0294b3e29..11a845c46 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtilTest.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/util/RepositoryPathUtilTest.java @@ -45,5 +45,8 @@ public class RepositoryPathUtilTest extends TestCase href = "repository/internal/org/apache/maven/someartifact.jar"; assertEquals("/org/apache/maven/someartifact.jar", RepositoryPathUtil.getLogicalResource(href)); + + href = "repository/internal/org/apache/maven/"; + assertEquals( "/org/apache/maven/", RepositoryPathUtil.getLogicalResource( href ) ); } } -- 2.39.5