mirror of https://github.com/apache/archiva.git
[MRM-781] Removal of Archiva-Webdav implementation in favor of Jackrabbit-webdav
Submitted by: James William Dumay git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@649352 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4a6a9ff697
commit
558d0c2a4f
|
@ -255,7 +255,7 @@
|
|||
</build>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>codehaus.org</id>
|
||||
<id>codehaus.snapshots</id>
|
||||
<url>http://snapshots.repository.codehaus.org/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.apache.maven.archiva.web.util;
|
||||
package org.apache.maven.archiva.security;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
|
@ -27,8 +27,6 @@ import org.codehaus.plexus.redback.system.SecuritySession;
|
|||
import org.codehaus.plexus.redback.system.SecuritySystemConstants;
|
||||
import org.codehaus.plexus.redback.users.User;
|
||||
|
||||
import com.opensymphony.xwork.ActionContext;
|
||||
|
||||
/**
|
||||
* ArchivaXworkUser
|
||||
*
|
||||
|
@ -37,35 +35,21 @@ import com.opensymphony.xwork.ActionContext;
|
|||
*/
|
||||
public class ArchivaXworkUser
|
||||
{
|
||||
private static Map<String, Object> getContextSession()
|
||||
public static String getActivePrincipal( Map<String, Object> sessionMap )
|
||||
{
|
||||
ActionContext context = ActionContext.getContext();
|
||||
Map<String, Object> sessionMap = context.getSession();
|
||||
if ( sessionMap == null )
|
||||
{
|
||||
sessionMap = new HashMap<String, Object>();
|
||||
return ArchivaRoleConstants.PRINCIPAL_GUEST;
|
||||
}
|
||||
|
||||
return sessionMap;
|
||||
}
|
||||
|
||||
private static SecuritySession getSecuritySession()
|
||||
{
|
||||
SecuritySession securitySession =
|
||||
(SecuritySession) getContextSession().get( SecuritySystemConstants.SECURITY_SESSION_KEY );
|
||||
(SecuritySession) sessionMap.get( SecuritySystemConstants.SECURITY_SESSION_KEY );
|
||||
|
||||
if ( securitySession == null )
|
||||
{
|
||||
securitySession = (SecuritySession) getContextSession().get( SecuritySession.ROLE );
|
||||
securitySession = (SecuritySession) sessionMap.get( SecuritySession.ROLE );
|
||||
}
|
||||
|
||||
return securitySession;
|
||||
}
|
||||
|
||||
public static String getActivePrincipal()
|
||||
{
|
||||
SecuritySession securitySession = getSecuritySession();
|
||||
|
||||
if ( securitySession == null )
|
||||
{
|
||||
return ArchivaRoleConstants.PRINCIPAL_GUEST;
|
|
@ -136,16 +136,6 @@
|
|||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-http</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-file</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.opensymphony</groupId>
|
||||
<artifactId>webwork</artifactId>
|
||||
|
|
|
@ -22,15 +22,13 @@ package org.apache.maven.archiva.web.action;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.opensymphony.xwork.ActionContext;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.maven.archiva.database.browsing.BrowsingResults;
|
||||
import org.apache.maven.archiva.database.browsing.RepositoryBrowsing;
|
||||
import org.apache.maven.archiva.security.AccessDeniedException;
|
||||
import org.apache.maven.archiva.security.ArchivaSecurityException;
|
||||
import org.apache.maven.archiva.security.PrincipalNotFoundException;
|
||||
import org.apache.maven.archiva.security.UserRepositories;
|
||||
import org.apache.maven.archiva.web.util.ArchivaXworkUser;
|
||||
import org.apache.maven.archiva.security.*;
|
||||
import org.apache.maven.archiva.security.ArchivaXworkUser;
|
||||
import org.codehaus.plexus.xwork.action.PlexusActionSupport;
|
||||
|
||||
/**
|
||||
|
@ -121,7 +119,7 @@ public class BrowseAction
|
|||
|
||||
private String getPrincipal()
|
||||
{
|
||||
return ArchivaXworkUser.getActivePrincipal();
|
||||
return ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
|
||||
}
|
||||
|
||||
private List<String> getObservableRepos()
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.net.MalformedURLException;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.opensymphony.xwork.ActionContext;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.maven.archiva.database.ArchivaDAO;
|
||||
|
@ -33,11 +34,8 @@ import org.apache.maven.archiva.indexer.RepositoryIndexSearchException;
|
|||
import org.apache.maven.archiva.indexer.search.CrossRepositorySearch;
|
||||
import org.apache.maven.archiva.indexer.search.SearchResultLimits;
|
||||
import org.apache.maven.archiva.indexer.search.SearchResults;
|
||||
import org.apache.maven.archiva.security.AccessDeniedException;
|
||||
import org.apache.maven.archiva.security.ArchivaSecurityException;
|
||||
import org.apache.maven.archiva.security.PrincipalNotFoundException;
|
||||
import org.apache.maven.archiva.security.UserRepositories;
|
||||
import org.apache.maven.archiva.web.util.ArchivaXworkUser;
|
||||
import org.apache.maven.archiva.security.*;
|
||||
import org.apache.maven.archiva.security.ArchivaXworkUser;
|
||||
import org.codehaus.plexus.xwork.action.PlexusActionSupport;
|
||||
|
||||
/**
|
||||
|
@ -155,7 +153,7 @@ public class SearchAction
|
|||
|
||||
private String getPrincipal()
|
||||
{
|
||||
return ArchivaXworkUser.getActivePrincipal();
|
||||
return ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
|
||||
}
|
||||
|
||||
private List<String> getObservableRepos()
|
||||
|
|
|
@ -31,9 +31,10 @@ import org.apache.maven.archiva.security.AccessDeniedException;
|
|||
import org.apache.maven.archiva.security.ArchivaSecurityException;
|
||||
import org.apache.maven.archiva.security.PrincipalNotFoundException;
|
||||
import org.apache.maven.archiva.security.UserRepositories;
|
||||
import org.apache.maven.archiva.web.util.ArchivaXworkUser;
|
||||
import org.apache.maven.archiva.security.ArchivaXworkUser;
|
||||
import org.codehaus.plexus.xwork.action.PlexusActionSupport;
|
||||
|
||||
import com.opensymphony.xwork.ActionContext;
|
||||
import com.opensymphony.xwork.Validateable;
|
||||
|
||||
/**
|
||||
|
@ -173,7 +174,7 @@ public class ShowArtifactAction
|
|||
|
||||
private String getPrincipal()
|
||||
{
|
||||
return ArchivaXworkUser.getActivePrincipal();
|
||||
return ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
|
||||
}
|
||||
|
||||
private List<String> getObservableRepos()
|
||||
|
|
|
@ -51,9 +51,10 @@ import org.apache.maven.archiva.repository.project.writers.ProjectModel400Writer
|
|||
import org.apache.maven.archiva.security.ArchivaSecurityException;
|
||||
import org.apache.maven.archiva.security.PrincipalNotFoundException;
|
||||
import org.apache.maven.archiva.security.UserRepositories;
|
||||
import org.apache.maven.archiva.web.util.ArchivaXworkUser;
|
||||
import org.apache.maven.archiva.security.ArchivaXworkUser;
|
||||
import org.codehaus.plexus.xwork.action.PlexusActionSupport;
|
||||
|
||||
import com.opensymphony.xwork.ActionContext;
|
||||
import com.opensymphony.xwork.Preparable;
|
||||
import com.opensymphony.xwork.Validateable;
|
||||
|
||||
|
@ -325,7 +326,7 @@ public class UploadAction
|
|||
|
||||
private String getPrincipal()
|
||||
{
|
||||
return ArchivaXworkUser.getActivePrincipal();
|
||||
return ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
|
||||
}
|
||||
|
||||
private void copyFile( File targetPath, String artifactFilename )
|
||||
|
|
|
@ -1,598 +0,0 @@
|
|||
package org.apache.maven.archiva.web.repository;
|
||||
|
||||
/*
|
||||
* 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.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.maven.archiva.common.utils.PathUtil;
|
||||
import org.apache.maven.archiva.model.ArtifactReference;
|
||||
import org.apache.maven.archiva.model.ProjectReference;
|
||||
import org.apache.maven.archiva.model.VersionedReference;
|
||||
import org.apache.maven.archiva.policies.ProxyDownloadException;
|
||||
import org.apache.maven.archiva.proxy.RepositoryProxyConnectors;
|
||||
import org.apache.maven.archiva.repository.ManagedRepositoryContent;
|
||||
import org.apache.maven.archiva.repository.RepositoryContentFactory;
|
||||
import org.apache.maven.archiva.repository.RepositoryException;
|
||||
import org.apache.maven.archiva.repository.RepositoryNotFoundException;
|
||||
import org.apache.maven.archiva.repository.audit.AuditEvent;
|
||||
import org.apache.maven.archiva.repository.audit.AuditListener;
|
||||
import org.apache.maven.archiva.repository.audit.Auditable;
|
||||
import org.apache.maven.archiva.repository.content.RepositoryRequest;
|
||||
import org.apache.maven.archiva.repository.layout.LayoutException;
|
||||
import org.apache.maven.archiva.repository.metadata.MetadataTools;
|
||||
import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
|
||||
import org.apache.maven.archiva.web.util.ArchivaXworkUser;
|
||||
import org.apache.maven.archiva.webdav.AbstractDavServerComponent;
|
||||
import org.apache.maven.archiva.webdav.DavServerComponent;
|
||||
import org.apache.maven.archiva.webdav.DavServerException;
|
||||
import org.apache.maven.archiva.webdav.DavServerListener;
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
|
||||
import org.apache.maven.model.DistributionManagement;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.Relocation;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
|
||||
/**
|
||||
* ProxiedDavServer
|
||||
*
|
||||
* @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
|
||||
* @version $Id$
|
||||
* @plexus.component role="org.apache.maven.archiva.webdav.DavServerComponent"
|
||||
* role-hint="proxied" instantiation-strategy="per-lookup"
|
||||
*/
|
||||
public class ProxiedDavServer
|
||||
extends AbstractDavServerComponent
|
||||
implements Auditable
|
||||
{
|
||||
/**
|
||||
* @plexus.requirement role-hint="simple"
|
||||
*/
|
||||
private DavServerComponent davServer;
|
||||
|
||||
/**
|
||||
* @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
|
||||
*/
|
||||
private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private RepositoryContentFactory repositoryFactory;
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private RepositoryRequest repositoryRequest;
|
||||
|
||||
/**
|
||||
* @plexus.requirement role-hint="default"
|
||||
*/
|
||||
private RepositoryProxyConnectors connectors;
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private MetadataTools metadataTools;
|
||||
|
||||
private ManagedRepositoryContent managedRepository;
|
||||
|
||||
public String getPrefix()
|
||||
{
|
||||
return davServer.getPrefix();
|
||||
}
|
||||
|
||||
public File getRootDirectory()
|
||||
{
|
||||
return davServer.getRootDirectory();
|
||||
}
|
||||
|
||||
public void setPrefix( String prefix )
|
||||
{
|
||||
davServer.setPrefix( prefix );
|
||||
}
|
||||
|
||||
public void setRootDirectory( File rootDirectory )
|
||||
{
|
||||
davServer.setRootDirectory( rootDirectory );
|
||||
}
|
||||
|
||||
public void init( ServletConfig servletConfig )
|
||||
throws DavServerException
|
||||
{
|
||||
davServer.init( servletConfig );
|
||||
|
||||
try
|
||||
{
|
||||
managedRepository = repositoryFactory.getManagedRepositoryContent( getPrefix() );
|
||||
}
|
||||
catch ( RepositoryNotFoundException e )
|
||||
{
|
||||
throw new DavServerException( e.getMessage(), e );
|
||||
}
|
||||
catch ( RepositoryException e )
|
||||
{
|
||||
throw new DavServerException( e.getMessage(), e );
|
||||
}
|
||||
}
|
||||
|
||||
public void process( DavServerRequest request, HttpServletResponse response )
|
||||
throws DavServerException, ServletException, IOException
|
||||
{
|
||||
boolean isGet = WebdavMethodUtil.isReadMethod( request.getRequest().getMethod() );
|
||||
boolean isPut = WebdavMethodUtil.isWriteMethod( request.getRequest().getMethod() );
|
||||
String resource = request.getLogicalResource();
|
||||
|
||||
if ( isGet )
|
||||
{
|
||||
// Default behaviour is to treat the resource natively.
|
||||
File resourceFile = new File( managedRepository.getRepoRoot(), resource );
|
||||
|
||||
// If this a directory resource, then we are likely browsing.
|
||||
if ( resourceFile.exists() && resourceFile.isDirectory() )
|
||||
{
|
||||
String requestURL = request.getRequest().getRequestURL().toString();
|
||||
|
||||
// [MRM-440] - If webdav URL lacks a trailing /, navigating to
|
||||
// all links in the listing return 404.
|
||||
if ( !requestURL.endsWith( "/" ) )
|
||||
{
|
||||
String redirectToLocation = requestURL + "/";
|
||||
response.sendRedirect( redirectToLocation );
|
||||
return;
|
||||
}
|
||||
|
||||
// Process the request.
|
||||
davServer.process( request, response );
|
||||
|
||||
// All done.
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point the incoming request can either be in default or
|
||||
// legacy layout format.
|
||||
try
|
||||
{
|
||||
boolean fromProxy = fetchContentFromProxies( request, resource );
|
||||
|
||||
// Perform an adjustment of the resource to the managed
|
||||
// repository expected path.
|
||||
resource =
|
||||
repositoryRequest
|
||||
.toNativePath( request.getLogicalResource(), managedRepository );
|
||||
resourceFile = new File( managedRepository.getRepoRoot(), resource );
|
||||
|
||||
// Adjust the pathInfo resource to be in the format that the dav
|
||||
// server impl expects.
|
||||
request.setLogicalResource( resource );
|
||||
|
||||
boolean previouslyExisted = resourceFile.exists();
|
||||
|
||||
// Attempt to fetch the resource from any defined proxy.
|
||||
if ( fromProxy )
|
||||
{
|
||||
processAuditEvents( request, resource, previouslyExisted, resourceFile,
|
||||
" (proxied)" );
|
||||
}
|
||||
}
|
||||
catch ( LayoutException e )
|
||||
{
|
||||
// Invalid resource, pass it on.
|
||||
respondResourceMissing( request, response, e );
|
||||
|
||||
// All done.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( resourceFile.exists() )
|
||||
{
|
||||
// [MRM-503] - Metadata file need Pragma:no-cache response
|
||||
// header.
|
||||
if ( request.getLogicalResource().endsWith( "/maven-metadata.xml" ) )
|
||||
{
|
||||
response.addHeader( "Pragma", "no-cache" );
|
||||
response.addHeader( "Cache-Control", "no-cache" );
|
||||
}
|
||||
|
||||
// TODO: [MRM-524] determine http caching options for other
|
||||
// types of files (artifacts, sha1, md5, snapshots)
|
||||
|
||||
davServer.process( request, response );
|
||||
}
|
||||
else
|
||||
{
|
||||
respondResourceMissing( request, response, null );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isPut )
|
||||
{
|
||||
/*
|
||||
* Create parent directories that don't exist when writing a file
|
||||
* This actually makes this implementation not compliant to the
|
||||
* WebDAV RFC - but we have enough knowledge about how the
|
||||
* collection is being used to do this reasonably and some versions
|
||||
* of Maven's WebDAV don't correctly create the collections
|
||||
* themselves.
|
||||
*/
|
||||
|
||||
File rootDirectory = getRootDirectory();
|
||||
if ( rootDirectory != null )
|
||||
{
|
||||
File destDir = new File( rootDirectory, resource ).getParentFile();
|
||||
if ( !destDir.exists() )
|
||||
{
|
||||
destDir.mkdirs();
|
||||
String relPath =
|
||||
PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
|
||||
triggerAuditEvent( request, relPath, AuditEvent.CREATE_DIR );
|
||||
}
|
||||
}
|
||||
|
||||
File resourceFile = new File( managedRepository.getRepoRoot(), resource );
|
||||
|
||||
boolean previouslyExisted = resourceFile.exists();
|
||||
|
||||
// Allow the dav server to process the put request.
|
||||
davServer.process( request, response );
|
||||
|
||||
processAuditEvents( request, resource, previouslyExisted, resourceFile, null );
|
||||
|
||||
// All done.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void respondResourceMissing( DavServerRequest request, HttpServletResponse response,
|
||||
Throwable t )
|
||||
{
|
||||
response.setStatus( HttpServletResponse.SC_NOT_FOUND );
|
||||
|
||||
try
|
||||
{
|
||||
StringBuffer missingUrl = new StringBuffer();
|
||||
missingUrl.append( request.getRequest().getScheme() ).append( "://" );
|
||||
missingUrl.append( request.getRequest().getServerName() ).append( ":" );
|
||||
missingUrl.append( request.getRequest().getServerPort() );
|
||||
missingUrl.append( request.getRequest().getServletPath() );
|
||||
|
||||
String message = "Error 404 Not Found";
|
||||
|
||||
PrintWriter out = new PrintWriter( response.getOutputStream() );
|
||||
|
||||
response.setContentType( "text/html; charset=\"UTF-8\"" );
|
||||
|
||||
out.println( "<html>" );
|
||||
out.println( "<head><title>" + message + "</title></head>" );
|
||||
out.println( "<body>" );
|
||||
|
||||
out.print( "<p><h1>" );
|
||||
out.print( message );
|
||||
out.println( "</h1></p>" );
|
||||
|
||||
out.print( "<p>The following resource does not exist: <a href=\"" );
|
||||
out.print( missingUrl.toString() );
|
||||
out.println( "\">" );
|
||||
out.print( missingUrl.toString() );
|
||||
out.println( "</a></p>" );
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
out.println( "<pre>" );
|
||||
t.printStackTrace( out );
|
||||
out.println( "</pre>" );
|
||||
}
|
||||
|
||||
out.println( "</body></html>" );
|
||||
|
||||
out.flush();
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean fetchContentFromProxies( DavServerRequest request, String resource )
|
||||
throws ServletException
|
||||
{
|
||||
if ( repositoryRequest.isSupportFile( resource ) )
|
||||
{
|
||||
// Checksums are fetched with artifact / metadata.
|
||||
|
||||
// Need to adjust the path for the checksum resource.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it a Metadata resource?
|
||||
if ( repositoryRequest.isDefault( resource ) && repositoryRequest.isMetadata( resource ) )
|
||||
{
|
||||
return fetchMetadataFromProxies( request, resource );
|
||||
}
|
||||
|
||||
// Not any of the above? Then it's gotta be an artifact reference.
|
||||
try
|
||||
{
|
||||
// Get the artifact reference in a layout neutral way.
|
||||
ArtifactReference artifact = repositoryRequest.toArtifactReference( resource );
|
||||
|
||||
if ( artifact != null )
|
||||
{
|
||||
applyServerSideRelocation( artifact );
|
||||
|
||||
File proxiedFile = connectors.fetchFromProxies( managedRepository, artifact );
|
||||
|
||||
// Set the path to the resource using managed repository
|
||||
// specific layout format.
|
||||
request.setLogicalResource( managedRepository.toPath( artifact ) );
|
||||
return ( proxiedFile != null );
|
||||
}
|
||||
}
|
||||
catch ( LayoutException e )
|
||||
{
|
||||
/* eat it */
|
||||
}
|
||||
catch ( ProxyDownloadException e )
|
||||
{
|
||||
throw new ServletException( "Unable to fetch artifact resource.", e );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean fetchMetadataFromProxies( DavServerRequest request, String resource )
|
||||
throws ServletException
|
||||
{
|
||||
ProjectReference project;
|
||||
VersionedReference versioned;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
versioned = metadataTools.toVersionedReference( resource );
|
||||
if ( versioned != null )
|
||||
{
|
||||
connectors.fetchFromProxies( managedRepository, versioned );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch ( RepositoryMetadataException e )
|
||||
{
|
||||
/* eat it */
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
project = metadataTools.toProjectReference( resource );
|
||||
if ( project != null )
|
||||
{
|
||||
connectors.fetchFromProxies( managedRepository, project );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch ( RepositoryMetadataException e )
|
||||
{
|
||||
/* eat it */
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A relocation capable client will request the POM prior to the artifact,
|
||||
* and will then read meta-data and do client side relocation. A simplier
|
||||
* client (like maven 1) will only request the artifact and not use the
|
||||
* metadatas.
|
||||
* <p>
|
||||
* For such clients, archiva does server-side relocation by reading itself
|
||||
* the <relocation> element in metadatas and serving the expected
|
||||
* artifact.
|
||||
*/
|
||||
protected void applyServerSideRelocation( ArtifactReference artifact )
|
||||
throws ProxyDownloadException
|
||||
{
|
||||
if ( "pom".equals( artifact.getType() ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the artifact POM reference
|
||||
ArtifactReference pomReference = new ArtifactReference();
|
||||
pomReference.setGroupId( artifact.getGroupId() );
|
||||
pomReference.setArtifactId( artifact.getArtifactId() );
|
||||
pomReference.setVersion( artifact.getVersion() );
|
||||
pomReference.setType( "pom" );
|
||||
|
||||
// Get the artifact POM from proxied repositories if needed
|
||||
connectors.fetchFromProxies( managedRepository, pomReference );
|
||||
|
||||
// Open and read the POM from the managed repo
|
||||
File pom = managedRepository.toFile( pomReference );
|
||||
|
||||
if ( !pom.exists() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Model model = new MavenXpp3Reader().read( new FileReader( pom ) );
|
||||
DistributionManagement dist = model.getDistributionManagement();
|
||||
if ( dist != null )
|
||||
{
|
||||
Relocation relocation = dist.getRelocation();
|
||||
if ( relocation != null )
|
||||
{
|
||||
// artifact is relocated : update the repositoryPath
|
||||
if ( relocation.getGroupId() != null )
|
||||
{
|
||||
artifact.setGroupId( relocation.getGroupId() );
|
||||
}
|
||||
if ( relocation.getArtifactId() != null )
|
||||
{
|
||||
artifact.setArtifactId( relocation.getArtifactId() );
|
||||
}
|
||||
if ( relocation.getVersion() != null )
|
||||
{
|
||||
artifact.setVersion( relocation.getVersion() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( FileNotFoundException e )
|
||||
{
|
||||
// Artifact has no POM in repo : ignore
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
// Unable to read POM : ignore.
|
||||
}
|
||||
catch ( XmlPullParserException e )
|
||||
{
|
||||
// Invalid POM : ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener( DavServerListener listener )
|
||||
{
|
||||
super.addListener( listener );
|
||||
davServer.addListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseIndexHtml()
|
||||
{
|
||||
return davServer.isUseIndexHtml();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResource( String resource )
|
||||
{
|
||||
return davServer.hasResource( resource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( DavServerListener listener )
|
||||
{
|
||||
davServer.removeListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUseIndexHtml( boolean useIndexHtml )
|
||||
{
|
||||
super.setUseIndexHtml( useIndexHtml );
|
||||
davServer.setUseIndexHtml( useIndexHtml );
|
||||
}
|
||||
|
||||
public ManagedRepositoryContent getRepository()
|
||||
{
|
||||
return managedRepository;
|
||||
}
|
||||
|
||||
private void processAuditEvents( DavServerRequest request, String resource,
|
||||
boolean previouslyExisted, File resourceFile, String suffix )
|
||||
{
|
||||
if ( suffix == null )
|
||||
{
|
||||
suffix = "";
|
||||
}
|
||||
|
||||
// Process Create Audit Events.
|
||||
if ( !previouslyExisted && resourceFile.exists() )
|
||||
{
|
||||
if ( resourceFile.isFile() )
|
||||
{
|
||||
triggerAuditEvent( request, resource, AuditEvent.CREATE_FILE + suffix );
|
||||
}
|
||||
else if ( resourceFile.isDirectory() )
|
||||
{
|
||||
triggerAuditEvent( request, resource, AuditEvent.CREATE_DIR + suffix );
|
||||
}
|
||||
}
|
||||
// Process Remove Audit Events.
|
||||
else if ( previouslyExisted && !resourceFile.exists() )
|
||||
{
|
||||
if ( resourceFile.isFile() )
|
||||
{
|
||||
triggerAuditEvent( request, resource, AuditEvent.REMOVE_FILE + suffix );
|
||||
}
|
||||
else if ( resourceFile.isDirectory() )
|
||||
{
|
||||
triggerAuditEvent( request, resource, AuditEvent.REMOVE_DIR + suffix );
|
||||
}
|
||||
}
|
||||
// Process modify events.
|
||||
else
|
||||
{
|
||||
if ( resourceFile.isFile() )
|
||||
{
|
||||
triggerAuditEvent( request, resource, AuditEvent.MODIFY_FILE + suffix );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerAuditEvent( String user, String remoteIP, String resource, String action )
|
||||
{
|
||||
AuditEvent event = new AuditEvent( this.getPrefix(), user, resource, action );
|
||||
event.setRemoteIP( remoteIP );
|
||||
|
||||
for ( AuditListener listener : auditListeners )
|
||||
{
|
||||
listener.auditEvent( event );
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerAuditEvent( DavServerRequest request, String resource, String action )
|
||||
{
|
||||
triggerAuditEvent( ArchivaXworkUser.getActivePrincipal(), getRemoteIP( request ), resource,
|
||||
action );
|
||||
}
|
||||
|
||||
private String getRemoteIP( DavServerRequest request )
|
||||
{
|
||||
return request.getRequest().getRemoteAddr();
|
||||
}
|
||||
|
||||
public void addAuditListener( AuditListener listener )
|
||||
{
|
||||
this.auditListeners.add( listener );
|
||||
}
|
||||
|
||||
public void clearAuditListeners()
|
||||
{
|
||||
this.auditListeners.clear();
|
||||
}
|
||||
|
||||
public void removeAuditListener( AuditListener listener )
|
||||
{
|
||||
this.auditListeners.remove( listener );
|
||||
}
|
||||
}
|
|
@ -23,29 +23,24 @@ import org.apache.maven.archiva.configuration.ArchivaConfiguration;
|
|||
import org.apache.maven.archiva.configuration.ConfigurationEvent;
|
||||
import org.apache.maven.archiva.configuration.ConfigurationListener;
|
||||
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
|
||||
import org.apache.maven.archiva.security.ArchivaRoleConstants;
|
||||
import org.apache.maven.archiva.webdav.DavServerComponent;
|
||||
import org.apache.maven.archiva.webdav.DavServerException;
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
import org.apache.maven.archiva.webdav.servlet.multiplexed.MultiplexedWebDavServlet;
|
||||
import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
|
||||
import org.codehaus.plexus.redback.authentication.AuthenticationException;
|
||||
import org.codehaus.plexus.redback.authentication.AuthenticationResult;
|
||||
import org.codehaus.plexus.redback.authorization.AuthorizationException;
|
||||
import org.codehaus.plexus.redback.authorization.AuthorizationResult;
|
||||
import org.codehaus.plexus.redback.policy.AccountLockedException;
|
||||
import org.codehaus.plexus.redback.policy.MustChangePasswordException;
|
||||
import org.codehaus.plexus.redback.system.SecuritySession;
|
||||
import org.apache.maven.archiva.webdav.ArchivaDavLocatorFactory;
|
||||
import org.apache.maven.archiva.webdav.ArchivaDavResourceFactory;
|
||||
import org.apache.maven.archiva.webdav.ArchivaDavSessionProvider;
|
||||
import org.apache.maven.archiva.webdav.UnauthorizedDavException;
|
||||
import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
|
||||
import org.apache.jackrabbit.webdav.*;
|
||||
import org.codehaus.plexus.redback.system.SecuritySystem;
|
||||
import org.codehaus.plexus.redback.xwork.filter.authentication.HttpAuthenticator;
|
||||
import org.codehaus.plexus.spring.PlexusToSpringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
@ -57,9 +52,11 @@ import java.util.Map;
|
|||
* @version $Id$
|
||||
*/
|
||||
public class RepositoryServlet
|
||||
extends MultiplexedWebDavServlet
|
||||
extends AbstractWebdavServlet
|
||||
implements ConfigurationListener
|
||||
{
|
||||
private Logger log = LoggerFactory.getLogger(RepositoryServlet.class);
|
||||
|
||||
private SecuritySystem securitySystem;
|
||||
|
||||
private HttpAuthenticator httpAuth;
|
||||
|
@ -67,17 +64,76 @@ public class RepositoryServlet
|
|||
private ArchivaConfiguration configuration;
|
||||
|
||||
private Map<String, ManagedRepositoryConfiguration> repositoryMap;
|
||||
|
||||
private ArchivaMimeTypeLoader mimeTypeLoader;
|
||||
|
||||
private DavLocatorFactory locatorFactory;
|
||||
|
||||
private DavResourceFactory resourceFactory;
|
||||
|
||||
private DavSessionProvider sessionProvider;
|
||||
|
||||
private final Object reloadLock = new Object();
|
||||
|
||||
public void init(javax.servlet.ServletConfig servletConfig)
|
||||
throws ServletException
|
||||
{
|
||||
super.init(servletConfig);
|
||||
initServers(servletConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service the given request.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ServletException
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
WebdavRequest webdavRequest = new WebdavRequestImpl(request, getLocatorFactory());
|
||||
// DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
|
||||
int methodCode = DavMethods.getMethodCode(request.getMethod());
|
||||
boolean noCache = DavMethods.isDeltaVMethod(webdavRequest) && !(DavMethods.DAV_VERSION_CONTROL == methodCode || DavMethods.DAV_REPORT == methodCode);
|
||||
WebdavResponse webdavResponse = new WebdavResponseImpl(response, noCache);
|
||||
try {
|
||||
// make sure there is a authenticated user
|
||||
if (!getDavSessionProvider().attachSession(webdavRequest)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check matching if=header for lock-token relevant operations
|
||||
DavResource resource = getResourceFactory().createResource(webdavRequest.getRequestLocator(), webdavRequest, webdavResponse);
|
||||
if (!isPreconditionValid(webdavRequest, resource)) {
|
||||
webdavResponse.sendError(DavServletResponse.SC_PRECONDITION_FAILED);
|
||||
return;
|
||||
}
|
||||
if (!execute(webdavRequest, webdavResponse, methodCode, resource)) {
|
||||
super.service(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
catch (UnauthorizedDavException e)
|
||||
{
|
||||
webdavResponse.setHeader("WWW-Authenticate", getAuthenticateHeaderValue(e.getRepositoryName()));
|
||||
webdavResponse.sendError(e.getErrorCode(), e.getStatusPhrase());
|
||||
}
|
||||
catch (DavException e) {
|
||||
if (e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED) {
|
||||
log.error("Should throw UnauthorizedDavException");
|
||||
} else {
|
||||
webdavResponse.sendError(e);
|
||||
}
|
||||
} finally {
|
||||
getDavSessionProvider().releaseSession(webdavRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void initServers( ServletConfig servletConfig )
|
||||
throws DavServerException
|
||||
{
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
|
||||
|
||||
mimeTypeLoader = (ArchivaMimeTypeLoader) wac.getBean(
|
||||
PlexusToSpringUtils.buildSpringId( ArchivaMimeTypeLoader.class.getName() ) );
|
||||
|
||||
securitySystem = (SecuritySystem) wac.getBean( PlexusToSpringUtils.buildSpringId( SecuritySystem.ROLE ) );
|
||||
httpAuth =
|
||||
(HttpAuthenticator) wac.getBean( PlexusToSpringUtils.buildSpringId( HttpAuthenticator.ROLE, "basic" ) );
|
||||
|
@ -101,120 +157,11 @@ public class RepositoryServlet
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DavServerComponent server = createServer( repo.getId(), repoDir, servletConfig );
|
||||
|
||||
server.setUseIndexHtml( true );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void service( HttpServletRequest httpRequest, HttpServletResponse httpResponse )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// Wrap the incoming request to adjust paths and whatnot.
|
||||
super.service( new PolicingServletRequest( httpRequest ), httpResponse );
|
||||
}
|
||||
|
||||
public synchronized ManagedRepositoryConfiguration getRepository( String prefix )
|
||||
{
|
||||
if ( repositoryMap.isEmpty() )
|
||||
{
|
||||
repositoryMap.putAll( configuration.getConfiguration().getManagedRepositoriesAsMap() );
|
||||
}
|
||||
return repositoryMap.get( prefix );
|
||||
}
|
||||
|
||||
private String getRepositoryName( DavServerRequest request )
|
||||
{
|
||||
ManagedRepositoryConfiguration repoConfig = getRepository( request.getPrefix() );
|
||||
if ( repoConfig == null )
|
||||
{
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
return repoConfig.getName();
|
||||
}
|
||||
|
||||
public boolean isAuthenticated( DavServerRequest davRequest, HttpServletResponse response )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
HttpServletRequest request = davRequest.getRequest();
|
||||
|
||||
// Authentication Tests.
|
||||
try
|
||||
{
|
||||
AuthenticationResult result = httpAuth.getAuthenticationResult( request, response );
|
||||
|
||||
if ( result != null && !result.isAuthenticated() )
|
||||
{
|
||||
// Must Authenticate.
|
||||
httpAuth.challenge( request, response, "Repository " + getRepositoryName( davRequest ),
|
||||
new AuthenticationException( "User Credentials Invalid" ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch ( AuthenticationException e )
|
||||
{
|
||||
log( "Fatal Http Authentication Error.", e );
|
||||
throw new ServletException( "Fatal Http Authentication Error.", e );
|
||||
}
|
||||
catch ( AccountLockedException e )
|
||||
{
|
||||
httpAuth.challenge( request, response, "Repository " + getRepositoryName( davRequest ),
|
||||
new AuthenticationException( "User account is locked" ) );
|
||||
}
|
||||
catch ( MustChangePasswordException e )
|
||||
{
|
||||
httpAuth.challenge( request, response, "Repository " + getRepositoryName( davRequest ),
|
||||
new AuthenticationException( "You must change your password." ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAuthorized( DavServerRequest davRequest, HttpServletResponse response )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// Authorization Tests.
|
||||
HttpServletRequest request = davRequest.getRequest();
|
||||
|
||||
boolean isWriteRequest = WebdavMethodUtil.isWriteMethod( request.getMethod() );
|
||||
|
||||
SecuritySession securitySession = httpAuth.getSecuritySession();
|
||||
try
|
||||
{
|
||||
String permission = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS;
|
||||
|
||||
if ( isWriteRequest )
|
||||
{
|
||||
permission = ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD;
|
||||
}
|
||||
|
||||
AuthorizationResult authzResult =
|
||||
securitySystem.authorize( securitySession, permission, davRequest.getPrefix() );
|
||||
|
||||
if ( !authzResult.isAuthorized() )
|
||||
{
|
||||
if ( authzResult.getException() != null )
|
||||
{
|
||||
log( "Authorization Denied [ip=" + request.getRemoteAddr() + ",isWriteRequest=" + isWriteRequest +
|
||||
",permission=" + permission + ",repo=" + davRequest.getPrefix() + "] : " +
|
||||
authzResult.getException().getMessage() );
|
||||
}
|
||||
|
||||
// Issue HTTP Challenge.
|
||||
httpAuth.challenge( request, response, "Repository " + getRepositoryName( davRequest ),
|
||||
new AuthenticationException( "Authorization Denied." ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch ( AuthorizationException e )
|
||||
{
|
||||
throw new ServletException( "Fatal Authorization Subsystem Error." );
|
||||
}
|
||||
|
||||
return true;
|
||||
resourceFactory = (DavResourceFactory)wac.getBean(PlexusToSpringUtils.buildSpringId(ArchivaDavResourceFactory.class));
|
||||
locatorFactory = new ArchivaDavLocatorFactory();
|
||||
sessionProvider = new ArchivaDavSessionProvider(wac);
|
||||
}
|
||||
|
||||
public void configurationEvent( ConfigurationEvent event )
|
||||
|
@ -233,25 +180,68 @@ public class RepositoryServlet
|
|||
repositoryMap.putAll( configuration.getConfiguration().getManagedRepositoriesAsMap() );
|
||||
}
|
||||
|
||||
synchronized ( davManager )
|
||||
synchronized ( reloadLock )
|
||||
{
|
||||
// Clear out the old servers.
|
||||
davManager.removeAllServers();
|
||||
|
||||
// Create new servers.
|
||||
try
|
||||
{
|
||||
initServers( getServletConfig() );
|
||||
}
|
||||
catch ( DavServerException e )
|
||||
{
|
||||
log( "Unable to init servers: " + e.getMessage(), e );
|
||||
}
|
||||
initServers( getServletConfig() );
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ManagedRepositoryConfiguration getRepository( String prefix )
|
||||
{
|
||||
if ( repositoryMap.isEmpty() )
|
||||
{
|
||||
repositoryMap.putAll( configuration.getConfiguration().getManagedRepositoriesAsMap() );
|
||||
}
|
||||
return repositoryMap.get( prefix );
|
||||
}
|
||||
|
||||
ArchivaConfiguration getConfiguration()
|
||||
{
|
||||
return configuration;
|
||||
}
|
||||
|
||||
protected boolean isPreconditionValid(final WebdavRequest request, final DavResource davResource)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public DavSessionProvider getDavSessionProvider()
|
||||
{
|
||||
return sessionProvider;
|
||||
}
|
||||
|
||||
public void setDavSessionProvider(final DavSessionProvider davSessionProvider)
|
||||
{
|
||||
this.sessionProvider = davSessionProvider;
|
||||
}
|
||||
|
||||
public DavLocatorFactory getLocatorFactory()
|
||||
{
|
||||
return locatorFactory;
|
||||
}
|
||||
|
||||
public void setLocatorFactory(final DavLocatorFactory davLocatorFactory)
|
||||
{
|
||||
locatorFactory = davLocatorFactory;
|
||||
}
|
||||
|
||||
public DavResourceFactory getResourceFactory()
|
||||
{
|
||||
return resourceFactory;
|
||||
}
|
||||
|
||||
public void setResourceFactory(final DavResourceFactory davResourceFactory)
|
||||
{
|
||||
resourceFactory = davResourceFactory;
|
||||
}
|
||||
|
||||
public String getAuthenticateHeaderValue()
|
||||
{
|
||||
throw new UnsupportedOperationException("");
|
||||
}
|
||||
|
||||
public String getAuthenticateHeaderValue(String repository)
|
||||
{
|
||||
return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,19 +66,6 @@
|
|||
</configuration>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<role>org.apache.maven.archiva.webdav.DavServerManager</role>
|
||||
<role-hint>default</role-hint>
|
||||
<implementation>org.apache.maven.archiva.webdav.DefaultDavServerManager</implementation>
|
||||
<description>DefaultDavServerManager</description>
|
||||
<requirements>
|
||||
<requirement>
|
||||
<role>org.apache.maven.archiva.webdav.DavServerComponent</role>
|
||||
<role-hint>proxied</role-hint>
|
||||
</requirement>
|
||||
</requirements>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<role>org.codehaus.plexus.jdo.JdoFactory</role>
|
||||
<role-hint>archiva</role-hint>
|
||||
|
@ -187,14 +174,14 @@
|
|||
</configuration>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<!-- <component>
|
||||
<role>org.apache.maven.archiva.webdav.util.MimeTypes</role>
|
||||
<implementation>org.apache.maven.archiva.webdav.util.MimeTypes</implementation>
|
||||
<description>MimeTypes</description>
|
||||
<configuration>
|
||||
<resource>archiva-mime-types.txt</resource>
|
||||
</configuration>
|
||||
</component>
|
||||
</component> -->
|
||||
|
||||
<!--
|
||||
| Logger manager
|
||||
|
|
|
@ -28,13 +28,13 @@ import org.codehaus.plexus.spring.PlexusInSpringTestCase;
|
|||
* @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ArchivaMimeTypeLoaderTest
|
||||
public class MimeTypesLoaderTest
|
||||
extends PlexusInSpringTestCase
|
||||
{
|
||||
public void testArchivaTypes()
|
||||
throws Exception
|
||||
{
|
||||
lookup( ArchivaMimeTypeLoader.class );
|
||||
lookup( MimeTypes.class );
|
||||
MimeTypes mimeTypes = (MimeTypes) lookup( MimeTypes.class );
|
||||
assertNotNull( mimeTypes );
|
||||
|
||||
|
@ -43,5 +43,6 @@ public class ArchivaMimeTypeLoaderTest
|
|||
assertEquals( "md5", "text/plain", mimeTypes.getMimeType( "foo.md5" ) );
|
||||
assertEquals( "pgp", "application/pgp-encrypted", mimeTypes.getMimeType( "foo.pgp" ) );
|
||||
assertEquals( "jar", "application/java-archive", mimeTypes.getMimeType( "foo.jar" ) );
|
||||
assertEquals( "Default", "application/octet-stream", mimeTypes.getMimeType(".SomeUnknownExtension"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.apache.maven.archiva.web.repository;
|
||||
|
||||
/*
|
||||
* 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.maven.archiva.webdav.ArchivaDavSessionProvider;
|
||||
import org.apache.jackrabbit.webdav.WebdavRequest;
|
||||
import org.apache.jackrabbit.webdav.DavException;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class UnauthenticatedDavSessionProvider extends ArchivaDavSessionProvider
|
||||
{
|
||||
public UnauthenticatedDavSessionProvider(WebApplicationContext applicationContext)
|
||||
{
|
||||
super(applicationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAuthorized( WebdavRequest request, String repositoryId )
|
||||
throws DavException
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAuthenticated( WebdavRequest request, String repositoryId )
|
||||
throws DavException
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -19,11 +19,10 @@ package org.apache.maven.archiva.web.repository;
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletConfig;
|
||||
|
||||
/**
|
||||
* UnauthenticatedRepositoryServlet
|
||||
|
@ -34,16 +33,14 @@ import java.io.IOException;
|
|||
public class UnauthenticatedRepositoryServlet
|
||||
extends RepositoryServlet
|
||||
{
|
||||
public boolean isAuthorized( DavServerRequest davRequest, HttpServletResponse response )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated( DavServerRequest davRequest, HttpServletResponse response )
|
||||
throws ServletException, IOException
|
||||
public synchronized void initServers( ServletConfig servletConfig )
|
||||
{
|
||||
return true;
|
||||
super.initServers(servletConfig);
|
||||
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
|
||||
|
||||
UnauthenticatedDavSessionProvider sessionProvider = new UnauthenticatedDavSessionProvider(wac);
|
||||
setDavSessionProvider(sessionProvider);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,45 @@
|
|||
</parent>
|
||||
|
||||
<artifactId>archiva-webdav</artifactId>
|
||||
<name>Archiva WebDAV Provider</name>
|
||||
<name>Archiva Web :: WebDAV</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- Archiva Modules -->
|
||||
<dependency>
|
||||
<groupId>org.apache.archiva</groupId>
|
||||
<artifactId>archiva-repository-layer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.archiva</groupId>
|
||||
<artifactId>archiva-proxy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.archiva</groupId>
|
||||
<artifactId>archiva-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.archiva</groupId>
|
||||
<artifactId>archiva-configuration</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus.redback</groupId>
|
||||
<artifactId>redback-xwork-integration</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-container-default</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- end Archiva Modules -->
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-file</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
|
@ -37,51 +73,40 @@
|
|||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-component-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-utils</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-container-default</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-spring</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>2.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jackrabbit</groupId>
|
||||
<artifactId>jackrabbit-webdav</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
<!-- We import these classes directly to be able to patch them, since this library hasn't been released in some time
|
||||
<dependency>
|
||||
<groupId>it.could</groupId>
|
||||
<artifactId>webdav</artifactId>
|
||||
<version>0.4</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<!-- Required by it.could classes -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>slide</groupId>
|
||||
<artifactId>slide-webdavlib</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<version>6.0.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- Required by it.could classes -->
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* <p>An utility class providing various static methods operating on
|
||||
* {@link InputStream input} and {@link OutputStream output} streams.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public final class StreamTools {
|
||||
|
||||
/** <p>Deny construction.</p> */
|
||||
private StreamTools() { };
|
||||
|
||||
/**
|
||||
* <p>Copy every byte from the specified {@link InputStream} to the specifed
|
||||
* {@link OutputStream} and then close both of them.</p>
|
||||
*
|
||||
* <p>This method is equivalent to a call to the following method:
|
||||
* {@link #copy(InputStream,OutputStream,boolean) copy(in, out, true)}.</p>
|
||||
*
|
||||
* @param in the {@link InputStream} to read bytes from.
|
||||
* @param out the {@link OutputStream} to write bytes to.
|
||||
* @return the number of bytes copied.
|
||||
* @throws IOException if an I/O error occurred copying the data.
|
||||
*/
|
||||
public static long copy(InputStream in, OutputStream out)
|
||||
throws IOException {
|
||||
return copy(in, out, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Copy every byte from the specified {@link InputStream} to the specifed
|
||||
* {@link OutputStream} and then optionally close both of them.</p>
|
||||
*
|
||||
* @param in the {@link InputStream} to read bytes from.
|
||||
* @param out the {@link OutputStream} to write bytes to.
|
||||
* @param close whether to close the streams or not.
|
||||
* @return the number of bytes copied.
|
||||
* @throws IOException if an I/O error occurred copying the data.
|
||||
*/
|
||||
public static long copy(InputStream in, OutputStream out, boolean close)
|
||||
throws IOException {
|
||||
if (in == null) throw new NullPointerException("Null input");
|
||||
if (out == null) throw new NullPointerException("Null output");
|
||||
|
||||
final byte buffer[] = new byte[4096];
|
||||
int length = -1;
|
||||
long total = 0;
|
||||
while ((length = in.read(buffer)) >= 0) {
|
||||
out.write(buffer, 0, length);
|
||||
total += length;
|
||||
}
|
||||
|
||||
if (close) {
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the output stream. The output stream can be null and any IOException's will be swallowed.
|
||||
*
|
||||
* @param outputStream The stream to close.
|
||||
*/
|
||||
public static void close( OutputStream outputStream )
|
||||
{
|
||||
if ( outputStream == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
outputStream.close();
|
||||
}
|
||||
catch( IOException ex )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the input stream. The input stream can be null and any IOException's will be swallowed.
|
||||
*
|
||||
* @param inputStream The stream to close.
|
||||
*/
|
||||
public static void close( InputStream inputStream )
|
||||
{
|
||||
if ( inputStream == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
catch( IOException ex )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util;
|
||||
|
||||
import it.could.util.encoding.Encodable;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* <p>An utility class providing various static methods operating on
|
||||
* {@link String}s.</p>
|
||||
*
|
||||
* <p>This class implement the {@link Encodable} interface from which it
|
||||
* inherits its {@link Encodable#DEFAULT_ENCODING default encoding}.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public final class StringTools {
|
||||
|
||||
/** <p>The {@link SimpleDateFormat} RFC-822 date format.</p> */
|
||||
private static final String FORMAT_822 = "EEE, dd MMM yyyy HH:mm:ss 'GMT'";
|
||||
/** <p>The {@link SimpleDateFormat} RFC-822 date format.</p> */
|
||||
private static final String FORMAT_ISO = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
||||
/** <p>The {@link TimeZone} to use for dates.</p> */
|
||||
private static final TimeZone TIMEZONE = TimeZone.getTimeZone("GMT");
|
||||
/** <p>The {@link Locale} to use for dates.</p> */
|
||||
private static final Locale LOCALE = Locale.US;
|
||||
|
||||
/** <p>Deny construction.</p> */
|
||||
private StringTools() { }
|
||||
|
||||
/* ====================================================================== */
|
||||
/* NUMBER AND DATE PARSING AND FORMATTING */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Format a {@link Number} into a {@link String} making sure that
|
||||
* {@link NullPointerException}s are not thrown.</p>
|
||||
*
|
||||
* @param number the {@link Number} to format.
|
||||
* @return a {@link String} instance or <b>null</b> if the object was null.
|
||||
*/
|
||||
public static String formatNumber(Number number) {
|
||||
if (number == null) return null;
|
||||
return (number.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse a {@link String} into a {@link Long}.</p>
|
||||
*
|
||||
* @param string the {@link String} to parse.
|
||||
* @return a {@link Long} instance or <b>null</b> if the date was null or
|
||||
* if there was an error parsing the specified {@link String}.
|
||||
*/
|
||||
public static Long parseNumber(String string) {
|
||||
if (string == null) return null;
|
||||
try {
|
||||
return new Long(string);
|
||||
} catch (NumberFormatException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Format a {@link Date} according to the HTTP/1.1 RFC.</p>
|
||||
*
|
||||
* @param date the {@link Date} to format.
|
||||
* @return a {@link String} instance or <b>null</b> if the date was null.
|
||||
*/
|
||||
public static String formatHttpDate(Date date) {
|
||||
if (date == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_822, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
return formatter.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Format a {@link Date} according to the ISO 8601 specification.</p>
|
||||
*
|
||||
* @param date the {@link Date} to format.
|
||||
* @return a {@link String} instance or <b>null</b> if the date was null.
|
||||
*/
|
||||
public static String formatIsoDate(Date date) {
|
||||
if (date == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_ISO, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
return formatter.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse a {@link String} into a {@link Date} according to the
|
||||
* HTTP/1.1 RFC (<code>Mon, 31 Jan 2000 11:59:00 GMT</code>).</p>
|
||||
*
|
||||
* @param string the {@link String} to parse.
|
||||
* @return a {@link Date} instance or <b>null</b> if the date was null or
|
||||
* if there was an error parsing the specified {@link String}.
|
||||
*/
|
||||
public static Date parseHttpDate(String string) {
|
||||
if (string == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_822, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
try {
|
||||
return formatter.parse(string);
|
||||
} catch (ParseException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse a {@link String} into a {@link Date} according to the ISO 8601
|
||||
* specification (<code>2000-12-31T11:59:00Z</code>).</p>
|
||||
*
|
||||
* @param string the {@link String} to parse.
|
||||
* @return a {@link Date} instance or <b>null</b> if the date was null or
|
||||
* if there was an error parsing the specified {@link String}.
|
||||
*/
|
||||
public static Date parseIsoDate(String string) {
|
||||
if (string == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_ISO, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
try {
|
||||
return formatter.parse(string);
|
||||
} catch (ParseException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* STRING SPLITTING */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Split the specified string in two parts according to the specified
|
||||
* delimiter, and any resulting path of zero length will be converted to
|
||||
* <b>null</b>.</p>
|
||||
*/
|
||||
public static String[] splitOnce(String source, char delimiter,
|
||||
boolean noDelimReturnSecond) {
|
||||
if (source == null) return new String[] { null, null };
|
||||
final int position = source.indexOf(delimiter);
|
||||
if (position < 0) { // --> first
|
||||
if (noDelimReturnSecond) return new String[] { null, source };
|
||||
else return new String[] { source, null };
|
||||
} else if (position == 0) {
|
||||
if (source.length() == 1) { // --> |
|
||||
return new String[] { null, null };
|
||||
} else { // --> |second
|
||||
return new String[] { null, source.substring(1) };
|
||||
}
|
||||
} else {
|
||||
final String first = source.substring(0, position);
|
||||
if (source.length() -1 == position) { // --> first|
|
||||
return new String[] { first, null };
|
||||
} else { // --> first|second
|
||||
return new String[] { first, source.substring(position + 1) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Split the specified string according to the specified delimiter, and
|
||||
* any resulting path of zero length will be converted to <b>null</b>.</p>
|
||||
*/
|
||||
public static String[] splitAll(String source, char delimiter) {
|
||||
final List strings = new ArrayList();
|
||||
String current = source;
|
||||
while (current != null) {
|
||||
String split[] = splitOnce(current, delimiter, false);
|
||||
strings.add(split[0]);
|
||||
current = split[1];
|
||||
}
|
||||
if (current != null) strings.add(current);
|
||||
final int length = source.length();
|
||||
if ((length > 0) && (source.charAt(length - 1) == delimiter)) {
|
||||
strings.add(null);
|
||||
}
|
||||
return (String []) strings.toArray(new String[strings.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Find the first occurrence of one of the specified delimiter characters
|
||||
* in the specified source string.</p>
|
||||
*/
|
||||
public static int findFirst(String source, String delimiters) {
|
||||
final char array[] = source.toCharArray();
|
||||
final char delim[] = delimiters.toCharArray();
|
||||
for (int x = 0; x < array.length; x ++) {
|
||||
for (int y = 0; y < delim.length; y ++) {
|
||||
if (array[x] == delim[y]) return x;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util.encoding;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* <p>The {@link Encodable} interface describes an {@link Object} whose
|
||||
* {@link String} representation can vary depending on the encoding used.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public interface Encodable extends EncodingAware {
|
||||
|
||||
/**
|
||||
* <p>Return the {@link String} representation of this instance.</p>
|
||||
*
|
||||
* <p>This method is equivalent to a call to
|
||||
* {@link #toString(String) toString}({@link EncodingAware#DEFAULT_ENCODING
|
||||
* DEFAULT_ENCODING})</p>
|
||||
*/
|
||||
public String toString();
|
||||
|
||||
/**
|
||||
* <p>Return the {@link String} representation of this instance given
|
||||
* a specific character encoding.</p>
|
||||
*
|
||||
* @throws UnsupportedEncodingException if the specified encoding is not
|
||||
* supported by the platform.
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException;
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util.encoding;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
/**
|
||||
* <p>The {@link EncodingAware} interface describes an {@link Object} aware
|
||||
* of multiple encodings existing withing the platform.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public interface EncodingAware {
|
||||
|
||||
/** <p>The default encoding is specified as being <code>UTF-8</code>.</p> */
|
||||
public static final String DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
/** <p>The platform encoding is evaluated at runtime from the JVM.</p> */
|
||||
public static final String PLATFORM_ENCODING =
|
||||
new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
|
||||
|
||||
}
|
|
@ -1,274 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util.encoding;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* <p>An utility class providing various static methods dealing with
|
||||
* encodings and {@link Encodable} objects..</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public final class EncodingTools implements EncodingAware {
|
||||
|
||||
/** <p>The Base-64 alphabet.</p> */
|
||||
private static final char ALPHABET[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' };
|
||||
|
||||
/** <p>Deny construction of this class.</p> */
|
||||
private EncodingTools() { }
|
||||
|
||||
/* ====================================================================== */
|
||||
/* URL ENCODING / DECODING */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the {@link String} representation of the specified
|
||||
* {@link Encodable} object using the {@link EncodingAware#DEFAULT_ENCODING
|
||||
* default encoding}.</p>
|
||||
*
|
||||
* throws NullPointerException if the {@link Encodable} was <b>null</b>.
|
||||
*/
|
||||
public static String toString(Encodable encodable) {
|
||||
try {
|
||||
return encodable.toString(DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Default encoding \"" + DEFAULT_ENCODING +
|
||||
"\" not supported by the platform";
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* URL ENCODING / DECODING */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>URL-encode the specified string.</p>
|
||||
*/
|
||||
public static String urlEncode(String source, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (source == null) return null;
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
return URLEncoder.encode(source, encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>URL-encode the specified string.</p>
|
||||
*/
|
||||
public static String urlEncode(String source) {
|
||||
if (source == null) return null;
|
||||
try {
|
||||
return URLEncoder.encode(source, DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>URL-decode the specified string.</p>
|
||||
*/
|
||||
public static String urlDecode(String source, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (source == null) return null;
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
return URLDecoder.decode(source, encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>URL-decode the specified string.</p>
|
||||
*/
|
||||
public static String urlDecode(String source) {
|
||||
if (source == null) return null;
|
||||
try {
|
||||
return URLDecoder.decode(source, DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* BASE 64 ENCODING / DECODING */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Encode the specified string in base 64 using the specified
|
||||
* encoding.</p>
|
||||
*/
|
||||
public static final String base64Encode(String string, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
/* Check the source string for null or the empty string. */
|
||||
if (string == null) return (null);
|
||||
if (string.length() == 0) return "";
|
||||
|
||||
/* Check the encoding */
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
|
||||
/* Prepare the buffers that we'll use to encode in Base 64 */
|
||||
final byte bsrc[] = string.getBytes(encoding);
|
||||
final char bdst[] = new char[(bsrc.length + 2) / 3 * 4];
|
||||
|
||||
/* Iterate into the source in chunks of three bytes */
|
||||
int psrc = -1;
|
||||
int pdst = 0;
|
||||
int temp = 0;
|
||||
while ((psrc = psrc + 3) < bsrc.length) {
|
||||
/* For every three bytes processed ... */
|
||||
temp = ((bsrc[psrc - 2] << 16) & 0xFF0000) |
|
||||
((bsrc[psrc - 1] << 8) & 0x00FF00) |
|
||||
((bsrc[psrc ] ) & 0x0000FF);
|
||||
/* ... we append four bytes to the buffer */
|
||||
bdst[pdst ++] = ALPHABET[(temp >> 18) & 0x3f];
|
||||
bdst[pdst ++] = ALPHABET[(temp >> 12) & 0x3f];
|
||||
bdst[pdst ++] = ALPHABET[(temp >> 6) & 0x3f];
|
||||
bdst[pdst ++] = ALPHABET[(temp ) & 0x3f];
|
||||
}
|
||||
|
||||
/* Let's check whether we still have some bytes to encode */
|
||||
switch (psrc - bsrc.length) {
|
||||
case 0: /* Two bytes left to encode */
|
||||
temp = ((bsrc[psrc - 2] & 0xFF) << 8) | (bsrc[psrc - 1] & 0xFF);
|
||||
bdst[pdst ++] = ALPHABET[(temp >> 10) & 0x3f];
|
||||
bdst[pdst ++] = ALPHABET[(temp >> 4) & 0x3f];
|
||||
bdst[pdst ++] = ALPHABET[(temp << 2) & 0x3c];
|
||||
bdst[pdst ++] = ALPHABET[64];
|
||||
break;
|
||||
case 1: /* One byte left to encode */
|
||||
temp = (bsrc[psrc - 2] & 0xFF);
|
||||
bdst[pdst ++] = ALPHABET[(temp >> 2) & 0x3f];
|
||||
bdst[pdst ++] = ALPHABET[(temp << 4) & 0x30];
|
||||
bdst[pdst ++] = ALPHABET[64];
|
||||
bdst[pdst ++] = ALPHABET[64];
|
||||
}
|
||||
|
||||
/* Convert the character array into a proper string */
|
||||
return new String(bdst);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Encode the specified string in base 64 using the default encoding.</p>
|
||||
*/
|
||||
public static final String base64Encode(String string) {
|
||||
try {
|
||||
return (base64Encode(string, DEFAULT_ENCODING));
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Decode the specified base 64 string using the specified encoding.</p>
|
||||
*/
|
||||
public static final String base64Decode(String string, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
/* Check the source string for null or the empty string. */
|
||||
if (string == null) return (null);
|
||||
if (string.length() == 0) return "";
|
||||
|
||||
/* Check the encoding */
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
|
||||
/* Retrieve the array of characters of the source string. */
|
||||
final char characters[] = string.toCharArray();
|
||||
|
||||
/* Check the length, which must be dividible by 4. */
|
||||
if ((characters.length & 0x03) != 0)
|
||||
throw new IllegalArgumentException("Invalid length for the "+
|
||||
"encoded string (" + characters.length + ")");
|
||||
|
||||
/* The bytes array length is 3/4th of the characters array length */
|
||||
byte bytes[] = new byte[characters.length - (characters.length >> 2)];
|
||||
|
||||
/*
|
||||
* Since this might take a while check now for the last 4 characters
|
||||
* token: it must contain at most two == and those need to be in the
|
||||
* last two positions in the array (the only valid sequences are:
|
||||
* "????", "???=" and "??==").
|
||||
*/
|
||||
if (((characters[characters.length - 4] == '=') ||
|
||||
(characters[characters.length - 3] == '=')) ||
|
||||
((characters[characters.length - 2] == '=') &&
|
||||
(characters[characters.length - 1] != '='))) {
|
||||
throw new IllegalArgumentException("Invalid pattern for last " +
|
||||
"Base64 token in string to decode: " +
|
||||
characters[characters.length - 4] +
|
||||
characters[characters.length - 3] +
|
||||
characters[characters.length - 2] +
|
||||
characters[characters.length - 1]);
|
||||
}
|
||||
|
||||
/* Translate the Base64-encoded String in chunks of 4 characters. */
|
||||
int coff = 0;
|
||||
int boff = 0;
|
||||
while (coff < characters.length) {
|
||||
boolean last = (coff == (characters.length - 4));
|
||||
int curr = ((value(characters[coff ], last) << 0x12) |
|
||||
(value(characters[coff + 1], last) << 0x0c) |
|
||||
(value(characters[coff + 2], last) << 0x06) |
|
||||
(value(characters[coff + 3], last) ));
|
||||
bytes[boff + 2] = (byte)((curr ) & 0xff);
|
||||
bytes[boff + 1] = (byte)((curr >> 0x08) & 0xff);
|
||||
bytes[boff ] = (byte)((curr >> 0x10) & 0xff);
|
||||
coff += 4;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* Get the real decoded string length, checking out the trailing '=' */
|
||||
if (characters[coff - 1] == '=') boff--;
|
||||
if (characters[coff - 2] == '=') boff--;
|
||||
|
||||
/* All done */
|
||||
return (new String(bytes, 0, boff, encoding));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Decode the specified base 64 string using the default encoding.</p>
|
||||
*/
|
||||
public static final String base64Decode(String string) {
|
||||
try {
|
||||
return (base64Decode(string, DEFAULT_ENCODING));
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/** <p>Retrieve the offset of a character in the base 64 alphabet.</p> */
|
||||
private static final int value(char character, boolean last) {
|
||||
for (int x = 0; x < 64; x++) if (ALPHABET[x] == character) return (x);
|
||||
if (last && (character == ALPHABET[65])) return(0);
|
||||
final String message = "Character \"" + character + "\" invalid";
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Encoding Utilities</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package contains a number of utility classes dealing with generic
|
||||
encoding of {@link java.lang.String}s.
|
||||
</p>
|
||||
<p>
|
||||
Although this might sound useless at first (as {@link java.lang.String}s
|
||||
do support encoding internally already), this class deals with a very
|
||||
subtle problem encountered when merging Java {@link java.lang.String}s
|
||||
and old byte-based (non internationalized) transports, such as
|
||||
Base 64 and URL encoding.
|
||||
</p>
|
||||
<p>
|
||||
Let's consider (as an example) the URL encoded {@link java.lang.String}
|
||||
<code>%C2%A3 100</code> can be easily decomposed in a byte array using
|
||||
URL decoding techniques: we would end up with the following byte array:
|
||||
<code>0x0C2 0x0A3 0x20 0x31 0x30 0x30</code>.
|
||||
</p>
|
||||
<p>
|
||||
This byte-array, though, doesn't tell us anything about how to represent
|
||||
this as a readable and usable {@link java.lang.String} in Java. To be
|
||||
able to convert this we have to decode it again using a charset (or an
|
||||
encoding).
|
||||
</p>
|
||||
<p>
|
||||
So, for example, if we were to decode the above mentioned byte array using
|
||||
the <b>ISO-8859-1</b> encoding, we would obtain the string
|
||||
"<code>£ 100</code>", or in details:
|
||||
</p>
|
||||
<ul>
|
||||
<li>a latin capital letter "A" with a circumflex accent</li>
|
||||
<li>the pound sign</li>
|
||||
<li>a space</li>
|
||||
<li>the number 1</li>
|
||||
<li>the number 0</li>
|
||||
<li>the number 0</li>
|
||||
</ul>
|
||||
<p>
|
||||
If we were to decode the same byte sequence using <b>UTF-8</b>, on the
|
||||
other hand, we would obtain the (quite different) string
|
||||
"<code>£ 100</code>", or in details:
|
||||
</p>
|
||||
<ul>
|
||||
<li>the pound sign</li>
|
||||
<li>a space</li>
|
||||
<li>the number 1</li>
|
||||
<li>the number 0</li>
|
||||
<li>the number 0</li>
|
||||
</ul>
|
||||
<p>
|
||||
Therefore, as a conclusion, when Java {@link java.lang.String}s are
|
||||
encoded using Base 64, URL encoding, or similar techiques, one always
|
||||
have to remember that encoding (or decoding) must be done twice, and
|
||||
this package provides a way to deal with this mechanism.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -1,901 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util.http;
|
||||
|
||||
import it.could.util.StreamTools;
|
||||
import it.could.util.StringTools;
|
||||
import it.could.util.location.Location;
|
||||
import it.could.util.location.Path;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* <p>A class implementing an extremely simple WebDAV Level 1 client based on
|
||||
* the {@link HttpClient}.</p>
|
||||
*
|
||||
* <p>Once opened this class will represent a WebDAV collection. Users of this
|
||||
* class can then from an instance of this, deal with relative parent and
|
||||
* children resources.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class WebDavClient {
|
||||
|
||||
/** <p>The WebDAV resource asociated with this instance.</p> */
|
||||
private Resource resource;
|
||||
/** <p>A map of children resources of this instance.</p> */
|
||||
private Map children;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link WebDavClient} instance opening the collection
|
||||
* identified by the specified {@link Location}.</p>
|
||||
*
|
||||
* @param location the {@link Location} of the WebDAV collection to open.
|
||||
* @throws IOException if an I/O or network error occurred, or if the
|
||||
* {@link Location} specified does not point to a
|
||||
* WebDAV collection.
|
||||
* @throws NullPointerException if the {@link Location} was <b>null</b>.
|
||||
*/
|
||||
public WebDavClient(Location location)
|
||||
throws NullPointerException, IOException {
|
||||
if (location == null) throw new NullPointerException("Null location");
|
||||
this.reload(location);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* ACTIONS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Refresh this {@link WebDavClient} instance re-connecting to the remote
|
||||
* collection and re-reading its properties.</p>
|
||||
*
|
||||
* @return this {@link WebDavClient} instance.
|
||||
*/
|
||||
public WebDavClient refresh()
|
||||
throws IOException {
|
||||
this.reload(this.resource.location);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Fetch the contents of the specified child resource of the collection
|
||||
* represented by this {@link WebDavClient} instance.</p>
|
||||
*
|
||||
* @see #isCollection(String)
|
||||
* @return a <b>non-null</b> {@link InputStream}.
|
||||
* @throws IOException if an I/O or network error occurred, or if the
|
||||
* child specified represents a collection.
|
||||
* @throws NullPointerException if the child was <b>null</b>.
|
||||
*/
|
||||
public InputStream get(String child)
|
||||
throws NullPointerException, IOException {
|
||||
if (child == null) throw new NullPointerException("Null child");
|
||||
if (! this.isCollection(child)) {
|
||||
final Location location = this.getLocation(child);
|
||||
final HttpClient client = new HttpClient(location);
|
||||
client.setAcceptableStatus(200).connect("GET");
|
||||
return client.getResponseStream();
|
||||
}
|
||||
throw new IOException("Child \"" + child + "\" is a collection");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Delete the child resource (or collection) of the collection
|
||||
* represented by this {@link WebDavClient} instance.</p>
|
||||
*
|
||||
* @return this {@link WebDavClient} instance.
|
||||
* @throws IOException if an I/O or network error occurred, or if the
|
||||
* child specified represents a collection.
|
||||
* @throws NullPointerException if the child was <b>null</b>.
|
||||
*/
|
||||
public WebDavClient delete(String child)
|
||||
throws NullPointerException, IOException {
|
||||
if (child == null) throw new NullPointerException("Null child");
|
||||
final HttpClient client = new HttpClient(this.getLocation(child));
|
||||
client.setAcceptableStatus(204).connect("DELETE").disconnect();
|
||||
return this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new collection as a child of the collection represented
|
||||
* by this {@link WebDavClient} instance.</p>
|
||||
*
|
||||
* <p>In comparison to {@link #put(String)} and {@link #put(String, long)}
|
||||
* this method will fail if the specified child already exist.</p>
|
||||
*
|
||||
* @see #hasChild(String)
|
||||
* @return this {@link WebDavClient} instance.
|
||||
* @throws IOException if an I/O or network error occurred, or if the
|
||||
* child specified already exist.
|
||||
* @throws NullPointerException if the child was <b>null</b>.
|
||||
*/
|
||||
public WebDavClient mkcol(String child)
|
||||
throws NullPointerException, IOException {
|
||||
if (child == null) throw new NullPointerException("Null child");
|
||||
if (this.hasChild(child))
|
||||
throw new IOException("Child \"" + child + "\" already exists");
|
||||
final Location location = this.resource.location.resolve(child);
|
||||
final HttpClient client = new HttpClient(location);
|
||||
client.setAcceptableStatus(201).connect("MKCOL").disconnect();
|
||||
return this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new (or update the contents of a) child of of the collection
|
||||
* represented by this {@link WebDavClient} instance.</p>
|
||||
*
|
||||
* <p>This method will behave exactly like the {@link #put(String, long)}
|
||||
* method, but the data written to the returned {@link OutputStream} will
|
||||
* be <i>buffered in memory</i> and will be transmitted to the remote
|
||||
* server only when the {@link OutputStream#close()} method is called.</p>
|
||||
*
|
||||
* <p>If the returned {@link OutputStream} is garbage collected before the
|
||||
* {@link OutputStream#close() close()} method is called, the entire
|
||||
* transaction will be aborted and no connection to the remote server will
|
||||
* be established.</p>
|
||||
*
|
||||
* <p>Use this method in extreme cases. In normal circumstances always rely
|
||||
* on the {@link #put(String, long)} method.</p>
|
||||
*
|
||||
* @see #put(String, long)
|
||||
* @return a <b>non-null</b> {@link OutputStream} instance.
|
||||
* @throws NullPointerException if the child was <b>null</b>.
|
||||
*/
|
||||
public OutputStream put(final String child)
|
||||
throws NullPointerException {
|
||||
if (child == null) throw new NullPointerException("Null child");
|
||||
final WebDavClient client = this;
|
||||
return new ByteArrayOutputStream() {
|
||||
private boolean closed = false;
|
||||
public void close()
|
||||
throws IOException {
|
||||
if (this.closed) return;
|
||||
this.flush();
|
||||
OutputStream output = client.put(child, this.buf.length);
|
||||
output.write(this.buf);
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
|
||||
protected void finalize()
|
||||
throws Throwable {
|
||||
this.closed = true;
|
||||
super.finalize();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new (or update the contents of a) child of of the collection
|
||||
* represented by this {@link WebDavClient} instance.</p>
|
||||
*
|
||||
* <p>If the specified child {@link #hasChild(String) already exists} on
|
||||
* the remote server, it will be {@link #delete(String) deleted} before
|
||||
* writing.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link OutputStream} instance.
|
||||
* @throws NullPointerException if the child was <b>null</b>.
|
||||
* @throws IOException if an I/O or network error occurred, or if the
|
||||
* child specified already exist.
|
||||
*/
|
||||
public OutputStream put(String child, long length)
|
||||
throws NullPointerException, IOException {
|
||||
if (child == null) throw new NullPointerException("Null child");
|
||||
if (this.hasChild(child)) this.delete(child);
|
||||
final Location location = this.resource.location.resolve(child);
|
||||
final HttpClient client = new HttpClient(location);
|
||||
client.setAcceptableStatuses(new int[] { 201, 204 });
|
||||
client.connect("PUT", length);
|
||||
|
||||
final WebDavClient webdav = this;
|
||||
return new BufferedOutputStream(client.getRequestStream()) {
|
||||
boolean closed = false;
|
||||
public void close()
|
||||
throws IOException {
|
||||
if (this.closed) return;
|
||||
try {
|
||||
super.close();
|
||||
} finally {
|
||||
this.closed = true;
|
||||
webdav.refresh();
|
||||
}
|
||||
}
|
||||
protected void finalize()
|
||||
throws Throwable {
|
||||
try {
|
||||
this.close();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Open the specified child collection of the collection represented by
|
||||
* this {@link WebDavClient} as a new {@link WebDavClient} instance.</p>
|
||||
*
|
||||
* <p>If the specified child is "<code>.</code>" this method
|
||||
* will behave exactly like {@link #refresh()} and <i>this instance</i>
|
||||
* will be returned.</p>
|
||||
*
|
||||
* <p>If the specified child is "<code>..</code>" this method
|
||||
* will behave exactly like {@link #parent()}.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link WebDavClient} instance.
|
||||
* @throws NullPointerException if the child was <b>null</b>.
|
||||
* @throws IOException if an I/O or network error occurred, or if the
|
||||
* child specified did not exist.
|
||||
*/
|
||||
public WebDavClient open(String child)
|
||||
throws NullPointerException, IOException {
|
||||
if (child == null) throw new NullPointerException("Null child");
|
||||
if (".".equals(child)) return this.refresh();
|
||||
if ("..".equals(child)) return this.parent();
|
||||
if (resource.collection) {
|
||||
Location loc = this.getLocation().resolve(this.getLocation(child));
|
||||
return new WebDavClient(loc);
|
||||
}
|
||||
throw new IOException("Child \"" + child + "\" is not a collection");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Open the parent collection of the collection represented by this
|
||||
* {@link WebDavClient} as a new {@link WebDavClient} instance.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link WebDavClient} instance.
|
||||
* @throws IOException if an I/O or network error occurred, or if the
|
||||
* child specified did not exist.
|
||||
*/
|
||||
public WebDavClient parent()
|
||||
throws IOException {
|
||||
final Location location = this.resource.location.resolve("..");
|
||||
return new WebDavClient(location);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* ACCESSOR METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return an {@link Iterator} over {@link String}s for all the children
|
||||
* of the collection represented by this {@link WebDavClient} instance.</p>
|
||||
*/
|
||||
public Iterator iterator() {
|
||||
return this.children.keySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks if the collection represented by this {@link WebDavClient}
|
||||
* contains the specified child.</p>
|
||||
*/
|
||||
public boolean hasChild(String child) {
|
||||
return this.children.containsKey(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link Location} associated with the collection
|
||||
* represented by this {@link WebDavClient}.</p>
|
||||
*
|
||||
* <p>The returned {@link Location} can be different from the one specified
|
||||
* at construction, in case the server redirected us upon connection.</p>
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return this.resource.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the content length (in bytes) of the collection represented
|
||||
* by this {@link WebDavClient} as passed to us by the WebDAV server.</p>
|
||||
*/
|
||||
public long getContentLength() {
|
||||
return this.resource.contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the content type (mime-type) of the collection represented
|
||||
* by this {@link WebDavClient} as passed to us by the WebDAV server.</p>
|
||||
*/
|
||||
public String getContentType() {
|
||||
return this.resource.contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the last modified {@link Date} of the collection represented
|
||||
* by this {@link WebDavClient} as passed to us by the WebDAV server.</p>
|
||||
*/
|
||||
public Date getLastModified() {
|
||||
return this.resource.lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the creation {@link Date} of the collection represented
|
||||
* by this {@link WebDavClient} as passed to us by the WebDAV server.</p>
|
||||
*/
|
||||
public Date getCreationDate() {
|
||||
return this.resource.creationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link Location} associated with the specified child of
|
||||
* the collection represented by this {@link WebDavClient}.</p>
|
||||
*
|
||||
* @throws IOException if the specified child does not exist.
|
||||
* @throws NullPointerException if the specified child was <b>null</b>.
|
||||
*/
|
||||
public Location getLocation(String child)
|
||||
throws IOException {
|
||||
Location location = this.getResource(child).location;
|
||||
return this.resource.location.resolve(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks if the specified child of the collection represented by this
|
||||
* {@link WebDavClient} instance is a collection.</p>
|
||||
*/
|
||||
public boolean isCollection(String child)
|
||||
throws IOException {
|
||||
return this.getResource(child).collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the content length (in bytes) associated with the specified
|
||||
* child of the collection represented by this {@link WebDavClient}.</p>
|
||||
*
|
||||
* @throws IOException if the specified child does not exist.
|
||||
* @throws NullPointerException if the specified child was <b>null</b>.
|
||||
*/
|
||||
public long getContentLength(String child)
|
||||
throws IOException {
|
||||
return this.getResource(child).contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the content type (mime-type) associated with the specified
|
||||
* child of the collection represented by this {@link WebDavClient}.</p>
|
||||
*
|
||||
* @throws IOException if the specified child does not exist.
|
||||
* @throws NullPointerException if the specified child was <b>null</b>.
|
||||
*/
|
||||
public String getContentType(String child)
|
||||
throws IOException {
|
||||
return this.getResource(child).contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the last modified {@link Date} associated with the specified
|
||||
* child of the collection represented by this {@link WebDavClient}.</p>
|
||||
*
|
||||
* @throws IOException if the specified child does not exist.
|
||||
* @throws NullPointerException if the specified child was <b>null</b>.
|
||||
*/
|
||||
public Date getLastModified(String child)
|
||||
throws IOException {
|
||||
return this.getResource(child).lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the creation {@link Date} associated with the specified
|
||||
* child of the collection represented by this {@link WebDavClient}.</p>
|
||||
*
|
||||
* @throws IOException if the specified child does not exist.
|
||||
* @throws NullPointerException if the specified child was <b>null</b>.
|
||||
*/
|
||||
public Date getCreationDate(String child)
|
||||
throws IOException {
|
||||
return this.getResource(child).creationDate;
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* INTERNAL METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the resource associated with the specified child.</p>
|
||||
*
|
||||
* @throws IOException if the specified child does not exist.
|
||||
* @throws NullPointerException if the specified child was <b>null</b>.
|
||||
*/
|
||||
private Resource getResource(String child)
|
||||
throws IOException {
|
||||
if (child == null) throw new NullPointerException();
|
||||
final Resource resource = (Resource) this.children.get(child);
|
||||
if (resource == null) throw new IOException("Not found: " + child);
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Contact the remote WebDAV server and fetch all properties.</p>
|
||||
*/
|
||||
private void reload(Location location)
|
||||
throws IOException {
|
||||
|
||||
/* Do an OPTIONS over onto the location */
|
||||
location = this.options(location);
|
||||
|
||||
/* Do a PROPFIND to figure out the properties and the children */
|
||||
final Iterator iterator = this.propfind(location).iterator();
|
||||
final Map children = new HashMap();
|
||||
while (iterator.hasNext()) {
|
||||
final Resource resource = (Resource) iterator.next();
|
||||
final Path path = resource.location.getPath();
|
||||
if (path.size() == 0) {
|
||||
resource.location = location.resolve(resource.location);
|
||||
this.resource = resource;
|
||||
} else if (path.size() == 1) {
|
||||
final Path.Element element = (Path.Element) path.get(0);
|
||||
if ("..".equals(element.getName())) continue;
|
||||
children.put(element.toString(), resource);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the current resource was discovered */
|
||||
if (this.resource == null)
|
||||
throw new IOException("Current resource not returned in PROOPFIND");
|
||||
|
||||
/* Don't actually allow resources to be modified */
|
||||
this.children = Collections.unmodifiableMap(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Contact the remote WebDAV server and do an OPTIONS lookup.</p>
|
||||
*/
|
||||
private Location options(Location location)
|
||||
throws IOException {
|
||||
/* Create the new HttpClient instance associated with the location */
|
||||
final HttpClient client = new HttpClient(location);
|
||||
client.setAcceptableStatus(200).connect("OPTIONS", true).disconnect();
|
||||
|
||||
/* Check that the remote server returned the "Dav" header */
|
||||
final List davHeader = client.getResponseHeaderValues("dav");
|
||||
if (davHeader == null) {
|
||||
throw new IOException("Server did not respond with a DAV header");
|
||||
}
|
||||
|
||||
/* Check if the OPTIONS request contained the DAV header */
|
||||
final Iterator iterator = davHeader.iterator();
|
||||
boolean foundLevel1 = false;
|
||||
while (iterator.hasNext() && (! foundLevel1)) {
|
||||
String value = (String) iterator.next();
|
||||
StringTokenizer tokenizer = new StringTokenizer(value, ",");
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
if (! "1".equals(tokenizer.nextToken().trim())) continue;
|
||||
foundLevel1 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the (possibly redirected) location or fail miserably */
|
||||
if (foundLevel1) return client.getLocation();
|
||||
throw new IOException("Server doesn't support DAV Level 1");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Contact the remote WebDAV server and do a PROPFIND lookup, returning
|
||||
* a {@link List} of all scavenged resources.</p>
|
||||
*/
|
||||
private List propfind(Location location)
|
||||
throws IOException {
|
||||
/* Create the new HttpClient instance associated with the location */
|
||||
final HttpClient client = new HttpClient(location);
|
||||
client.addRequestHeader("Depth", "1");
|
||||
client.setAcceptableStatus(207).connect("PROPFIND", true);
|
||||
|
||||
/* Get the XML SAX Parser and parse the output of the PROPFIND */
|
||||
try {
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setNamespaceAware(true);
|
||||
final SAXParser parser = factory.newSAXParser();
|
||||
final String systemId = location.toString();
|
||||
final InputSource source = new InputSource(systemId);
|
||||
final Handler handler = new Handler(location);
|
||||
source.setByteStream(client.getResponseStream());
|
||||
parser.parse(source, handler);
|
||||
return handler.list;
|
||||
|
||||
} catch (ParserConfigurationException exception) {
|
||||
Exception throwable = new IOException("Error creating XML parser");
|
||||
throw (IOException) throwable.initCause(exception);
|
||||
} catch (SAXException exception) {
|
||||
Exception throwable = new IOException("Error creating XML parser");
|
||||
throw (IOException) throwable.initCause(exception);
|
||||
} finally {
|
||||
client.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* INTERNAL CLASSES */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>An internal XML {@link DefaultHandler} used to parse out the various
|
||||
* details of a PROPFIND response.</p>
|
||||
*/
|
||||
private static final class Handler extends DefaultHandler {
|
||||
|
||||
/* ================================================================== */
|
||||
/* PSEUDO-XPATH LOCATIONS FOR QUICK-AND-DIRTY LOCATION LOOKUP */
|
||||
/* ================================================================== */
|
||||
private static final String RESPONSE_PATH = "/multistatus/response";
|
||||
private static final String HREF_PATH = "/multistatus/response/href";
|
||||
private static final String COLLECTION_PATH =
|
||||
"/multistatus/response/propstat/prop/resourcetype/collection";
|
||||
private static final String GETCONTENTTYPE_PATH =
|
||||
"/multistatus/response/propstat/prop/getcontenttype";
|
||||
private static final String GETLASTMODIFIED_PATH =
|
||||
"/multistatus/response/propstat/prop/getlastmodified";
|
||||
private static final String GETCONTENTLENGTH_PATH =
|
||||
"/multistatus/response/propstat/prop/getcontentlength";
|
||||
private static final String CREATIONDATE_PATH =
|
||||
"/multistatus/response/propstat/prop/creationdate";
|
||||
|
||||
/** <p>The {@link Location} for resolving all other links.</p> */
|
||||
private final Location base;
|
||||
/** <p>The {@link List} of all scavenged resources.</p> */
|
||||
private final List list = new ArrayList();
|
||||
/** <p>The resource currently being processed.</p> */
|
||||
private Resource rsrc = null;
|
||||
/** <p>A {@link StringBuffer} holding character data.</p> */
|
||||
private StringBuffer buff = null;
|
||||
/** <p>A {@link Stack} for quick-and-dirty pseudo XPath lookups.</p> */
|
||||
private Stack stack = new Stack();
|
||||
|
||||
/**
|
||||
* <p>Create a new instance specifying the base {@link Location}.</p>
|
||||
*/
|
||||
private Handler(Location location) {
|
||||
this.base = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Push an element name in the stack for pseudo-XPath lookups.</p>
|
||||
*
|
||||
* @return a {@link String} like <code>/element/element/element</code>.
|
||||
*/
|
||||
private String pushPath(String path) {
|
||||
this.stack.push(path.toLowerCase());
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
for (int x = 0; x < this.stack.size(); x ++)
|
||||
buffer.append('/').append(this.stack.get(x));
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Pop the last element name from the pseudo-XPath lookup stack.</p>
|
||||
*
|
||||
* @return a {@link String} like <code>/element/element/element</code>.
|
||||
*/
|
||||
private String popPath(String path)
|
||||
throws SAXException {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
final String last = (String) this.stack.pop();
|
||||
if (path.toLowerCase().equals(last)) {
|
||||
for (int x = 0; x < this.stack.size(); x ++)
|
||||
buffer.append('/').append(this.stack.get(x));
|
||||
return buffer.append('/').append(last).toString();
|
||||
}
|
||||
throw new SAXException("Tag <" + path + "/> unbalanced at path \""
|
||||
+ pushPath(last) + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Handle the start-of-element SAX event.</p>
|
||||
*/
|
||||
public void startElement(String uri, String l, String q, Attributes a)
|
||||
throws SAXException {
|
||||
if (! "DAV:".equals(uri.toUpperCase())) return;
|
||||
final String path = this.pushPath(l);
|
||||
|
||||
if (RESPONSE_PATH.equals(path)) {
|
||||
this.rsrc = new Resource();
|
||||
|
||||
} else if (COLLECTION_PATH.equals(path)) {
|
||||
if (this.rsrc != null) this.rsrc.collection = true;
|
||||
|
||||
} else if (GETCONTENTTYPE_PATH.equals(path) ||
|
||||
GETLASTMODIFIED_PATH.equals(path) ||
|
||||
GETCONTENTLENGTH_PATH.equals(path) ||
|
||||
CREATIONDATE_PATH.equals(path) ||
|
||||
HREF_PATH.equals(path)) {
|
||||
this.buff = new StringBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Handle the end-of-element SAX event.</p>
|
||||
*/
|
||||
public void endElement(String uri, String l, String q)
|
||||
throws SAXException {
|
||||
if (! "DAV:".equals(uri.toUpperCase())) return;
|
||||
final String path = this.popPath(l);
|
||||
final String data = this.resetBuffer();
|
||||
|
||||
if (RESPONSE_PATH.equals(path)) {
|
||||
if (this.rsrc != null) {
|
||||
if (this.rsrc.location != null) {
|
||||
if (this.rsrc.location.isAbsolute()) {
|
||||
final String z = this.rsrc.location.toString();
|
||||
throw new SAXException("Unresolved location " + z);
|
||||
} else {
|
||||
this.list.add(this.rsrc);
|
||||
}
|
||||
} else {
|
||||
throw new SAXException("Null location for resource");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (HREF_PATH.equals(path)) {
|
||||
if (this.rsrc != null) try {
|
||||
final Location resolved = this.base.resolve(data);
|
||||
this.rsrc.location = this.base.relativize(resolved);
|
||||
if (! this.rsrc.location.isRelative())
|
||||
throw new SAXException("Unable to relativize location "
|
||||
+ this.rsrc.location);
|
||||
} catch (MalformedURLException exception) {
|
||||
final String msg = "Unable to resolve URL \"" + data + "\"";
|
||||
SAXException throwable = new SAXException(msg, exception);
|
||||
throw (SAXException) throwable.initCause(exception);
|
||||
}
|
||||
|
||||
} else if (CREATIONDATE_PATH.equals(path)) {
|
||||
if (this.rsrc != null)
|
||||
this.rsrc.creationDate = StringTools.parseIsoDate(data);
|
||||
|
||||
} else if (GETCONTENTTYPE_PATH.equals(path)) {
|
||||
if (this.rsrc != null) this.rsrc.contentType = data;
|
||||
|
||||
} else if (GETLASTMODIFIED_PATH.equals(path)) {
|
||||
if (this.rsrc != null)
|
||||
this.rsrc.lastModified = StringTools.parseHttpDate(data);
|
||||
|
||||
} else if (GETCONTENTLENGTH_PATH.equals(path)) {
|
||||
if (this.rsrc != null) {
|
||||
Long length = StringTools.parseNumber(data);
|
||||
if (length != null) {
|
||||
this.rsrc.contentLength = length.longValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Handle SAX characters notification.</p>
|
||||
*/
|
||||
public void characters(char buffer[], int offset, int length) {
|
||||
if (this.buff != null) this.buff.append(buffer, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reset the current characters buffer and return it as a
|
||||
* {@link String}.</p>
|
||||
*/
|
||||
private String resetBuffer() {
|
||||
if (this.buff == null) return null;
|
||||
if (this.buff.length() == 0) {
|
||||
this.buff = null;
|
||||
return null;
|
||||
}
|
||||
final String value = this.buff.toString();
|
||||
this.buff = null;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A simple class holding the core resource properties.</p>
|
||||
*/
|
||||
private static class Resource {
|
||||
private Location location = null;
|
||||
private boolean collection = false;
|
||||
private long contentLength = -1;
|
||||
private String contentType = null;
|
||||
private Date lastModified = null;
|
||||
private Date creationDate = null;
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* COMMAND LINE CLIENT */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>A command-line interface to a WebDAV repository.</p>
|
||||
*
|
||||
* <p>When invoked from the command line, this class requires one only
|
||||
* argument, the URL location of the WebDAV repository to connect to.</p>
|
||||
*
|
||||
* <p>After connection this method will interact with the user using an
|
||||
* extremely simple console-based interface.</p>
|
||||
*/
|
||||
public static void main(String args[])
|
||||
throws IOException {
|
||||
final InputStreamReader r = new InputStreamReader(System.in);
|
||||
final BufferedReader in = new BufferedReader(r);
|
||||
WebDavClient client = new WebDavClient(Location.parse(args[0]));
|
||||
|
||||
while (true) try {
|
||||
System.out.print("[" + client.getLocation() + "] -> ");
|
||||
args = parse(in.readLine());
|
||||
if (args == null) break;
|
||||
if (args[0].equals("list")) {
|
||||
if (args[1] == null) list(client, System.out);
|
||||
else list(client.open(args[1]), System.out);
|
||||
|
||||
} else if (args[0].equals("refresh")) {
|
||||
client = client.refresh();
|
||||
|
||||
} else if (args[0].equals("get")) {
|
||||
if (args[1] != null) {
|
||||
final InputStream input = client.get(args[1]);
|
||||
final File file = new File(args[2]).getCanonicalFile();
|
||||
final OutputStream output = new FileOutputStream(file);
|
||||
final long bytes = StreamTools.copy(input, output);
|
||||
System.out.println("Fetched child \"" + args[1] +
|
||||
"\" to file \"" + file + "\" (" +
|
||||
bytes + " bytes)");
|
||||
}
|
||||
else System.out.print("Can't \"get\" null");
|
||||
|
||||
} else if (args[0].equals("put")) {
|
||||
if (args[1] != null) {
|
||||
final File file = new File(args[1]).getCanonicalFile();
|
||||
final InputStream input = new FileInputStream(file);
|
||||
final OutputStream output = client.put(args[2], file.length());
|
||||
final long bytes = StreamTools.copy(input, output);
|
||||
System.out.println("Uploaded file \"" + file +
|
||||
"\" to child \"" + args[2] + "\" (" +
|
||||
bytes + " bytes)");
|
||||
}
|
||||
else System.out.print("Can't \"put\" null");
|
||||
|
||||
} else if (args[0].equals("mkcol")) {
|
||||
if (args[1] != null) {
|
||||
client.mkcol(args[1]);
|
||||
System.out.println("Created \"" + args[1] + "\"");
|
||||
}
|
||||
else System.out.print("Can't \"mkcol\" null");
|
||||
|
||||
} else if (args[0].equals("delete")) {
|
||||
if (args[1] != null) {
|
||||
client.delete(args[1]);
|
||||
System.out.println("Deleted \"" + args[1] + "\"");
|
||||
}
|
||||
else System.out.print("Can't \"delete\" null");
|
||||
|
||||
} else if (args[0].equals("cd")) {
|
||||
if (args[1] != null) client = client.open(args[1]);
|
||||
else System.out.print("Can't \"cd\" to null");
|
||||
|
||||
} else if (args[0].equals("quit")) {
|
||||
break;
|
||||
|
||||
} else {
|
||||
System.out.print("Invalid command \"" + args[0] + "\". ");
|
||||
System.out.println("Valid commands are:");
|
||||
System.out.println(" - \"list\" list the children child");
|
||||
System.out.println(" - \"get\" fetch the specified child");
|
||||
System.out.println(" - \"put\" put the specified child");
|
||||
System.out.println(" - \"mkcol\" create a collection");
|
||||
System.out.println(" - \"delete\" delete a child");
|
||||
System.out.println(" - \"put\" put the specified resource");
|
||||
System.out.println(" - \"cd\" change the location");
|
||||
System.out.println(" - \"refresh\" refresh this location");
|
||||
System.out.println(" - \"quit\" quit this application");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace(System.err);
|
||||
}
|
||||
System.err.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse a line entered by the user returning a three-tokens argument
|
||||
* list (command, argument 1, argument 2)</p>
|
||||
*/
|
||||
private static String[] parse(String line) {
|
||||
if (line == null) return null;
|
||||
final String array[] = new String[3];
|
||||
final StringTokenizer tokenizer = new StringTokenizer(line);
|
||||
int offset = 0;
|
||||
while (tokenizer.hasMoreTokens() && (offset < 3))
|
||||
array[offset ++] = tokenizer.nextToken();
|
||||
if (array[0] == null) return null;
|
||||
if (array[2] == null) array[2] = array[1];
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Pseudo-nicely display a list of the children of a collection</p>
|
||||
*/
|
||||
private static void list(WebDavClient client, PrintStream out)
|
||||
throws IOException {
|
||||
out.print("C | ");
|
||||
out.print("CONTENT TYPE | ");
|
||||
out.print("CREATED | ");
|
||||
out.print("MODIFIED | ");
|
||||
out.print("SIZE | ");
|
||||
out.println("NAME ");
|
||||
for (Iterator iterator = client.iterator(); iterator.hasNext() ; ) {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
String child = (String) iterator.next();
|
||||
if (client.isCollection(child)) buffer.append("* | ");
|
||||
else buffer.append(" | ");
|
||||
format(buffer, client.getContentType(child), 15).append(" | ");
|
||||
format(buffer, client.getCreationDate(child), 19).append(" | ");
|
||||
format(buffer, client.getLastModified(child), 19).append(" | ");
|
||||
format(buffer, client.getContentLength(child), 10).append(" | ");
|
||||
out.println(buffer.append(child));
|
||||
}
|
||||
}
|
||||
|
||||
/** <p>Format a number aligning it to the right of a string.</p> */
|
||||
private static StringBuffer format(StringBuffer buf, long num, int len) {
|
||||
final String data;
|
||||
if (num < 0) data = "";
|
||||
else data = Long.toString(num);
|
||||
final int spaces = len - data.length();
|
||||
for (int x = 0; x < spaces; x++) buf.append(' ');
|
||||
buf.append(data);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** <p>Format a string into an exact number of characters.</p> */
|
||||
private static StringBuffer format(StringBuffer buf, Object obj, int len) {
|
||||
final String string;
|
||||
if (obj == null) {
|
||||
string = ("[null]");
|
||||
} else if (obj instanceof Date) {
|
||||
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
string = f.format((Date) obj);
|
||||
} else {
|
||||
string = obj.toString();
|
||||
}
|
||||
final StringBuffer buffer = new StringBuffer(string);
|
||||
for (int x = string.length(); x < len; x ++) buffer.append(' ');
|
||||
return buf.append(buffer.substring(0, len));
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>HTTP Utilities</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package contains a number of utility classes to access
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a> and
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a> servers.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,805 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util.location;
|
||||
|
||||
import it.could.util.StringTools;
|
||||
import it.could.util.encoding.Encodable;
|
||||
import it.could.util.encoding.EncodingTools;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <p>An utility class representing an HTTP-like URL.</p>
|
||||
*
|
||||
* <p>This class can be used to represent any URL that roughly uses the HTTP
|
||||
* format. Compared to the standard {@link java.net.URL} class, the scheme part
|
||||
* of the a {@link Location} is never checked, and it's up to the application
|
||||
* to verify its correctness, while compared to the {@link java.net.URI} class,
|
||||
* its parsing mechanism is a lot more relaxed (be liberal in what you accept,
|
||||
* be strict in what you send).</p>
|
||||
*
|
||||
* <p>For a bigger picture on how this class works, this is an easy-to-read
|
||||
* representation of what the different parts of a {@link Location} are:</p>
|
||||
*
|
||||
* <div align="center">
|
||||
* <a href="url.pdf" target="_new" title="PDF Version">
|
||||
* <img src="url.gif" alt="URL components" border="0">
|
||||
* </a>
|
||||
* </div>
|
||||
*
|
||||
* <p>One important difference between this implementation and the description
|
||||
* of <a href="http://www.ietf.org/rfc/rfc1738.txt">URLs</a> and
|
||||
* <a href="http://www.ietf.org/rfc/rfc2396.txt">URIs</a> is that parameter
|
||||
* paths are represented <i>only at the end of the entire path structure</i>
|
||||
* rather than for each path element. This over-simplification allows easy
|
||||
* relativization of {@link Location}s when used with servlet containers, which
|
||||
* normally use path parameters to encode the session id.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class Location implements Encodable {
|
||||
|
||||
/** <p>A {@link Map} of schemes and their default port number.</p> */
|
||||
private static final Map schemePorts = new HashMap();
|
||||
static {
|
||||
schemePorts.put("acap", new Integer( 674));
|
||||
schemePorts.put("dav", new Integer( 80));
|
||||
schemePorts.put("ftp", new Integer( 21));
|
||||
schemePorts.put("gopher", new Integer( 70));
|
||||
schemePorts.put("http", new Integer( 80));
|
||||
schemePorts.put("https", new Integer( 443));
|
||||
schemePorts.put("imap", new Integer( 143));
|
||||
schemePorts.put("ldap", new Integer( 389));
|
||||
schemePorts.put("mailto", new Integer( 25));
|
||||
schemePorts.put("news", new Integer( 119));
|
||||
schemePorts.put("nntp", new Integer( 119));
|
||||
schemePorts.put("pop", new Integer( 110));
|
||||
schemePorts.put("rtsp", new Integer( 554));
|
||||
schemePorts.put("sip", new Integer(5060));
|
||||
schemePorts.put("sips", new Integer(5061));
|
||||
schemePorts.put("snmp", new Integer( 161));
|
||||
schemePorts.put("telnet", new Integer( 23));
|
||||
schemePorts.put("tftp", new Integer( 69));
|
||||
}
|
||||
|
||||
/** <p>The {@link List} of schemes of this {@link Location}.</p> */
|
||||
private final Schemes schemes;
|
||||
/** <p>The {@link Authority} of this {@link Location}.</p> */
|
||||
private final Authority authority;
|
||||
/** <p>The {@link Path} of this {@link Location}.</p> */
|
||||
private final Path path;
|
||||
/** <p>The {@link Parameters} of this {@link Location}.</p> */
|
||||
private final Parameters parameters;
|
||||
/** <p>The fragment part of this {@link Location}.</p> */
|
||||
private final String fragment;
|
||||
/** <p>The string representation of this {@link Location}.</p> */
|
||||
private final String string;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Location} instance.</p>
|
||||
*/
|
||||
public Location(Schemes schemes, Authority authority, Path path,
|
||||
Parameters parameters, String fragment)
|
||||
throws MalformedURLException {
|
||||
if ((schemes == null) && (authority != null))
|
||||
throw new MalformedURLException("No schemes specified");
|
||||
if ((schemes != null) && (authority == null))
|
||||
throw new MalformedURLException("No authority specified");
|
||||
if (path == null) throw new MalformedURLException("No path specified");
|
||||
|
||||
this.schemes = schemes;
|
||||
this.authority = authority;
|
||||
this.path = path;
|
||||
this.parameters = parameters;
|
||||
this.fragment = fragment;
|
||||
this.string = EncodingTools.toString(this);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* STATIC CONSTRUCTION METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
public static Location parse(String url)
|
||||
throws MalformedURLException {
|
||||
try {
|
||||
return parse(url, DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static Location parse(String url, String encoding)
|
||||
throws MalformedURLException, UnsupportedEncodingException {
|
||||
if (url == null) return null;;
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
final String components[] = parseComponents(url);
|
||||
final Schemes schemes = parseSchemes(components[0], encoding);
|
||||
final int port = findPort(schemes, encoding);
|
||||
final Authority auth = parseAuthority(components[1], port, encoding);
|
||||
final Path path = Path.parse(components[2], encoding);
|
||||
final Parameters params = Parameters.parse(components[3], '&', encoding);
|
||||
final String fragment = components[4];
|
||||
return new Location(schemes, auth, path, params, fragment);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* ACCESSOR METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return an unmodifiable {@link Schemes list of all schemes} for this
|
||||
* {@link Location} instance or <b>null</b>.</p>
|
||||
*/
|
||||
public Schemes getSchemes() {
|
||||
return this.schemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link Location.Authority Authority} part for this
|
||||
* {@link Location} or <b>null</b>.</p>
|
||||
*/
|
||||
public Authority getAuthority() {
|
||||
return this.authority;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the <b>non-null</b> {@link Path Path} structure
|
||||
* associated with this {@link Location} instance.</p>
|
||||
*/
|
||||
public Path getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return an unmodifiable {@link Parameters list of all parameters}
|
||||
* parsed from this {@link Location}'s query string or <b>null</b>.</p>
|
||||
*/
|
||||
public Parameters getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the fragment of this {@link Location} unencoded.</p>
|
||||
*/
|
||||
public String getFragment() {
|
||||
return this.fragment;
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* OBJECT METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Check if the specified {@link Object} is equal to this instance.</p>
|
||||
*
|
||||
* <p>The specified {@link Object} must be a <b>non-null</b>
|
||||
* {@link Location} instance whose {@link #toString() string value} equals
|
||||
* this one's.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof Location)) {
|
||||
return this.string.equals(((Location)object).string);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the hash code value for this {@link Location} instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.string.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link String} representation of this {@link Location}
|
||||
* instance.</p>
|
||||
*/
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link String} representation of this {@link Location}
|
||||
* instance using the specified character encoding.</p>
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
|
||||
/* Render the schemes */
|
||||
if (this.schemes != null)
|
||||
buffer.append(this.schemes.toString(encoding)).append("://");
|
||||
|
||||
/* Render the authority part */
|
||||
if (this.authority != null)
|
||||
buffer.append(this.authority.toString(encoding));
|
||||
|
||||
/* Render the paths */
|
||||
buffer.append(this.path.toString(encoding));
|
||||
|
||||
/* Render the query string */
|
||||
if (this.parameters != null)
|
||||
buffer.append('?').append(this.parameters.toString(encoding));
|
||||
|
||||
/* Render the fragment */
|
||||
if (this.fragment != null) {
|
||||
buffer.append('#');
|
||||
buffer.append(EncodingTools.urlEncode(this.fragment, encoding));
|
||||
}
|
||||
|
||||
/* Return the string */
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* PUBLIC METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Checks whether this {@link Location} is absolute or not.</p>
|
||||
*
|
||||
* <p>This method must not be confused with the similarly named
|
||||
* {@link Path#isAbsolute() Path.isAbsolute()} method.
|
||||
* This method will check whether the full {@link Location} is absolute (it
|
||||
* has a scheme), while the one exposed by the {@link Path Path}
|
||||
* class will check if the path is absolute.</p>
|
||||
*/
|
||||
public boolean isAbsolute() {
|
||||
return this.schemes != null && this.authority != null;
|
||||
}
|
||||
|
||||
public boolean isRelative() {
|
||||
return ! (this.isAbsolute() || this.path.isAbsolute());
|
||||
}
|
||||
|
||||
public boolean isAuthoritative(Location location) {
|
||||
if (! this.isAbsolute()) return false;
|
||||
if (! location.isAbsolute()) return true;
|
||||
return this.schemes.equals(location.schemes) &&
|
||||
this.authority.equals(location.authority);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* RESOLUTION METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
public Location resolve(String url)
|
||||
throws MalformedURLException {
|
||||
try {
|
||||
return this.resolve(parse(url, DEFAULT_ENCODING));
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public Location resolve(String url, String encoding)
|
||||
throws MalformedURLException, UnsupportedEncodingException {
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
return this.resolve(parse(url, encoding));
|
||||
}
|
||||
|
||||
public Location resolve(Location location) {
|
||||
if (! this.isAuthoritative(location)) return location;
|
||||
|
||||
/* Schemes are the same */
|
||||
final Schemes schemes = this.schemes;
|
||||
|
||||
/* Authority needs to be merged (for username and password) */
|
||||
final Authority auth;
|
||||
if (location.authority != null) {
|
||||
final String username = location.authority.username != null ?
|
||||
location.authority.username :
|
||||
this.authority.username;
|
||||
final String password = location.authority.password != null ?
|
||||
location.authority.password :
|
||||
this.authority.password;
|
||||
final String host = location.authority.host;
|
||||
final int port = location.authority.port;
|
||||
auth = new Authority(username, password, host, port);
|
||||
} else {
|
||||
auth = this.authority;
|
||||
}
|
||||
|
||||
/* Path can be resolved */
|
||||
final Path path = this.path.resolve(location.path);
|
||||
|
||||
/* Parametrs and fragment are the ones of the target */
|
||||
final Parameters params = location.parameters;
|
||||
final String fragment = location.fragment;
|
||||
|
||||
/* Create a new {@link Location} instance */
|
||||
try {
|
||||
return new Location(schemes, auth, path, params, fragment);
|
||||
} catch (MalformedURLException exception) {
|
||||
/* Should really never happen */
|
||||
Error error = new InternalError("Can't instantiate Location");
|
||||
throw (Error) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* RELATIVIZATION METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
public Location relativize(String url)
|
||||
throws MalformedURLException {
|
||||
try {
|
||||
return this.relativize(parse(url, DEFAULT_ENCODING));
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public Location relativize(String url, String encoding)
|
||||
throws MalformedURLException, UnsupportedEncodingException {
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
return this.relativize(parse(url, encoding));
|
||||
}
|
||||
|
||||
public Location relativize(Location location) {
|
||||
final Path path;
|
||||
if (!location.isAbsolute()) {
|
||||
/* Target location is not absolute, its path might */
|
||||
path = this.path.relativize(location.path);
|
||||
} else {
|
||||
if (this.isAuthoritative(location)) {
|
||||
/* Target location is not on the same authority, process path */
|
||||
path = this.path.relativize(location.path);
|
||||
} else {
|
||||
/* Not authoritative for a non-relative location, yah! */
|
||||
return location;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new Location(null, null, path, location.parameters,
|
||||
location.fragment);
|
||||
} catch (MalformedURLException exception) {
|
||||
/* Should really never happen */
|
||||
Error error = new InternalError("Can't instantiate Location");
|
||||
throw (Error) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* INTERNAL PARSING ROUTINES */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the port number associated with the specified schemes.</p>
|
||||
*/
|
||||
public static int findPort(List schemes, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (schemes == null) return -1;
|
||||
if (schemes.size() < 1) return -1;
|
||||
Integer p = (Integer) schemePorts.get(schemes.get(schemes.size() - 1));
|
||||
return p == null ? -1 : p.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse <code>scheme://authority/path?query#fragment</code>.</p>
|
||||
*
|
||||
* @return an array of five {@link String}s: scheme (0), authority (1),
|
||||
* path (2), query (3) and fragment (4).
|
||||
*/
|
||||
private static String[] parseComponents(String url)
|
||||
throws MalformedURLException {
|
||||
/* Scheme, easy and simple */
|
||||
final String scheme;
|
||||
final String afterScheme;
|
||||
final int schemeEnd = url.indexOf(":/");
|
||||
if (schemeEnd > 0) {
|
||||
scheme = url.substring(0, schemeEnd).toLowerCase();
|
||||
afterScheme = url.substring(schemeEnd + 2);
|
||||
} else if (schemeEnd == 0) {
|
||||
throw new MalformedURLException("Missing scheme");
|
||||
} else {
|
||||
scheme = null;
|
||||
afterScheme = url;
|
||||
}
|
||||
|
||||
/* Authority (can be tricky because it can be emtpy) */
|
||||
final String auth;
|
||||
final String afterAuth;
|
||||
if (scheme == null) {
|
||||
// --> /path... or path...
|
||||
afterAuth = afterScheme;
|
||||
auth = null;
|
||||
} else if (afterScheme.length() > 0 && afterScheme.charAt(0) == '/') {
|
||||
// --> scheme://...
|
||||
final int pathStart = afterScheme.indexOf('/', 1);
|
||||
if (pathStart == 1) {
|
||||
// --> scheme:///path...
|
||||
afterAuth = afterScheme.substring(pathStart);
|
||||
auth = null;
|
||||
} else if (pathStart > 1) {
|
||||
// --> scheme://authority/path...
|
||||
afterAuth = afterScheme.substring(pathStart);
|
||||
auth = afterScheme.substring(1, pathStart);
|
||||
} else {
|
||||
// --> scheme://authority (but no slashes for the path)
|
||||
final int authEnds = StringTools.findFirst(afterScheme, "?#");
|
||||
if (authEnds < 0) {
|
||||
// --> scheme://authority (that's it, return)
|
||||
auth = afterScheme.substring(1);
|
||||
return new String[] { scheme, auth, "/", null, null };
|
||||
}
|
||||
// --> scheme://authority?... or scheme://authority#...
|
||||
auth = afterScheme.substring(1, authEnds);
|
||||
afterAuth = "/" + afterScheme.substring(authEnds);
|
||||
}
|
||||
} else {
|
||||
// --> scheme:/path...
|
||||
afterAuth = url.substring(schemeEnd + 1);
|
||||
auth = null;
|
||||
}
|
||||
|
||||
/* Path, can be terminated by '?' or '#' whichever is first */
|
||||
final int pathEnds = StringTools.findFirst(afterAuth, "?#");
|
||||
if (pathEnds < 0) {
|
||||
// --> ...path... (no fragment or query, return now)
|
||||
return new String[] { scheme, auth, afterAuth, null, null };
|
||||
}
|
||||
|
||||
/* We have either a query, a fragment or both after the path */
|
||||
final String path = afterAuth.substring(0, pathEnds);
|
||||
final String afterPath = afterAuth.substring(pathEnds + 1);
|
||||
|
||||
/* Query? The query can contain a "#" and has an extra fragment */
|
||||
if (afterAuth.charAt(pathEnds) == '?') {
|
||||
final int fragmPos = afterPath.indexOf('#');
|
||||
if (fragmPos < 0) {
|
||||
// --> ...path...?... (no fragment)
|
||||
return new String[] { scheme, auth, path, afterPath, null };
|
||||
}
|
||||
|
||||
// --> ...path...?...#... (has also a fragment)
|
||||
final String query = afterPath.substring(1, fragmPos);
|
||||
final String fragm = afterPath.substring(fragmPos + 1);
|
||||
return new String[] { scheme, auth, path, query, fragm };
|
||||
}
|
||||
|
||||
// --> ...path...#... (a path followed by a fragment but no query)
|
||||
return new String[] { scheme, auth, path, null, afterPath };
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse <code>scheme:scheme:scheme...</code>.</p>
|
||||
*/
|
||||
private static Schemes parseSchemes(String scheme, String encoding)
|
||||
throws MalformedURLException, UnsupportedEncodingException {
|
||||
if (scheme == null) return null;
|
||||
final String split[] = StringTools.splitAll(scheme, ':');
|
||||
List list = new ArrayList();
|
||||
for (int x = 0; x < split.length; x++) {
|
||||
if (split[x] == null) continue;
|
||||
list.add(EncodingTools.urlDecode(split[x], encoding));
|
||||
}
|
||||
if (list.size() != 0) return new Schemes(list);
|
||||
throw new MalformedURLException("Empty scheme detected");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse <code>username:password@hostname:port</code>.</p>
|
||||
*/
|
||||
private static Authority parseAuthority(String auth, int defaultPort,
|
||||
String encoding)
|
||||
throws MalformedURLException, UnsupportedEncodingException {
|
||||
if (auth == null) return null;
|
||||
final String split[] = StringTools.splitOnce(auth, '@', true);
|
||||
final String uinfo[] = StringTools.splitOnce(split[0], ':', false);
|
||||
final String hinfo[] = StringTools.splitOnce(split[1], ':', false);
|
||||
final int port;
|
||||
|
||||
if ((split[0] != null) && (split[1] == null))
|
||||
throw new MalformedURLException("Missing required host info part");
|
||||
if ((uinfo[0] == null) && (uinfo[1] != null))
|
||||
throw new MalformedURLException("Password specified without user");
|
||||
if ((hinfo[0] == null) && (hinfo[1] != null))
|
||||
throw new MalformedURLException("Port specified without host");
|
||||
try {
|
||||
if (hinfo[1] != null) {
|
||||
final int parsedPort = Integer.parseInt(hinfo[1]);
|
||||
if ((parsedPort < 1) || (parsedPort > 65535)) {
|
||||
final String message = "Invalid port number " + parsedPort;
|
||||
throw new MalformedURLException(message);
|
||||
}
|
||||
/* If the specified port is the default one, ignore it! */
|
||||
if (defaultPort == parsedPort) port = -1;
|
||||
else port = parsedPort;
|
||||
} else {
|
||||
port = -1;
|
||||
}
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new MalformedURLException("Specified port is not a number");
|
||||
}
|
||||
return new Authority(EncodingTools.urlDecode(uinfo[0], encoding),
|
||||
EncodingTools.urlDecode(uinfo[1], encoding),
|
||||
EncodingTools.urlDecode(hinfo[0], encoding),
|
||||
port);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* PUBLIC INNER CLASSES */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>The {@link Location.Schemes Schemes} class represents an unmodifiable
|
||||
* ordered collection of {@link String} schemes for a {@link Location}.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public static class Schemes extends AbstractList implements Encodable {
|
||||
/** <p>All the {@link String} schemes in order.</p> */
|
||||
private final String schemes[];
|
||||
/** <p>The {@link String} representation of this instance.</p> */
|
||||
private final String string;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Schemes} instance.</p>
|
||||
*/
|
||||
private Schemes(List schemes) {
|
||||
final int size = schemes.size();
|
||||
this.schemes = (String []) schemes.toArray(new String[size]);
|
||||
this.string = EncodingTools.toString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link String} scheme at the specified index.</p>
|
||||
*/
|
||||
public Object get(int index) {
|
||||
return this.schemes[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the number of {@link String} schemes contained by this
|
||||
* {@link Location.Schemes Schemes} instance.</p>
|
||||
*/
|
||||
public int size() {
|
||||
return this.schemes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Location.Schemes Schemes} instance.</p>
|
||||
*/
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Location.Schemes Schemes} instance using the specified
|
||||
* character encoding.</p>
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
for (int x = 0; x < this.schemes.length; x ++) {
|
||||
buffer.append(':');
|
||||
buffer.append(EncodingTools.urlEncode(this.schemes[x], encoding));
|
||||
}
|
||||
return buffer.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the hash code value for this
|
||||
* {@link Location.Schemes Schemes} instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.string.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check if the specified {@link Object} is equal to this
|
||||
* {@link Location.Schemes Schemes} instance.</p>
|
||||
*
|
||||
* <p>The specified {@link Object} is considered equal to this one if
|
||||
* it is <b>non-null</b>, it is a {@link Location.Schemes Schemes}
|
||||
* instance, and its {@link #toString() string representation} equals
|
||||
* this one's.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof Schemes)) {
|
||||
return this.string.equals(((Schemes) object).string);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>The {@link Location.Authority Authority} class represents the autority
|
||||
* and user information for a {@link Location}.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public static class Authority implements Encodable {
|
||||
/** <p>The username of this instance (decoded).</p> */
|
||||
private final String username;
|
||||
/** <p>The password of this instance (decoded).</p> */
|
||||
private final String password;
|
||||
/** <p>The host name of this instance (decoded).</p> */
|
||||
private final String host;
|
||||
/** <p>The port number of this instance.</p> */
|
||||
private final int port;
|
||||
/** <p>The encoded host and port representation.</p> */
|
||||
private final String hostinfo;
|
||||
/** <p>The encoded string representation of this instance.</p> */
|
||||
private final String string;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Location.Authority Authority} instance.</p>
|
||||
*/
|
||||
private Authority(String user, String pass, String host, int port) {
|
||||
this.username = user;
|
||||
this.password = pass;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
try {
|
||||
this.hostinfo = this.getHostInfo(DEFAULT_ENCODING);
|
||||
this.string = this.toString(DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Default encoding \"" + DEFAULT_ENCODING
|
||||
+ "\" not supported by the platform";
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the decoded user name.</p>
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the decoded password.</p>
|
||||
*/
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the "user info" field.</p>
|
||||
*
|
||||
* <p>This method will concatenate the username and password using the
|
||||
* colon character and return a <b>non-null</b> {@link String} only if
|
||||
* both of them are <b>non-null</b>.</p>
|
||||
*/
|
||||
public String getUserInfo() {
|
||||
if ((this.username == null) || (this.password == null)) return null;
|
||||
return this.username + ':' + this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the decoded host name.</p>
|
||||
*/
|
||||
public String getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the port number.</p>
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the host info part of the
|
||||
* {@link Location.Authority Authority}.</p>
|
||||
*
|
||||
* <p>This is the encoded representation of the
|
||||
* {@link #getUsername() user name} optionally follwed by the colon (:)
|
||||
* character and the encoded {@link #getPassword() password}.</p>
|
||||
*/
|
||||
public String getHostInfo() {
|
||||
return this.hostinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the host info part of the
|
||||
* {@link Location.Authority Authority} using the specified character
|
||||
* encoding.</p>
|
||||
*
|
||||
* <p>This is the encoded representation of the
|
||||
* {@link #getUsername() user name} optionally follwed by the colon (:)
|
||||
* character and the encoded {@link #getPassword() password}.</p>
|
||||
*/
|
||||
public String getHostInfo(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
final StringBuffer hostinfo = new StringBuffer();
|
||||
hostinfo.append(EncodingTools.urlEncode(this.host, encoding));
|
||||
if (port >= 0) hostinfo.append(':').append(port);
|
||||
return hostinfo.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Location.Authority Authority} instance.</p>
|
||||
*/
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Location.Authority Authority} instance using the specified
|
||||
* character encoding.</p>
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
final StringBuffer buffer;
|
||||
if (this.username != null) {
|
||||
buffer = new StringBuffer();
|
||||
buffer.append(EncodingTools.urlEncode(this.username, encoding));
|
||||
if (this.password != null) {
|
||||
buffer.append(':');
|
||||
buffer.append(EncodingTools.urlEncode(this.password, encoding));
|
||||
}
|
||||
} else {
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
if (buffer == null) return this.getHostInfo(encoding);
|
||||
buffer.append('@').append(this.getHostInfo(encoding));
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the hash code value for this
|
||||
* {@link Location.Authority Authority} instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.hostinfo.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check if the specified {@link Object} is equal to this
|
||||
* {@link Location.Authority Authority} instance.</p>
|
||||
*
|
||||
* <p>The specified {@link Object} is considered equal to this one if
|
||||
* it is <b>non-null</b>, it is a {@link Location.Authority Authority}
|
||||
* instance, and its {@link #getHostInfo() host info} equals
|
||||
* this one's.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof Authority)) {
|
||||
return this.hostinfo.equals(((Authority) object).hostinfo);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,474 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util.location;
|
||||
|
||||
import it.could.util.StringTools;
|
||||
import it.could.util.encoding.Encodable;
|
||||
import it.could.util.encoding.EncodingTools;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* <p>The {@link Parameters Parameters} class represents a never empty and
|
||||
* immutable {@link List} of {@link Parameters.Parameter Parameter} instances,
|
||||
* normally created parsing a query string.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class Parameters extends AbstractList implements Encodable {
|
||||
|
||||
/** <p>The default delimiter for a {@link Parameters} instance.</p> */
|
||||
public static final char DEFAULT_DELIMITER = '&';
|
||||
|
||||
/** <p>All the {@link Parameter}s in order.</p> */
|
||||
private final Parameter parameters[];
|
||||
/** <p>The {@link Map} view over all parameters (names are keys).</p> */
|
||||
private final Map map;
|
||||
/** <p>The {@link Set} of all parameter names.</p> */
|
||||
final Set names;
|
||||
/** <p>The character delimiting different parameters.</p> */
|
||||
private final char delimiter;
|
||||
/** <p>The encoded {@link String} representation of this.</p> */
|
||||
private final String string;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Parameters Parameters} instance from
|
||||
* a {@link List} of {@link Parameters.Parameter Parameter} instances
|
||||
* using the {@link #DEFAULT_DELIMITER default parameter delimiter}.</p>
|
||||
*
|
||||
* @throws NullPointerExceptoin if the {@link List} was <b>null</b>.
|
||||
* @throws IllegalArgumentException if the {@link List} was empty.
|
||||
* @throws ClassCastException if any of the elements in the {@link List} was
|
||||
* not a {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public Parameters(List parameters) {
|
||||
this(parameters, DEFAULT_DELIMITER);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Parameters Parameters} instance from
|
||||
* a {@link List} of {@link Parameters.Parameter Parameter} instances
|
||||
* using the specified character as the parameters delimiter.</p>
|
||||
*
|
||||
* @throws NullPointerExceptoin if the {@link List} was <b>null</b>.
|
||||
* @throws IllegalArgumentException if the {@link List} was empty.
|
||||
* @throws ClassCastException if any of the elements in the {@link List} was
|
||||
* not a {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public Parameters(List parameters, char delimiter) {
|
||||
if (parameters.size() == 0) throw new IllegalArgumentException();
|
||||
final Parameter array[] = new Parameter[parameters.size()];
|
||||
final Map map = new HashMap();
|
||||
for (int x = 0; x < array.length; x ++) {
|
||||
final Parameter parameter = (Parameter) parameters.get(x);
|
||||
final String key = parameter.getName();
|
||||
List values = (List) map.get(key);
|
||||
if (values == null) {
|
||||
values = new ArrayList();
|
||||
map.put(key, values);
|
||||
}
|
||||
values.add(parameter.getValue());
|
||||
array[x] = parameter;
|
||||
}
|
||||
|
||||
/* Make all parameter value lists unmodifiable */
|
||||
for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
|
||||
final Map.Entry entry = (Map.Entry) iter.next();
|
||||
final List list = (List) entry.getValue();
|
||||
entry.setValue(Collections.unmodifiableList(list));
|
||||
}
|
||||
|
||||
/* Store the current values */
|
||||
this.delimiter = delimiter;
|
||||
this.map = Collections.unmodifiableMap(map);
|
||||
this.names = Collections.unmodifiableSet(map.keySet());
|
||||
this.parameters = array;
|
||||
this.string = EncodingTools.toString(this);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* STATIC CONSTRUCTION METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Utility method to create a new {@link Parameters} instance from a
|
||||
* {@link List} of {@link Parameters.Parameter Parameter} instances.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters} instance or
|
||||
* <b>null</b> if the specified {@link List} was <b>null</b>, empty
|
||||
* or did not contain any {@link Parameters.Parameter Parameter}.
|
||||
* @throws ClassCastException if any of the elements in the {@link List} was
|
||||
* not a {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public static Parameters create(List parameters) {
|
||||
return create(parameters, DEFAULT_DELIMITER);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Utility method to create a new {@link Parameters} instance from a
|
||||
* {@link List} of {@link Parameters.Parameter Parameter} instances.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters} instance or
|
||||
* <b>null</b> if the specified {@link List} was <b>null</b>, empty
|
||||
* or did not contain any {@link Parameters.Parameter Parameter}.
|
||||
* @throws ClassCastException if any of the elements in the {@link List} was
|
||||
* not a {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public static Parameters create(List parameters, char delimiter) {
|
||||
if (parameters == null) return null;
|
||||
final List dedupes = new ArrayList();
|
||||
for (Iterator iter = parameters.iterator(); iter.hasNext(); ) {
|
||||
Object next = iter.next();
|
||||
if (dedupes.contains(next)) continue;
|
||||
dedupes.add(next);
|
||||
}
|
||||
if (dedupes.size() == 0) return null;
|
||||
return new Parameters(dedupes, delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified parameters {@link String} into a
|
||||
* {@link Parameters} instance using the {@link #DEFAULT_DELIMITER default
|
||||
* parameter delimiter}.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters} instance or
|
||||
* <b>null</b> if the specified string was <b>null</b>, empty or
|
||||
* did not contain any {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public static Parameters parse(String parameters) {
|
||||
try {
|
||||
return parse(parameters, DEFAULT_DELIMITER, DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified parameters {@link String} into a
|
||||
* {@link Parameters} instance using the specified character as the
|
||||
* parameters delimiter.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters} instance or
|
||||
* <b>null</b> if the specified string was <b>null</b>, empty or
|
||||
* did not contain any {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public static Parameters parse(String parameters, char delimiter) {
|
||||
try {
|
||||
return parse(parameters, delimiter, DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified parameters {@link String} into a
|
||||
* {@link Parameters} instance using the {@link #DEFAULT_DELIMITER default
|
||||
* parameter delimiter}.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters} instance or
|
||||
* <b>null</b> if the specified string was <b>null</b>, empty or
|
||||
* did not contain any {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public static Parameters parse(String parameters, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
return parse(parameters, DEFAULT_DELIMITER, encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified parameters {@link String} into a
|
||||
* {@link Parameters} instance using the specified character as the
|
||||
* parameters delimiter.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters} instance or
|
||||
* <b>null</b> if the specified string was <b>null</b>, empty or
|
||||
* did not contain any {@link Parameters.Parameter Parameter}.
|
||||
*/
|
||||
public static Parameters parse(String parameters, char delimiter,
|
||||
String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (parameters == null) return null;
|
||||
if (parameters.length() == 0) return null;
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
final String split[] = StringTools.splitAll(parameters, delimiter);
|
||||
final List list = new ArrayList();
|
||||
for (int x = 0; x < split.length; x ++) {
|
||||
if (split[x] == null) continue;
|
||||
if (split[x].length() == 0) continue;
|
||||
Parameter parameter = Parameter.parse(split[x], encoding);
|
||||
if (parameter != null) list.add(parameter);
|
||||
}
|
||||
if (list.size() == 0) return null;
|
||||
return new Parameters(list, delimiter);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* PUBLIC EXPOSED METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the number of {@link Parameters.Parameter Parameter}s
|
||||
* contained by this instance.</p>
|
||||
*/
|
||||
public int size() {
|
||||
return this.parameters.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link Parameters.Parameter Parameter} stored by this\
|
||||
* instance at the specified index.</p>
|
||||
*/
|
||||
public Object get(int index) {
|
||||
return this.parameters[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return an immutable {@link Set} of {@link String}s containing all
|
||||
* known {@link Parameters.Parameter Parameter}
|
||||
* {@link Parameters.Parameter#getName() names}.</p>
|
||||
*/
|
||||
public Set getNames() {
|
||||
return this.names;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the first {@link String} value associated with the
|
||||
* specified parameter name, or <b>null</b>.</p>
|
||||
*/
|
||||
public String getValue(String name) {
|
||||
final List values = (List) this.map.get(name);
|
||||
return values == null ? null : (String) values.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return an immutable {@link List} of all {@link String} values
|
||||
* associated with the specified parameter name, or <b>null</b>.</p>
|
||||
*/
|
||||
public List getValues(String name) {
|
||||
return (List) this.map.get(name);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* OBJECT METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Parameters Parameters} instance.</p>
|
||||
*/
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Parameters Parameters} instance using the specified
|
||||
* character encoding.</p>
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (int x = 0; x < this.parameters.length; x ++) {
|
||||
buffer.append(this.delimiter);
|
||||
buffer.append(this.parameters[x].toString(encoding));
|
||||
}
|
||||
return buffer.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the hash code value of this
|
||||
* {@link Parameters Parameters} instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.string.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check if the specified {@link Object} is equal to this
|
||||
* {@link Parameters Parameters} instance.</p>
|
||||
*
|
||||
* <p>The specified {@link Object} is considered equal to this one if
|
||||
* it is <b>non-null</b>, it is a {@link Parameters Parameters}
|
||||
* instance, and its {@link #toString() string representation} equals
|
||||
* this one's.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof Parameters)) {
|
||||
return this.string.equals(((Parameters) object).string);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* PUBLIC INNER CLASSES */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>The {@link Parameters.Parameter Parameter} class represents a single
|
||||
* parameter either parsed from a query string or a path element.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public static class Parameter implements Encodable {
|
||||
/** <p>The name of the parameter (decoded).</p> */
|
||||
private final String name;
|
||||
/** <p>The value of the parameter (decoded).</p> */
|
||||
private final String value;
|
||||
/** <p>The encoded {@link String} representation of this.</p> */
|
||||
private final String string;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Parameters.Parameter Parameter} given an
|
||||
* encoded parameter name and value.</p>
|
||||
*
|
||||
* @throws NullPointerException if the name was <b>null</b>.
|
||||
* @throws IllegalArgumentException if the name was an empty string.
|
||||
*/
|
||||
public Parameter(String name, String value) {
|
||||
if (name == null) throw new NullPointerException();
|
||||
if (name.length() == 0) throw new IllegalArgumentException();
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.string = EncodingTools.toString(this);
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* STATIC CONSTRUCTION METHODS */
|
||||
/* ================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Parse the specified parameters {@link String} into a
|
||||
* {@link Parameters.Parameter} instance.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters.Parameter}
|
||||
* instance or <b>null</b> if the specified string was
|
||||
* <b>null</b> or empty.
|
||||
*/
|
||||
public static Parameter parse(String parameter)
|
||||
throws UnsupportedEncodingException {
|
||||
try {
|
||||
return parse(parameter, DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified parameters {@link String} into a
|
||||
* {@link Parameters.Parameter} instance.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> and not empty {@link Parameters.Parameter}
|
||||
* instance or <b>null</b> if the specified string was
|
||||
* <b>null</b> or empty.
|
||||
*/
|
||||
public static Parameter parse(String parameter, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (parameter == null) return null;
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
String split[] = StringTools.splitOnce(parameter, '=', false);
|
||||
if (split[0] == null) return null;
|
||||
return new Parameter(split[0], split[1]);
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* PUBLIC EXPOSED METHODS */
|
||||
/* ================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the URL-decoded name of this
|
||||
* {@link Parameters.Parameter Parameter} instance.</p>
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-decoded value of this
|
||||
* {@link Parameters.Parameter Parameter} instance.</p>
|
||||
*/
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* OBJECT METHODS */
|
||||
/* ================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Parameters.Parameter Parameter} instance.</p>
|
||||
*/
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Parameters.Parameter Parameter} instance using the specified
|
||||
* character encoding.</p>
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (this.value != null) {
|
||||
return EncodingTools.urlEncode(this.name, encoding) + "=" +
|
||||
EncodingTools.urlEncode(this.value, encoding);
|
||||
} else {
|
||||
return EncodingTools.urlEncode(this.name, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the hash code value for this
|
||||
* {@link Parameters.Parameter Parameter} instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.string.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check if the specified {@link Object} is equal to this
|
||||
* {@link Parameters.Parameter Parameter} instance.</p>
|
||||
*
|
||||
* <p>The specified {@link Object} is considered equal to this one if
|
||||
* it is <b>non-null</b>, it is a {@link Parameters.Parameter Parameter}
|
||||
* instance, and its {@link #toString() string representation} equals
|
||||
* this one's.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof Parameter)) {
|
||||
return this.string.equals(((Parameter) object).string);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,559 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.util.location;
|
||||
|
||||
import it.could.util.StringTools;
|
||||
import it.could.util.encoding.Encodable;
|
||||
import it.could.util.encoding.EncodingTools;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
|
||||
/**
|
||||
* <p>The {@link Path Path} class is an ordered collection of
|
||||
* {@link Path.Element Element} instances representing a path
|
||||
* structure.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class Path extends AbstractList implements Encodable {
|
||||
|
||||
/** <p>The array of {@link Path.Element Element}s.</p> */
|
||||
private final Element paths[];
|
||||
/** <p>The current {@link Parameters} instance or <b>null</b>.</p> */
|
||||
private final Parameters parameters;
|
||||
/** <p>A flag indicating whether this path is absolute or not.</p> */
|
||||
private final boolean absolute;
|
||||
/** <p>A flag indicating if this path is a collection or not.</p> */
|
||||
private final boolean collection;
|
||||
/** <p>The {@link String} representation of this (encoded).</p> */
|
||||
private final String string;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Path Path} instance.</p>
|
||||
*
|
||||
* @throws ClassCastException if any of the elements in the {@link List}
|
||||
* was not a {@link Path.Element Element}.
|
||||
*/
|
||||
public Path(List elements, boolean absolute, boolean collection) {
|
||||
this(elements, absolute, collection, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Path Path} instance.</p>
|
||||
*
|
||||
* @throws ClassCastException if any of the elements in the {@link List}
|
||||
* was not a {@link Path.Element Element}.
|
||||
*/
|
||||
public Path(List elements, boolean absolute, boolean collection,
|
||||
Parameters parameters) {
|
||||
final Stack resolved = resolve(null, absolute, elements);
|
||||
final Element array[] = new Element[resolved.size()];
|
||||
this.paths = (Element []) resolved.toArray(array);
|
||||
this.parameters = parameters;
|
||||
this.absolute = absolute;
|
||||
this.collection = collection;
|
||||
this.string = EncodingTools.toString(this);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* STATIC CONSTRUCTION METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Parse the specified {@link String} into a {@link Path} structure.</p>
|
||||
*/
|
||||
public static Path parse(String path) {
|
||||
try {
|
||||
return parse(path, DEFAULT_ENCODING);
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified {@link String} into a {@link Path} structure.</p>
|
||||
*/
|
||||
public static Path parse(String path, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
final List params = new ArrayList();
|
||||
final List elems = new ArrayList();
|
||||
|
||||
/* No path, flog it! */
|
||||
if ((path == null) || (path.length() == 0)) {
|
||||
return new Path(elems, false, false, null);
|
||||
}
|
||||
|
||||
/* Check for a proper encoding */
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
|
||||
/* Split up the path structure into its path element components */
|
||||
final String split[] = StringTools.splitAll(path, '/');
|
||||
|
||||
/* Check if this path is an absolute path */
|
||||
final boolean absolute = path.charAt(0) == '/';
|
||||
|
||||
/* Check every single path element and append it to the current one */
|
||||
Element element = null;
|
||||
for (int x = 0; x < split.length; x++) {
|
||||
if (split[x] == null) continue; /* Collapse double slashes */
|
||||
element = parsePath(split[x], params, encoding);
|
||||
if (element != null) elems.add(element);
|
||||
}
|
||||
|
||||
/* Check if this is a collection */
|
||||
final boolean collection = ((split[split.length - 1] == null)
|
||||
|| (element == null)
|
||||
|| element.getName().equals(".")
|
||||
|| element.getName().equals(".."));
|
||||
|
||||
/* Setup the last path in our chain and return the first one */
|
||||
final Parameters parameters = Parameters.create(params, ';');
|
||||
return new Path(elems, absolute, collection, parameters);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Parse a single path element like <code>path!extra;param</code>.</p>
|
||||
*/
|
||||
private static Element parsePath(String path, List parameters,
|
||||
String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
final int pathEnds = StringTools.findFirst(path, "!;");
|
||||
final Element element;
|
||||
|
||||
if (pathEnds < 0) {
|
||||
element = new Element(EncodingTools.urlDecode(path, encoding), null);
|
||||
} else if (path.charAt(pathEnds) == ';') {
|
||||
// --> pathname;pathparameter
|
||||
final String name = path.substring(0, pathEnds);
|
||||
final String param = path.substring(pathEnds + 1);
|
||||
final Parameters params = Parameters.parse(param, ';', encoding);
|
||||
if (params != null) parameters.addAll(params);
|
||||
element = new Element(EncodingTools.urlDecode(name, encoding), null);
|
||||
} else {
|
||||
// --> pathname!extra...
|
||||
final String name = path.substring(0, pathEnds);
|
||||
final String more = path.substring(pathEnds + 1);
|
||||
final String split[] = StringTools.splitOnce(more, ';', false);
|
||||
final Parameters params = Parameters.parse(split[1], ';', encoding);
|
||||
if (params != null) parameters.addAll(params);
|
||||
element = new Element(EncodingTools.urlDecode(name, encoding),
|
||||
EncodingTools.urlDecode(split[0], encoding));
|
||||
}
|
||||
if (element.toString().length() == 0) return null;
|
||||
return element;
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* RESOLUTION METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Resolve the specified {@link Path} against this one.</p>
|
||||
*/
|
||||
public Path resolve(Path path) {
|
||||
/* Merge the parameters */
|
||||
final List params = new ArrayList();
|
||||
if (this.parameters != null) params.addAll(this.parameters);
|
||||
if (path.parameters != null) params.addAll(path.parameters);
|
||||
final Parameters parameters = Parameters.create(params, ';');
|
||||
|
||||
/* No path, return this instance */
|
||||
if (path == null) return this;
|
||||
|
||||
/* If the target is absolute, only merge the parameters */
|
||||
if (path.absolute)
|
||||
return new Path(path, true, path.collection, parameters);
|
||||
|
||||
/* Resolve the path */
|
||||
final Stack source = new Stack();
|
||||
source.addAll(this);
|
||||
if (! this.collection && (source.size() > 0)) source.pop();
|
||||
final List resolved = resolve(source, this.absolute, path);
|
||||
|
||||
/* Figure out if the resolved path is a collection and return it */
|
||||
final boolean c = path.size() == 0 ? this.collection : path.collection;
|
||||
return new Path(resolved, this.absolute, c, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified {@link String} into a {@link Path} and resolve it
|
||||
* against this one.</p>
|
||||
*/
|
||||
public Path resolve(String path) {
|
||||
try {
|
||||
return this.resolve(parse(path, DEFAULT_ENCODING));
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified {@link String} into a {@link Path} and resolve it
|
||||
* against this one.</p>
|
||||
*
|
||||
* @throws NullPointerException if the path {@link String} was <b>null</b>.
|
||||
*/
|
||||
public Path resolve(String path, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
if (path == null) return this;
|
||||
return this.resolve(parse(path, encoding));
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
private static Stack resolve(Stack stack, boolean absolute, List elements) {
|
||||
/* If we have no source stack we create a new empty one */
|
||||
if (stack == null) stack = new Stack();
|
||||
/* A flag indicating whether we are at the "root" path element. */
|
||||
boolean atroot = absolute && stack.empty();
|
||||
/* Iterate through the current path elements to see what to do. */
|
||||
for (Iterator iter = elements.iterator(); iter.hasNext(); ) {
|
||||
final Element element = (Element) iter.next();
|
||||
/* If this is the "." (current) path element, skip it. */
|
||||
if (".".equals(element.getName())) continue;
|
||||
/* If this is the ".." (parent) path element, it gets nasty. */
|
||||
if ("..".equals(element.getName())) {
|
||||
/* The root path's parent is always itself */
|
||||
if (atroot) continue;
|
||||
/* We're not at root and have the stack, relative ".." */
|
||||
if (stack.size() == 0) {
|
||||
stack.push(element);
|
||||
/* We're not at root, but we have stuff in the stack */
|
||||
} else {
|
||||
/* Get the last element in the stack */
|
||||
final Element prev = (Element) stack.peek();
|
||||
/* If the last element is "..", add another one */
|
||||
if ("..".equals(prev.getName())) stack.push(element);
|
||||
/* The last element was not "..", pop it out */
|
||||
else stack.pop();
|
||||
/* If absoulte and stack is empty, we're at root */
|
||||
if (absolute) atroot = stack.size() == 0;
|
||||
}
|
||||
} else {
|
||||
/* Normal element processing follows... */
|
||||
stack.push(element);
|
||||
atroot = false;
|
||||
}
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* RELATIVIZATION METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Parse the specified {@link String} into a {@link Path} and relativize
|
||||
* it against this one.</p>
|
||||
*/
|
||||
public Path relativize(String path) {
|
||||
try {
|
||||
return this.relativize(parse(path, DEFAULT_ENCODING));
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
final String message = "Unsupported encoding " + DEFAULT_ENCODING;
|
||||
final InternalError error = new InternalError(message);
|
||||
throw (InternalError) error.initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the specified {@link String} into a {@link Path} and relativize
|
||||
* it against this one.</p>
|
||||
*/
|
||||
public Path relativize(String path, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
if (encoding == null) encoding = DEFAULT_ENCODING;
|
||||
return this.relativize(parse(path, encoding));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieve the relativization path from this {@link Path} to the
|
||||
* specified {@link Path}.</p>
|
||||
*/
|
||||
public Path relativize(Path path) {
|
||||
/* No matter what, always return the aggregate of all parameters */
|
||||
final List parameters = new ArrayList();
|
||||
if (this.parameters != null) parameters.addAll(this.parameters);
|
||||
if (path.parameters != null) parameters.addAll(path.parameters);
|
||||
final Parameters params = Parameters.create(parameters, ';');
|
||||
|
||||
/* We are absolute and the specified path is absolute, we process */
|
||||
if ((path.absolute) && (this.absolute)) {
|
||||
/* Find the max number of paths we should examine */
|
||||
final int num = this.collection ? this.size() : this.size() - 1;
|
||||
|
||||
/* Process the two absolute paths to check common elements */
|
||||
int skip = 0;
|
||||
for (int x = 0; (x < num) && (x < path.size()); x ++) {
|
||||
if (path.paths[x].equals(this.paths[x])) skip ++;
|
||||
else break;
|
||||
}
|
||||
|
||||
/* Figure out if the resulting path is a collection */
|
||||
final boolean collection;
|
||||
if (path.size() > skip) collection = path.collection;
|
||||
else if (this.size() > skip) collection = true;
|
||||
else collection = this.collection;
|
||||
|
||||
/* Recreate the path to return by adding ".." and the paths */
|
||||
final List elems = new ArrayList();
|
||||
for (int x = skip; x < num; x ++) elems.add(new Element("..", null));
|
||||
elems.addAll(path.subList(skip, path.size()));
|
||||
return new Path(elems, false, collection);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we are in one of the following cases:
|
||||
* - the specified path is already relative, so why bother?
|
||||
* - we are relative and the specified path is absolute: in this case
|
||||
* we can't possibly know how far away we are located from the root
|
||||
* so, we only have one option, to return the absolute path.
|
||||
* In all cases, though, before returning the specified path, we just
|
||||
* merge ours and the path's parameters.
|
||||
*/
|
||||
if (this.absolute && (! path.absolute)) {
|
||||
/*
|
||||
* Ok, let's bother, we're absolute and the specified is not. This
|
||||
* means that if we resolve the path, we can find another absolute
|
||||
* path, and therefore we can do a better job at relativizin it.
|
||||
*/
|
||||
return this.relativize(this.resolve(path));
|
||||
}
|
||||
/* We'll never going to be able to do better than this */
|
||||
return new Path(path, path.absolute, path.collection, params);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* PUBLIC EXPOSED METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the {@link Path.Element Element} instance at
|
||||
* the specified index.</p>
|
||||
*/
|
||||
public Object get(int index) {
|
||||
return this.paths[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the number of {@link Path.Element Element}
|
||||
* instances contained by this instance.</p>
|
||||
*/
|
||||
public int size() {
|
||||
return this.paths.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks if this {@link Path Path} instance represents
|
||||
* an absolute path.</p>
|
||||
*/
|
||||
public boolean isAbsolute() {
|
||||
return this.absolute;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks if this {@link Path Path} instance represents
|
||||
* a collection.</p>
|
||||
*/
|
||||
public boolean isCollection() {
|
||||
return this.collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the collection of {@link Parameters Parameters}
|
||||
* contained by this instance or <b>null</b>.</p>
|
||||
*/
|
||||
public Parameters getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* OBJECT METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Path Path} instance.</p>
|
||||
*/
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Path Path} instance using the specified
|
||||
* character encoding.</p>
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
if (this.absolute) buffer.append('/');
|
||||
final int last = this.paths.length - 1;
|
||||
for (int x = 0; x < last; x ++) {
|
||||
buffer.append(this.paths[x].toString(encoding)).append('/');
|
||||
}
|
||||
if (last >= 0) {
|
||||
buffer.append(this.paths[last].toString(encoding));
|
||||
if (this.collection) buffer.append('/');
|
||||
}
|
||||
if (this.parameters != null)
|
||||
buffer.append(';').append(this.parameters.toString(encoding));
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the hash code value of this
|
||||
* {@link Path Path} instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.string.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check if the specified {@link Object} is equal to this
|
||||
* {@link Path Path} instance.</p>
|
||||
*
|
||||
* <p>The specified {@link Object} is considered equal to this one if
|
||||
* it is <b>non-null</b>, is a {@link Path Path}
|
||||
* instance and its {@link #toString() string representation} equals
|
||||
* this one's.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof Path)) {
|
||||
return this.string.equals(((Path) object).string);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* PUBLIC INNER CLASSES */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>The {@link Path.Element Element} class represents a path
|
||||
* element within the {@link Path Path} structure.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public static class Element implements Encodable {
|
||||
|
||||
/** <p>The name of this path element (decoded).</p> */
|
||||
private final String name;
|
||||
/** <p>The extra path information of this path element (decoded).</p> */
|
||||
private final String extra;
|
||||
/** <p>The {@link String} representation of this (encoded).</p> */
|
||||
private final String string;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link Path.Element Element} instance given its
|
||||
* url-decoded components name and extra.</p>
|
||||
*
|
||||
* @throws NullPointerException if the specified name was <b>null</b>.
|
||||
*/
|
||||
public Element(String name, String extra) {
|
||||
if (name == null) throw new NullPointerException("Null path name");
|
||||
this.name = name;
|
||||
this.extra = extra;
|
||||
this.string = EncodingTools.toString(this);
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* PUBLIC EXPOSED METHODS */
|
||||
/* ================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the url-decoded {@link String} name of this
|
||||
* {@link Path.Element Element}.</p>
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the url-decoded {@link String} extra path of this
|
||||
* {@link Path.Element Element}.</p>
|
||||
*/
|
||||
public String getExtra() {
|
||||
return this.extra;
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* OBJECT METHODS */
|
||||
/* ================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Path.Element Element} instance.</p>
|
||||
*/
|
||||
public String toString() {
|
||||
return this.string;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the URL-encoded {@link String} representation of this
|
||||
* {@link Path.Element Element} instance using the specified
|
||||
* character encoding.</p>
|
||||
*/
|
||||
public String toString(String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(EncodingTools.urlEncode(this.name, encoding));
|
||||
if (this.extra != null) {
|
||||
buffer.append('!');
|
||||
buffer.append(EncodingTools.urlEncode(this.extra, encoding));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the hash code value of this
|
||||
* {@link Path.Element Element} instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.string.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check if the specified {@link Object} is equal to this
|
||||
* {@link Path.Element Element} instance.</p>
|
||||
*
|
||||
* <p>The specified {@link Object} is considered equal to this one if
|
||||
* it is <b>non-null</b>, is a {@link Path.Element Element}
|
||||
* instance and its {@link #toString() string representation} equals
|
||||
* this one's.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof Element)) {
|
||||
return this.string.equals(((Element) object).string);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Location Utilities</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package contains a number of utility classes to parse and
|
||||
work with URLs.
|
||||
</p>
|
||||
<p>
|
||||
The {@link java.net.URL} class already provides most of the functionality
|
||||
covered by this package, but certain limitations in its implementation
|
||||
(for example, all schemes <i>must</i> be registered with the
|
||||
{java.net.URLStreamHandler} class before they can be used), prompted
|
||||
the re-development of a similar API.
|
||||
</p>
|
||||
<p>
|
||||
For further details on what the different classes in this package mean
|
||||
and how they interact, see the {@link it.could.util.location.Location}
|
||||
class documentation, but as a reference, this is a picture outlining
|
||||
the structure:
|
||||
</p>
|
||||
<div align="center">
|
||||
<a href="url.pdf" target="_new" title="PDF Version">
|
||||
<img src="url.gif" alt="URL components" border="0">
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,11 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Encoding Utilities</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package contains a number of utility classes which can come handy
|
||||
from time to time when writing Java code.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,132 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A {@link RuntimeException} representing a
|
||||
* <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* response for a specified {@link DAVResource}.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVException extends RuntimeException {
|
||||
|
||||
private DAVResource resource = null;
|
||||
private int status = 0;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVException} instance.</p>
|
||||
*/
|
||||
public DAVException(int status, String message) {
|
||||
this(status, message, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVException} instance.</p>
|
||||
*/
|
||||
public DAVException(int status, String message, Throwable throwable) {
|
||||
this(status, message, throwable, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVException} instance.</p>
|
||||
*/
|
||||
public DAVException(int status, String message, DAVResource resource) {
|
||||
this(status, message, null, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVException} instance.</p>
|
||||
*/
|
||||
public DAVException(int s, String m, Throwable t, DAVResource r) {
|
||||
super(m, t);
|
||||
this.resource = r;
|
||||
this.status = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the status code associated with this instance.</p>
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link DAVResource} associated with this instance.</p>
|
||||
*/
|
||||
public DAVResource getResource() {
|
||||
return this.resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write the body of this {@link DAVException} to the specified
|
||||
* {@link DAVTransaction}'s output.</p>
|
||||
*/
|
||||
public void write(DAVTransaction transaction)
|
||||
throws IOException {
|
||||
transaction.setContentType("text/html; charset=\"UTF-8\"");
|
||||
transaction.setStatus(this.getStatus());
|
||||
|
||||
/* Prepare and log the error message */
|
||||
String message = DAVUtilities.getStatusMessage(this.getStatus());
|
||||
if (message == null) {
|
||||
transaction.setStatus(500);
|
||||
message = Integer.toString(this.getStatus()) + " Unknown";
|
||||
}
|
||||
|
||||
/* Write the error message to the client */
|
||||
PrintWriter out = transaction.write("UTF-8");
|
||||
out.println("<html>");
|
||||
out.print("<head><title>Error ");
|
||||
out.print(message);
|
||||
out.println("</title></head>");
|
||||
out.println("<body>");
|
||||
out.print("<p><b>Error ");
|
||||
out.print(message);
|
||||
out.println("</b></p>");
|
||||
|
||||
/* Check if we have a resource associated with the extension */
|
||||
if (this.getResource() != null) {
|
||||
String r = transaction.lookup(this.getResource()).toASCIIString();
|
||||
out.print("<p>Resource in error: <a href=\"");
|
||||
out.print(r);
|
||||
out.println("\">");
|
||||
out.print(r);
|
||||
out.println("</a></p>");
|
||||
}
|
||||
|
||||
/* Process any exception and its cause */
|
||||
Throwable throwable = this;
|
||||
out.println("<hr /><p>Exception details:</p>");
|
||||
while (throwable != null) {
|
||||
out.print("<pre>");
|
||||
throwable.printStackTrace(out);
|
||||
out.println("</pre>");
|
||||
throwable = throwable.getCause();
|
||||
if (throwable != null) out.println("<hr /><p>Caused by:</p>");
|
||||
}
|
||||
|
||||
/* Close up the HTML */
|
||||
out.println("</body>");
|
||||
out.println("</html>");
|
||||
out.flush();
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A specialized {@link InputStream} to read from {@link DAVResource}s.</p>
|
||||
*
|
||||
* <p>This specialized {@link InputStream} never throws {@link IOException}s,
|
||||
* but rather relies on the unchecked {@link DAVException} to notify the
|
||||
* framework of the correct DAV errors.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVInputStream extends InputStream {
|
||||
|
||||
/** <p>The {@link InputStream} of the source {@link File}. </p> */
|
||||
protected InputStream input = null;
|
||||
/** <p>The {@link DAVResource} associated with this instance. </p> */
|
||||
private DAVResource resource = null;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVInputStream} instance.</p>
|
||||
*/
|
||||
protected DAVInputStream(DAVResource resource) {
|
||||
if (resource == null) throw new NullPointerException();
|
||||
init(resource);
|
||||
}
|
||||
|
||||
protected void init(DAVResource resource)
|
||||
{
|
||||
try {
|
||||
this.input = new FileInputStream(resource.getFile());
|
||||
} catch (IOException e) {
|
||||
String message = "Unable to read from resource";
|
||||
throw new DAVException (403, message, e, resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Read data from this {@link InputStream}.</p>
|
||||
*/
|
||||
public int read() {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
return input.read();
|
||||
} catch (IOException e) {
|
||||
throw new DAVException(403, "Can't read data", e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Read data from this {@link InputStream}.</p>
|
||||
*/
|
||||
public int read(byte b[]) {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
return input.read(b);
|
||||
} catch (IOException e) {
|
||||
throw new DAVException(403, "Can't read data", e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Read data from this {@link InputStream}.</p>
|
||||
*/
|
||||
public int read(byte b[], int off, int len) {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
return input.read(b, off, len);
|
||||
} catch (IOException e) {
|
||||
throw new DAVException(403, "Can't read data", e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Skip a specified amount of data reading from this
|
||||
* {@link InputStream}.</p>
|
||||
*/
|
||||
public long skip(long n) {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
return input.skip(n);
|
||||
} catch (IOException e) {
|
||||
throw new DAVException(403, "Can't skip over", e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the number of bytes that can be read or skipped from this
|
||||
* {@link InputStream} without blocking.</p>
|
||||
*/
|
||||
public int available() {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
return input.available();
|
||||
} catch (IOException e) {
|
||||
throw new DAVException(403, "Can't skip over", e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the number of bytes that can be read or skipped from this
|
||||
* {@link InputStream} without blocking.</p>
|
||||
*/
|
||||
public void close() {
|
||||
if (this.input == null) return;
|
||||
try {
|
||||
this.input.close();
|
||||
} catch (IOException e) {
|
||||
throw new DAVException(403, "Can't close", e, this.resource);
|
||||
} finally {
|
||||
this.input = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Marks the current position in this {@link InputStream}.</p>
|
||||
*/
|
||||
public void mark(int readlimit) {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
this.input.mark(readlimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Repositions this stream to the position at the time the
|
||||
* {@link #mark(int)} method was last called on this
|
||||
* {@link InputStream}.</p>
|
||||
*/
|
||||
public void reset() {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
input.reset();
|
||||
} catch (IOException e) {
|
||||
throw new DAVException(403, "Can't reset", e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Tests if this {@link InputStream} supports the {@link #mark(int)}
|
||||
* and {@link #reset()} methods.</p>
|
||||
*/
|
||||
public boolean markSupported() {
|
||||
if (this.input == null) throw new IllegalStateException("Closed");
|
||||
return this.input.markSupported();
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
/**
|
||||
* <p>A simple interface identifying a {@link DAVRepository} event listener.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public interface DAVListener {
|
||||
|
||||
/** <p>An event representing the creation of a collection.</p> */
|
||||
public static final int COLLECTION_CREATED = 1;
|
||||
/** <p>An event representing the deletion of a collection.</p> */
|
||||
public static final int COLLECTION_REMOVED = 2;
|
||||
/** <p>An event representing the creation of a resource.</p> */
|
||||
public static final int RESOURCE_CREATED = 3;
|
||||
/** <p>An event representing the deletion of a resource.</p> */
|
||||
public static final int RESOURCE_REMOVED = 4;
|
||||
/** <p>An event representing the modification of a resource.</p> */
|
||||
public static final int RESOURCE_MODIFIED = 5;
|
||||
|
||||
/**
|
||||
* <p>Notify this {@link DAVListener} of an action occurred on a
|
||||
* specified {@link DAVResource}.</p>
|
||||
*
|
||||
* @param resource the {@link DAVResource} associated with the notification.
|
||||
* @param event a number identifying the type of the notification.
|
||||
*/
|
||||
public void notify(DAVResource resource, int event);
|
||||
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
/**
|
||||
* <p>A simplicisting class defining an esay way to log stuff to the
|
||||
* {@link ServletContext}.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVLogger {
|
||||
|
||||
private final ServletContext context;
|
||||
private final String servletName;
|
||||
private final boolean debug;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVLogger} from a {@link ServletConfig}.</p>
|
||||
*/
|
||||
public DAVLogger(ServletConfig config, boolean debug) {
|
||||
this.context = config.getServletContext();
|
||||
this.servletName = config.getServletName();
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log a debug message to the context logger.</p>
|
||||
*/
|
||||
public void debug(String message) {
|
||||
if (this.debug) this.doLog(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log a debug message and related exception to the context logger.</p>
|
||||
*/
|
||||
public void debug(String message, Throwable throwable) {
|
||||
if (this.debug) this.doLog(message, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log a message to the context logger.</p>
|
||||
*/
|
||||
public void log(String message) {
|
||||
this.doLog(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Log a message and related exception to the context logger.</p>
|
||||
*/
|
||||
public void log(String message, Throwable throwable) {
|
||||
this.doLog(message, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Internal method for formatting messages and logging.</p>
|
||||
*/
|
||||
private void doLog(String message, Throwable throwable) {
|
||||
if ((message == null) && (throwable == null)) return;
|
||||
if ((message == null) || ("".equals(message))) message = "No message";
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append('[');
|
||||
buffer.append(this.servletName);
|
||||
buffer.append("] ");
|
||||
buffer.append(message);
|
||||
if (throwable == null) this.context.log(buffer.toString());
|
||||
else this.context.log(buffer.toString(), throwable);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* <p>An interface describing the implementation of a
|
||||
* <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* method.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public interface DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Process the specified {@link DAVTransaction}.</p>
|
||||
*
|
||||
* @param transaction An object encapsulaing a WebDAV request/response.
|
||||
* @param resource The {@link DAVResource} to process.
|
||||
* @throws IOException If an I/O error occurred.
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException;
|
||||
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A {@link DAVException} representing a
|
||||
* <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>207</code> (Multi-Status) response.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVMultiStatus extends DAVException {
|
||||
|
||||
private Set responses = new HashSet();
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVMultiStatus} instance.</p>
|
||||
*/
|
||||
public DAVMultiStatus() {
|
||||
super(207, "Multi-Status response");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write the body of the multi-status response to the specified
|
||||
* {@link DAVTransaction}'s output.</p>
|
||||
*/
|
||||
public void write(DAVTransaction transaction)
|
||||
throws IOException {
|
||||
/* What to do on a collection resource */
|
||||
transaction.setStatus(207);
|
||||
transaction.setContentType("text/xml; charset=\"UTF-8\"");
|
||||
PrintWriter out = transaction.write("UTF-8");
|
||||
|
||||
/* Output the XML declaration and the root document tag */
|
||||
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
out.println("<D:multistatus xmlns:D=\"DAV:\">");
|
||||
|
||||
Iterator responses = this.responses.iterator();
|
||||
while (responses.hasNext()) {
|
||||
Response response = (Response) responses.next();
|
||||
out.println(" <D:response>");
|
||||
out.print(" <D:href>");
|
||||
out.print(transaction.lookup(response.resource));
|
||||
out.println("</D:href>");
|
||||
|
||||
if (response.status != 0) {
|
||||
out.print(" <D:status>HTTP/1.1 ");
|
||||
out.print(DAVUtilities.getStatusMessage(response.status));
|
||||
out.println("</D:status>");
|
||||
}
|
||||
|
||||
if (response.message != null) {
|
||||
out.print(" <D:responsedescription>");
|
||||
out.print(response.message);
|
||||
out.println("</D:responsedescription>");
|
||||
}
|
||||
|
||||
out.println(" </D:response>");
|
||||
}
|
||||
|
||||
out.println("</D:multistatus>");
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the number of responses held in this instance.</p>
|
||||
*/
|
||||
public int size() {
|
||||
return this.responses.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Merge the responses held into the specified {@link DAVMultiStatus}
|
||||
* into this instance.</p>
|
||||
*/
|
||||
public void merge(DAVMultiStatus multistatus) {
|
||||
if (multistatus == null) return;
|
||||
Iterator iterator = multistatus.responses.iterator();
|
||||
while (iterator.hasNext()) this.responses.add(iterator.next());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Merge the details held into the specified {@link DAVException}
|
||||
* into this instance.</p>
|
||||
*/
|
||||
public void merge(DAVException exception) {
|
||||
DAVResource resource = exception.getResource();
|
||||
if (resource == null) throw exception;
|
||||
|
||||
int status = exception.getStatus();
|
||||
String message = exception.getMessage();
|
||||
this.responses.add(new Response(resource, status, message));
|
||||
}
|
||||
|
||||
private static class Response implements Comparable {
|
||||
private DAVResource resource = null;
|
||||
private int status = 0;
|
||||
private String message = null;
|
||||
|
||||
public Response(Response response) {
|
||||
this(response.resource, response.status, response.message);
|
||||
}
|
||||
|
||||
public Response(DAVResource resource, int status, String message) {
|
||||
if (resource == null) throw new NullPointerException();
|
||||
this.resource = resource;
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.resource.hashCode();
|
||||
}
|
||||
|
||||
public int compareTo(Object object) {
|
||||
Response response = (Response) object;
|
||||
return (this.resource.compareTo(response.resource));
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if (object instanceof Response) {
|
||||
Response response = (Response) object;
|
||||
return (this.resource.equals(response.resource));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* <p>A simple {@link DAVException} encapsulating an
|
||||
* <a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a> not modified
|
||||
* response.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVNotModified extends DAVException {
|
||||
|
||||
private DAVResource resource = null;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVNotModified} instance.</p>
|
||||
*/
|
||||
public DAVNotModified(DAVResource resource) {
|
||||
super(304, "Resource Not Modified");
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write the body of this {@link DAVNotModified} to the specified
|
||||
* {@link DAVTransaction}'s output.</p>
|
||||
*/
|
||||
public void write(DAVTransaction transaction)
|
||||
throws IOException {
|
||||
transaction.setStatus(this.getStatus());
|
||||
|
||||
/* Figure out what we're dealing with here */
|
||||
String etag = resource.getEntityTag();
|
||||
String lmod = DAVUtilities.formatHttpDate(resource.getLastModified());
|
||||
|
||||
/* Set the normal headers that are required for a GET */
|
||||
if (etag != null) transaction.setHeader("ETag", etag);
|
||||
if (lmod != null) transaction.setHeader("Last-Modified", lmod);
|
||||
}
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A specialized {@link OutputStream} to write to {@link DAVResource}s.</p>
|
||||
*
|
||||
* <p>When writing to this {@link OutputStream} the data will be written to
|
||||
* a temporary file. This temporary file will be moved to its final destination
|
||||
* (the original file identifying the resource) when the {@link #close()}
|
||||
* method is called.</p>
|
||||
*
|
||||
* <p>This specialized {@link OutputStream} never throws {@link IOException}s,
|
||||
* but rather relies on the unchecked {@link DAVException} to notify the
|
||||
* framework of the correct DAV errors.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVOutputStream extends OutputStream {
|
||||
|
||||
/** <p>The original resource {@link File}.</p> */
|
||||
private File temporary = null;
|
||||
/** <p>The {@link OutputStream} of the temporary {@link File}. </p> */
|
||||
protected OutputStream output = null;
|
||||
/** <p>The {@link DAVResource} associated with this instance. </p> */
|
||||
private DAVResource resource = null;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVOutputStream} instance.</p>
|
||||
*/
|
||||
protected DAVOutputStream(DAVResource resource) {
|
||||
if (resource == null) throw new NullPointerException();
|
||||
this.resource = resource;
|
||||
init(resource);
|
||||
}
|
||||
|
||||
protected void init(DAVResource resource) {
|
||||
try {
|
||||
this.temporary = resource.getParent().getFile();
|
||||
this.temporary = File.createTempFile(DAVResource.PREFIX,
|
||||
DAVResource.SUFFIX,
|
||||
this.temporary);
|
||||
this.output = new FileOutputStream(this.temporary);
|
||||
} catch (IOException e) {
|
||||
String message = "Unable to create temporary file";
|
||||
throw new DAVException(507, message, e, resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Rename the temporary {@link File} to the original one.</p>
|
||||
*/
|
||||
protected void rename(File temporary, File original)
|
||||
throws IOException {
|
||||
if ((original.exists()) && (!original.delete())) {
|
||||
throw new IOException("Unable to delete original file");
|
||||
}
|
||||
if (!temporary.renameTo(original)) {
|
||||
throw new IOException("Unable to rename temporary file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Abort any data written to the temporary file and delete it.</p>
|
||||
*/
|
||||
public void abort() {
|
||||
if (this.temporary.exists()) this.temporary.delete();
|
||||
if (this.output != null) try {
|
||||
this.output.close();
|
||||
} catch (IOException exception) {
|
||||
// Swallow the IOException on close
|
||||
} finally {
|
||||
this.output = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Close this {@link OutputStream} {@link #rename(File,File) renaming}
|
||||
* the temporary file to the {@link DAVResource#getFile() original} one.</p>
|
||||
*/
|
||||
public void close() {
|
||||
if (this.output == null) return;
|
||||
try {
|
||||
/* What kind of event should this invocation trigger? */
|
||||
int event = this.resource.getFile().exists() ?
|
||||
DAVListener.RESOURCE_MODIFIED:
|
||||
DAVListener.RESOURCE_CREATED;
|
||||
|
||||
/* Make sure that everything is closed and named properly */
|
||||
this.output.close();
|
||||
this.output = null;
|
||||
this.rename(this.temporary, this.resource.getFile());
|
||||
|
||||
/* Send notifications to all listeners of the repository */
|
||||
this.resource.getRepository().notify(this.resource, event);
|
||||
|
||||
} catch (IOException e) {
|
||||
String message = "Error processing temporary file";
|
||||
throw new DAVException(507, message, e, this.resource);
|
||||
} finally {
|
||||
this.abort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Flush any unwritten data to the disk.</p>
|
||||
*/
|
||||
public void flush() {
|
||||
if (this.output == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
this.output.flush();
|
||||
} catch (IOException e) {
|
||||
this.abort();
|
||||
String message = "Unable to flush buffers";
|
||||
throw new DAVException(507, message, e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write data to this {@link OutputStream}.</p>
|
||||
*/
|
||||
public void write(int b) {
|
||||
if (this.output == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
this.output.write(b);
|
||||
} catch (IOException e) {
|
||||
this.abort();
|
||||
String message = "Unable to write data";
|
||||
throw new DAVException(507, message, e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write data to this {@link OutputStream}.</p>
|
||||
*/
|
||||
public void write(byte b[]) {
|
||||
if (this.output == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
this.output.write(b);
|
||||
} catch (IOException e) {
|
||||
this.abort();
|
||||
String message = "Unable to write data";
|
||||
throw new DAVException(507, message, e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write data to this {@link OutputStream}.</p>
|
||||
*/
|
||||
public void write(byte b[], int o, int l) {
|
||||
if (this.output == null) throw new IllegalStateException("Closed");
|
||||
try {
|
||||
this.output.write(b, o, l);
|
||||
} catch (IOException e) {
|
||||
this.abort();
|
||||
String message = "Unable to write data";
|
||||
throw new DAVException(507, message, e, this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Finalize this {@link DAVOutputStream} instance.</p>
|
||||
*/
|
||||
public void finalize() {
|
||||
this.abort();
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* <p>The <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* transactions processor.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVProcessor {
|
||||
|
||||
/** <p>All the implemented methods, comma separated.</p> */
|
||||
public static final String METHODS = "COPY,DELETE,GET,HEAD,MKCOL,MOVE," +
|
||||
"OPTIONS,PROPFIND,PROPPATCH,PUT";
|
||||
|
||||
/** <p>A static map of all known webdav methods.</p> */
|
||||
private static Map INSTANCES = new HashMap();
|
||||
static {
|
||||
/* Load and verify all the known methods */
|
||||
final String thisName = DAVProcessor.class.getName();
|
||||
final int packageDelimiter = thisName.lastIndexOf('.');
|
||||
final String packageName = packageDelimiter < 1 ? "methods." :
|
||||
thisName.substring(0, packageDelimiter) + ".methods.";
|
||||
final StringTokenizer tokenizer = new StringTokenizer(METHODS, ",");
|
||||
final ClassLoader classLoader = DAVProcessor.class.getClassLoader();
|
||||
while (tokenizer.hasMoreTokens()) try {
|
||||
final String method = tokenizer.nextToken();
|
||||
final String className = packageName + method;
|
||||
final Class clazz = classLoader.loadClass(className);
|
||||
INSTANCES.put(method, (DAVMethod) clazz.newInstance());
|
||||
} catch (Throwable throwable) {
|
||||
InternalError error = new InternalError("Error loading method");
|
||||
throw (InternalError) error.initCause(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
/** <p>The {@link DAVRepository} associated with this instance.</p> */
|
||||
private DAVRepository repository = null;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVProcessor} instance.</p>
|
||||
*/
|
||||
public DAVProcessor(DAVRepository repository) {
|
||||
if (repository == null) throw new NullPointerException();
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the specified {@link DAVTransaction} fully.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction)
|
||||
throws IOException {
|
||||
try {
|
||||
String method = transaction.getMethod();
|
||||
if (INSTANCES.containsKey(method)) {
|
||||
String path = transaction.getNormalizedPath();
|
||||
DAVResource resource = this.repository.getResource(path);
|
||||
DAVMethod instance = ((DAVMethod) INSTANCES.get(method));
|
||||
instance.process(transaction, resource);
|
||||
} else {
|
||||
String message = "Method \"" + method + "\" not implemented";
|
||||
throw new DAVException(501, message);
|
||||
}
|
||||
} catch (DAVException exception) {
|
||||
exception.write(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMethod( String methodKey, DAVMethod method ) {
|
||||
INSTANCES.put( methodKey, method );
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>A simple class representing a {@link File} based WebDAV repository.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVRepository {
|
||||
|
||||
/** <p>A {@link String} of all acceptable characters in a URI.</p> */
|
||||
private static final String ACCEPTABLE =
|
||||
"ABCDEFGHIJLKMNOPQRSTUVWXYZ" + // ALPHA (UPPER)
|
||||
"abcdefghijklmnopqrstuvwxyz" + // ALPHA (LOWER)
|
||||
"0123456789" + // DIGIT
|
||||
"_-!.~'()*" + // UNRESERVED
|
||||
",;:$&+=" + // PUNCT
|
||||
"?/[]@"; // RESERVED
|
||||
|
||||
|
||||
/** <p>The {@link File} identifying the root of this repository.</p> */
|
||||
protected File root = null;
|
||||
/** <p>The {@link URI} associated with the root of this repository.</p> */
|
||||
protected URI base = null;
|
||||
/** <p>The {@link Set} of all configured {@link DAVListener}s.</p> */
|
||||
private Set listeners = new HashSet();
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVRepository} instance.</p>
|
||||
*
|
||||
* @param root The {@link File} identifying the root of the repository.
|
||||
* @throws IOException If the specified root is not a directory.
|
||||
* @throws NullPointerExceptoin If the specified root was <b>null</b>.
|
||||
*/
|
||||
public DAVRepository(File root)
|
||||
throws IOException {
|
||||
init(root);
|
||||
}
|
||||
|
||||
protected void init(File root)
|
||||
throws IOException {
|
||||
if (root == null) throw new NullPointerException("Null root");
|
||||
if (root.isDirectory()) {
|
||||
this.root = root.getCanonicalFile();
|
||||
this.base = this.root.toURI().normalize();
|
||||
} else {
|
||||
throw new IOException("Root \"" + root + "\" is not a directory");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link URI} representing the root directory of this
|
||||
* {@link DAVRepository}.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link URI} instance.
|
||||
*/
|
||||
protected URI getRepositoryURI() {
|
||||
return (this.base);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link DAVResource} associated with the given name.</p>
|
||||
*
|
||||
* @param name a {@link String} identifying the resource name.
|
||||
* @return a <b>non-null</b> {@link DAVResource} instance.
|
||||
* @throws IOException If the resource could not be resolved.
|
||||
*/
|
||||
public DAVResource getResource(String name)
|
||||
throws IOException {
|
||||
if (name == null) return this.getResource((URI) null);
|
||||
|
||||
try {
|
||||
/* Encode the string into a URI */
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
byte encoded[] = name.getBytes("UTF-8");
|
||||
for (int x = 0; x < encoded.length; x ++) {
|
||||
if (ACCEPTABLE.indexOf((int)encoded[x]) < 0) {
|
||||
buffer.append('%');
|
||||
buffer.append(DAVUtilities.toHexString(encoded[x]));
|
||||
continue;
|
||||
}
|
||||
buffer.append((char) encoded[x]);
|
||||
}
|
||||
|
||||
return this.getResource(new URI(buffer.toString()));
|
||||
} catch (URISyntaxException exception) {
|
||||
String message = "Invalid resource name \"" + name + "\"";
|
||||
throw (IOException) new IOException(message).initCause(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link DAVResource} associated with a {@link URI}.</p>
|
||||
*
|
||||
* <p>If the specified {@link URI} is relative it will be resolved against
|
||||
* the root of this {@link DAVRepository}.</p>
|
||||
*
|
||||
* @param uri an absolute or relative {@link URI} identifying the resource.
|
||||
* @return a <b>non-null</b> {@link DAVResource} instance.
|
||||
* @throws IOException If the resource could not be resolved.
|
||||
*/
|
||||
public DAVResource getResource(URI uri)
|
||||
throws IOException {
|
||||
if (uri == null) return new DAVResource(this, this.root);
|
||||
|
||||
if (! uri.isAbsolute()) uri = this.base.resolve(uri).normalize();
|
||||
return new DAVResource(this, new File(uri).getAbsoluteFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Add a new {@link DAVListener} to the list of instances notified by
|
||||
* this {@link DAVRepository}.</p>
|
||||
*/
|
||||
public void addListener(DAVListener listener) {
|
||||
if (listener != null) this.listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Remove a {@link DAVListener} from the list of instances notified by
|
||||
* this {@link DAVRepository}.</p>
|
||||
*/
|
||||
public void removeListener(DAVListener listener) {
|
||||
if (listener != null) this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Notify all configured {@link DAVListener}s of an event.</p>
|
||||
*/
|
||||
protected void notify(DAVResource resource, int event) {
|
||||
if (resource == null) throw new NullPointerException("Null resource");
|
||||
if (resource.getRepository() != this)
|
||||
throw new IllegalArgumentException("Invalid resource");
|
||||
|
||||
Iterator iterator = this.listeners.iterator();
|
||||
while (iterator.hasNext()) try {
|
||||
((DAVListener)iterator.next()).notify(resource, event);
|
||||
} catch (RuntimeException exception) {
|
||||
// Swallow any RuntimeException thrown by listeners.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,514 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A simple representation of a WebDAV resource based on {@link File}s.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVResource implements Comparable {
|
||||
|
||||
/** <p>The mime type when {@link #isCollection()} is <b>true</b>.</p> */
|
||||
public static final String COLLECTION_MIME_TYPE = "httpd/unix-directory";
|
||||
|
||||
/** <p>The prefix for all temporary resources.</p> */
|
||||
protected static final String PREFIX = ".dav_";
|
||||
/** <p>The suffix for all temporary resources.</p> */
|
||||
protected static final String SUFFIX = ".temp";
|
||||
/** <p>The {@link DAVRepository} instance containing this resource.</p> */
|
||||
private DAVRepository repository = null;
|
||||
/** <p>The {@link File} associated with this resource.</p> */
|
||||
private File file = null;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Constructors */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVResource} instance.</p>
|
||||
*/
|
||||
protected DAVResource(DAVRepository repo, File file) {
|
||||
if (repo == null) throw new NullPointerException("Null repository");
|
||||
if (file == null) throw new NullPointerException("Null resource");
|
||||
init(repo, file);
|
||||
}
|
||||
|
||||
protected void init(DAVRepository repo, File file)
|
||||
{
|
||||
this.repository = repo;
|
||||
this.file = file;
|
||||
|
||||
if (this.getRelativeURI().isAbsolute())
|
||||
throw new DAVException(412, "Error relativizing resource");
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Generic object methods */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return an integer number for the hash value of this instance.</p>
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.file.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Compare this instance to another object for equality.</p>
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if (object == null) return (false);
|
||||
if (object instanceof DAVResource) {
|
||||
DAVResource resource = (DAVResource) object;
|
||||
boolean u = this.file.equals(resource.file);
|
||||
boolean r = this.repository == resource.repository;
|
||||
return (u && r);
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Compare this instance to another object for sorting.</p>
|
||||
*/
|
||||
public int compareTo(Object object) {
|
||||
DAVResource resource = (DAVResource) object;
|
||||
return (this.file.compareTo(resource.file));
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Resource checkers */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Checks if this {@link DAVResource} is a null (non existant) one.</p>
|
||||
*
|
||||
* @return <b>true</b> if this resource does not esist (is a null resource).
|
||||
*/
|
||||
public boolean isNull() {
|
||||
return (! this.file.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks if this {@link DAVResource} is a collection.</p>
|
||||
*
|
||||
* @return <b>true</b> if this resource is a collection.
|
||||
*/
|
||||
public boolean isCollection() {
|
||||
if (this.isNull()) return false;
|
||||
return (this.file.isDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks if this {@link DAVResource} is an existing resource.</p>
|
||||
*
|
||||
* @return <b>true</b> if this resource is a collection.
|
||||
*/
|
||||
public boolean isResource() {
|
||||
if (this.isNull()) return false;
|
||||
return (! this.isCollection());
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Resource methods */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the {@link File} associated with this resource.</p>
|
||||
*/
|
||||
protected File getFile() {
|
||||
return this.file;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link DAVRepository} associated with this resource.</p>
|
||||
*/
|
||||
public DAVRepository getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the bare name of this resource (without any "/"
|
||||
* slashes at the end if it is a collection).</p>
|
||||
*
|
||||
* @return a <b>non null</b> {@link String}.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.file.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the display name of this resource (with an added "/"
|
||||
* slash at the end if it is a collection).</p>
|
||||
*
|
||||
* @return a <b>non null</b> {@link String}.
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
String name = this.getName();
|
||||
if (this.isCollection()) return (name + "/");
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the path of this {@link DAVResource} relative to the root
|
||||
* of the associated {@link DAVRepository}.</p>
|
||||
*
|
||||
* @return a <b>non null</b> {@link String}.
|
||||
*/
|
||||
public String getRelativePath() {
|
||||
return this.getRelativeURI().toASCIIString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link URI} of this {@link DAVResource} relative to the
|
||||
* root of the associated {@link DAVRepository}.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link URI} instance.
|
||||
*/
|
||||
public URI getRelativeURI() {
|
||||
URI uri = this.file.toURI();
|
||||
return this.repository.getRepositoryURI().relativize(uri).normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the parent {@link DAVResource} of this instance.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link DAVResource} instance or <b>null</b>
|
||||
* if this {@link DAVResource} is the repository root.
|
||||
*/
|
||||
public DAVResource getParent() {
|
||||
try {
|
||||
return new DAVResource(this.repository, this.file.getParentFile());
|
||||
} catch (Throwable throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return an {@link Iterator} over all children of this instance.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link Iterator} instance or <b>null</b> if
|
||||
* this {@link DAVResource} is not a collection.
|
||||
* @throws IOException If the resource could not be resolved.
|
||||
*/
|
||||
public Iterator getChildren() {
|
||||
if (! this.isCollection()) return null;
|
||||
|
||||
File children[] = this.file.listFiles();
|
||||
if (children == null) children = new File[0];
|
||||
List resources = new ArrayList(children.length);
|
||||
|
||||
for (int x = 0; x < children.length; x++) {
|
||||
String c = children[x].getName();
|
||||
if (c.startsWith(PREFIX) && c.endsWith(SUFFIX)) continue;
|
||||
resources.add(new DAVResource(this.repository, children[x]));
|
||||
}
|
||||
|
||||
return resources.iterator();
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* DAV Properties */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the MIME Content-Type of this {@link DAVResource}.</p>
|
||||
*
|
||||
* <p>If the {@link #isCollection()} method returns <b>true</b> this
|
||||
* method always returns <code>text/html</code>.</p>
|
||||
*
|
||||
* @return a {@link String} instance or <b>null</b> if this resource does
|
||||
* not exist.
|
||||
*/
|
||||
public String getContentType() {
|
||||
if (this.isNull()) return null;
|
||||
if (this.isCollection()) return COLLECTION_MIME_TYPE;
|
||||
return DAVUtilities.getMimeType(this.getDisplayName());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the MIME Content-Length of this {@link DAVResource}.</p>
|
||||
*
|
||||
* @return a {@link Long} instance or <b>null</b> if this resource does
|
||||
* not exist or is a collection.
|
||||
*/
|
||||
public Long getContentLength() {
|
||||
if (this.isNull() || this.isCollection()) return null;
|
||||
return new Long(this.file.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the creation date of this {@link DAVResource}.</p>
|
||||
*
|
||||
* <p>As this implementation relies on a {@link File} backend, this method
|
||||
* will always return the same as {@link #getLastModified()}.</p>
|
||||
*
|
||||
* @return a {@link String} instance or <b>null</b> if this resource does
|
||||
* not exist.
|
||||
*/
|
||||
public Date getCreationDate() {
|
||||
if (this.isNull()) return null;
|
||||
return new Date(this.file.lastModified());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the last modification date of this {@link DAVResource}.</p>
|
||||
*
|
||||
* @return a {@link String} instance or <b>null</b> if this resource does
|
||||
* not exist.
|
||||
*/
|
||||
public Date getLastModified() {
|
||||
if (this.isNull()) return null;
|
||||
return new Date(this.file.lastModified());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a {@link String} representing the Entity Tag of this
|
||||
* {@link DAVResource} as described by the
|
||||
* <a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP RFC</a>.</p>
|
||||
*
|
||||
* @return a {@link String} instance or <b>null</b> if this resource does
|
||||
* not exist.
|
||||
*/
|
||||
public String getEntityTag() {
|
||||
if (this.isNull()) return null;
|
||||
|
||||
String path = this.getRelativePath();
|
||||
StringBuffer etag = new StringBuffer();
|
||||
etag.append('"');
|
||||
|
||||
/* Append the MD5 hash of this resource name */
|
||||
try {
|
||||
MessageDigest digester = MessageDigest.getInstance("MD5");
|
||||
digester.reset();
|
||||
digester.update(path.getBytes("UTF8"));
|
||||
etag.append(DAVUtilities.toHexString(digester.digest()));
|
||||
etag.append('-');
|
||||
} catch (Exception e) {
|
||||
// If we can't get the MD5 HASH, let's ignore and hope...
|
||||
}
|
||||
|
||||
/* Append the hashCode of this resource name */
|
||||
etag.append(DAVUtilities.toHexString(path.hashCode()));
|
||||
|
||||
/* Append the last modification date if possible */
|
||||
Date date = this.getLastModified();
|
||||
if (date != null) {
|
||||
etag.append('-');
|
||||
etag.append(DAVUtilities.toHexString(date.getTime()));
|
||||
}
|
||||
|
||||
/* Close the ETag */
|
||||
etag.append('"');
|
||||
return(etag.toString());
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* DAV Operations */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Delete this resource.</p>
|
||||
*
|
||||
* @throws DAVException If for any reason this resource cannot be deleted.
|
||||
*/
|
||||
public void delete()
|
||||
throws DAVMultiStatus {
|
||||
if (this.isNull()) throw new DAVException(404, "Not found", this);
|
||||
|
||||
if (this.isResource()) {
|
||||
if (!windowsSafeDelete(this.file)) {
|
||||
throw new DAVException(403, "Can't delete resource", this);
|
||||
} else {
|
||||
this.repository.notify(this, DAVListener.RESOURCE_REMOVED);
|
||||
}
|
||||
} else if (this.isCollection()) {
|
||||
DAVMultiStatus multistatus = new DAVMultiStatus();
|
||||
|
||||
Iterator children = this.getChildren();
|
||||
while (children.hasNext()) try {
|
||||
((DAVResource)children.next()).delete();
|
||||
} catch (DAVException exception) {
|
||||
multistatus.merge(exception);
|
||||
}
|
||||
|
||||
if (multistatus.size() > 0) throw multistatus;
|
||||
if (!this.file.delete()) {
|
||||
throw new DAVException(403, "Can't delete collection", this);
|
||||
} else {
|
||||
this.repository.notify(this, DAVListener.COLLECTION_REMOVED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Copy this resource to the specified destination.</p>
|
||||
*
|
||||
* @throws DAVException If for any reason this resource cannot be deleted.
|
||||
*/
|
||||
public void copy(DAVResource dest, boolean overwrite, boolean recursive)
|
||||
throws DAVMultiStatus {
|
||||
|
||||
/*
|
||||
* NOTE: Since the COPY operation relies on other operation defined in
|
||||
* this class (and in DAVOutputStream for resources) rather than on
|
||||
* files temselves, notifications are sent elsewhere, not here.
|
||||
*/
|
||||
|
||||
if (this.isNull()) throw new DAVException(404, "Not found", this);
|
||||
|
||||
/* Check if the destination exists and delete if possible */
|
||||
if (!dest.isNull()) {
|
||||
if (! overwrite) {
|
||||
String msg = "Not overwriting existing destination";
|
||||
throw new DAVException(412, msg, dest);
|
||||
}
|
||||
dest.delete();
|
||||
}
|
||||
|
||||
/* Copy a single resource (destination is null as we deleted it) */
|
||||
if (this.isResource()) {
|
||||
DAVInputStream in = this.read();
|
||||
DAVOutputStream out = dest.write();
|
||||
byte buffer[] = new byte[4096];
|
||||
int k = -1;
|
||||
while ((k = in.read(buffer)) != -1) out.write(buffer, 0, k);
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
/* Copy the collection and all nested members */
|
||||
if (this.isCollection()) {
|
||||
dest.makeCollection();
|
||||
if (! recursive) return;
|
||||
|
||||
DAVMultiStatus multistatus = new DAVMultiStatus();
|
||||
Iterator children = this.getChildren();
|
||||
while (children.hasNext()) try {
|
||||
DAVResource childResource = (DAVResource) children.next();
|
||||
File child = new File(dest.file, childResource.file.getName());
|
||||
DAVResource target = new DAVResource(this.repository, child);
|
||||
childResource.copy(target, overwrite, recursive);
|
||||
} catch (DAVException exception) {
|
||||
multistatus.merge(exception);
|
||||
}
|
||||
if (multistatus.size() > 0) throw multistatus;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Moves this resource to the specified destination.</p>
|
||||
*
|
||||
* @throws DAVException If for any reason this resource cannot be deleted.
|
||||
*/
|
||||
public void move(DAVResource dest, boolean overwrite, boolean recursive)
|
||||
throws DAVMultiStatus {
|
||||
// the base class implementation is just copy-then-delete
|
||||
copy(dest, overwrite, recursive);
|
||||
this.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a collection identified by this {@link DAVResource}.</p>
|
||||
*
|
||||
* <p>This resource must be {@link #isNull() non-null} and its
|
||||
* {@link #getParent() parent} must be accessible and be a
|
||||
* {@link #isCollection() collection}.</p>
|
||||
*
|
||||
* @throws DAVException If for any reason a collection identified by this
|
||||
* resource cannot be created.
|
||||
*/
|
||||
public void makeCollection() {
|
||||
DAVResource parent = this.getParent();
|
||||
if (!this.isNull())
|
||||
throw new DAVException(405, "Resource exists", this);
|
||||
if (parent.isNull())
|
||||
throw new DAVException(409, "Parent does not not exist", this);
|
||||
if (!parent.isCollection())
|
||||
throw new DAVException(403, "Parent not a collection", this);
|
||||
if (!this.file.mkdir())
|
||||
throw new DAVException(507, "Can't create collection", this);
|
||||
this.repository.notify(this, DAVListener.COLLECTION_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return an {@link InputStream} reading the resource.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link InputStream} instance.
|
||||
*/
|
||||
public DAVInputStream read() {
|
||||
if (this.isNull()) throw new DAVException(404, "Not found", this);
|
||||
if (this.isCollection())
|
||||
throw new DAVException (403, "Resource is collection", this);
|
||||
return new DAVInputStream(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a {@link DAVOutputStream} writing to this {@link DAVResource}
|
||||
* instance.</p>
|
||||
*
|
||||
* @return a <b>non-null</b> {@link DAVOutputStream} instance.
|
||||
*/
|
||||
public DAVOutputStream write() {
|
||||
DAVResource parent = this.getParent();
|
||||
if (this.isCollection())
|
||||
throw new DAVException(409, "Can't write a collection", this);
|
||||
if (parent.isNull())
|
||||
throw new DAVException(409, "Parent doesn't exist", this);
|
||||
if (! parent.isCollection())
|
||||
throw new DAVException(403, "Parent not a collection", this);
|
||||
return new DAVOutputStream(this);
|
||||
}
|
||||
|
||||
/** File.delete(file) sometimes fails transiently on Windows.
|
||||
* This occurs even in low-I/O conditions, with file Explorer closed.
|
||||
* Delete can still fail (correctly) due to the separate Windows problem
|
||||
* of file sharing violations.
|
||||
* @return the status of the last attempt of File.delete()
|
||||
*/
|
||||
private static boolean windowsSafeDelete(File f)
|
||||
{
|
||||
// www.mail-archive.com/java-user@lucene.apache.org/msg08994.html
|
||||
boolean success = f.delete();
|
||||
int attempts = 1;
|
||||
while(!success && f.exists() && attempts < 3) {
|
||||
if(attempts > 2) {
|
||||
System.gc();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
success = f.delete();
|
||||
attempts++;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A very simple servlet capable of processing very simple
|
||||
* <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* requests.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVServlet implements Servlet, DAVListener {
|
||||
|
||||
/** <p>The {@link DAVRepository} configured for this instance.</p> */
|
||||
protected DAVRepository repository = null;
|
||||
/** <p>The {@link DAVLogger} configured for this instance.</p> */
|
||||
protected DAVLogger logger = null;
|
||||
/** <p>The {@link DAVProcessor} configured for this instance.</p> */
|
||||
protected DAVProcessor processor = null;
|
||||
/** <p>The {@link ServletContext} associated with this instance.</p> */
|
||||
private ServletContext context = null;
|
||||
/** <p>The {@link ServletConfig} associated with this instance.</p> */
|
||||
private ServletConfig config= null;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVServlet} instance.</p>
|
||||
*/
|
||||
public DAVServlet() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Initialize this {@link Servlet} instance.</p>
|
||||
*
|
||||
* <p>The only initialization parameter required by this servlet is the
|
||||
* "<code>rootPath</code>" parameter specifying the path
|
||||
* of the repository root (either absolute or relative to the configured
|
||||
* {@link ServletContext}.</p>
|
||||
*
|
||||
* <p>If the specified root is relative, it will be considered to
|
||||
* be relative to the {@link ServletContext} deployment path.</p>
|
||||
*
|
||||
* <p>In any case, the specified root must ultimately point to an existing
|
||||
* directory on a locally-accessible file system.</p>
|
||||
*
|
||||
* <p>When set to <code>true</code>, an optional parameter called
|
||||
* <code>xmlOnly</code> will force this {@link DAVServlet} to use an
|
||||
* {@link XMLRepository} instead of the default {@link DAVRepository}.</p>
|
||||
*
|
||||
* <p>Finally, when set to <code>true</code>, the optional parameter
|
||||
* <code>debugEnabled</code> will enable logging of method invocation and
|
||||
* events in the repository.</p>
|
||||
*/
|
||||
public void init(ServletConfig config)
|
||||
throws ServletException {
|
||||
/* Remember the configuration instance */
|
||||
this.config = config;
|
||||
this.context = config.getServletContext();
|
||||
|
||||
/* Setup logging */
|
||||
boolean debug = "true".equals(config.getInitParameter("debugEnabled"));
|
||||
this.logger = new DAVLogger(config, debug);
|
||||
|
||||
/* Try to retrieve the WebDAV root path from the configuration */
|
||||
String rootPath = config.getInitParameter("rootPath");
|
||||
if (rootPath == null)
|
||||
throw new ServletException("Parameter \"rootPath\" not specified");
|
||||
|
||||
/* Create repository and processor */
|
||||
try {
|
||||
File root = new File(rootPath);
|
||||
// The repository may not be the local filesystem. It may be rooted at "/".
|
||||
// But then on Windows new File("/").isAbsolute() is false.
|
||||
boolean unixAbsolute = rootPath.startsWith("/");
|
||||
boolean localAbsolute = root.isAbsolute();
|
||||
if (! unixAbsolute && !localAbsolute) {
|
||||
URL url = this.context.getResource("/" + rootPath);
|
||||
if (! "file".equals(url.getProtocol())) {
|
||||
throw new ServletException("Invalid root \"" + url + "\"");
|
||||
} else {
|
||||
root = new File(url.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
/* Discover the repository implementation at runtime */
|
||||
String repositoryClass = config.getInitParameter("repositoryClass");
|
||||
if(repositoryClass != null) {
|
||||
this.repository = DAVServlet.newRepository(repositoryClass, root);
|
||||
} else {
|
||||
// legacy configuration format. keep for now
|
||||
/* Make sure that we use the correct repository type */
|
||||
if ("true".equalsIgnoreCase(config.getInitParameter("xmlOnly"))) {
|
||||
this.repository = new XMLRepository(root);
|
||||
} else {
|
||||
this.repository = new DAVRepository(root);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the processor and register ourselves as listeners */
|
||||
this.processor = new DAVProcessor(this.repository);
|
||||
this.repository.addListener(this);
|
||||
this.logger.log("Initialized from " + root.getPath());
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
throw new ServletException("Can't resolve \"" + rootPath + "\"", e);
|
||||
} catch (IOException e) {
|
||||
String msg = "Can't initialize repository at \"" + rootPath + "\"";
|
||||
throw new ServletException(msg, e);
|
||||
}
|
||||
|
||||
/* Finally, register this repository in the servlet context */
|
||||
final String key = getRepositoryKey(config.getServletName());
|
||||
this.context.setAttribute(key, this.repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieve a {@link DAVRepository} for a given {@link File}.</p>
|
||||
*/
|
||||
public DAVRepository getRepository(File root)
|
||||
throws IOException {
|
||||
return new XMLRepository(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detroy this {@link Servlet} instance.</p>
|
||||
*/
|
||||
public void destroy() {
|
||||
this.repository.removeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link ServletConfig} associated with this instance.</p>
|
||||
*/
|
||||
public ServletConfig getServletConfig() {
|
||||
return (this.config);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link ServletContext} associated with this instance.</p>
|
||||
*/
|
||||
public ServletContext getServletContext() {
|
||||
return (this.context);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a informative {@link String} about this servlet.</p>
|
||||
*/
|
||||
public String getServletInfo() {
|
||||
return DAVUtilities.SERVLET_INFORMATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Execute the current request.</p>
|
||||
*/
|
||||
public void service(ServletRequest request, ServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
HttpServletResponse res = (HttpServletResponse) response;
|
||||
|
||||
/* Mark our presence */
|
||||
res.setHeader("Server", this.context.getServerInfo() + ' ' +
|
||||
DAVUtilities.SERVLET_SIGNATURE);
|
||||
|
||||
/* Normal methods are processed by their individual instances */
|
||||
DAVTransaction transaction = new DAVTransaction(req, res);
|
||||
try {
|
||||
this.processor.process(transaction);
|
||||
} catch (RuntimeException exception) {
|
||||
final String header = req.getMethod() + ' ' + req.getRequestURI()
|
||||
+ ' ' + req.getProtocol();
|
||||
this.context.log("Error processing: " + header);
|
||||
this.context.log("Exception processing DAV transaction", exception);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* DAV LISTENER INTERFACE IMPLEMENTATION */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Receive notification of an event occurred in a specific
|
||||
* {@link DAVRepository}.</p>
|
||||
*/
|
||||
public void notify(DAVResource resource, int event) {
|
||||
String message = "Unknown event";
|
||||
switch (event) {
|
||||
case DAVListener.COLLECTION_CREATED:
|
||||
message = "Collection created";
|
||||
break;
|
||||
case DAVListener.COLLECTION_REMOVED:
|
||||
message = "Collection removed";
|
||||
break;
|
||||
case DAVListener.RESOURCE_CREATED:
|
||||
message = "Resource created";
|
||||
break;
|
||||
case DAVListener.RESOURCE_REMOVED:
|
||||
message = "Resource removed";
|
||||
break;
|
||||
case DAVListener.RESOURCE_MODIFIED:
|
||||
message = "Resource modified";
|
||||
break;
|
||||
}
|
||||
this.logger.debug(message + ": \"" + resource.getRelativePath() + "\"");
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* CONTEXT METHODS */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Retrieve the key in the {@link ServletContext} where the instance of
|
||||
* the {@link DAVRepository} associated with a named {@link DAVServlet}
|
||||
* can be found.</p>
|
||||
*
|
||||
* @param servletName the name of the {@link DAVServlet} as specified in
|
||||
* the <code>web.xml</code> deployment descriptor.</p>
|
||||
*/
|
||||
public static String getRepositoryKey(String servletName) {
|
||||
if (servletName == null) throw new NullPointerException();
|
||||
return DAVRepository.class.getName() + "." + servletName;
|
||||
}
|
||||
|
||||
/** factory for subclasses configured in web.xml
|
||||
* @param repositoryClass must extend DAVRepository and have a public constructor(File).
|
||||
* */
|
||||
static DAVRepository newRepository(String repositoryClass, File root)
|
||||
throws ServletException
|
||||
{
|
||||
try {
|
||||
Class c = Class.forName(repositoryClass);
|
||||
Constructor ctor = c.getConstructor(new Class[]{File.class});
|
||||
DAVRepository repo = (DAVRepository)ctor.newInstance(new Object[]{root});
|
||||
return repo;
|
||||
} catch(ClassNotFoundException e) {
|
||||
throw new ServletException(e);
|
||||
} catch(LinkageError le) {
|
||||
throw new ServletException(le);
|
||||
} catch(NoSuchMethodException ns) {
|
||||
throw new ServletException(ns);
|
||||
} catch(InvocationTargetException it) {
|
||||
throw new ServletException(it);
|
||||
} catch(IllegalAccessException ia) {
|
||||
throw new ServletException(ia);
|
||||
} catch(InstantiationException ie) {
|
||||
throw new ServletException(ie);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A simple wrapper isolating the Java Servlet API from this
|
||||
* <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVTransaction {
|
||||
|
||||
/**
|
||||
* <p>The identifyication of the <code>infinity</code> value
|
||||
* in the <code>Depth</code> header.</p>
|
||||
*/
|
||||
public static final int INFINITY = Integer.MAX_VALUE;
|
||||
|
||||
/** <p>The nested {@link HttpServletRequest}.</p> */
|
||||
private HttpServletRequest request = null;
|
||||
/** <p>The nested {@link HttpServletResponse}.</p> */
|
||||
private HttpServletResponse response = null;
|
||||
/** <p>The {@link URI} associated with the base of the repository.</p> */
|
||||
private URI base = null;
|
||||
/** <p>The status for the HTTP response.</p> */
|
||||
private int status = -1;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Constructors */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVTransaction} instance.</p>
|
||||
*/
|
||||
public DAVTransaction(ServletRequest request, ServletResponse response)
|
||||
throws ServletException {
|
||||
if (request == null) throw new NullPointerException("Null request");
|
||||
if (response == null) throw new NullPointerException("Null response");
|
||||
this.request = (HttpServletRequest) request;
|
||||
this.response = (HttpServletResponse) response;
|
||||
this.response.setHeader("DAV", "1");
|
||||
this.response.setHeader("MS-Author-Via", "DAV");
|
||||
|
||||
try {
|
||||
String scheme = this.request.getScheme();
|
||||
String host = this.request.getServerName();
|
||||
String path = this.request.getContextPath() +
|
||||
this.request.getServletPath();
|
||||
int port = this.request.getServerPort();
|
||||
if (! path.endsWith("/")) path += "/";
|
||||
this.base = new URI(scheme, null, host, port, path, null, null);
|
||||
this.base = this.base.normalize();
|
||||
} catch (URISyntaxException exception) {
|
||||
throw new ServletException("Unable to create base URI", exception);
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Request methods */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Return the path originally requested by the client.</p>
|
||||
*/
|
||||
public String getMethod() {
|
||||
return this.request.getMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the path originally requested by the client.</p>
|
||||
*/
|
||||
public String getOriginalPath() {
|
||||
String path = this.request.getPathInfo();
|
||||
if (path == null) return "";
|
||||
if ((path.length() > 1) && (path.charAt(0) == '/')) {
|
||||
return path.substring(1);
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the path originally requested by the client.</p>
|
||||
*/
|
||||
public String getNormalizedPath() {
|
||||
final String path = this.getOriginalPath();
|
||||
if (! path.endsWith("/")) return path;
|
||||
return path.substring(0, path.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the depth requested by the client for this transaction.</p>
|
||||
*/
|
||||
public int getDepth() {
|
||||
String depth = request.getHeader("Depth");
|
||||
if (depth == null) return INFINITY;
|
||||
if ("infinity".equalsIgnoreCase(depth)) return INFINITY;
|
||||
try {
|
||||
return Integer.parseInt(depth);
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new DAVException(412, "Unable to parse depth", exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a {@link URI}
|
||||
*/
|
||||
public URI getDestination() {
|
||||
String destination = this.request.getHeader("Destination");
|
||||
if (destination != null) try {
|
||||
return this.base.relativize(new URI(destination));
|
||||
} catch (URISyntaxException exception) {
|
||||
throw new DAVException(412, "Can't parse destination", exception);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the overwrite flag requested by the client for this
|
||||
* transaction.</p>
|
||||
*/
|
||||
public boolean getOverwrite() {
|
||||
String overwrite = request.getHeader("Overwrite");
|
||||
if (overwrite == null) return true;
|
||||
if ("T".equals(overwrite)) return true;
|
||||
if ("F".equals(overwrite)) return false;
|
||||
throw new DAVException(412, "Unable to parse overwrite flag");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Check if the client requested a date-based conditional operation.</p>
|
||||
*/
|
||||
public Date getIfModifiedSince() {
|
||||
String name = "If-Modified-Since";
|
||||
if (this.request.getHeader(name) == null) return null;
|
||||
return new Date(this.request.getDateHeader(name));
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Response methods */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Set the HTTP status code of the response.</p>
|
||||
*/
|
||||
public void setStatus(int status) {
|
||||
this.response.setStatus(status);
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the HTTP status code of the response.</p>
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the HTTP <code>Content-Type</code> header.</p>
|
||||
*/
|
||||
public void setContentType(String type) {
|
||||
this.response.setContentType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set an HTTP header in the response.</p>
|
||||
*/
|
||||
public void setHeader(String name, String value) {
|
||||
this.response.setHeader(name, value);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* I/O methods */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Check if there is a body in the request.</p>
|
||||
*
|
||||
* <p>This method differs from checking if the return value of the
|
||||
* {@link #read()} method is not <b>null</b> as a request body of length
|
||||
* zero will return <b>false</b> in this case, while in the {@link #read()}
|
||||
* method will return an empty {@link InputStream}.</p>
|
||||
*/
|
||||
public boolean hasRequestBody()
|
||||
throws IOException {
|
||||
/* We don't support ranges */
|
||||
if (request.getHeader("Content-Range") != null)
|
||||
throw new DAVException(501, "Content-Range not supported");
|
||||
|
||||
if (this.request.getContentLength() > 0) return true;
|
||||
String len = this.request.getHeader("Content-Length");
|
||||
if (len != null) try {
|
||||
return (Long.parseLong(len) > 0);
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new DAVException(411, "Invalid Content-Length specified");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Read from the body of the original request.</p>
|
||||
*/
|
||||
public InputStream read()
|
||||
throws IOException {
|
||||
/* We don't support ranges */
|
||||
if (request.getHeader("Content-Range") != null)
|
||||
throw new DAVException(501, "Content-Range not supported");
|
||||
|
||||
if (this.request.getContentLength() >= 0) {
|
||||
return this.request.getInputStream();
|
||||
}
|
||||
|
||||
String len = this.request.getHeader("Content-Length");
|
||||
if (len != null) try {
|
||||
if (Long.parseLong(len) >= 0) return this.request.getInputStream();
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new DAVException(411, "Invalid Content-Length specified");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write the body of the response.</p>
|
||||
*/
|
||||
public OutputStream write()
|
||||
throws IOException {
|
||||
return this.response.getOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Write the body of the response.</p>
|
||||
*/
|
||||
public PrintWriter write(String encoding)
|
||||
throws IOException {
|
||||
return new PrintWriter(new OutputStreamWriter(this.write(), encoding));
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Lookup methods */
|
||||
/* ====================================================================== */
|
||||
|
||||
/**
|
||||
* <p>Look up the final URI of a {@link DAVResource} as visible from the
|
||||
* HTTP client requesting this transaction.</p>
|
||||
*/
|
||||
public URI lookup(DAVResource resource) {
|
||||
URI uri = resource.getRelativeURI();
|
||||
return this.base.resolve(uri).normalize();
|
||||
}
|
||||
}
|
|
@ -1,420 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A collection of static utilities.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public final class DAVUtilities {
|
||||
|
||||
/** <p>A {@link HashMap} of configured mime types.</p> */
|
||||
private static Map MIME_TYPES = new HashMap();
|
||||
/** <p>A {@link HashMap} of configured mime types.</p> */
|
||||
private static Properties PROPERTIES = new Properties();
|
||||
/** <p>The {@link SimpleDateFormat} RFC-822 date format.</p> */
|
||||
private static final String FORMAT_822 = "EEE, dd MMM yyyy HH:mm:ss 'GMT'";
|
||||
/** <p>The {@link SimpleDateFormat} RFC-822 date format.</p> */
|
||||
private static final String FORMAT_ISO = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
||||
/** <p>The {@link TimeZone} to use for dates.</p> */
|
||||
private static final TimeZone TIMEZONE = TimeZone.getTimeZone("GMT");
|
||||
/** <p>The {@link Locale} to use for dates.</p> */
|
||||
private static final Locale LOCALE = Locale.US;
|
||||
|
||||
/**
|
||||
* <p>Load the mime types map from a resource.</p>
|
||||
*/
|
||||
static {
|
||||
Class clazz = DAVUtilities.class;
|
||||
ClassLoader loader = clazz.getClassLoader();
|
||||
|
||||
/* Load up the properties file */
|
||||
String webdavPropResource = "plexus-webdav/webdav.props";
|
||||
InputStream prop = loader.getResourceAsStream(webdavPropResource);
|
||||
if (prop != null) try {
|
||||
DAVUtilities.PROPERTIES.load(prop);
|
||||
prop.close();
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
} else {
|
||||
System.err.println("Invalid resource: " + webdavPropResource);
|
||||
}
|
||||
|
||||
/* Load up the mime types table */
|
||||
String mimeTypeResource = "plexus-webdav/mime.types";
|
||||
InputStream mime = loader.getResourceAsStream(mimeTypeResource);
|
||||
if (mime != null) try {
|
||||
InputStreamReader read = new InputStreamReader(mime);
|
||||
BufferedReader buff = new BufferedReader(read);
|
||||
String line = null;
|
||||
while ((line = buff.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.length() == 0) continue;
|
||||
if (line.charAt(0) == '#') continue;
|
||||
StringTokenizer tokenizer = new StringTokenizer(line);
|
||||
if (tokenizer.countTokens() > 1) {
|
||||
String type = tokenizer.nextToken();
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String extension = '.' + tokenizer.nextToken();
|
||||
DAVUtilities.MIME_TYPES.put(extension, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
buff.close();
|
||||
read.close();
|
||||
mime.close();
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
} else {
|
||||
System.err.println("Invalid resource: " + mimeTypeResource);
|
||||
}
|
||||
}
|
||||
|
||||
/** <p>The signature of this package usable from a servlet.</p> */
|
||||
public static final String SERVLET_SIGNATURE =
|
||||
DAVUtilities.getProperty("servlet.signature") + '/' +
|
||||
DAVUtilities.getProperty("version");
|
||||
|
||||
/** <p>The information detail of this package usable from a servlet.</p> */
|
||||
public static final String SERVLET_INFORMATION =
|
||||
DAVUtilities.getProperty("servlet.information") + " version " +
|
||||
DAVUtilities.getProperty("version");
|
||||
|
||||
/**
|
||||
* <p>Deny public construction of {@link DAVUtilities} instances.</p>
|
||||
*/
|
||||
private DAVUtilities() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the value of a property configured for this package.</p>
|
||||
*
|
||||
* @param name the property name
|
||||
* @return a {@link String} instance or <b>null</b> if unknown.
|
||||
*/
|
||||
public static String getProperty(String name) {
|
||||
if (name == null) return null;
|
||||
return DAVUtilities.PROPERTIES.getProperty(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the MIME Type configured for a given resource.</p>
|
||||
*
|
||||
* @param name the resource name whose MIME Type needs to be looked up.
|
||||
* @return a {@link String} instance or <b>null</b> if the type is unknown.
|
||||
*/
|
||||
public static String getMimeType(String name) {
|
||||
if (name == null) return null;
|
||||
|
||||
Iterator iterator = DAVUtilities.MIME_TYPES.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String extension = (String) iterator.next();
|
||||
if (name.endsWith(extension)) {
|
||||
return (String) DAVUtilities.MIME_TYPES.get(extension);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a {@link String} message given an HTTP status code.</p>
|
||||
*/
|
||||
public static String getStatusMessage(int status) {
|
||||
switch (status) {
|
||||
/* HTTP/1.1 RFC-2616 */
|
||||
case 100: return "100 Continue";
|
||||
case 101: return "101 Switching Protocols";
|
||||
case 200: return "200 OK";
|
||||
case 201: return "201 Created";
|
||||
case 202: return "202 Accepted";
|
||||
case 203: return "203 Non-Authoritative Information";
|
||||
case 204: return "204 No Content";
|
||||
case 205: return "205 Reset Content";
|
||||
case 206: return "206 Partial Content";
|
||||
case 300: return "300 Multiple Choices";
|
||||
case 301: return "301 Moved Permanently";
|
||||
case 302: return "302 Found";
|
||||
case 303: return "303 See Other";
|
||||
case 304: return "304 Not Modified";
|
||||
case 305: return "305 Use Proxy";
|
||||
case 306: return "306 (Unused)";
|
||||
case 307: return "307 Temporary Redirect";
|
||||
case 400: return "400 Bad Request";
|
||||
case 401: return "401 Unauthorized";
|
||||
case 402: return "402 Payment Required";
|
||||
case 403: return "403 Forbidden";
|
||||
case 404: return "404 Not Found";
|
||||
case 405: return "405 Method Not Allowed";
|
||||
case 406: return "406 Not Acceptable";
|
||||
case 407: return "407 Proxy Authentication Required";
|
||||
case 408: return "408 Request Timeout";
|
||||
case 409: return "409 Conflict";
|
||||
case 410: return "410 Gone";
|
||||
case 411: return "411 Length Required";
|
||||
case 412: return "412 Precondition Failed";
|
||||
case 413: return "413 Request Entity Too Large";
|
||||
case 414: return "414 Request-URI Too Long";
|
||||
case 415: return "415 Unsupported Media Type";
|
||||
case 416: return "416 Requested Range Not Satisfiable";
|
||||
case 417: return "417 Expectation Failed";
|
||||
case 500: return "500 Internal Server Error";
|
||||
case 501: return "501 Not Implemented";
|
||||
case 502: return "502 Bad Gateway";
|
||||
case 503: return "503 Service Unavailable";
|
||||
case 504: return "504 Gateway Timeout";
|
||||
case 505: return "505 HTTP Version Not Supported";
|
||||
|
||||
/* DAV/1.0 RFC-2518 */
|
||||
case 102: return "102 Processing";
|
||||
case 207: return "207 Multi-Status";
|
||||
case 422: return "422 Unprocessable Entity";
|
||||
case 423: return "423 Locked";
|
||||
case 424: return "424 Failed Dependency";
|
||||
case 507: return "507 Insufficient Storage";
|
||||
|
||||
/* Unknown */
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Format a {@link Number} into a {@link String} making sure that
|
||||
* {@link NullPointerException}s are not thrown.</p>
|
||||
*
|
||||
* @param number the {@link Number} to format.
|
||||
* @return a {@link String} instance or <b>null</b> if the object was null.
|
||||
*/
|
||||
public static String formatNumber(Number number) {
|
||||
if (number == null) return null;
|
||||
return (number.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse a {@link String} into a {@link Long}.</p>
|
||||
*
|
||||
* @param string the {@link String} to parse.
|
||||
* @return a {@link Long} instance or <b>null</b> if the date was null or
|
||||
* if there was an error parsing the specified {@link String}.
|
||||
*/
|
||||
public static Long parseNumber(String string) {
|
||||
if (string == null) return null;
|
||||
try {
|
||||
return new Long(string);
|
||||
} catch (NumberFormatException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Format a {@link Date} according to the HTTP/1.1 RFC.</p>
|
||||
*
|
||||
* @param date the {@link Date} to format.
|
||||
* @return a {@link String} instance or <b>null</b> if the date was null.
|
||||
*/
|
||||
public static String formatHttpDate(Date date) {
|
||||
if (date == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_822, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
return formatter.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Format a {@link Date} according to the ISO 8601 specification.</p>
|
||||
*
|
||||
* @param date the {@link Date} to format.
|
||||
* @return a {@link String} instance or <b>null</b> if the date was null.
|
||||
*/
|
||||
public static String formatIsoDate(Date date) {
|
||||
if (date == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_ISO, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
return formatter.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse a {@link String} into a {@link Date} according to the
|
||||
* HTTP/1.1 RFC (<code>Mon, 31 Jan 2000 11:59:00 GMT</code>).</p>
|
||||
*
|
||||
* @param string the {@link String} to parse.
|
||||
* @return a {@link Date} instance or <b>null</b> if the date was null or
|
||||
* if there was an error parsing the specified {@link String}.
|
||||
*/
|
||||
public static Date parseHttpDate(String string) {
|
||||
if (string == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_822, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
try {
|
||||
return formatter.parse(string);
|
||||
} catch (ParseException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse a {@link String} into a {@link Date} according to the ISO 8601
|
||||
* specification (<code>2000-12-31T11:59:00Z</code>).</p>
|
||||
*
|
||||
* @param string the {@link String} to parse.
|
||||
* @return a {@link Date} instance or <b>null</b> if the date was null or
|
||||
* if there was an error parsing the specified {@link String}.
|
||||
*/
|
||||
public static Date parseIsoDate(String string) {
|
||||
if (string == null) return null;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_ISO, LOCALE);
|
||||
formatter.setTimeZone(TIMEZONE);
|
||||
try {
|
||||
return formatter.parse(string);
|
||||
} catch (ParseException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the HEX representation of an array of bytes.</p>
|
||||
*
|
||||
* @param buffer the array of bytes to convert in a HEX {@link String}.
|
||||
* @return a <b>non-null</b> {@link String} instance.
|
||||
*/
|
||||
public static String toHexString(byte buffer[]) {
|
||||
char output[] = new char[buffer.length * 2];
|
||||
int position = 0;
|
||||
for (int x = 0; x < buffer.length; x++) {
|
||||
output[position ++] = DAVUtilities.toHexDigit(buffer[x] >> 4);
|
||||
output[position ++] = DAVUtilities.toHexDigit(buffer[x]);
|
||||
}
|
||||
return new String(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the HEX representation of a long integer.</p>
|
||||
*
|
||||
* @param number the long to convert in a HEX {@link String}.
|
||||
* @return a <b>non-null</b> 16-characters {@link String} instance.
|
||||
*/
|
||||
public static String toHexString(long number) {
|
||||
char output[] = new char[16];
|
||||
output[0] = DAVUtilities.toHexDigit((int)(number >> 60));
|
||||
output[1] = DAVUtilities.toHexDigit((int)(number >> 56));
|
||||
output[2] = DAVUtilities.toHexDigit((int)(number >> 52));
|
||||
output[3] = DAVUtilities.toHexDigit((int)(number >> 48));
|
||||
output[4] = DAVUtilities.toHexDigit((int)(number >> 44));
|
||||
output[5] = DAVUtilities.toHexDigit((int)(number >> 40));
|
||||
output[6] = DAVUtilities.toHexDigit((int)(number >> 36));
|
||||
output[7] = DAVUtilities.toHexDigit((int)(number >> 32));
|
||||
output[8] = DAVUtilities.toHexDigit((int)(number >> 28));
|
||||
output[9] = DAVUtilities.toHexDigit((int)(number >> 24));
|
||||
output[10] = DAVUtilities.toHexDigit((int)(number >> 20));
|
||||
output[11] = DAVUtilities.toHexDigit((int)(number >> 16));
|
||||
output[12] = DAVUtilities.toHexDigit((int)(number >> 12));
|
||||
output[13] = DAVUtilities.toHexDigit((int)(number >> 8));
|
||||
output[14] = DAVUtilities.toHexDigit((int)(number >> 4));
|
||||
output[15] = DAVUtilities.toHexDigit((int)(number));
|
||||
return new String(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the HEX representation of an integer.</p>
|
||||
*
|
||||
* @param number the int to convert in a HEX {@link String}.
|
||||
* @return a <b>non-null</b> 8-characters {@link String} instance.
|
||||
*/
|
||||
public static String toHexString(int number) {
|
||||
char output[] = new char[8];
|
||||
output[0] = DAVUtilities.toHexDigit((int)(number >> 28));
|
||||
output[1] = DAVUtilities.toHexDigit((int)(number >> 24));
|
||||
output[2] = DAVUtilities.toHexDigit((int)(number >> 20));
|
||||
output[3] = DAVUtilities.toHexDigit((int)(number >> 16));
|
||||
output[4] = DAVUtilities.toHexDigit((int)(number >> 12));
|
||||
output[5] = DAVUtilities.toHexDigit((int)(number >> 8));
|
||||
output[6] = DAVUtilities.toHexDigit((int)(number >> 4));
|
||||
output[7] = DAVUtilities.toHexDigit((int)(number));
|
||||
return new String(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the HEX representation of a char.</p>
|
||||
*
|
||||
* @param number the char to convert in a HEX {@link String}.
|
||||
* @return a <b>non-null</b> 4-characters {@link String} instance.
|
||||
*/
|
||||
public static String toHexString(char number) {
|
||||
char output[] = new char[4];
|
||||
output[0] = DAVUtilities.toHexDigit((int)(number >> 12));
|
||||
output[1] = DAVUtilities.toHexDigit((int)(number >> 8));
|
||||
output[2] = DAVUtilities.toHexDigit((int)(number >> 4));
|
||||
output[3] = DAVUtilities.toHexDigit((int)(number));
|
||||
return new String(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the HEX representation of a byte.</p>
|
||||
*
|
||||
* @param number the byte to convert in a HEX {@link String}.
|
||||
* @return a <b>non-null</b> 2-characters {@link String} instance.
|
||||
*/
|
||||
public static String toHexString(byte number) {
|
||||
char output[] = new char[2];
|
||||
output[0] = DAVUtilities.toHexDigit((int)(number >> 4));
|
||||
output[1] = DAVUtilities.toHexDigit((int)(number));
|
||||
return new String(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the single digit character representing the HEX encoding of
|
||||
* the lower four bits of a given integer.</p>
|
||||
*/
|
||||
private static char toHexDigit(int number) {
|
||||
switch (number & 0x0F) {
|
||||
case 0x00: return '0';
|
||||
case 0x01: return '1';
|
||||
case 0x02: return '2';
|
||||
case 0x03: return '3';
|
||||
case 0x04: return '4';
|
||||
case 0x05: return '5';
|
||||
case 0x06: return '6';
|
||||
case 0x07: return '7';
|
||||
case 0x08: return '8';
|
||||
case 0x09: return '9';
|
||||
case 0x0A: return 'A';
|
||||
case 0x0B: return 'B';
|
||||
case 0x0C: return 'C';
|
||||
case 0x0D: return 'D';
|
||||
case 0x0E: return 'E';
|
||||
case 0x0F: return 'F';
|
||||
}
|
||||
String message = "Invalid HEX digit " + Integer.toHexString(number);
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* <p>A {@link DAVRepository} instance enforcing all {@link DAVResource}s to
|
||||
* be XML files.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class XMLRepository extends DAVRepository {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link XMLRepository} instance.</p>
|
||||
*/
|
||||
public XMLRepository(File root)
|
||||
throws IOException {
|
||||
super(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link DAVResource} associated with a {@link URI}.</p>
|
||||
*/
|
||||
public DAVResource getResource(URI uri)
|
||||
throws IOException {
|
||||
return new XMLResource(this, super.getResource(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A simple {@link DAVResource} extension enforcing XML writes.</p>
|
||||
*/
|
||||
private static final class XMLResource extends DAVResource {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link XMLResource} instance.</p>
|
||||
*/
|
||||
public XMLResource(XMLRepository repository, DAVResource resource) {
|
||||
super(repository, resource.getFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Override the MIME Content-Type to <code>text/xml</code> for
|
||||
* normal resources.</p>
|
||||
*/
|
||||
public String getContentType() {
|
||||
if (this.isResource()) return "text/xml";
|
||||
return super.getContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a {@link DAVOutputStream} enforcing XML formatted data.</p>
|
||||
*/
|
||||
public DAVOutputStream write() {
|
||||
return new XMLOutputStream(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A simple {@link DAVOutputStream} enforcing XML formatted data.</p>
|
||||
*/
|
||||
private static final class XMLOutputStream extends DAVOutputStream {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link XMLOutputStream} instance.</p>
|
||||
*/
|
||||
protected XMLOutputStream(XMLResource resource) {
|
||||
super(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Ensure that whatever is in the temporary file is XML.</p>
|
||||
*/
|
||||
protected void rename(File temporary, File original)
|
||||
throws IOException {
|
||||
try {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(false);
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
parser.parse(temporary, new DefaultHandler());
|
||||
super.rename(temporary, original);
|
||||
} catch (ParserConfigurationException exception) {
|
||||
throw new DAVException(500, "JAXP parser error", exception);
|
||||
} catch (SAXException exception) {
|
||||
throw new DAVException(415, "Error parsing data", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVMultiStatus;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>COPY</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class COPY implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link COPY} instance.</p>
|
||||
*/
|
||||
public COPY() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>COPY</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
|
||||
URI target = transaction.getDestination();
|
||||
if (target == null) throw new DAVException(412, "No destination");
|
||||
DAVResource dest = resource.getRepository().getResource(target);
|
||||
|
||||
int depth = transaction.getDepth();
|
||||
boolean recursive = false;
|
||||
if (depth == 0) {
|
||||
recursive = false;
|
||||
} else if (depth == DAVTransaction.INFINITY) {
|
||||
recursive = true;
|
||||
} else {
|
||||
throw new DAVException(412, "Invalid Depth specified");
|
||||
}
|
||||
|
||||
try {
|
||||
resource.copy(dest, transaction.getOverwrite(), recursive);
|
||||
transaction.setStatus(transaction.getOverwrite() ? 204 : 201);
|
||||
} catch (DAVMultiStatus multistatus) {
|
||||
multistatus.write(transaction);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVMultiStatus;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>DELETE</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DELETE implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DELETE} instance.</p>
|
||||
*/
|
||||
public DELETE() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>DELETE</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
try {
|
||||
resource.delete();
|
||||
transaction.setStatus(204);
|
||||
} catch (DAVMultiStatus multistatus) {
|
||||
multistatus.write(transaction);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVInputStream;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a>
|
||||
* <code>GET</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class GET extends HEAD {
|
||||
|
||||
/** <p>The encoding charset to repsesent collections.</p> */
|
||||
public static final String ENCODING = "UTF-8";
|
||||
|
||||
/** <p>The mime type that {@link GET} will use serving collections.</p> */
|
||||
public static final String COLLECTION_MIME_TYPE = "text/html ;charset=\""
|
||||
+ ENCODING + "\"";
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link GET} instance.</p>
|
||||
*/
|
||||
public GET() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>GET</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
super.process(transaction, resource);
|
||||
|
||||
final String originalPath = transaction.getOriginalPath();
|
||||
final String normalizedPath = transaction.getNormalizedPath();
|
||||
final String current;
|
||||
final String parent;
|
||||
if (originalPath.equals(normalizedPath)) {
|
||||
final String relativePath = resource.getRelativePath();
|
||||
if (relativePath.equals("")) {
|
||||
current = transaction.lookup(resource).toASCIIString();
|
||||
} else {
|
||||
current = relativePath;
|
||||
}
|
||||
parent = "./";
|
||||
} else {
|
||||
current = "./";
|
||||
parent = "../";
|
||||
}
|
||||
|
||||
if (resource.isCollection()) {
|
||||
transaction.setHeader( "Content-Disposition", "inline; filename=\"index.html\"");
|
||||
PrintWriter out = transaction.write(ENCODING);
|
||||
String path = resource.getRelativePath();
|
||||
out.println("<html>");
|
||||
out.println("<head>");
|
||||
out.println("<title>Collection: /" + path + "</title>");
|
||||
out.println("</head>");
|
||||
out.println("<body>");
|
||||
out.println("<h2>Collection: /" + path + "</h2>");
|
||||
out.println("<ul>");
|
||||
|
||||
/* Process the parent */
|
||||
final DAVResource parentResource = resource.getParent();
|
||||
if (parentResource != null) {
|
||||
out.print("<li><a href=\"");
|
||||
out.print(parent);
|
||||
out.print("\">");
|
||||
out.print(parentResource.getDisplayName());
|
||||
out.println("</a> <i><small>(Parent)</small></i></li>");
|
||||
out.println("</ul>");
|
||||
out.println("<ul>");
|
||||
}
|
||||
|
||||
/* Process the children (in two sorted sets, for nice ordering) */
|
||||
Set resources = new TreeSet();
|
||||
Set collections = new TreeSet();
|
||||
Iterator iterator = resource.getChildren();
|
||||
while (iterator.hasNext()) {
|
||||
final DAVResource child = (DAVResource) iterator.next();
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
final String childPath = child.getDisplayName();
|
||||
buffer.append("<li><a href=\"");
|
||||
buffer.append(current);
|
||||
buffer.append(childPath);
|
||||
buffer.append("\">");
|
||||
buffer.append(childPath);
|
||||
buffer.append("</li>");
|
||||
if (child.isCollection()) {
|
||||
collections.add(buffer.toString());
|
||||
} else {
|
||||
resources.add(buffer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/* Spit out the collections first and the resources then */
|
||||
for (Iterator i = collections.iterator(); i.hasNext(); )
|
||||
out.println(i.next());
|
||||
for (Iterator i = resources.iterator(); i.hasNext(); )
|
||||
out.println(i.next());
|
||||
|
||||
out.println("</ul>");
|
||||
out.println("</body>");
|
||||
out.println("</html>");
|
||||
out.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Processing a normal resource request */
|
||||
OutputStream out = transaction.write();
|
||||
DAVInputStream in = resource.read();
|
||||
byte buffer[] = new byte[4096];
|
||||
int k = -1;
|
||||
while ((k = in.read(buffer)) != -1) out.write(buffer, 0, k);
|
||||
in.close();
|
||||
out.flush();
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVNotModified;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
import it.could.webdav.DAVUtilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a>
|
||||
* <code>HEAD</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class HEAD implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link HEAD} instance.</p>
|
||||
*/
|
||||
public HEAD() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>HEAD</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
/* Check if we have to force a resource not found or a redirection */
|
||||
if (resource.isNull())
|
||||
throw new DAVException(404, "Not found", resource);
|
||||
|
||||
/* Check if this is a conditional (processable only for resources) */
|
||||
Date ifmod = transaction.getIfModifiedSince();
|
||||
Date lsmod = resource.getLastModified();
|
||||
if (resource.isResource() && (ifmod != null) && (lsmod != null)) {
|
||||
/* HTTP doesn't send milliseconds, but Java does, so, reset them */
|
||||
lsmod = new Date(((long)(lsmod.getTime() / 1000)) * 1000);
|
||||
if (!ifmod.before(lsmod)) throw new DAVNotModified(resource);
|
||||
}
|
||||
|
||||
/* Get the headers of this method */
|
||||
String ctyp = resource.getContentType();
|
||||
String etag = resource.getEntityTag();
|
||||
String lmod = DAVUtilities.formatHttpDate(resource.getLastModified());
|
||||
String clen = DAVUtilities.formatNumber(resource.getContentLength());
|
||||
|
||||
/* Set the normal headers that are required for a GET */
|
||||
if (resource.isCollection()) {
|
||||
transaction.setContentType(GET.COLLECTION_MIME_TYPE);
|
||||
} else if (ctyp != null) {
|
||||
transaction.setContentType(ctyp);
|
||||
}
|
||||
if (etag != null) transaction.setHeader("ETag", etag);
|
||||
if (lmod != null) transaction.setHeader("Last-Modified", lmod);
|
||||
if (clen != null) transaction.setHeader("Content-Length", clen);
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>MKCOL</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class MKCOL implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link MKCOL} instance.</p>
|
||||
*/
|
||||
public MKCOL() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>MKCOL</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
|
||||
/* Unsupported media type, we don't want content */
|
||||
if (transaction.hasRequestBody()) {
|
||||
throw new DAVException (415, "No request body allowed in request");
|
||||
}
|
||||
|
||||
/* Create the collection */
|
||||
resource.makeCollection();
|
||||
transaction.setStatus(201);
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVMultiStatus;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>MOVE</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class MOVE implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link MOVE} instance.</p>
|
||||
*/
|
||||
public MOVE() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>MOVE</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
URI target = transaction.getDestination();
|
||||
if (target == null) throw new DAVException(412, "No destination");
|
||||
DAVResource dest = resource.getRepository().getResource(target);
|
||||
|
||||
int depth = transaction.getDepth();
|
||||
boolean recursive = false;
|
||||
if (depth == 0) {
|
||||
recursive = false;
|
||||
} else if (depth == DAVTransaction.INFINITY) {
|
||||
recursive = true;
|
||||
} else {
|
||||
throw new DAVException(412, "Invalid Depth specified");
|
||||
}
|
||||
|
||||
try {
|
||||
int status;
|
||||
if(! dest.isNull() && ! transaction.getOverwrite()) {
|
||||
status = 412; // MOVE-on-existing should fail with 412
|
||||
} else {
|
||||
resource.move(dest, transaction.getOverwrite(), recursive);
|
||||
if(transaction.getOverwrite()) {
|
||||
status = 204; // No Content
|
||||
} else {
|
||||
status = 201; // Created
|
||||
}
|
||||
}
|
||||
transaction.setStatus(status);
|
||||
} catch (DAVMultiStatus multistatus) {
|
||||
multistatus.write(transaction);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVProcessor;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a>
|
||||
* <code>OPTIONS</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class OPTIONS implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link OPTIONS} instance.</p>
|
||||
*/
|
||||
public OPTIONS() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>OPTIONS</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
transaction.setHeader("Content-Type", resource.getContentType());
|
||||
transaction.setHeader("Allow", DAVProcessor.METHODS);
|
||||
transaction.setStatus(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
import it.could.webdav.DAVUtilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>PROPFIND</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class PROPFIND implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link PROPFIND} instance.</p>
|
||||
*/
|
||||
public PROPFIND() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>PROPFIND</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
/* Check if we have to force a resource not found or a redirection */
|
||||
if (resource.isNull())
|
||||
throw new DAVException(404, "Not found", resource);
|
||||
|
||||
/* Check depth */
|
||||
int depth = transaction.getDepth();
|
||||
if (depth > 1) new DAVException(403, "Invalid depth");
|
||||
|
||||
/* What to do on a collection resource */
|
||||
transaction.setStatus(207);
|
||||
transaction.setContentType("text/xml; charset=\"UTF-8\"");
|
||||
PrintWriter out = transaction.write("UTF-8");
|
||||
|
||||
/* Output the XML declaration and the root document tag */
|
||||
out.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
out.println("<D:multistatus xmlns:D=\"DAV:\">");
|
||||
|
||||
/* Process this resource's property (always) */
|
||||
this.process(transaction, out, resource);
|
||||
|
||||
/* Process this resource's children (if required) */
|
||||
if (resource.isCollection() && (depth > 0)) {
|
||||
Iterator children = resource.getChildren();
|
||||
while (children.hasNext()) {
|
||||
DAVResource child = (DAVResource) children.next();
|
||||
this.process(transaction, out, child);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close up the XML Multi-Status response */
|
||||
out.println("</D:multistatus>");
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private void process(DAVTransaction txn, PrintWriter out, DAVResource res) {
|
||||
/* The href of the resource is only the absolute path */
|
||||
out.println(" <D:response>");
|
||||
out.println(" <D:href>" + txn.lookup(res).getPath() + "</D:href>");
|
||||
out.println(" <D:propstat>");
|
||||
out.println(" <D:prop>");
|
||||
|
||||
/* Figure out what we're dealing with here */
|
||||
if (res.isCollection()) {
|
||||
this.process(out, "resourcetype", "<D:collection/>");
|
||||
}
|
||||
this.process(out, "getcontenttype", res.getContentType());
|
||||
|
||||
this.process(out, "getetag", res.getEntityTag());
|
||||
String date = DAVUtilities.formatIsoDate(res.getCreationDate());
|
||||
this.process(out, "creationdate", date);
|
||||
String lmod = DAVUtilities.formatHttpDate(res.getLastModified());
|
||||
this.process(out, "getlastmodified", lmod);
|
||||
String clen = DAVUtilities.formatNumber(res.getContentLength());
|
||||
this.process(out, "getcontentlength", clen);
|
||||
|
||||
out.println(" </D:prop>");
|
||||
out.println(" <D:status>HTTP/1.1 200 OK</D:status>");
|
||||
out.println(" </D:propstat>");
|
||||
out.println(" </D:response>");
|
||||
}
|
||||
|
||||
private void process(PrintWriter out, String name, String value) {
|
||||
if (value == null) return;
|
||||
out.print(" <D:");
|
||||
out.print(name);
|
||||
out.print(">");
|
||||
out.print(value);
|
||||
out.print("</D:");
|
||||
out.print(name);
|
||||
out.println(">");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>PROPPATCH</code> metohd implementation.</p>
|
||||
*
|
||||
* <p>As this servlet does not handle the creation of custom properties, this
|
||||
* method will always fail with a <code>403</code> (Forbidden).</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class PROPPATCH implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link PROPPATCH} instance.</p>
|
||||
*/
|
||||
public PROPPATCH() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>PROPPATCH</code> method.</p>
|
||||
*
|
||||
* <p>As this servlet does not handle the creation of custom properties,
|
||||
* this method will always fail with a <code>403</code> (Forbidden).</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
throw new DAVException(403, "All properties are immutable");
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.methods;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVOutputStream;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* <p><a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
* <code>PUT</code> metohd implementation.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class PUT implements DAVMethod {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link PUT} instance.</p>
|
||||
*/
|
||||
public PUT() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>PUT</code> method.</p>
|
||||
*/
|
||||
public void process(DAVTransaction transaction, DAVResource resource)
|
||||
throws IOException {
|
||||
/*
|
||||
* The HTTP status code will depend on the existance of the resource:
|
||||
* if not found: HTTP/1.1 201 Created
|
||||
* if existing: HTTP/1.1 204 No Content
|
||||
*/
|
||||
transaction.setStatus(resource.isNull()? 201: 204);
|
||||
|
||||
/* Open the streams for reading and writing */
|
||||
InputStream in = transaction.read();
|
||||
if (in == null) throw new DAVException(411, "Content-Length required");
|
||||
DAVOutputStream out = resource.write();
|
||||
|
||||
/* Write the content from the PUT to the specified resource */
|
||||
try {
|
||||
byte buffer[] = new byte[4096];
|
||||
int k = -1;
|
||||
while ((k = in.read(buffer)) != -1) out.write(buffer, 0, k);
|
||||
in.close();
|
||||
out.close();
|
||||
} finally {
|
||||
out.abort();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Could.IT WebDAV Servlet</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package contains the implementation of all Level 1
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
methods provided by this framework.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,134 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Could.IT WebDAV Servlet</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package contains a minimal
|
||||
<a href="http://java.sun.com/products/servlet/">Servlet</a>
|
||||
based implementation of the
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
specification.
|
||||
</p>
|
||||
<p>
|
||||
This implementation does not in any way try to replace or extend the
|
||||
<a href="http://jakarta.apache.org/slide/">Apache Slide</a>
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
implementation, but tries to provide a <i>very light</i> and <i>extremely
|
||||
minimal</i> alternative to be used in those scenarios where space is
|
||||
a constraint (the <code>.jar</code> file is less than 100 kylobites),
|
||||
and advanced features are not required.
|
||||
</p>
|
||||
<p>
|
||||
The most visible limitations of this approach is that this
|
||||
implementation does not offer any support for the <code>LOCK</code>
|
||||
method (it is therefore not <i>DAV Level 2</i> compliant), and that
|
||||
there limited support for properties:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
The <code>PROPFIND</code> will only return the <i>read-only</i>
|
||||
<code>getcontenttype</code>, <code>getlastmodified</code>,
|
||||
<code>getcontentlength</code>, <code>getetag</code> and
|
||||
<code>resourcetype</code> properties.
|
||||
</li>
|
||||
<li>
|
||||
The <code>PROPPATCH</code> will <i>always</i> fail with a
|
||||
<code>403</code> <i>Not Found</i> error.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Another important limitation is that this implementation will only and
|
||||
exclusively provide access to a {@link java.io.File} based backend.
|
||||
If you want to deploy your repository on another kind of backend (such
|
||||
as SQL databases) please look at the WebDAV implementation provided by
|
||||
<a href="http://jakarta.apache.org/slide/">Apache Slide</a>.
|
||||
</p>
|
||||
|
||||
<h2>Configuration</h2>
|
||||
<p>
|
||||
The main entry point of this implementation is defined in the
|
||||
{@link it.could.webdav.DAVServlet} class, which will handle all
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a> and
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a> requests
|
||||
for the URI path it is configured to handle.
|
||||
</p>
|
||||
<p>
|
||||
To operate properly the {@link it.could.webdav.DAVServlet} class
|
||||
must be configured in the web-application's <code>web.xml</code>
|
||||
deployment descriptor. The relevant parts of a snippet of an example
|
||||
configuration deployment descriptor might look like the following:
|
||||
</p>
|
||||
<pre>
|
||||
<servlet>
|
||||
<servlet-name>dav</servlet-name>
|
||||
<servlet-class>it.could.webdav.DAVServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>rootPath</param-name>
|
||||
<param-value>dav</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>xmlOnly</param-name>
|
||||
<param-value>false</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>debugEnabled</param-name>
|
||||
<param-value>false</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
...
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>dav</servlet-name>
|
||||
<url-pattern>/dav/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
</pre>
|
||||
<p>
|
||||
In this example the {@link it.could.webdav.DAVServlet} servlet
|
||||
is configured with all parameters its parameters:
|
||||
</p>
|
||||
<dl>
|
||||
<dt>rootPath</dt>
|
||||
<dd>
|
||||
<i>[required]</i> This parameter indicates the path of the root of the
|
||||
repository.<br />
|
||||
If the specified parameter represents a relative path, it will be
|
||||
treated as a {@link javax.servlet.ServletContext#getResource(String)
|
||||
ServletContext resource}.<br />
|
||||
Note that if you choose to distribute your web application in a
|
||||
<code>.war</code> archive, your container will have to expand it
|
||||
before intializing the {@link javax.servlet.ServletContext} as this
|
||||
this implementation <i>requires</i> a {@link java.io.File} based
|
||||
repository.
|
||||
</dd>
|
||||
<dt>xmlOnly</dt>
|
||||
<dd>
|
||||
<i>[optional, default="<code>false</code>"]</i> This parameter
|
||||
will instruct the {@link it.could.webdav.DAVServlet} to create
|
||||
a very specialized version of the repository accepting only
|
||||
<a href="http://www.w3.org/TR/REC-xml/#sec-well-formed">well-formed
|
||||
XML</a> resources and collections.<br />
|
||||
Note that when set to <code>true</code> this implementation will rely
|
||||
on the <a href="http://java.sun.com/xml/jaxp/">JAXP</a> specification
|
||||
to access a XML parser used to verify the <code>PUT</code> content.
|
||||
</dd>
|
||||
<dt>debugEnabled</dt>
|
||||
<dd>
|
||||
<i>[optional, default="<code>false</code>"]</i> This parameter
|
||||
will instruct the {@link it.could.webdav.DAVServlet} to log
|
||||
unimportant debugging information (such as the methods called by the
|
||||
client) in the {@link javax.servlet.ServletContext#log(String) context
|
||||
log}.
|
||||
</dd>
|
||||
</dl>
|
||||
<p>
|
||||
The configured {@link it.could.webdav.DAVServlet} will then have
|
||||
to be mapped to a path, and in the example above, every request for
|
||||
any URL beginning in <code>/dav/</code> will be handled by this
|
||||
implementation, with a repository rooted in the <code>/dav/</code>
|
||||
directory of the web application.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,242 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.replication;
|
||||
|
||||
import it.could.util.StreamTools;
|
||||
import it.could.util.http.WebDavClient;
|
||||
import it.could.util.location.Location;
|
||||
import it.could.webdav.DAVListener;
|
||||
import it.could.webdav.DAVLogger;
|
||||
import it.could.webdav.DAVRepository;
|
||||
import it.could.webdav.DAVResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>TODO: Document this class.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVReplica extends Thread implements DAVListener {
|
||||
|
||||
private static final int SYNCHRONIZE = -1;
|
||||
|
||||
private final DAVRepository repository;
|
||||
private final DAVLogger logger;
|
||||
private final Location location;
|
||||
private final List actions = new ArrayList();
|
||||
|
||||
public DAVReplica(DAVRepository repository, Location location,
|
||||
DAVLogger logger)
|
||||
throws IOException {
|
||||
this.location = new WebDavClient(location).getLocation();
|
||||
this.repository = repository;
|
||||
this.logger = logger;
|
||||
this.start();
|
||||
}
|
||||
|
||||
public void synchronize()
|
||||
throws IOException {
|
||||
this.logger.log("Scheduling full synchronization");
|
||||
this.notify(this.repository.getResource((String)null), SYNCHRONIZE);
|
||||
}
|
||||
|
||||
public void notify(DAVResource resource, int event) {
|
||||
this.logger.debug("Event for \"" + resource.getRelativePath() + "\"");
|
||||
if (resource.getRepository() != this.repository) return;
|
||||
synchronized (this.actions) {
|
||||
this.actions.add(new Action(resource, event));
|
||||
this.actions.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
this.logger.debug("Starting background replica thread on " + location);
|
||||
while (true) try {
|
||||
final DAVReplica.Action array[];
|
||||
synchronized(this.actions) {
|
||||
try {
|
||||
if (this.actions.isEmpty()) this.actions.wait();
|
||||
final int s = this.actions.size();
|
||||
array = (Action []) this.actions.toArray(new Action[s]);
|
||||
this.actions.clear();
|
||||
} catch (InterruptedException exception) {
|
||||
this.logger.debug("Exiting background replica thread");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < array.length; x ++) try {
|
||||
this.replicate(array[x]);
|
||||
} catch (Throwable throwable) {
|
||||
final String path = array[x].resource.getRelativePath();
|
||||
final String message = "Error synchronizing resource " + path;
|
||||
this.logger.log(message, throwable);
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
this.logger.log("Replica thread attempted suicide", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private void replicate(DAVReplica.Action action) {
|
||||
final DAVResource resource = action.resource;
|
||||
|
||||
if (action.event == SYNCHRONIZE) {
|
||||
this.synchronize(resource);
|
||||
|
||||
} else try {
|
||||
final String path = resource.getParent().getRelativePath();
|
||||
final Location location = this.location.resolve(path);
|
||||
final WebDavClient client = new WebDavClient(location);
|
||||
final String child = resource.getName();
|
||||
|
||||
switch(action.event) {
|
||||
case RESOURCE_CREATED:
|
||||
case RESOURCE_MODIFIED:
|
||||
this.logger.debug("Putting resource " + path);
|
||||
this.put(resource, client);
|
||||
break;
|
||||
case RESOURCE_REMOVED:
|
||||
case COLLECTION_REMOVED:
|
||||
this.logger.debug("Deleting resource " + path);
|
||||
client.delete(child);
|
||||
break;
|
||||
case COLLECTION_CREATED:
|
||||
this.logger.debug("Creating collection " + path);
|
||||
client.mkcol(child);
|
||||
break;
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
String message = "Error replicating " + resource.getRelativePath();
|
||||
this.logger.log(message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void put(DAVResource resource, WebDavClient client)
|
||||
throws IOException {
|
||||
final String name = resource.getName();
|
||||
final long length = resource.getContentLength().longValue();
|
||||
final OutputStream output = client.put(name, length);
|
||||
final InputStream input = resource.read();
|
||||
StreamTools.copy(input, output);
|
||||
}
|
||||
|
||||
private void synchronize(DAVResource resource) {
|
||||
/* Figure out the path of the resource */
|
||||
final String path = resource.getRelativePath();
|
||||
|
||||
/* If it's a file or null, just skip the whole thing */
|
||||
if (! resource.isCollection()) {
|
||||
this.logger.log("Synchronization on non-collection " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Open a webdav client to the collection to synchronize */
|
||||
this.logger.log("Synchronizing collection " + path);
|
||||
final WebDavClient client;
|
||||
try {
|
||||
final Location location = this.location.resolve(path);
|
||||
client = new WebDavClient(location);
|
||||
} catch (IOException exception) {
|
||||
this.logger.log("Error creating WebDAV client", exception);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a list of all children from the DAV client */
|
||||
final Set children = new HashSet();
|
||||
for (Iterator iter = client.iterator(); iter.hasNext(); )
|
||||
children.add(iter.next());
|
||||
|
||||
/* Process all resource children one by one and ensure they exist */
|
||||
for (Iterator iter = resource.getChildren(); iter.hasNext(); ) {
|
||||
final DAVResource child = (DAVResource) iter.next();
|
||||
final String name = child.getName();
|
||||
|
||||
/* Remove this from the resources that will be removed later */
|
||||
children.remove(name);
|
||||
|
||||
/* If the client doesn't have this child, add it to the replica */
|
||||
if (! client.hasChild(name)) try {
|
||||
if (child.isCollection()) {
|
||||
this.logger.debug("Client doesn't have collection " + name);
|
||||
client.mkcol(name);
|
||||
this.synchronize(child);
|
||||
|
||||
} else {
|
||||
this.logger.debug("Client doesn't have resource " + name);
|
||||
this.put(child, client);
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
this.logger.log("Error creating new child " + name, exception);
|
||||
|
||||
/* If this child is a collection, it must be a collection on dav */
|
||||
} else if (child.isCollection()) try {
|
||||
if (!client.isCollection(name)) {
|
||||
this.logger.debug("Recreating collection " + name);
|
||||
client.delete(name).mkcol(name);
|
||||
}
|
||||
this.synchronize(child);
|
||||
} catch (IOException exception) {
|
||||
this.logger.log("Error creating collection " + name, exception);
|
||||
|
||||
/* Ok, the resource is a normal one, verify size and timestamp */
|
||||
} else try {
|
||||
final Date rlast = child.getLastModified();
|
||||
final Date dlast = client.getLastModified(name);
|
||||
if ((rlast != null) && (rlast.equals(dlast))) {
|
||||
final Long rlen = child.getContentLength();
|
||||
final long dlen = client.getContentLength(name);
|
||||
if ((rlen == null) || (rlen.longValue() != dlen)) {
|
||||
this.logger.debug("Resending resource " + name);
|
||||
this.put(child, client.delete(name));
|
||||
}
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
this.logger.log("Error resending resource " + name, exception);
|
||||
}
|
||||
}
|
||||
|
||||
/* Any other child that was not removed above, will go away now! */
|
||||
for (Iterator iter = children.iterator(); iter.hasNext(); ) {
|
||||
final String name = (String) iter.next();
|
||||
try {
|
||||
this.logger.debug("Removing leftovers " + name);
|
||||
client.delete(name);
|
||||
} catch (IOException exception) {
|
||||
this.logger.log("Error removing left over " + name, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Action {
|
||||
final DAVResource resource;
|
||||
final int event;
|
||||
|
||||
private Action(DAVResource resource, int event) {
|
||||
this.resource = resource;
|
||||
this.event = event;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package it.could.webdav.replication;
|
||||
|
||||
import it.could.util.location.Location;
|
||||
import it.could.webdav.DAVListener;
|
||||
import it.could.webdav.DAVLogger;
|
||||
import it.could.webdav.DAVRepository;
|
||||
import it.could.webdav.DAVServlet;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* <p>The {@link DAVReplicator} class is a {@link DAVListener} replicating
|
||||
* all content to the WebDAV repository specified at construction.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
*/
|
||||
public class DAVReplicator extends HttpServlet {
|
||||
|
||||
/** <p>The {@link DAVReplica} instances managed by this.</p> */
|
||||
private final List replicas = new ArrayList();
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVServlet} instance.</p>
|
||||
*/
|
||||
public DAVReplicator() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Initialize this {@link Servlet} instance.</p>
|
||||
*
|
||||
* <p>This servlet requires a couple of initialization parameters: the
|
||||
* first one is "<code>repository</code>" indicating the name of
|
||||
* the {@link DAVServlet} in the "<code>web.xml</code>" deployment
|
||||
* descriptor whose repository should be replicated.</p>
|
||||
*
|
||||
* <p>The second required parameter "<code>replicas</code>"
|
||||
* must contain a (whitespace separated list of) URL(s) where the original
|
||||
* repository should be replicated to.</p>
|
||||
*
|
||||
* <p>Finally, when set to <code>true</code>, the optional parameter
|
||||
* <code>debugEnabled</code> will enable logging of method invocation and
|
||||
* events in the repository.</p>
|
||||
*/
|
||||
public void init(ServletConfig config)
|
||||
throws ServletException {
|
||||
/* Initialize the super, just in case, and remember the context */
|
||||
super.init(config);
|
||||
|
||||
/* Setup logging */
|
||||
boolean debug = "true".equals(config.getInitParameter("debugEnabled"));
|
||||
DAVLogger logger = new DAVLogger(config, debug);
|
||||
|
||||
/* Try to retrieve the WebDAV repository from the servlet context */
|
||||
final String repositoryName = config.getInitParameter("repository");
|
||||
final DAVRepository repository;
|
||||
if (repositoryName == null) {
|
||||
throw new ServletException("Parameter \"rootPath\" not specified");
|
||||
} else try {
|
||||
final String key = DAVServlet.getRepositoryKey(repositoryName);
|
||||
final ServletContext context = config.getServletContext();
|
||||
repository = (DAVRepository) context.getAttribute(key);
|
||||
if (repository == null)
|
||||
throw new ServletException("Unable to access repository from " +
|
||||
"servlet \"" + repository + "\"");
|
||||
} catch (ClassCastException exception) {
|
||||
final String message = "Class cast exception accessing repository";
|
||||
throw new ServletException(message, exception);
|
||||
}
|
||||
|
||||
/* Access the different WebDAV replicas */
|
||||
final String replicas = config.getInitParameter("replicas");
|
||||
if (replicas == null) {
|
||||
throw new ServletException("Parameter \"replicas\" not specified");
|
||||
}
|
||||
|
||||
try {
|
||||
final StringTokenizer tokenizer = new StringTokenizer(replicas);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
final Location location = Location.parse(tokenizer.nextToken());
|
||||
final DAVReplica replica = new DAVReplica(repository, location,
|
||||
logger);
|
||||
logger.log("Added repository replica to \"" + location + "\"");
|
||||
repository.addListener(replica);
|
||||
this.replicas.add(replica);
|
||||
replica.synchronize();
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
throw new ServletException("Error creating replica", exception);
|
||||
}
|
||||
|
||||
/* Check that we have at least one replica in */
|
||||
if (this.replicas.size() != 0) return;
|
||||
throw new ServletException("No replicas specified for repository");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Destroy {@link DAVServlet} instance interrupting all running
|
||||
* {@link DAVReplica} instances.</p>
|
||||
*/
|
||||
public void destroy() {
|
||||
for (Iterator iter = this.replicas.iterator(); iter.hasNext() ; ) {
|
||||
((DAVReplica) iter.next()).interrupt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Could.IT WebDAV Servlet</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package contains a framework for maintaining fully replicated
|
||||
<a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
|
||||
repositories.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,159 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AbstractDavServerComponent
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: AbstractDavServerComponent.java 6000 2007-03-04 22:01:49Z joakime $
|
||||
*/
|
||||
public abstract class AbstractDavServerComponent
|
||||
implements DavServerComponent
|
||||
{
|
||||
private List listeners;
|
||||
protected boolean useIndexHtml = false;
|
||||
|
||||
public AbstractDavServerComponent()
|
||||
{
|
||||
listeners = new ArrayList();
|
||||
}
|
||||
|
||||
public void addListener( DavServerListener listener )
|
||||
{
|
||||
listeners.add( listener );
|
||||
}
|
||||
|
||||
public void removeListener( DavServerListener listener )
|
||||
{
|
||||
listeners.remove( listener );
|
||||
}
|
||||
|
||||
protected void triggerCollectionCreated( String resource )
|
||||
{
|
||||
Iterator it = listeners.iterator();
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
DavServerListener listener = (DavServerListener) it.next();
|
||||
try
|
||||
{
|
||||
listener.serverCollectionCreated( this, resource );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void triggerCollectionRemoved( String resource )
|
||||
{
|
||||
Iterator it = listeners.iterator();
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
DavServerListener listener = (DavServerListener) it.next();
|
||||
try
|
||||
{
|
||||
listener.serverCollectionRemoved( this, resource );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void triggerResourceCreated( String resource )
|
||||
{
|
||||
Iterator it = listeners.iterator();
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
DavServerListener listener = (DavServerListener) it.next();
|
||||
try
|
||||
{
|
||||
listener.serverResourceCreated( this, resource );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void triggerResourceRemoved( String resource )
|
||||
{
|
||||
Iterator it = listeners.iterator();
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
DavServerListener listener = (DavServerListener) it.next();
|
||||
try
|
||||
{
|
||||
listener.serverResourceRemoved( this, resource );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void triggerResourceModified( String resource )
|
||||
{
|
||||
Iterator it = listeners.iterator();
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
DavServerListener listener = (DavServerListener) it.next();
|
||||
try
|
||||
{
|
||||
listener.serverResourceModified( this, resource );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasResource( String resource )
|
||||
{
|
||||
File rootDir = getRootDirectory();
|
||||
if ( rootDir == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
File resourceFile = new File( rootDir, resource );
|
||||
return resourceFile.exists();
|
||||
}
|
||||
|
||||
public boolean isUseIndexHtml()
|
||||
{
|
||||
return this.useIndexHtml;
|
||||
}
|
||||
|
||||
public void setUseIndexHtml( boolean useIndexHtml )
|
||||
{
|
||||
this.useIndexHtml = useIndexHtml;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
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 org.apache.jackrabbit.webdav.DavLocatorFactory;
|
||||
import org.apache.jackrabbit.webdav.DavResourceLocator;
|
||||
import org.apache.jackrabbit.util.Text;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.maven.archiva.webdav.util.RepositoryPathUtil;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class ArchivaDavLocatorFactory 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 String workspaceName = RepositoryPathUtil.getRepositoryName(href);
|
||||
|
||||
return new ArchivaDavResourceLocator(b.toString(), Text.unescape(href), workspaceName, this);
|
||||
}
|
||||
|
||||
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 String repository = RepositoryPathUtil.getRepositoryName(path);
|
||||
return new ArchivaDavResourceLocator(prefix, path, repository, this);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
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 org.apache.jackrabbit.webdav.*;
|
||||
import org.apache.jackrabbit.webdav.property.DavPropertySet;
|
||||
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
|
||||
import org.apache.jackrabbit.webdav.property.DavProperty;
|
||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
||||
import org.apache.jackrabbit.webdav.io.InputContext;
|
||||
import org.apache.jackrabbit.webdav.io.OutputContext;
|
||||
import org.apache.jackrabbit.webdav.lock.*;
|
||||
import org.apache.jackrabbit.util.Text;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.maven.archiva.webdav.util.MimeTypes;
|
||||
import org.apache.maven.archiva.webdav.util.IndexWriter;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Date;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class ArchivaDavResource implements DavResource
|
||||
{
|
||||
private final MimeTypes mimeTypes;
|
||||
|
||||
private final DavResourceLocator locator;
|
||||
|
||||
private final DavResourceFactory factory;
|
||||
|
||||
private final DavSession session;
|
||||
|
||||
private final File localResource;
|
||||
|
||||
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;
|
||||
|
||||
public ArchivaDavResource(String localResource, String logicalResource, MimeTypes mimeTypes, DavResourceLocator locator, DavResourceFactory factory, DavSession session)
|
||||
{
|
||||
this.mimeTypes = mimeTypes;
|
||||
this.localResource = new File(localResource);
|
||||
this.logicalResource = logicalResource;
|
||||
this.locator = locator;
|
||||
this.factory = factory;
|
||||
this.session = session;
|
||||
this.properties = new DavPropertySet();
|
||||
}
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
return mimeTypes.getMimeType(localResource.getName());
|
||||
}
|
||||
|
||||
public String getComplianceClass()
|
||||
{
|
||||
return COMPLIANCE_CLASS;
|
||||
}
|
||||
|
||||
public String getSupportedMethods()
|
||||
{
|
||||
return METHODS;
|
||||
}
|
||||
|
||||
public boolean exists()
|
||||
{
|
||||
return localResource.exists();
|
||||
}
|
||||
|
||||
public boolean isCollection()
|
||||
{
|
||||
return localResource.isDirectory();
|
||||
}
|
||||
|
||||
public String getDisplayName()
|
||||
{
|
||||
String resPath = getResourcePath();
|
||||
return (resPath != null) ? Text.getName(resPath) : resPath;
|
||||
}
|
||||
|
||||
public DavResourceLocator getLocator()
|
||||
{
|
||||
return locator;
|
||||
}
|
||||
|
||||
public String getResourcePath()
|
||||
{
|
||||
return locator.getResourcePath();
|
||||
}
|
||||
|
||||
public String getHref()
|
||||
{
|
||||
return locator.getHref(isCollection());
|
||||
}
|
||||
|
||||
public long getModificationTime()
|
||||
{
|
||||
return localResource.lastModified();
|
||||
}
|
||||
|
||||
public long getContentLength()
|
||||
{
|
||||
return localResource.length();
|
||||
}
|
||||
|
||||
public void spool(OutputContext outputContext) throws IOException
|
||||
{
|
||||
if (!isCollection())
|
||||
{
|
||||
IOUtils.copy(new FileInputStream(localResource), outputContext.getOutputStream());
|
||||
}
|
||||
else
|
||||
{
|
||||
IndexWriter writer = new IndexWriter(this, localResource, logicalResource);
|
||||
writer.write(outputContext);
|
||||
}
|
||||
}
|
||||
|
||||
public DavPropertyName[] getPropertyNames()
|
||||
{
|
||||
return new DavPropertyName[0];
|
||||
}
|
||||
|
||||
public DavProperty getProperty(DavPropertyName name)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public DavPropertySet getProperties()
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperty(DavProperty property) throws DavException
|
||||
{
|
||||
}
|
||||
|
||||
public void removeProperty(DavPropertyName propertyName) throws DavException
|
||||
{
|
||||
}
|
||||
|
||||
public MultiStatusResponse alterProperties(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames) throws DavException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public MultiStatusResponse alterProperties(List changeList) throws DavException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
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(), locator.getWorkspacePath(), parentPath);
|
||||
try {
|
||||
parent = factory.createResource(parentloc, session);
|
||||
} catch (DavException e) {
|
||||
// should not occur
|
||||
}
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void addMember(DavResource resource, InputContext inputContext) throws DavException
|
||||
{
|
||||
File localFile = new File(localResource, resource.getDisplayName());
|
||||
if (!resource.isCollection() && isCollection() && inputContext.hasStream()) //New File
|
||||
{
|
||||
boolean deleteFile = false;
|
||||
FileOutputStream stream = null;
|
||||
try
|
||||
{
|
||||
stream = new FileOutputStream(localFile);
|
||||
IOUtils.copy(inputContext.getInputStream(), stream);
|
||||
if (inputContext.getContentLength() != localFile.length())
|
||||
{
|
||||
deleteFile = true;
|
||||
throw new DavException(HttpServletResponse.SC_BAD_REQUEST, "Content Header length was "
|
||||
+ inputContext.getContentLength() + " but was " + localFile.length());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(stream);
|
||||
if (deleteFile)
|
||||
{
|
||||
FileUtils.deleteQuietly(localFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (resource.isCollection() && isCollection()) //New directory
|
||||
{
|
||||
localFile.mkdir();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DavException(HttpServletResponse.SC_BAD_REQUEST, "Could not write member "
|
||||
+ resource.getResourcePath() + " at " + getResourcePath());
|
||||
}
|
||||
}
|
||||
|
||||
public DavResourceIterator getMembers()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeMember(DavResource member) throws DavException
|
||||
{
|
||||
}
|
||||
|
||||
public void move(DavResource destination) throws DavException
|
||||
{
|
||||
}
|
||||
|
||||
public void copy(DavResource destination, boolean shallow) throws DavException
|
||||
{
|
||||
}
|
||||
|
||||
public boolean isLockable(Type type, Scope scope)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasLock(Type type, Scope scope)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public ActiveLock getLock(Type type, Scope scope)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ActiveLock[] getLocks()
|
||||
{
|
||||
return new ActiveLock[0];
|
||||
}
|
||||
|
||||
public ActiveLock lock(LockInfo reqLockInfo) throws DavException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken) throws DavException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void unlock(String lockToken) throws DavException
|
||||
{
|
||||
}
|
||||
|
||||
public void addLockManager(LockManager lockmgr)
|
||||
{
|
||||
}
|
||||
|
||||
public DavResourceFactory getFactory()
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
|
||||
public DavSession getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,497 @@
|
|||
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 com.opensymphony.xwork.ActionContext;
|
||||
import org.apache.jackrabbit.webdav.*;
|
||||
import org.apache.maven.archiva.repository.ManagedRepositoryContent;
|
||||
import org.apache.maven.archiva.repository.RepositoryNotFoundException;
|
||||
import org.apache.maven.archiva.repository.RepositoryException;
|
||||
import org.apache.maven.archiva.repository.RepositoryContentFactory;
|
||||
import org.apache.maven.archiva.repository.layout.LayoutException;
|
||||
import org.apache.maven.archiva.repository.content.RepositoryRequest;
|
||||
import org.apache.maven.archiva.repository.audit.AuditListener;
|
||||
import org.apache.maven.archiva.repository.audit.Auditable;
|
||||
import org.apache.maven.archiva.repository.audit.AuditEvent;
|
||||
import org.apache.maven.archiva.repository.metadata.MetadataTools;
|
||||
import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
|
||||
import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
|
||||
import org.apache.maven.archiva.webdav.util.MimeTypes;
|
||||
import org.apache.maven.archiva.webdav.util.RepositoryPathUtil;
|
||||
import org.apache.maven.archiva.proxy.RepositoryProxyConnectors;
|
||||
import org.apache.maven.archiva.common.utils.PathUtil;
|
||||
import org.apache.maven.archiva.model.ArtifactReference;
|
||||
import org.apache.maven.archiva.model.ProjectReference;
|
||||
import org.apache.maven.archiva.model.VersionedReference;
|
||||
import org.apache.maven.archiva.policies.ProxyDownloadException;
|
||||
import org.apache.maven.archiva.security.ArchivaXworkUser;
|
||||
import org.apache.maven.model.DistributionManagement;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.Relocation;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
* @plexus.component role="org.apache.maven.archiva.webdav.ArchivaDavResourceFactory"
|
||||
*/
|
||||
public class ArchivaDavResourceFactory implements DavResourceFactory, Auditable
|
||||
{
|
||||
private Logger log = LoggerFactory.getLogger(ArchivaDavResourceFactory.class);
|
||||
|
||||
/**
|
||||
* @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
|
||||
*/
|
||||
private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private RepositoryContentFactory repositoryFactory;
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private RepositoryRequest repositoryRequest;
|
||||
|
||||
/**
|
||||
* @plexus.requirement role-hint="default"
|
||||
*/
|
||||
private RepositoryProxyConnectors connectors;
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private MetadataTools metadataTools;
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private MimeTypes mimeTypes;
|
||||
|
||||
public DavResource createResource(final DavResourceLocator locator, final DavServletRequest request, final DavServletResponse response) throws DavException
|
||||
{
|
||||
final ManagedRepositoryContent managedRepository = getManagedRepository(locator.getWorkspaceName());
|
||||
final LogicalResource logicalResource = new LogicalResource(RepositoryPathUtil.getLogicalResource(locator.getResourcePath()));
|
||||
|
||||
DavResource resource = null;
|
||||
|
||||
if (managedRepository != null)
|
||||
{
|
||||
final boolean isGet = WebdavMethodUtil.isReadMethod( request.getMethod() );
|
||||
final boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() );
|
||||
|
||||
if (isGet)
|
||||
{
|
||||
resource = doGet(managedRepository, request, locator, logicalResource);
|
||||
}
|
||||
|
||||
if (isPut)
|
||||
{
|
||||
resource = doPut(managedRepository, request, locator, logicalResource);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DavException(HttpServletResponse.SC_NOT_FOUND, "Repository does not exist");
|
||||
}
|
||||
|
||||
if (resource != null)
|
||||
{
|
||||
setHeaders(locator, response);
|
||||
return resource;
|
||||
}
|
||||
|
||||
throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not get resource for method " + request.getMethod());
|
||||
}
|
||||
|
||||
public DavResource createResource(final DavResourceLocator locator, final DavSession davSession) throws DavException
|
||||
{
|
||||
final ManagedRepositoryContent managedRepository = getManagedRepository(locator.getWorkspaceName());
|
||||
final String logicalResource = RepositoryPathUtil.getLogicalResource(locator.getResourcePath());
|
||||
final File resourceFile = new File ( managedRepository.getRepoRoot(), logicalResource);
|
||||
|
||||
return new ArchivaDavResource(resourceFile.getAbsolutePath(), logicalResource, mimeTypes, locator, this, null);
|
||||
}
|
||||
|
||||
private DavResource doGet(ManagedRepositoryContent managedRepository, DavServletRequest request, DavResourceLocator locator, LogicalResource logicalResource) throws DavException
|
||||
{
|
||||
File resourceFile = new File ( managedRepository.getRepoRoot(), logicalResource.getPath());
|
||||
ArchivaDavResource resource = new ArchivaDavResource(resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, locator, this, null);
|
||||
|
||||
if ( !resource.isCollection() )
|
||||
{
|
||||
// At this point the incoming request can either be in default or
|
||||
// legacy layout format.
|
||||
try
|
||||
{
|
||||
boolean fromProxy = fetchContentFromProxies(managedRepository, request, logicalResource );
|
||||
|
||||
// Perform an adjustment of the resource to the managed
|
||||
// repository expected path.
|
||||
String localResourcePath = repositoryRequest.toNativePath( logicalResource.getPath(), managedRepository );
|
||||
resourceFile = new File( managedRepository.getRepoRoot(), localResourcePath );
|
||||
|
||||
boolean previouslyExisted = resourceFile.exists();
|
||||
|
||||
// Attempt to fetch the resource from any defined proxy.
|
||||
if ( fromProxy )
|
||||
{
|
||||
processAuditEvents(request, locator.getWorkspaceName(), logicalResource.getPath(), previouslyExisted, resourceFile, " (proxied)");
|
||||
}
|
||||
resource = new ArchivaDavResource(resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, locator, this, null);
|
||||
|
||||
}
|
||||
catch ( LayoutException e )
|
||||
{
|
||||
throw new DavException(HttpServletResponse.SC_NOT_FOUND, e);
|
||||
}
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
private DavResource doPut(ManagedRepositoryContent managedRepository, DavServletRequest request, DavResourceLocator locator, LogicalResource logicalResource) throws DavException
|
||||
{
|
||||
/*
|
||||
* Create parent directories that don't exist when writing a file
|
||||
* This actually makes this implementation not compliant to the
|
||||
* WebDAV RFC - but we have enough knowledge about how the
|
||||
* collection is being used to do this reasonably and some versions
|
||||
* of Maven's WebDAV don't correctly create the collections
|
||||
* themselves.
|
||||
*/
|
||||
|
||||
File rootDirectory = new File(managedRepository.getRepoRoot());
|
||||
File destDir = new File( rootDirectory, logicalResource.getPath() ).getParentFile();
|
||||
if ( !destDir.exists() )
|
||||
{
|
||||
destDir.mkdirs();
|
||||
String relPath =
|
||||
PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir );
|
||||
triggerAuditEvent(request, logicalResource.getPath(), relPath, AuditEvent.CREATE_DIR );
|
||||
}
|
||||
|
||||
File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() );
|
||||
|
||||
boolean previouslyExisted = resourceFile.exists();
|
||||
|
||||
processAuditEvents(request, locator.getWorkspaceName(), logicalResource.getPath(), previouslyExisted, resourceFile, null );
|
||||
|
||||
return new ArchivaDavResource(resourceFile.getAbsolutePath(), logicalResource.getPath(), mimeTypes, locator, this, null);
|
||||
}
|
||||
|
||||
private boolean fetchContentFromProxies( ManagedRepositoryContent managedRepository, DavServletRequest request, LogicalResource resource )
|
||||
throws DavException
|
||||
{
|
||||
if ( repositoryRequest.isSupportFile( resource.getPath() ) )
|
||||
{
|
||||
// Checksums are fetched with artifact / metadata.
|
||||
|
||||
// Need to adjust the path for the checksum resource.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it a Metadata resource?
|
||||
if ( repositoryRequest.isDefault( resource.getPath() ) && repositoryRequest.isMetadata( resource.getPath() ) )
|
||||
{
|
||||
return fetchMetadataFromProxies(managedRepository, request, resource );
|
||||
}
|
||||
|
||||
// Not any of the above? Then it's gotta be an artifact reference.
|
||||
try
|
||||
{
|
||||
// Get the artifact reference in a layout neutral way.
|
||||
ArtifactReference artifact = repositoryRequest.toArtifactReference( resource.getPath() );
|
||||
|
||||
if ( artifact != null )
|
||||
{
|
||||
applyServerSideRelocation(managedRepository, artifact );
|
||||
|
||||
File proxiedFile = connectors.fetchFromProxies( managedRepository, artifact );
|
||||
|
||||
resource.setPath( managedRepository.toPath( artifact ) );
|
||||
|
||||
return ( proxiedFile != null );
|
||||
}
|
||||
}
|
||||
catch ( LayoutException e )
|
||||
{
|
||||
/* eat it */
|
||||
}
|
||||
catch ( ProxyDownloadException e )
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to fetch artifact resource.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean fetchMetadataFromProxies(ManagedRepositoryContent managedRepository, DavServletRequest request, LogicalResource resource )
|
||||
throws DavException
|
||||
{
|
||||
ProjectReference project;
|
||||
VersionedReference versioned;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
versioned = metadataTools.toVersionedReference( resource.getPath() );
|
||||
if ( versioned != null )
|
||||
{
|
||||
connectors.fetchFromProxies( managedRepository, versioned );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch ( RepositoryMetadataException e )
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
project = metadataTools.toProjectReference( resource.getPath() );
|
||||
if ( project != null )
|
||||
{
|
||||
connectors.fetchFromProxies( managedRepository, project );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch ( RepositoryMetadataException e )
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A relocation capable client will request the POM prior to the artifact,
|
||||
* and will then read meta-data and do client side relocation. A simplier
|
||||
* client (like maven 1) will only request the artifact and not use the
|
||||
* metadatas.
|
||||
* <p>
|
||||
* For such clients, archiva does server-side relocation by reading itself
|
||||
* the <relocation> element in metadatas and serving the expected
|
||||
* artifact.
|
||||
*/
|
||||
protected void applyServerSideRelocation( ManagedRepositoryContent managedRepository, ArtifactReference artifact )
|
||||
throws ProxyDownloadException
|
||||
{
|
||||
if ( "pom".equals( artifact.getType() ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the artifact POM reference
|
||||
ArtifactReference pomReference = new ArtifactReference();
|
||||
pomReference.setGroupId( artifact.getGroupId() );
|
||||
pomReference.setArtifactId( artifact.getArtifactId() );
|
||||
pomReference.setVersion( artifact.getVersion() );
|
||||
pomReference.setType( "pom" );
|
||||
|
||||
// Get the artifact POM from proxied repositories if needed
|
||||
connectors.fetchFromProxies( managedRepository, pomReference );
|
||||
|
||||
// Open and read the POM from the managed repo
|
||||
File pom = managedRepository.toFile( pomReference );
|
||||
|
||||
if ( !pom.exists() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Model model = new MavenXpp3Reader().read( new FileReader( pom ) );
|
||||
DistributionManagement dist = model.getDistributionManagement();
|
||||
if ( dist != null )
|
||||
{
|
||||
Relocation relocation = dist.getRelocation();
|
||||
if ( relocation != null )
|
||||
{
|
||||
// artifact is relocated : update the repositoryPath
|
||||
if ( relocation.getGroupId() != null )
|
||||
{
|
||||
artifact.setGroupId( relocation.getGroupId() );
|
||||
}
|
||||
if ( relocation.getArtifactId() != null )
|
||||
{
|
||||
artifact.setArtifactId( relocation.getArtifactId() );
|
||||
}
|
||||
if ( relocation.getVersion() != null )
|
||||
{
|
||||
artifact.setVersion( relocation.getVersion() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( FileNotFoundException e )
|
||||
{
|
||||
// Artifact has no POM in repo : ignore
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
// Unable to read POM : ignore.
|
||||
}
|
||||
catch ( XmlPullParserException e )
|
||||
{
|
||||
// Invalid POM : ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void processAuditEvents( DavServletRequest request, String repositoryId, String resource,
|
||||
boolean previouslyExisted, File resourceFile, String suffix )
|
||||
{
|
||||
if ( suffix == null )
|
||||
{
|
||||
suffix = "";
|
||||
}
|
||||
|
||||
// Process Create Audit Events.
|
||||
if ( !previouslyExisted && resourceFile.exists() )
|
||||
{
|
||||
if ( resourceFile.isFile() )
|
||||
{
|
||||
triggerAuditEvent( request, repositoryId, resource, AuditEvent.CREATE_FILE + suffix );
|
||||
}
|
||||
else if ( resourceFile.isDirectory() )
|
||||
{
|
||||
triggerAuditEvent( request, repositoryId, resource, AuditEvent.CREATE_DIR + suffix );
|
||||
}
|
||||
}
|
||||
// Process Remove Audit Events.
|
||||
else if ( previouslyExisted && !resourceFile.exists() )
|
||||
{
|
||||
if ( resourceFile.isFile() )
|
||||
{
|
||||
triggerAuditEvent( request, repositoryId, resource, AuditEvent.REMOVE_FILE + suffix );
|
||||
}
|
||||
else if ( resourceFile.isDirectory() )
|
||||
{
|
||||
triggerAuditEvent( request, repositoryId, resource, AuditEvent.REMOVE_DIR + suffix );
|
||||
}
|
||||
}
|
||||
// Process modify events.
|
||||
else
|
||||
{
|
||||
if ( resourceFile.isFile() )
|
||||
{
|
||||
triggerAuditEvent( request, repositoryId, resource, AuditEvent.MODIFY_FILE + suffix );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerAuditEvent( String user, String remoteIP, String repositoryId, String resource, String action )
|
||||
{
|
||||
AuditEvent event = new AuditEvent( repositoryId, user, resource, action );
|
||||
event.setRemoteIP( remoteIP );
|
||||
|
||||
for ( AuditListener listener : auditListeners )
|
||||
{
|
||||
listener.auditEvent( event );
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerAuditEvent( DavServletRequest request, String repositoryId, String resource, String action )
|
||||
{
|
||||
triggerAuditEvent( ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() ), getRemoteIP( request ), repositoryId, resource, action );
|
||||
}
|
||||
|
||||
private String getRemoteIP( DavServletRequest request )
|
||||
{
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
|
||||
public void addAuditListener( AuditListener listener )
|
||||
{
|
||||
this.auditListeners.add( listener );
|
||||
}
|
||||
|
||||
public void clearAuditListeners()
|
||||
{
|
||||
this.auditListeners.clear();
|
||||
}
|
||||
|
||||
public void removeAuditListener( AuditListener listener )
|
||||
{
|
||||
this.auditListeners.remove( listener );
|
||||
}
|
||||
|
||||
private void setHeaders(DavResourceLocator locator, DavServletResponse response)
|
||||
{
|
||||
// [MRM-503] - Metadata file need Pragma:no-cache response
|
||||
// header.
|
||||
if ( locator.getResourcePath().endsWith( "/maven-metadata.xml" ) )
|
||||
{
|
||||
response.addHeader( "Pragma", "no-cache" );
|
||||
response.addHeader( "Cache-Control", "no-cache" );
|
||||
}
|
||||
|
||||
// TODO: [MRM-524] determine http caching options for other types of files (artifacts, sha1, md5, snapshots)
|
||||
}
|
||||
|
||||
private ManagedRepositoryContent getManagedRepository(String respositoryId) throws DavException
|
||||
{
|
||||
if (respositoryId != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return repositoryFactory.getManagedRepositoryContent(respositoryId);
|
||||
}
|
||||
catch (RepositoryNotFoundException e)
|
||||
{
|
||||
throw new DavException(HttpServletResponse.SC_NOT_FOUND, e);
|
||||
}
|
||||
catch (RepositoryException e)
|
||||
{
|
||||
throw new DavException(HttpServletResponse.SC_NOT_FOUND, e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class LogicalResource
|
||||
{
|
||||
private String path;
|
||||
|
||||
public LogicalResource(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
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 org.apache.jackrabbit.webdav.DavResourceLocator;
|
||||
import org.apache.jackrabbit.webdav.DavLocatorFactory;
|
||||
import org.apache.jackrabbit.util.Text;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class ArchivaDavResourceLocator implements DavResourceLocator
|
||||
{
|
||||
private String prefix;
|
||||
|
||||
private String resourcePath;
|
||||
|
||||
private String href;
|
||||
|
||||
private String workspaceName;
|
||||
|
||||
private DavLocatorFactory davLocatorFactory;
|
||||
|
||||
public ArchivaDavResourceLocator(String prefix, String resourcePath, String workspaceName, DavLocatorFactory davLocatorFactory)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.workspaceName = workspaceName;
|
||||
this.davLocatorFactory = davLocatorFactory;
|
||||
|
||||
// remove trailing '/' that is not part of the resourcePath except for the root item.
|
||||
if (resourcePath.endsWith("/") && !"/".equals(resourcePath)) {
|
||||
resourcePath = resourcePath.substring(0, resourcePath.length()-1);
|
||||
}
|
||||
this.resourcePath = resourcePath;
|
||||
|
||||
href = prefix + Text.escapePath(resourcePath);
|
||||
}
|
||||
|
||||
public String getPrefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public String getResourcePath()
|
||||
{
|
||||
return resourcePath;
|
||||
}
|
||||
|
||||
public String getWorkspacePath()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getWorkspaceName()
|
||||
{
|
||||
return workspaceName;
|
||||
}
|
||||
|
||||
public boolean isSameWorkspace(DavResourceLocator locator)
|
||||
{
|
||||
return isSameWorkspace(locator.getWorkspaceName());
|
||||
}
|
||||
|
||||
public boolean isSameWorkspace(String workspaceName)
|
||||
{
|
||||
return getWorkspaceName().equals(workspaceName);
|
||||
}
|
||||
|
||||
public String getHref(boolean isCollection)
|
||||
{
|
||||
// avoid doubled trailing '/' for the root item
|
||||
String suffix = (isCollection && !isRootLocation()) ? "/" : "";
|
||||
return href + suffix;
|
||||
}
|
||||
|
||||
public boolean isRootLocation()
|
||||
{
|
||||
return "/".equals(resourcePath);
|
||||
}
|
||||
|
||||
public DavLocatorFactory getFactory()
|
||||
{
|
||||
return davLocatorFactory;
|
||||
}
|
||||
|
||||
public String getRepositoryPath()
|
||||
{
|
||||
return getResourcePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
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 org.apache.jackrabbit.webdav.DavSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class ArchivaDavSession implements DavSession
|
||||
{
|
||||
public void addReference(Object o)
|
||||
{
|
||||
throw new UnsupportedOperationException("No yet implemented.");
|
||||
}
|
||||
|
||||
public void removeReference(Object o)
|
||||
{
|
||||
throw new UnsupportedOperationException("No yet implemented.");
|
||||
}
|
||||
|
||||
public void addLockToken(String s)
|
||||
{
|
||||
throw new UnsupportedOperationException("No yet implemented.");
|
||||
}
|
||||
|
||||
public String[] getLockTokens()
|
||||
{
|
||||
throw new UnsupportedOperationException("No yet implemented.");
|
||||
}
|
||||
|
||||
public void removeLockToken(String s)
|
||||
{
|
||||
throw new UnsupportedOperationException("No yet implemented.");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
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 org.apache.jackrabbit.webdav.DavSessionProvider;
|
||||
import org.apache.jackrabbit.webdav.WebdavRequest;
|
||||
import org.apache.jackrabbit.webdav.DavException;
|
||||
import org.apache.jackrabbit.webdav.DavServletRequest;
|
||||
import org.apache.maven.archiva.webdav.util.WebdavMethodUtil;
|
||||
import org.apache.maven.archiva.webdav.util.RepositoryPathUtil;
|
||||
import org.apache.maven.archiva.security.ArchivaRoleConstants;
|
||||
import org.codehaus.plexus.redback.xwork.filter.authentication.HttpAuthenticator;
|
||||
import org.codehaus.plexus.redback.authentication.AuthenticationResult;
|
||||
import org.codehaus.plexus.redback.authentication.AuthenticationException;
|
||||
import org.codehaus.plexus.redback.system.SecuritySystem;
|
||||
import org.codehaus.plexus.redback.system.SecuritySession;
|
||||
import org.codehaus.plexus.redback.policy.MustChangePasswordException;
|
||||
import org.codehaus.plexus.redback.policy.AccountLockedException;
|
||||
import org.codehaus.plexus.redback.authorization.AuthorizationResult;
|
||||
import org.codehaus.plexus.redback.authorization.AuthorizationException;
|
||||
import org.codehaus.plexus.spring.PlexusToSpringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class ArchivaDavSessionProvider implements DavSessionProvider
|
||||
{
|
||||
private Logger log = LoggerFactory.getLogger(ArchivaDavSessionProvider.class);
|
||||
|
||||
private SecuritySystem securitySystem;
|
||||
|
||||
private HttpAuthenticator httpAuth;
|
||||
|
||||
public ArchivaDavSessionProvider(WebApplicationContext applicationContext)
|
||||
{
|
||||
securitySystem = (SecuritySystem) applicationContext.getBean( PlexusToSpringUtils.buildSpringId( SecuritySystem.ROLE ) );
|
||||
httpAuth = (HttpAuthenticator) applicationContext.getBean( PlexusToSpringUtils.buildSpringId( HttpAuthenticator.ROLE, "basic" ) );
|
||||
}
|
||||
|
||||
public boolean attachSession(WebdavRequest request) throws DavException
|
||||
{
|
||||
final String repositoryId = RepositoryPathUtil.getRepositoryName(removeContextPath(request));
|
||||
return isAuthenticated(request, repositoryId) && isAuthorized(request, repositoryId);
|
||||
}
|
||||
|
||||
public void releaseSession(WebdavRequest webdavRequest)
|
||||
{
|
||||
}
|
||||
|
||||
protected boolean isAuthenticated( WebdavRequest request, String repositoryId )
|
||||
throws DavException
|
||||
{
|
||||
// Authentication Tests.
|
||||
try
|
||||
{
|
||||
AuthenticationResult result = httpAuth.getAuthenticationResult(request, null);
|
||||
|
||||
if ( result == null || !result.isAuthenticated() )
|
||||
{
|
||||
//Unfortunatly, the DavSessionProvider does not pass in the response
|
||||
httpAuth.authenticate(request, null);
|
||||
}
|
||||
}
|
||||
catch ( AuthenticationException e )
|
||||
{
|
||||
throw new UnauthorizedDavException(repositoryId, "You are not authenticated");
|
||||
}
|
||||
catch ( AccountLockedException e )
|
||||
{
|
||||
throw new UnauthorizedDavException(repositoryId, "User account is locked.");
|
||||
}
|
||||
catch ( MustChangePasswordException e )
|
||||
{
|
||||
throw new UnauthorizedDavException(repositoryId, "You must change your password.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isAuthorized( WebdavRequest request, String repositoryId )
|
||||
throws DavException
|
||||
{
|
||||
// Authorization Tests.
|
||||
final boolean isWriteRequest = WebdavMethodUtil.isWriteMethod( request.getMethod() );
|
||||
|
||||
SecuritySession securitySession = httpAuth.getSecuritySession();
|
||||
try
|
||||
{
|
||||
String permission = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS;
|
||||
|
||||
if ( isWriteRequest )
|
||||
{
|
||||
permission = ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD;
|
||||
}
|
||||
|
||||
//DavServletRequestInfo requestInfo = new DavServletRequestInfo(request);
|
||||
|
||||
AuthorizationResult authzResult =
|
||||
securitySystem.authorize( securitySession, permission, repositoryId);
|
||||
|
||||
if ( !authzResult.isAuthorized() )
|
||||
{
|
||||
if ( authzResult.getException() != null )
|
||||
{
|
||||
log.info( "Authorization Denied [ip=" + request.getRemoteAddr() + ",isWriteRequest=" + isWriteRequest +
|
||||
",permission=" + permission + ",repo=" + repositoryId + "] : " +
|
||||
authzResult.getException().getMessage() );
|
||||
}
|
||||
throw new DavException(HttpServletResponse.SC_UNAUTHORIZED, "Access denied for repository " + repositoryId);
|
||||
}
|
||||
}
|
||||
catch ( AuthorizationException e )
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
throw new DavException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Fatal Authorization Subsystem Error." );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private String removeContextPath(final DavServletRequest request)
|
||||
{
|
||||
String path = request.getRequestURI();
|
||||
String ctx = request.getContextPath();
|
||||
if (path.startsWith(ctx)) {
|
||||
path = path.substring(ctx.length());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -1,143 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* DavServerComponent
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: DavServerComponent.java 6000 2007-03-04 22:01:49Z joakime $
|
||||
*/
|
||||
public interface DavServerComponent
|
||||
{
|
||||
/** The Plexus ROLE name */
|
||||
public static final String ROLE = DavServerComponent.class.getName();
|
||||
|
||||
/**
|
||||
* Get the Prefix for this server component.
|
||||
* @return the prefix associated with this component.
|
||||
*/
|
||||
public String getPrefix();
|
||||
|
||||
/**
|
||||
* Set the prefix for this server component.
|
||||
* @param prefix the prefix to use.
|
||||
*/
|
||||
public void setPrefix( String prefix );
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Flag to indicate how the dav server component should treat a GET request against
|
||||
* a DAV Collection.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If true, the collection being requested will be searched for an index.html (or index.htm)
|
||||
* file to serve back, before it defaults to displaying the collection (directory) contents.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If false, the collection will always be presented in as a list of contents.
|
||||
* </p>
|
||||
*
|
||||
* @return true to use the index.html instead of directory contents.
|
||||
*/
|
||||
public boolean isUseIndexHtml();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Flag to indicate how the dav server component should treat a GET request against
|
||||
* a DAV Collection.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If true, the collection being requested will be searched for an index.html (or index.htm)
|
||||
* file to serve back, before it defaults to displaying the collection (directory) contents.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If false, the collection will always be presented in as a list of contents.
|
||||
* </p>
|
||||
*
|
||||
* @param useIndexHtml true to use the index.html instead of directory contents.
|
||||
*/
|
||||
public void setUseIndexHtml( boolean useIndexHtml );
|
||||
|
||||
/**
|
||||
* Get the root directory for this server.
|
||||
*
|
||||
* @return the root directory for this server.
|
||||
*/
|
||||
public File getRootDirectory();
|
||||
|
||||
/**
|
||||
* Set the root directory for this server's content.
|
||||
*
|
||||
* @param rootDirectory the root directory for this server's content.
|
||||
*/
|
||||
public void setRootDirectory( File rootDirectory );
|
||||
|
||||
/**
|
||||
* Add a Server Listener for this server component.
|
||||
*
|
||||
* @param listener the listener to add for this component.
|
||||
*/
|
||||
public void addListener( DavServerListener listener );
|
||||
|
||||
/**
|
||||
* Remove a server listener for this server component.
|
||||
*
|
||||
* @param listener the listener to remove.
|
||||
*/
|
||||
public void removeListener( DavServerListener listener );
|
||||
|
||||
/**
|
||||
* Perform any initialization needed.
|
||||
*
|
||||
* @param servletConfig the servlet config that might be needed.
|
||||
* @throws DavServerException if there was a problem initializing the server component.
|
||||
*/
|
||||
public void init( ServletConfig servletConfig ) throws DavServerException;
|
||||
|
||||
/**
|
||||
* Performs a simple filesystem check for the specified resource.
|
||||
*
|
||||
* @param resource the resource to check for.
|
||||
* @return true if the resource exists.
|
||||
*/
|
||||
public boolean hasResource( String resource );
|
||||
|
||||
/**
|
||||
* Process incoming request.
|
||||
*
|
||||
* @param request the incoming request to process.
|
||||
* @param response the outgoing response to provide.
|
||||
*/
|
||||
public void process( DavServerRequest request, HttpServletResponse response )
|
||||
throws DavServerException, ServletException, IOException;
|
||||
}
|
|
@ -1,39 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
/**
|
||||
* DavServerListener
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: DavServerListener.java 5379 2007-01-07 22:54:41Z joakime $
|
||||
*/
|
||||
public interface DavServerListener
|
||||
{
|
||||
public void serverCollectionCreated( DavServerComponent server, String resource );
|
||||
|
||||
public void serverCollectionRemoved( DavServerComponent server, String resource );
|
||||
|
||||
public void serverResourceCreated( DavServerComponent server, String resource );
|
||||
|
||||
public void serverResourceRemoved( DavServerComponent server, String resource );
|
||||
|
||||
public void serverResourceModified( DavServerComponent server, String resource );
|
||||
}
|
|
@ -1,74 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* DavServerManager
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: DavServerManager.java 6017 2007-03-06 00:39:53Z joakime $
|
||||
*/
|
||||
public interface DavServerManager
|
||||
{
|
||||
/** The Plexus ROLE name. */
|
||||
public static final String ROLE = DavServerManager.class.getName();
|
||||
|
||||
/**
|
||||
* Create a DavServerComponent and start tracking it.
|
||||
*
|
||||
* @param prefix the prefix for this component.
|
||||
* @param rootDirectory the root directory for this component's content. null to not set a root directory.
|
||||
* @return the created component, suitable for use.
|
||||
* @throws DavServerException
|
||||
*/
|
||||
public DavServerComponent createServer( String prefix, File rootDirectory ) throws DavServerException;
|
||||
|
||||
/**
|
||||
* Get the collection of tracked servers.
|
||||
*
|
||||
* @return Collection of {@link DavServerComponent} objects.
|
||||
*/
|
||||
public Collection getServers();
|
||||
|
||||
/**
|
||||
* Removes a specific server from the tracked list of servers.
|
||||
*
|
||||
* NOTE: This does not remove the associated files on disk, merely the reference being tracked.
|
||||
*
|
||||
* @param prefix the prefix to remove.
|
||||
*/
|
||||
public void removeServer( String prefix );
|
||||
|
||||
/**
|
||||
* Get the {@link DavServerComponent} associated with the specified prefix.
|
||||
*
|
||||
* @param prefix the prefix for the dav server component to use.
|
||||
* @return the DavServerComponent, or null if not found.
|
||||
*/
|
||||
public DavServerComponent getServer( String prefix );
|
||||
|
||||
/**
|
||||
* Remove all servers being tracked by the manager.
|
||||
*/
|
||||
public void removeAllServers();
|
||||
}
|
|
@ -1,88 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DefaultDavServerManager
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: DefaultDavServerManager.java 7009 2007-10-25 23:34:43Z joakime $
|
||||
*
|
||||
* @plexus.component role="org.apache.maven.archiva.webdav.DavServerManager" role-hint="default"
|
||||
*/
|
||||
public class DefaultDavServerManager
|
||||
implements DavServerManager
|
||||
{
|
||||
/**
|
||||
* @plexus.requirement role-hint="simple"
|
||||
*/
|
||||
private DavServerComponent server;
|
||||
|
||||
private Map servers;
|
||||
|
||||
public DefaultDavServerManager()
|
||||
{
|
||||
servers = new HashMap();
|
||||
}
|
||||
|
||||
public DavServerComponent createServer( String prefix, File rootDirectory )
|
||||
throws DavServerException
|
||||
{
|
||||
if ( servers.containsKey( prefix ) )
|
||||
{
|
||||
throw new DavServerException( "Unable to create a new server on a pre-existing prefix [" + prefix + "]" );
|
||||
}
|
||||
|
||||
server.setPrefix( prefix );
|
||||
if ( rootDirectory != null )
|
||||
{
|
||||
server.setRootDirectory( rootDirectory );
|
||||
}
|
||||
|
||||
servers.put( prefix, server );
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
public DavServerComponent getServer( String prefix )
|
||||
{
|
||||
return (DavServerComponent) servers.get( prefix );
|
||||
}
|
||||
|
||||
public void removeServer( String prefix )
|
||||
{
|
||||
servers.remove( prefix );
|
||||
}
|
||||
|
||||
public Collection getServers()
|
||||
{
|
||||
return servers.values();
|
||||
}
|
||||
|
||||
public void removeAllServers()
|
||||
{
|
||||
servers.clear();
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
|
@ -7,7 +9,7 @@
|
|||
* "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
|
||||
* 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
|
||||
|
@ -17,23 +19,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.servlet;
|
||||
|
||||
import org.apache.maven.archiva.webdav.util.WrappedRepositoryRequest;
|
||||
|
||||
/**
|
||||
* DavServerRequest
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: DavServerRequest.java 7073 2007-11-22 04:04:50Z brett $
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public interface DavServerRequest
|
||||
public class LogicalResource
|
||||
{
|
||||
public String getPrefix();
|
||||
private String path;
|
||||
|
||||
public String getLogicalResource();
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setLogicalResource( String logicalResource );
|
||||
|
||||
public WrappedRepositoryRequest getRequest();
|
||||
public void setPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
|
@ -7,7 +9,7 @@
|
|||
* "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
|
||||
* 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
|
||||
|
@ -17,35 +19,25 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav;
|
||||
import org.apache.jackrabbit.webdav.DavException;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* DavServerException
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: DavServerException.java 5379 2007-01-07 22:54:41Z joakime $
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class DavServerException
|
||||
extends Exception
|
||||
public class UnauthorizedDavException extends DavException
|
||||
{
|
||||
final private String repositoryName;
|
||||
|
||||
public DavServerException()
|
||||
public UnauthorizedDavException(String repositoryName, String message)
|
||||
{
|
||||
super(HttpServletResponse.SC_UNAUTHORIZED, message);
|
||||
this.repositoryName = repositoryName;
|
||||
}
|
||||
|
||||
public DavServerException( String message )
|
||||
public String getRepositoryName()
|
||||
{
|
||||
super( message );
|
||||
return repositoryName;
|
||||
}
|
||||
|
||||
public DavServerException( Throwable cause )
|
||||
{
|
||||
super( cause );
|
||||
}
|
||||
|
||||
public DavServerException( String message, Throwable cause )
|
||||
{
|
||||
super( message, cause );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,164 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.servlet;
|
||||
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.maven.archiva.webdav.DavServerManager;
|
||||
import org.codehaus.plexus.spring.PlexusToSpringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* AbstractWebDavServlet
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: AbstractWebDavServlet.java 7009 2007-10-25 23:34:43Z joakime $
|
||||
*/
|
||||
public abstract class AbstractWebDavServlet
|
||||
extends HttpServlet
|
||||
{
|
||||
public static final String INIT_USE_INDEX_HTML = "dav.use.index.html";
|
||||
|
||||
private boolean debug = false;
|
||||
|
||||
protected DavServerManager davManager;
|
||||
|
||||
public String getServletInfo()
|
||||
{
|
||||
return "Plexus WebDAV Servlet";
|
||||
}
|
||||
|
||||
public void init( ServletConfig config )
|
||||
throws ServletException
|
||||
{
|
||||
super.init( config );
|
||||
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( config.getServletContext() );
|
||||
davManager = (DavServerManager) wac.getBean( PlexusToSpringUtils.buildSpringId( DavServerManager.ROLE ) );
|
||||
if ( davManager == null )
|
||||
{
|
||||
throw new ServletException( "Unable to lookup davManager" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any authentication steps here.
|
||||
*
|
||||
* If authentication fails, it is the responsibility of the implementor to issue
|
||||
* the appropriate status codes and/or challenge back on the response object, then
|
||||
* return false on the overridden version of this method.
|
||||
*
|
||||
* To effectively not have authentication, just implement this method and always
|
||||
* return true.
|
||||
*
|
||||
* @param davRequest the incoming dav request.
|
||||
* @param httpResponse the outgoing http response.
|
||||
* @return true if user is authenticated, false if not.
|
||||
* @throws ServletException if there was a problem performing authencation.
|
||||
* @throws IOException if there was a problem obtaining credentials or issuing challenge.
|
||||
*/
|
||||
public boolean isAuthenticated( DavServerRequest davRequest, HttpServletResponse httpResponse )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// Always return true. Effectively no Authentication done.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any authorization steps here.
|
||||
*
|
||||
* If authorization fails, it is the responsibility of the implementor to issue
|
||||
* the appropriate status codes and/or challenge back on the response object, then
|
||||
* return false on the overridden version of this method.
|
||||
*
|
||||
* to effectively not have authorization, just implement this method and always
|
||||
* return true.
|
||||
*
|
||||
* @param davRequest
|
||||
* @param httpResponse
|
||||
* @return
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean isAuthorized( DavServerRequest davRequest, HttpServletResponse httpResponse )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// Always return true. Effectively no Authorization done.
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDebug()
|
||||
{
|
||||
return debug;
|
||||
}
|
||||
|
||||
public void setDebug( boolean debug )
|
||||
{
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
protected void requestDebug( HttpServletRequest request )
|
||||
{
|
||||
if ( debug )
|
||||
{
|
||||
System.out.println( "-->>> request ----------------------------------------------------------" );
|
||||
System.out.println( "--> " + request.getScheme() + "://" + request.getServerName() + ":"
|
||||
+ request.getServerPort() + request.getServletPath() );
|
||||
System.out.println( request.getMethod() + " " + request.getRequestURI()
|
||||
+ ( request.getQueryString() != null ? "?" + request.getQueryString() : "" ) + " " + "HTTP/1.1" );
|
||||
|
||||
Enumeration enHeaders = request.getHeaderNames();
|
||||
while ( enHeaders.hasMoreElements() )
|
||||
{
|
||||
String headerName = (String) enHeaders.nextElement();
|
||||
String headerValue = request.getHeader( headerName );
|
||||
System.out.println( headerName + ": " + headerValue );
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
|
||||
System.out.println( "------------------------------------------------------------------------" );
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void setUseIndexHtml( boolean useIndexHtml );
|
||||
|
||||
public boolean getUseIndexHtml( ServletConfig config )
|
||||
throws ServletException
|
||||
{
|
||||
String useIndexHtml = config.getInitParameter( INIT_USE_INDEX_HTML );
|
||||
|
||||
if ( StringUtils.isEmpty( useIndexHtml ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return BooleanUtils.toBoolean( useIndexHtml );
|
||||
}
|
||||
}
|
|
@ -1,67 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.servlet.basic;
|
||||
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
import org.apache.maven.archiva.webdav.util.WrappedRepositoryRequest;
|
||||
|
||||
/**
|
||||
* BasicDavServerRequest - for requests that have a prefix based off of the servlet path id.
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: BasicDavServerRequest.java 7073 2007-11-22 04:04:50Z brett $
|
||||
*/
|
||||
public class BasicDavServerRequest
|
||||
implements DavServerRequest
|
||||
{
|
||||
private WrappedRepositoryRequest request;
|
||||
|
||||
private String prefix;
|
||||
|
||||
private String logicalResource;
|
||||
|
||||
public BasicDavServerRequest( WrappedRepositoryRequest request )
|
||||
{
|
||||
this.request = request;
|
||||
this.prefix = request.getServletPath();
|
||||
this.logicalResource = request.getPathInfo();
|
||||
}
|
||||
|
||||
public void setLogicalResource( String logicalResource )
|
||||
{
|
||||
this.logicalResource = logicalResource;
|
||||
this.request.setPathInfo( logicalResource );
|
||||
}
|
||||
|
||||
public String getLogicalResource()
|
||||
{
|
||||
return this.logicalResource;
|
||||
}
|
||||
|
||||
public String getPrefix()
|
||||
{
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
public WrappedRepositoryRequest getRequest()
|
||||
{
|
||||
return request;
|
||||
}
|
||||
}
|
|
@ -1,142 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.servlet.basic;
|
||||
|
||||
import org.apache.maven.archiva.webdav.DavServerComponent;
|
||||
import org.apache.maven.archiva.webdav.DavServerException;
|
||||
import org.apache.maven.archiva.webdav.servlet.AbstractWebDavServlet;
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
import org.apache.maven.archiva.webdav.util.WrappedRepositoryRequest;
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* BasicWebDavServlet - Basic implementation of a single WebDAV server as servlet.
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: BasicWebDavServlet.java 6017 2007-03-06 00:39:53Z joakime $
|
||||
*/
|
||||
public class BasicWebDavServlet
|
||||
extends AbstractWebDavServlet
|
||||
{
|
||||
public static final String INIT_ROOT_DIRECTORY = "dav.root";
|
||||
|
||||
private DavServerComponent davServer;
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Servlet Implementation
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public void init( ServletConfig config )
|
||||
throws ServletException
|
||||
{
|
||||
super.init( config );
|
||||
|
||||
String prefix = config.getServletName();
|
||||
|
||||
boolean useIndexHtml = getUseIndexHtml( config );
|
||||
File rootDir = getRootDirectory( config );
|
||||
|
||||
if ( rootDir != null && !rootDir.isDirectory() )
|
||||
{
|
||||
log( "Invalid configuration, the dav root " + rootDir.getPath()
|
||||
+ " is not a directory: [" + rootDir.getAbsolutePath() + "]" );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
davServer = davManager.createServer( prefix, rootDir );
|
||||
davServer.setUseIndexHtml( useIndexHtml );
|
||||
davServer.init( config );
|
||||
}
|
||||
catch ( DavServerException e )
|
||||
{
|
||||
throw new ServletException( "Unable to create DAV Server component for prefix [" + prefix
|
||||
+ "] mapped to root directory [" + rootDir.getPath() + "]", e );
|
||||
}
|
||||
}
|
||||
|
||||
public File getRootDirectory( ServletConfig config )
|
||||
throws ServletException
|
||||
{
|
||||
String rootDirName = config.getInitParameter( INIT_ROOT_DIRECTORY );
|
||||
|
||||
if ( StringUtils.isEmpty( rootDirName ) )
|
||||
{
|
||||
log( "Init Parameter '" + INIT_ROOT_DIRECTORY + "' is empty." );
|
||||
return null;
|
||||
}
|
||||
|
||||
return new File( rootDirName );
|
||||
}
|
||||
|
||||
protected void service( HttpServletRequest httpRequest, HttpServletResponse httpResponse )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
DavServerRequest davRequest = new BasicDavServerRequest( new WrappedRepositoryRequest( httpRequest ) );
|
||||
|
||||
if ( davServer == null )
|
||||
{
|
||||
throw new ServletException( "Unable to service DAV request due to unconfigured DavServerComponent." );
|
||||
}
|
||||
|
||||
requestDebug( httpRequest );
|
||||
|
||||
if ( !isAuthenticated( davRequest, httpResponse ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !isAuthorized( davRequest, httpResponse ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
davServer.process( davRequest, httpResponse );
|
||||
}
|
||||
catch ( DavServerException e )
|
||||
{
|
||||
throw new ServletException( "Unable to process request.", e );
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseIndexHtml( boolean useIndexHtml )
|
||||
{
|
||||
davServer.setUseIndexHtml( useIndexHtml );
|
||||
}
|
||||
|
||||
public DavServerComponent getDavServer()
|
||||
{
|
||||
return davServer;
|
||||
}
|
||||
|
||||
public void setDavServer( DavServerComponent davServer )
|
||||
{
|
||||
this.davServer = davServer;
|
||||
}
|
||||
}
|
|
@ -1,123 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.servlet.multiplexed;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
import org.apache.maven.archiva.webdav.util.WrappedRepositoryRequest;
|
||||
|
||||
/**
|
||||
* <p/>
|
||||
* MultiplexedDavServerRequest - For requests that contain the server prefix information within the requested
|
||||
* servlet's pathInfo parameter (as the first path entry).
|
||||
* </p>
|
||||
* <p/>
|
||||
* <p/>
|
||||
* You would use this dav server request object when you are working with a single servlet that is handling
|
||||
* multiple dav server components.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: MultiplexedDavServerRequest.java 7073 2007-11-22 04:04:50Z brett $
|
||||
*/
|
||||
public class MultiplexedDavServerRequest
|
||||
implements DavServerRequest
|
||||
{
|
||||
private WrappedRepositoryRequest request;
|
||||
|
||||
private String prefix;
|
||||
|
||||
private String logicalResource;
|
||||
|
||||
public MultiplexedDavServerRequest( WrappedRepositoryRequest request )
|
||||
{
|
||||
String requestPathInfo = StringUtils.defaultString( request.getPathInfo() );
|
||||
|
||||
// Remove prefixing slash as the repository id doesn't contain it;
|
||||
if ( requestPathInfo.startsWith( "/" ) )
|
||||
{
|
||||
requestPathInfo = requestPathInfo.substring( 1 );
|
||||
}
|
||||
|
||||
// Find first element, if slash exists.
|
||||
int slash = requestPathInfo.indexOf( '/' );
|
||||
if ( slash > 0 )
|
||||
{
|
||||
// Filtered: "central/org/apache/maven/" -> "central"
|
||||
this.prefix = requestPathInfo.substring( 0, slash );
|
||||
|
||||
this.logicalResource = requestPathInfo.substring( slash );
|
||||
|
||||
if ( this.logicalResource.endsWith( "/.." ) )
|
||||
{
|
||||
this.logicalResource += "/";
|
||||
}
|
||||
|
||||
/* Perform a simple security normalization of the requested pathinfo.
|
||||
* This is to prevent requests for information outside of the root directory.
|
||||
*/
|
||||
this.logicalResource = FilenameUtils.normalize( logicalResource );
|
||||
|
||||
if ( logicalResource != null )
|
||||
{
|
||||
logicalResource = logicalResource.replace( '\\', '/' );
|
||||
|
||||
if ( logicalResource.startsWith( "//" ) )
|
||||
{
|
||||
logicalResource = logicalResource.substring( 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.logicalResource = "/";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.prefix = requestPathInfo;
|
||||
this.logicalResource = "/";
|
||||
}
|
||||
|
||||
this.request = request;
|
||||
this.request.setPathInfo( logicalResource );
|
||||
}
|
||||
|
||||
public void setLogicalResource( String logicalResource )
|
||||
{
|
||||
this.logicalResource = logicalResource;
|
||||
this.request.setPathInfo( logicalResource );
|
||||
}
|
||||
|
||||
public String getLogicalResource()
|
||||
{
|
||||
return this.logicalResource;
|
||||
}
|
||||
|
||||
public String getPrefix()
|
||||
{
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
public WrappedRepositoryRequest getRequest()
|
||||
{
|
||||
return request;
|
||||
}
|
||||
}
|
|
@ -1,137 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.servlet.multiplexed;
|
||||
|
||||
import org.apache.maven.archiva.webdav.DavServerComponent;
|
||||
import org.apache.maven.archiva.webdav.DavServerException;
|
||||
import org.apache.maven.archiva.webdav.DavServerManager;
|
||||
import org.apache.maven.archiva.webdav.servlet.AbstractWebDavServlet;
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
import org.apache.maven.archiva.webdav.util.WrappedRepositoryRequest;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* MultiplexedWebDavServlet - and abstracted multiplexed webdav servlet.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Implementations of this servlet should override the {@link #initServers} method and create all of the
|
||||
* appropriate DavServerComponents needed using the {@link DavServerManager} obtained via the {@link #getDavManager()}
|
||||
* method.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: MultiplexedWebDavServlet.java 6000 2007-03-04 22:01:49Z joakime $
|
||||
*/
|
||||
public abstract class MultiplexedWebDavServlet
|
||||
extends AbstractWebDavServlet
|
||||
{
|
||||
private boolean useIndexHtml = false;
|
||||
|
||||
public void init( ServletConfig config )
|
||||
throws ServletException
|
||||
{
|
||||
super.init( config );
|
||||
|
||||
this.useIndexHtml = getUseIndexHtml( config );
|
||||
|
||||
try
|
||||
{
|
||||
initServers( config );
|
||||
}
|
||||
catch ( DavServerException e )
|
||||
{
|
||||
throw new ServletException( e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create any DavServerComponents here.
|
||||
* Use the {@link #createServer(String, File, ServletConfig)} method to create your servers.
|
||||
*
|
||||
* @param config the config to use.
|
||||
* @throws DavServerException if there was a problem initializing the server components.
|
||||
*/
|
||||
public abstract void initServers( ServletConfig config )
|
||||
throws DavServerException;
|
||||
|
||||
public DavServerComponent createServer( String prefix, File rootDirectory, ServletConfig config )
|
||||
throws DavServerException
|
||||
{
|
||||
DavServerComponent serverComponent = davManager.createServer( prefix, rootDirectory );
|
||||
serverComponent.setUseIndexHtml( useIndexHtml );
|
||||
serverComponent.init( config );
|
||||
return serverComponent;
|
||||
}
|
||||
|
||||
protected void service( HttpServletRequest httpRequest, HttpServletResponse httpResponse )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
DavServerRequest davRequest = new MultiplexedDavServerRequest( new WrappedRepositoryRequest( httpRequest ) );
|
||||
|
||||
DavServerComponent davServer = davManager.getServer( davRequest.getPrefix() );
|
||||
|
||||
if ( davServer == null )
|
||||
{
|
||||
String errorMessage = "[" + davRequest.getPrefix() + "] Not Found (Likely Unconfigured).";
|
||||
httpResponse.sendError( HttpURLConnection.HTTP_NOT_FOUND, errorMessage );
|
||||
return;
|
||||
}
|
||||
|
||||
requestDebug( httpRequest );
|
||||
|
||||
if ( !isAuthenticated( davRequest, httpResponse ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !isAuthorized( davRequest, httpResponse ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
davServer.process( davRequest, httpResponse );
|
||||
}
|
||||
catch ( DavServerException e )
|
||||
{
|
||||
throw new ServletException( "Unable to process request.", e );
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseIndexHtml( boolean useIndexHtml )
|
||||
{
|
||||
for ( Iterator it = davManager.getServers().iterator(); it.hasNext(); )
|
||||
{
|
||||
DavServerComponent davServer = (DavServerComponent) it.next();
|
||||
davServer.setUseIndexHtml( useIndexHtml );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,130 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.simple;
|
||||
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVMultiStatus;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* HackedMoveMethod - Created to address the needs for inter-repository moves.
|
||||
*
|
||||
* @author Pier Fumagalli (Original it.could.webdav 0.4 version)
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> (Hacked Version)
|
||||
* @version $Id: HackedMoveMethod.java 6000 2007-03-04 22:01:49Z joakime $
|
||||
*/
|
||||
public class HackedMoveMethod
|
||||
implements DAVMethod
|
||||
{
|
||||
|
||||
public HackedMoveMethod()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>MOVE</code> method.</p>
|
||||
*/
|
||||
public void process( DAVTransaction transaction, DAVResource resource )
|
||||
throws IOException
|
||||
{
|
||||
URI target = transaction.getDestination();
|
||||
if ( target == null )
|
||||
throw new DAVException( 412, "No destination" );
|
||||
|
||||
if ( target.getScheme() == null )
|
||||
{
|
||||
// This is a relative file system destination target.
|
||||
DAVResource dest = resource.getRepository().getResource( target );
|
||||
moveWithinRepository( transaction, resource, dest );
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a inter-repository move request.
|
||||
URI dest = target;
|
||||
moveInterRepository( transaction, resource, dest );
|
||||
}
|
||||
}
|
||||
|
||||
private void moveInterRepository( DAVTransaction transaction, DAVResource resource, URI dest )
|
||||
throws DAVException
|
||||
{
|
||||
/* TODO: Figure out how to handle a Repository to Repository MOVE of content, and still maintain
|
||||
* the security credentials from the original request. (Need to support NTLM, Digest, BASIC)
|
||||
*
|
||||
* IDEA: Could support non-secured Webdav Destination using slide client libraries.
|
||||
*/
|
||||
transaction.setStatus( 501 );
|
||||
throw new DAVException( 501, "Server side MOVE to external WebDAV instance not supported." );
|
||||
}
|
||||
|
||||
private void moveWithinRepository( DAVTransaction transaction, DAVResource resource, DAVResource dest )
|
||||
throws IOException
|
||||
{
|
||||
int depth = transaction.getDepth();
|
||||
boolean recursive = false;
|
||||
if ( depth == 0 )
|
||||
{
|
||||
recursive = false;
|
||||
}
|
||||
else if ( depth == DAVTransaction.INFINITY )
|
||||
{
|
||||
recursive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DAVException( 412, "Invalid Depth specified" );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int status;
|
||||
if ( !dest.isNull() && !transaction.getOverwrite() )
|
||||
{
|
||||
status = 412; // MOVE-on-existing should fail with 412
|
||||
}
|
||||
else
|
||||
{
|
||||
resource.copy( dest, transaction.getOverwrite(), recursive );
|
||||
resource.delete();
|
||||
|
||||
if ( transaction.getOverwrite() )
|
||||
{
|
||||
status = 204; // No Content
|
||||
}
|
||||
else
|
||||
{
|
||||
status = 201; // Created
|
||||
}
|
||||
}
|
||||
transaction.setStatus( status );
|
||||
}
|
||||
catch ( DAVMultiStatus multistatus )
|
||||
{
|
||||
multistatus.write( transaction );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,303 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.simple;
|
||||
|
||||
import it.could.util.StreamTools;
|
||||
import it.could.webdav.DAVException;
|
||||
import it.could.webdav.DAVInputStream;
|
||||
import it.could.webdav.DAVMethod;
|
||||
import it.could.webdav.DAVNotModified;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
import it.could.webdav.DAVUtilities;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.maven.archiva.webdav.util.MimeTypes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* ReplacementGetMethod
|
||||
*
|
||||
* @author Pier Fumagalli (Original it.could.webdav 0.4 version)
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> (Replacement Version)
|
||||
* @version $Id: ReplacementGetMethod.java 7002 2007-10-23 22:40:37Z joakime $
|
||||
*
|
||||
* @plexus.component
|
||||
* role="it.could.webdav.DAVMethod"
|
||||
* role-hint="get-with-indexing"
|
||||
*/
|
||||
public class ReplacementGetMethod implements DAVMethod
|
||||
{
|
||||
/** <p>The encoding charset to repsesent collections.</p> */
|
||||
public static final String ENCODING = "UTF-8";
|
||||
|
||||
/** <p>The mime type that {@link ReplacementGetMethod} will use serving index.html files.</p> */
|
||||
public static final String HTML_MIME_TYPE = "text/html";
|
||||
|
||||
/** <p>The mime type that {@link ReplacementGetMethod} will use serving collections.</p> */
|
||||
public static final String COLLECTION_MIME_TYPE = HTML_MIME_TYPE + "; charset=\"" + ENCODING + "\"";
|
||||
|
||||
/** <p>The header for content disposition.</p> */
|
||||
public static final String CONTENT_DISPOSITION = "Content-Disposition";
|
||||
|
||||
/** <p>The content-disposition for fancy-indexing.</p> */
|
||||
public static final String INLINE_INDEX_HTML = "inline; filename=\"index.html\"";
|
||||
|
||||
/**
|
||||
* @plexus.requirement
|
||||
*/
|
||||
private MimeTypes mimeTypes;
|
||||
|
||||
private boolean useIndexHtml = false;
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link ReplacementGetMethod} instance.</p>
|
||||
*/
|
||||
public ReplacementGetMethod()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Process the <code>GET</code> method.</p>
|
||||
*/
|
||||
public void process( DAVTransaction transaction, DAVResource resource ) throws IOException
|
||||
{
|
||||
// Handle boilerplate
|
||||
if ( resource.isNull() )
|
||||
throw new DAVException( 404, "Not found", resource );
|
||||
|
||||
notModified( transaction, resource );
|
||||
|
||||
copyHeaders( transaction, resource );
|
||||
|
||||
// Process the request.
|
||||
final String originalPath = transaction.getOriginalPath();
|
||||
final String normalizedPath = transaction.getNormalizedPath();
|
||||
final String current;
|
||||
final String parent;
|
||||
|
||||
if ( originalPath.equals( normalizedPath ) )
|
||||
{
|
||||
final String relativePath = resource.getRelativePath();
|
||||
if ( relativePath.equals( "" ) )
|
||||
{
|
||||
current = transaction.lookup( resource ).toASCIIString();
|
||||
}
|
||||
else
|
||||
{
|
||||
current = relativePath;
|
||||
}
|
||||
parent = "./";
|
||||
}
|
||||
else
|
||||
{
|
||||
current = "./";
|
||||
parent = "../";
|
||||
}
|
||||
|
||||
if ( resource.isCollection() )
|
||||
{
|
||||
DAVResource indexHtml = null;
|
||||
|
||||
if ( useIndexHtml )
|
||||
{
|
||||
for ( Iterator it = resource.getChildren(); it.hasNext(); )
|
||||
{
|
||||
DAVResource child = (DAVResource) it.next();
|
||||
String name = child.getDisplayName().toLowerCase();
|
||||
if ( StringUtils.equals( "index.html", name ) || StringUtils.equals( "index.htm", name ) )
|
||||
{
|
||||
indexHtml = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( useIndexHtml && indexHtml != null )
|
||||
{
|
||||
transaction.setContentType( COLLECTION_MIME_TYPE );
|
||||
transaction.setHeader( CONTENT_DISPOSITION, INLINE_INDEX_HTML );
|
||||
sendResource( transaction, indexHtml );
|
||||
}
|
||||
else
|
||||
{
|
||||
transaction.setContentType( COLLECTION_MIME_TYPE );
|
||||
transaction.setHeader( CONTENT_DISPOSITION, INLINE_INDEX_HTML );
|
||||
sendFancyIndex( transaction, resource, current, parent );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Processing a normal resource request */
|
||||
transaction.setContentType( mimeTypes.getMimeType( resource.getDisplayName() ) );
|
||||
transaction.setHeader( CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getDisplayName() + "\"" );
|
||||
sendResource( transaction, resource );
|
||||
}
|
||||
}
|
||||
|
||||
private void copyHeaders( DAVTransaction transaction, DAVResource resource )
|
||||
{
|
||||
/* Get the headers of this method */
|
||||
String ctyp = resource.getContentType();
|
||||
String etag = resource.getEntityTag();
|
||||
String lmod = DAVUtilities.formatHttpDate( resource.getLastModified() );
|
||||
String clen = DAVUtilities.formatNumber( resource.getContentLength() );
|
||||
|
||||
/* Set the normal headers that are required for a GET */
|
||||
if ( ctyp != null )
|
||||
{
|
||||
transaction.setContentType( ctyp );
|
||||
}
|
||||
|
||||
if ( etag != null )
|
||||
{
|
||||
transaction.setHeader( "ETag", etag );
|
||||
}
|
||||
|
||||
if ( lmod != null )
|
||||
{
|
||||
transaction.setHeader( "Last-Modified", lmod );
|
||||
}
|
||||
|
||||
if ( clen != null )
|
||||
{
|
||||
transaction.setHeader( "Content-Length", clen );
|
||||
}
|
||||
}
|
||||
|
||||
private void sendResource( DAVTransaction transaction, DAVResource resource ) throws IOException
|
||||
{
|
||||
OutputStream out = null;
|
||||
DAVInputStream in = null;
|
||||
|
||||
try
|
||||
{
|
||||
out = transaction.write();
|
||||
in = resource.read();
|
||||
|
||||
byte buffer[] = new byte[4096 * 16];
|
||||
int k = -1;
|
||||
while ( ( k = in.read( buffer ) ) != -1 )
|
||||
{
|
||||
out.write( buffer, 0, k );
|
||||
}
|
||||
|
||||
out.flush();
|
||||
}
|
||||
finally
|
||||
{
|
||||
StreamTools.close( in );
|
||||
StreamTools.close( out );
|
||||
}
|
||||
}
|
||||
|
||||
private void sendFancyIndex( DAVTransaction transaction, DAVResource resource, final String current,
|
||||
final String parent ) throws IOException
|
||||
{
|
||||
PrintWriter out = transaction.write( ENCODING );
|
||||
String path = resource.getRelativePath();
|
||||
out.println( "<html>" );
|
||||
out.println( "<head>" );
|
||||
out.println( "<title>Collection: /" + path + "</title>" );
|
||||
out.println( "</head>" );
|
||||
out.println( "<body>" );
|
||||
out.println( "<h2>Collection: /" + path + "</h2>" );
|
||||
out.println( "<ul>" );
|
||||
|
||||
/* Process the parent */
|
||||
final DAVResource parentResource = resource.getParent();
|
||||
if ( parentResource != null )
|
||||
{
|
||||
out.print( "<li><a href=\"" );
|
||||
out.print( parent );
|
||||
out.print( "\">" );
|
||||
out.print( parentResource.getDisplayName() );
|
||||
out.println( "</a> <i><small>(Parent)</small></i></li>" );
|
||||
out.println( "</ul>" );
|
||||
out.println( "<ul>" );
|
||||
}
|
||||
|
||||
/* Process the children (in two sorted sets, for nice ordering) */
|
||||
Set resources = new TreeSet();
|
||||
Set collections = new TreeSet();
|
||||
Iterator iterator = resource.getChildren();
|
||||
while ( iterator.hasNext() )
|
||||
{
|
||||
final DAVResource child = (DAVResource) iterator.next();
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
final String childPath = child.getDisplayName();
|
||||
buffer.append( "<li><a href=\"" );
|
||||
buffer.append( current );
|
||||
buffer.append( childPath );
|
||||
buffer.append( "\">" );
|
||||
buffer.append( childPath );
|
||||
buffer.append( "</li>" );
|
||||
if ( child.isCollection() )
|
||||
{
|
||||
collections.add( buffer.toString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
resources.add( buffer.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
/* Spit out the collections first and the resources then */
|
||||
for ( Iterator i = collections.iterator(); i.hasNext(); )
|
||||
out.println( i.next() );
|
||||
for ( Iterator i = resources.iterator(); i.hasNext(); )
|
||||
out.println( i.next() );
|
||||
|
||||
out.println( "</ul>" );
|
||||
out.println( "</body>" );
|
||||
out.println( "</html>" );
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private void notModified( DAVTransaction transaction, DAVResource resource )
|
||||
{
|
||||
Date ifmod = transaction.getIfModifiedSince();
|
||||
Date lsmod = resource.getLastModified();
|
||||
if ( resource.isResource() && ( ifmod != null ) && ( lsmod != null ) )
|
||||
{
|
||||
/* HTTP doesn't send milliseconds, but Java does, so, reset them */
|
||||
lsmod = new Date( ( (long) ( lsmod.getTime() / 1000 ) ) * 1000 );
|
||||
if ( !ifmod.before( lsmod ) )
|
||||
throw new DAVNotModified( resource );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUseIndexHtml()
|
||||
{
|
||||
return useIndexHtml;
|
||||
}
|
||||
|
||||
public void setUseIndexHtml( boolean useIndexHtml )
|
||||
{
|
||||
this.useIndexHtml = useIndexHtml;
|
||||
}
|
||||
}
|
|
@ -1,185 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.simple;
|
||||
|
||||
import it.could.webdav.DAVListener;
|
||||
import it.could.webdav.DAVProcessor;
|
||||
import it.could.webdav.DAVRepository;
|
||||
import it.could.webdav.DAVResource;
|
||||
import it.could.webdav.DAVTransaction;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.maven.archiva.webdav.AbstractDavServerComponent;
|
||||
import org.apache.maven.archiva.webdav.DavServerException;
|
||||
import org.apache.maven.archiva.webdav.servlet.DavServerRequest;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* SimpleDavServerComponent
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: SimpleDavServerComponent.java 7097 2007-11-30 12:57:29Z handyande $
|
||||
*
|
||||
* @plexus.component role="org.apache.maven.archiva.webdav.DavServerComponent"
|
||||
* role-hint="simple"
|
||||
* instantiation-strategy="per-lookup"
|
||||
*/
|
||||
public class SimpleDavServerComponent
|
||||
extends AbstractDavServerComponent
|
||||
implements DAVListener
|
||||
{
|
||||
/**
|
||||
* @plexus.requirement
|
||||
* role="it.could.webdav.DAVMethod"
|
||||
* role-hint="get-with-indexing"
|
||||
*/
|
||||
public ReplacementGetMethod methodGet;
|
||||
|
||||
private String prefix;
|
||||
|
||||
private File rootDirectory;
|
||||
|
||||
private DAVRepository davRepository;
|
||||
|
||||
private DAVProcessor davProcessor;
|
||||
|
||||
public String getPrefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public File getRootDirectory()
|
||||
{
|
||||
return rootDirectory;
|
||||
}
|
||||
|
||||
public void setPrefix( String prefix )
|
||||
{
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public void setRootDirectory( File rootDirectory )
|
||||
{
|
||||
this.rootDirectory = rootDirectory;
|
||||
}
|
||||
|
||||
public void init( ServletConfig servletConfig )
|
||||
throws DavServerException
|
||||
{
|
||||
servletConfig.getServletContext().log( "Initializing " + this.getClass().getName() );
|
||||
try
|
||||
{
|
||||
davRepository = new DAVRepository( rootDirectory );
|
||||
davProcessor = new DAVProcessor( davRepository );
|
||||
davRepository.addListener( this );
|
||||
|
||||
hackDavProcessor( davProcessor );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
throw new DavServerException( "Unable to initialize DAVRepository.", e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the problematic dav methods with local hacked versions.
|
||||
*
|
||||
* @param davProcessor
|
||||
* @throws DavServerException
|
||||
*/
|
||||
private void hackDavProcessor( DAVProcessor davProcessor )
|
||||
throws DavServerException
|
||||
{
|
||||
davProcessor.setMethod( "MOVE", new HackedMoveMethod() );
|
||||
davProcessor.setMethod( "GET", methodGet );
|
||||
|
||||
/* Reflection based technique.
|
||||
try
|
||||
{
|
||||
Field fldInstance = davProcessor.getClass().getDeclaredField( "INSTANCES" );
|
||||
fldInstance.setAccessible( true );
|
||||
|
||||
Map mapInstances = (Map) fldInstance.get( davProcessor );
|
||||
|
||||
// Replace MOVE method.
|
||||
// TODO: Remove MOVE method when upgrading it.could.webdav to v0.5
|
||||
mapInstances.put( "MOVE", (DAVMethod) new HackedMoveMethod() );
|
||||
|
||||
// Replace GET method.
|
||||
mapInstances.put( "GET", (DAVMethod) methodGet );
|
||||
}
|
||||
catch ( Throwable e )
|
||||
{
|
||||
throw new DavServerException( "Unable to twiddle DAVProcessor.INSTANCES field.", e );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void process( DavServerRequest request, HttpServletResponse response )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
DAVTransaction transaction = new DAVTransaction( request.getRequest(), response );
|
||||
|
||||
/* BEGIN - it.could.webdav hacks
|
||||
* TODO: Remove hacks with release of it.could.webdav 0.5 (or newer)
|
||||
*/
|
||||
String depthValue = request.getRequest().getHeader( "Depth" );
|
||||
if ( StringUtils.equalsIgnoreCase( "infinity", depthValue ) )
|
||||
{
|
||||
// See - http://could.it/bugs/browse/DAV-3
|
||||
request.getRequest().setHeader( "Depth", "infinity" );
|
||||
}
|
||||
/* END - it.could.webdav hacks */
|
||||
|
||||
davProcessor.process( transaction );
|
||||
}
|
||||
|
||||
public void notify( DAVResource resource, int event )
|
||||
{
|
||||
switch ( event )
|
||||
{
|
||||
case DAVListener.COLLECTION_CREATED:
|
||||
triggerCollectionCreated( resource.getRelativePath() );
|
||||
break;
|
||||
case DAVListener.COLLECTION_REMOVED:
|
||||
triggerCollectionRemoved( resource.getRelativePath() );
|
||||
break;
|
||||
case DAVListener.RESOURCE_CREATED:
|
||||
triggerResourceCreated( resource.getRelativePath() );
|
||||
break;
|
||||
case DAVListener.RESOURCE_REMOVED:
|
||||
triggerResourceRemoved( resource.getRelativePath() );
|
||||
break;
|
||||
case DAVListener.RESOURCE_MODIFIED:
|
||||
triggerResourceModified( resource.getRelativePath() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseIndexHtml( boolean useIndexHtml )
|
||||
{
|
||||
super.setUseIndexHtml( useIndexHtml );
|
||||
this.methodGet.setUseIndexHtml( useIndexHtml );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package org.apache.maven.archiva.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.jackrabbit.webdav.DavResource;
|
||||
import org.apache.jackrabbit.webdav.io.OutputContext;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class IndexWriter
|
||||
{
|
||||
private final DavResource resource;
|
||||
|
||||
private final File localResource;
|
||||
|
||||
private final String logicalResource;
|
||||
|
||||
public IndexWriter(DavResource resource, File localResource, String logicalResource)
|
||||
{
|
||||
this.resource = resource;
|
||||
this.localResource = localResource;
|
||||
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>Collection: " + logicalResource + "<title>");
|
||||
writer.println("</head>");
|
||||
writer.println("<h3>Collection: " + logicalResource + "</h3>");
|
||||
|
||||
//Check if not root
|
||||
if (!"/".equals(logicalResource))
|
||||
{
|
||||
File file = new File(logicalResource);
|
||||
String parentName = file.getParent().equals("") ? "/" : file.getParent();
|
||||
|
||||
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 file : localResource.listFiles())
|
||||
{
|
||||
writeHyperlink(writer, file.getName(), file.isDirectory());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHyperlink(PrintWriter writer, String resourceName, boolean directory)
|
||||
{
|
||||
if (directory)
|
||||
{
|
||||
writer.println("<li><a href=\"./" + resourceName + "/\">" + resourceName + "</a></li>");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.println("<li><a href=\"./" + resourceName + "\">" + resourceName + "</a></li>");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.maven.archiva.webdav.util;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
|
@ -7,7 +9,7 @@
|
|||
* "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
|
||||
* 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
|
||||
|
@ -17,8 +19,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.util;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.codehaus.plexus.logging.AbstractLogEnabled;
|
||||
|
@ -49,10 +49,9 @@ public class MimeTypes
|
|||
extends AbstractLogEnabled
|
||||
implements Initializable
|
||||
{
|
||||
/**
|
||||
* @plexus.configuration default-value="org/apache/maven/archiva/webdav/util/mime-types.txt"
|
||||
*/
|
||||
private String resource;
|
||||
private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
|
||||
|
||||
private String resource = "org/apache/maven/archiva/webdav/util/mime.types";
|
||||
|
||||
private Map mimeMap = new HashMap();
|
||||
|
||||
|
@ -74,6 +73,13 @@ public class MimeTypes
|
|||
value = (String) mimeMap.get( filename.substring( index + 1 ).toLowerCase() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = DEFAULT_MIME_TYPE;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package org.apache.maven.archiva.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.StringUtils;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:james@atlassian.com">James William Dumay</a>
|
||||
*/
|
||||
public class RepositoryPathUtil
|
||||
{
|
||||
public static String getLogicalResource(final String href)
|
||||
{
|
||||
String logicalResource = null;
|
||||
String requestPathInfo = StringUtils.defaultString( href );
|
||||
|
||||
//remove prefix ie /repository/blah becomes /blah
|
||||
requestPathInfo = removePrefix(requestPathInfo);
|
||||
|
||||
// Remove prefixing slash as the repository 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 String getRepositoryName(final String href)
|
||||
{
|
||||
String requestPathInfo = StringUtils.defaultString( href );
|
||||
|
||||
//remove prefix ie /repository/blah becomes /blah
|
||||
requestPathInfo = removePrefix(requestPathInfo);
|
||||
|
||||
// Remove prefixing slash as the repository id doesn't contain it;
|
||||
if ( requestPathInfo.startsWith( "/" ) )
|
||||
{
|
||||
requestPathInfo = requestPathInfo.substring( 1 );
|
||||
}
|
||||
|
||||
// Find first element, if slash exists.
|
||||
int slash = requestPathInfo.indexOf( '/' );
|
||||
if ( slash > 0 )
|
||||
{
|
||||
// Filtered: "central/org/apache/maven/" -> "central"
|
||||
return requestPathInfo.substring( 0, slash );
|
||||
}
|
||||
return requestPathInfo;
|
||||
}
|
||||
|
||||
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 "/";
|
||||
}
|
||||
return StringUtils.join(parts, '/');
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.maven.archiva.webdav.util;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
|
@ -7,7 +9,7 @@
|
|||
* "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
|
||||
* 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
|
||||
|
@ -17,8 +19,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.util;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -1,184 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.util;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* RepositoryRequest - wrapped servlet request to adjust the incoming request before the components get it.
|
||||
* It eliminates the prefix from the pathInfo portion of the URL requested.
|
||||
* And also allows for Header adjustment.
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: WrappedRepositoryRequest.java 7001 2007-10-23 22:40:14Z joakime $
|
||||
*/
|
||||
public class WrappedRepositoryRequest
|
||||
extends HttpServletRequestWrapper
|
||||
{
|
||||
private String pathInfo;
|
||||
|
||||
private Map headers;
|
||||
|
||||
/**
|
||||
* The Date Formats most commonly seen in Request Headers.
|
||||
*/
|
||||
private SimpleDateFormat dateFormats[];
|
||||
|
||||
public WrappedRepositoryRequest( HttpServletRequest request )
|
||||
{
|
||||
super( request );
|
||||
|
||||
dateFormats = new SimpleDateFormat[] {
|
||||
new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss zzz" ),
|
||||
new SimpleDateFormat( "EEE, dd-MMM-yy HH:mm:ss" ),
|
||||
new SimpleDateFormat( "EEE MMM dd HH:mm:ss yyyy" ) };
|
||||
|
||||
headers = new HashMap();
|
||||
|
||||
Enumeration enHeaders = request.getHeaderNames();
|
||||
while ( enHeaders.hasMoreElements() )
|
||||
{
|
||||
String name = (String) enHeaders.nextElement();
|
||||
String value = request.getHeader( name );
|
||||
headers.put( name, value );
|
||||
}
|
||||
}
|
||||
|
||||
public void setHeader( String name, String value )
|
||||
{
|
||||
headers.put( name, value );
|
||||
}
|
||||
|
||||
public long getDateHeader( String name )
|
||||
{
|
||||
String value = (String) headers.get( name );
|
||||
if ( StringUtils.isEmpty( value ) )
|
||||
{
|
||||
// no value? return -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Try most common formats first.
|
||||
for ( int i = 0; i < dateFormats.length; i++ )
|
||||
{
|
||||
try
|
||||
{
|
||||
Date date = (Date) dateFormats[i].parseObject( value );
|
||||
return date.getTime();
|
||||
}
|
||||
catch ( java.lang.Exception e )
|
||||
{
|
||||
/* ignore exception */
|
||||
}
|
||||
}
|
||||
|
||||
// Now check for the odd "GMT" formats (hey, it happens)
|
||||
if ( value.endsWith( " GMT" ) )
|
||||
{
|
||||
value = value.substring( 0, value.length() - 4 );
|
||||
|
||||
for ( int i = 0; i < dateFormats.length; i++ )
|
||||
{
|
||||
try
|
||||
{
|
||||
Date date = (Date) dateFormats[i].parseObject( value );
|
||||
return date.getTime();
|
||||
}
|
||||
catch ( java.lang.Exception e )
|
||||
{
|
||||
/* ignore exception */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unrecognized format? return -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String getHeader( String name )
|
||||
{
|
||||
return (String) headers.get( name );
|
||||
}
|
||||
|
||||
public Enumeration getHeaderNames()
|
||||
{
|
||||
return new Enumeration()
|
||||
{
|
||||
private Iterator iter = headers.keySet().iterator();
|
||||
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return iter.hasNext();
|
||||
}
|
||||
|
||||
public Object nextElement()
|
||||
{
|
||||
return iter.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int getIntHeader( String name )
|
||||
{
|
||||
String value = getHeader( name );
|
||||
try
|
||||
{
|
||||
return Integer.parseInt( value );
|
||||
}
|
||||
catch ( NumberFormatException e )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void setPathInfo( String alternatePathInfo )
|
||||
{
|
||||
this.pathInfo = alternatePathInfo;
|
||||
}
|
||||
|
||||
public String getPathInfo()
|
||||
{
|
||||
if ( this.pathInfo != null )
|
||||
{
|
||||
return this.pathInfo;
|
||||
}
|
||||
|
||||
return super.getPathInfo();
|
||||
}
|
||||
|
||||
public String getServletPath()
|
||||
{
|
||||
if ( this.pathInfo != null )
|
||||
{
|
||||
return super.getServletPath() + "/" + this.pathInfo;
|
||||
}
|
||||
|
||||
return super.getServletPath();
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/* ========================================================================== *
|
||||
* Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/> *
|
||||
* All rights reserved. *
|
||||
* ========================================================================== *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
|
||||
* not use this file except in compliance with the License. You may obtain a *
|
||||
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
|
||||
* License for the specific language governing permissions and limitations *
|
||||
* under the License. *
|
||||
* *
|
||||
* ========================================================================== */
|
||||
package org.betaversion.webdav;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* <p>The {@link DAVServlet} class has been moved to a new package and should
|
||||
* now be referred as {@link it.could.webdav.DAVServlet}.</p>
|
||||
*
|
||||
* <p>This class will be preserved for some time (not so long) to give people
|
||||
* time to update their servlet deployment descriptors.</p>
|
||||
*
|
||||
* @author <a href="http://could.it/">Pier Fumagalli</a>
|
||||
* @deprecated This class has been moved into the <code>it.could.webdav</code>
|
||||
* package. Reconfigure your <code>web.xml</code> deployment
|
||||
* descriptor to use {@link it.could.webdav.DAVServlet}.
|
||||
*/
|
||||
public class DAVServlet extends it.could.webdav.DAVServlet {
|
||||
|
||||
/**
|
||||
* <p>Create a new {@link DAVServlet} instance.</p>
|
||||
*/
|
||||
public DAVServlet() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Initialize this {@link DAVServlet} instance reporting to the
|
||||
* {@link ServletContext} log that this class is deprecated.</p>
|
||||
*/
|
||||
public void init(ServletConfig config)
|
||||
throws ServletException {
|
||||
final ServletContext context = config.getServletContext();
|
||||
context.log("The class \"" + this.getClass().getName()
|
||||
+ "\" is deprecated");
|
||||
context.log("Modify the \"web.xml\" deployment descriptor to use \""
|
||||
+ it.could.webdav.DAVServlet.class.getName() + "\"");
|
||||
super.init(config);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Could.IT WebDAV Servlet</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This package is deprecated, but preserved to maintain compatibility
|
||||
with previous versions.
|
||||
</p>
|
||||
<p>
|
||||
Please refer to the documentation in the {@link it.could.webdav} package
|
||||
for the new version description.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,128 +0,0 @@
|
|||
# This is a comment. I love comments.
|
||||
|
||||
# This file controls what Internet media types are sent to the client for
|
||||
# given file extension(s). Sending the correct media type to the client
|
||||
# is important so they know how to handle the content of the file.
|
||||
# Extra types can either be added here or by using an AddType directive
|
||||
# in your config files. For more information about Internet media types,
|
||||
# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type
|
||||
# registry is at <http://www.iana.org/assignments/media-types/>.
|
||||
|
||||
# MIME type Extensions
|
||||
|
||||
application/andrew-inset ez
|
||||
application/atom+xml atom
|
||||
application/java-archive jar
|
||||
application/mac-binhex40 hqx
|
||||
application/mac-compactpro cpt
|
||||
application/mathml+xml mathml
|
||||
application/msword doc
|
||||
application/octet-stream bin dms lha lzh exe class so dll dmg
|
||||
application/oda oda
|
||||
application/ogg ogg
|
||||
application/pdf pdf
|
||||
application/postscript ai eps ps
|
||||
application/rdf+xml rdf
|
||||
application/smil smi smil
|
||||
application/srgs gram
|
||||
application/srgs+xml grxml
|
||||
application/vnd.mif mif
|
||||
application/vnd.mozilla.xul+xml xul
|
||||
application/vnd.ms-excel xls
|
||||
application/vnd.ms-powerpoint ppt
|
||||
application/vnd.rn-realmedia rm
|
||||
application/vnd.wap.wbxml wbxml
|
||||
application/vnd.wap.wmlc wmlc
|
||||
application/vnd.wap.wmlscriptc wmlsc
|
||||
application/voicexml+xml vxml
|
||||
application/x-bcpio bcpio
|
||||
application/x-cdlink vcd
|
||||
application/x-chess-pgn pgn
|
||||
application/x-cpio cpio
|
||||
application/x-csh csh
|
||||
application/x-director dcr dir dxr
|
||||
application/x-dvi dvi
|
||||
application/x-futuresplash spl
|
||||
application/x-gtar gtar
|
||||
application/x-hdf hdf
|
||||
application/x-java-jnlp-file jnlp
|
||||
application/x-javascript js
|
||||
application/x-koan skp skd skt skm
|
||||
application/x-latex latex
|
||||
application/x-netcdf nc cdf
|
||||
application/x-sh sh
|
||||
application/x-shar shar
|
||||
application/x-shockwave-flash swf
|
||||
application/x-stuffit sit
|
||||
application/x-sv4cpio sv4cpio
|
||||
application/x-sv4crc sv4crc
|
||||
application/x-tar tar
|
||||
application/x-tcl tcl
|
||||
application/x-tex tex
|
||||
application/x-texinfo texinfo texi
|
||||
application/x-troff t tr roff
|
||||
application/x-troff-man man
|
||||
application/x-troff-me me
|
||||
application/x-troff-ms ms
|
||||
application/x-ustar ustar
|
||||
application/x-wais-source src
|
||||
application/xhtml+xml xhtml xht
|
||||
application/xml xml xsl
|
||||
application/xml-dtd dtd
|
||||
application/xslt+xml xslt
|
||||
application/zip zip
|
||||
audio/basic au snd
|
||||
audio/midi mid midi kar
|
||||
audio/mpeg mpga mp2 mp3
|
||||
audio/x-aiff aif aiff aifc
|
||||
audio/x-mpegurl m3u
|
||||
audio/x-pn-realaudio ram ra
|
||||
audio/x-wav wav
|
||||
chemical/x-pdb pdb
|
||||
chemical/x-xyz xyz
|
||||
image/bmp bmp
|
||||
image/cgm cgm
|
||||
image/gif gif
|
||||
image/ief ief
|
||||
image/jp2 jp2
|
||||
image/jpeg jpeg jpg jpe
|
||||
image/pict pict pic pct
|
||||
image/png png
|
||||
image/svg+xml svg
|
||||
image/tiff tiff tif
|
||||
image/vnd.djvu djvu djv
|
||||
image/vnd.wap.wbmp wbmp
|
||||
image/x-cmu-raster ras
|
||||
image/x-icon ico
|
||||
image/x-macpaint pntg pnt mac
|
||||
image/x-portable-anymap pnm
|
||||
image/x-portable-bitmap pbm
|
||||
image/x-portable-graymap pgm
|
||||
image/x-portable-pixmap ppm
|
||||
image/x-quicktime qtif qti
|
||||
image/x-rgb rgb
|
||||
image/x-xbitmap xbm
|
||||
image/x-xpixmap xpm
|
||||
image/x-xwindowdump xwd
|
||||
model/iges igs iges
|
||||
model/mesh msh mesh silo
|
||||
model/vrml wrl vrml
|
||||
text/calendar ics ifb
|
||||
text/css css
|
||||
text/html html htm
|
||||
text/plain asc txt
|
||||
text/richtext rtx
|
||||
text/rtf rtf
|
||||
text/sgml sgml sgm
|
||||
text/tab-separated-values tsv
|
||||
text/vnd.wap.wml wml
|
||||
text/vnd.wap.wmlscript wmls
|
||||
text/x-setext etx
|
||||
video/mp4 mp4
|
||||
video/mpeg mpeg mpg mpe
|
||||
video/quicktime qt mov
|
||||
video/vnd.mpegurl mxu m4u
|
||||
video/x-dv dv dif
|
||||
video/x-msvideo avi
|
||||
video/x-sgi-movie movie
|
||||
x-conference/x-cooltalk ice
|
|
@ -1,5 +1,3 @@
|
|||
# This is a comment. I love comments.
|
||||
|
||||
# This file controls what Internet media types are sent to the client for
|
||||
# given file extension(s). Sending the correct media type to the client
|
||||
# is important so they know how to handle the content of the file.
|
||||
|
@ -12,6 +10,7 @@
|
|||
|
||||
application/andrew-inset ez
|
||||
application/atom+xml atom
|
||||
application/java-archive jar
|
||||
application/mac-binhex40 hqx
|
||||
application/mac-compactpro cpt
|
||||
application/mathml+xml mathml
|
||||
|
@ -20,6 +19,7 @@ application/octet-stream bin dms lha lzh exe class so dll dmg
|
|||
application/oda oda
|
||||
application/ogg ogg
|
||||
application/pdf pdf
|
||||
application/pgp-encrypted pgp
|
||||
application/postscript ai eps ps
|
||||
application/rdf+xml rdf
|
||||
application/smil smi smil
|
||||
|
@ -66,7 +66,7 @@ application/x-troff-ms ms
|
|||
application/x-ustar ustar
|
||||
application/x-wais-source src
|
||||
application/xhtml+xml xhtml xht
|
||||
application/xml xml xsl
|
||||
application/xml xml xsl pom
|
||||
application/xml-dtd dtd
|
||||
application/xslt+xml xslt
|
||||
application/zip zip
|
||||
|
@ -109,7 +109,7 @@ model/vrml wrl vrml
|
|||
text/calendar ics ifb
|
||||
text/css css
|
||||
text/html html htm
|
||||
text/plain asc txt
|
||||
text/plain asc txt sha1 md5
|
||||
text/richtext rtx
|
||||
text/rtf rtf
|
||||
text/sgml sgml sgm
|
|
@ -1,13 +0,0 @@
|
|||
#
|
||||
# A simple property file defining some strings that will be returned and/or
|
||||
# used by the Could.IT DAVServlet at different stages of processing
|
||||
#
|
||||
|
||||
# Returned by DAVServlet in the "getServletInfo()" method
|
||||
servlet.information = Could.IT WebDAV Servlet
|
||||
|
||||
# Added to the "Server" header every time a request is processed
|
||||
servlet.signature = CouldIT-WebDAV
|
||||
|
||||
# Version used in build files and combined to information and signature
|
||||
version = 0.5-dev
|
|
@ -1,495 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav;
|
||||
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.Principal;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TestableHttpServletRequest
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: TestableHttpServletRequest.java 6940 2007-10-16 01:02:02Z joakime $
|
||||
*/
|
||||
public class TestableHttpServletRequest
|
||||
implements HttpServletRequest
|
||||
{
|
||||
|
||||
public TestableHttpServletRequest()
|
||||
{
|
||||
setDefaults();
|
||||
}
|
||||
|
||||
public void setDefaults()
|
||||
{
|
||||
authType = null;
|
||||
scheme = "http";
|
||||
protocol = "HTTP/1.1";
|
||||
serverName = "localhost";
|
||||
serverPort = 80;
|
||||
remoteHost = "localhost";
|
||||
}
|
||||
|
||||
private String authType;
|
||||
|
||||
private String characterEncoding;
|
||||
|
||||
private int contentLength;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private String contextPath;
|
||||
|
||||
private Locale locale;
|
||||
|
||||
private String method;
|
||||
|
||||
private String pathInfo;
|
||||
|
||||
private String pathTranslated;
|
||||
|
||||
private String protocol;
|
||||
|
||||
private String queryString;
|
||||
|
||||
private String remoteAddr;
|
||||
|
||||
private String remoteHost;
|
||||
|
||||
private String remoteUser;
|
||||
|
||||
private String requestedSessionId;
|
||||
|
||||
private boolean requestedSessionIdFromCookie;
|
||||
|
||||
private boolean requestedSessionIdFromUrl;
|
||||
|
||||
private boolean requestedSessionIdValid;
|
||||
|
||||
private StringBuffer requestURL;
|
||||
|
||||
private String scheme;
|
||||
|
||||
private boolean secure;
|
||||
|
||||
private String serverName;
|
||||
|
||||
private int serverPort;
|
||||
|
||||
private String servletPath;
|
||||
|
||||
public Object getAttribute( String name )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getAttribute(String)" ) );
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames()
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getAttributeNames()" ) );
|
||||
}
|
||||
|
||||
public String getAuthType()
|
||||
{
|
||||
return authType;
|
||||
}
|
||||
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
return characterEncoding;
|
||||
}
|
||||
|
||||
public int getContentLength()
|
||||
{
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public String getContextPath()
|
||||
{
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
public Cookie[] getCookies()
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getCookies()" ) );
|
||||
}
|
||||
|
||||
public long getDateHeader( String name )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getDateHeader(String)" ) );
|
||||
}
|
||||
|
||||
public String getHeader( String name )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getHeader(String)" ) );
|
||||
}
|
||||
|
||||
private Map headers = new HashMap();
|
||||
|
||||
public Enumeration getHeaderNames()
|
||||
{
|
||||
return new IterEnumeration( headers.keySet().iterator() );
|
||||
}
|
||||
|
||||
public Enumeration getHeaders( String name )
|
||||
{
|
||||
throw new NotImplementedException( notImplemented( ".getHeaders(String)" ) );
|
||||
}
|
||||
|
||||
public ServletInputStream getInputStream()
|
||||
throws IOException
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getInputStream()" ) );
|
||||
}
|
||||
|
||||
public int getIntHeader( String name )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getIntHeader(String)" ) );
|
||||
}
|
||||
|
||||
public Locale getLocale()
|
||||
{
|
||||
return locale;
|
||||
}
|
||||
|
||||
public Enumeration getLocales()
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getLocales()" ) );
|
||||
}
|
||||
|
||||
public String getMethod()
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
public String getParameter( String name )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getParameter(String)" ) );
|
||||
}
|
||||
|
||||
public Map getParameterMap()
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getParameterMap()" ) );
|
||||
}
|
||||
|
||||
public Enumeration getParameterNames()
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getParameterNames()" ) );
|
||||
}
|
||||
|
||||
public String[] getParameterValues( String name )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getParameterValues(String)" ) );
|
||||
}
|
||||
|
||||
public String getPathInfo()
|
||||
{
|
||||
return pathInfo;
|
||||
}
|
||||
|
||||
public String getPathTranslated()
|
||||
{
|
||||
return pathTranslated;
|
||||
}
|
||||
|
||||
public String getProtocol()
|
||||
{
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getQueryString()
|
||||
{
|
||||
return queryString;
|
||||
}
|
||||
|
||||
public BufferedReader getReader()
|
||||
throws IOException
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getReader()" ) );
|
||||
}
|
||||
|
||||
public String getRealPath( String path )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getRealPath(String)" ) );
|
||||
}
|
||||
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
return remoteAddr;
|
||||
}
|
||||
|
||||
public String getRemoteHost()
|
||||
{
|
||||
return remoteHost;
|
||||
}
|
||||
|
||||
public String getRemoteUser()
|
||||
{
|
||||
return remoteUser;
|
||||
}
|
||||
|
||||
public RequestDispatcher getRequestDispatcher( String path )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getRequestDispatcher(String)" ) );
|
||||
}
|
||||
|
||||
public String getRequestedSessionId()
|
||||
{
|
||||
return requestedSessionId;
|
||||
}
|
||||
|
||||
public String getRequestURI()
|
||||
{
|
||||
return requestURL.toString();
|
||||
}
|
||||
|
||||
public StringBuffer getRequestURL()
|
||||
{
|
||||
return requestURL;
|
||||
}
|
||||
|
||||
public String getScheme()
|
||||
{
|
||||
return scheme;
|
||||
}
|
||||
|
||||
public String getServerName()
|
||||
{
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public int getServerPort()
|
||||
{
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
public String getServletPath()
|
||||
{
|
||||
return servletPath;
|
||||
}
|
||||
|
||||
public HttpSession getSession()
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getSession()" ) );
|
||||
}
|
||||
|
||||
public HttpSession getSession( boolean create )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getSession(boolean)" ) );
|
||||
}
|
||||
|
||||
public Principal getUserPrincipal()
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".getUserPrincipal()" ) );
|
||||
}
|
||||
|
||||
public boolean isRequestedSessionIdFromCookie()
|
||||
{
|
||||
return requestedSessionIdFromCookie;
|
||||
}
|
||||
|
||||
public boolean isRequestedSessionIdFromUrl()
|
||||
{
|
||||
return requestedSessionIdFromUrl;
|
||||
}
|
||||
|
||||
public boolean isRequestedSessionIdFromURL()
|
||||
{
|
||||
return requestedSessionIdFromUrl;
|
||||
}
|
||||
|
||||
public boolean isRequestedSessionIdValid()
|
||||
{
|
||||
return requestedSessionIdValid;
|
||||
}
|
||||
|
||||
public boolean isSecure()
|
||||
{
|
||||
return secure;
|
||||
}
|
||||
|
||||
public boolean isUserInRole( String role )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".isUserInRole(String)" ) );
|
||||
}
|
||||
|
||||
public void removeAttribute( String name )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".removeAttribute(String)" ) );
|
||||
}
|
||||
|
||||
public void setAttribute( String name, Object o )
|
||||
{
|
||||
// TODO: Implement if needed.
|
||||
throw new NotImplementedException( notImplemented( ".setAttribute(String, Object)" ) );
|
||||
}
|
||||
|
||||
public void setCharacterEncoding( String encoding )
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
this.characterEncoding = encoding;
|
||||
}
|
||||
|
||||
public void setContentLength( int contentLength )
|
||||
{
|
||||
this.contentLength = contentLength;
|
||||
}
|
||||
|
||||
public void setContentType( String contentType )
|
||||
{
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public void setContextPath( String contextPath )
|
||||
{
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
public void setMethod( String method )
|
||||
{
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public void setPathInfo( String pathInfo )
|
||||
{
|
||||
this.pathInfo = pathInfo;
|
||||
}
|
||||
|
||||
public void setProtocol( String protocol )
|
||||
{
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public void setQueryString( String queryString )
|
||||
{
|
||||
this.queryString = queryString;
|
||||
}
|
||||
|
||||
public void setScheme( String scheme )
|
||||
{
|
||||
this.scheme = scheme;
|
||||
}
|
||||
|
||||
public void setSecure( boolean secure )
|
||||
{
|
||||
this.secure = secure;
|
||||
}
|
||||
|
||||
public void setServerName( String serverName )
|
||||
{
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
public void setServerPort( int serverPort )
|
||||
{
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public void setServletPath( String servletPath )
|
||||
{
|
||||
this.servletPath = servletPath;
|
||||
}
|
||||
|
||||
public void setUrl( String urlString )
|
||||
throws MalformedURLException
|
||||
{
|
||||
URL url = new URL( urlString );
|
||||
this.queryString = url.getQuery();
|
||||
this.scheme = url.getProtocol();
|
||||
this.serverName = url.getHost();
|
||||
this.serverPort = url.getPort();
|
||||
|
||||
String path = url.getPath();
|
||||
if ( !path.startsWith( this.servletPath ) )
|
||||
{
|
||||
throw new MalformedURLException( "Unable to operate on request path [" + path
|
||||
+ "] outside of servletPath [" + this.servletPath + "]." );
|
||||
}
|
||||
|
||||
this.pathInfo = path.substring( this.servletPath.length() );
|
||||
this.requestURL = new StringBuffer( this.pathInfo );
|
||||
}
|
||||
|
||||
private String notImplemented( String msg )
|
||||
{
|
||||
return msg + " is not implemented in " + this.getClass().getName();
|
||||
}
|
||||
|
||||
class IterEnumeration
|
||||
implements Enumeration
|
||||
{
|
||||
private Iterator iter;
|
||||
|
||||
public IterEnumeration( Iterator it )
|
||||
{
|
||||
this.iter = it;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return this.iter.hasNext();
|
||||
}
|
||||
|
||||
public Object nextElement()
|
||||
{
|
||||
return this.iter.next();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.servlet.multiplexed;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.maven.archiva.webdav.TestableHttpServletRequest;
|
||||
import org.apache.maven.archiva.webdav.util.WrappedRepositoryRequest;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
/**
|
||||
* MultiplexedDavServerRequestTest
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: MultiplexedDavServerRequestTest.java 6940 2007-10-16 01:02:02Z joakime $
|
||||
*/
|
||||
public class MultiplexedDavServerRequestTest
|
||||
extends TestCase
|
||||
{
|
||||
private void assertMultiURL( String expectedPrefix, String expectedLogicalResource, String url )
|
||||
throws MalformedURLException
|
||||
{
|
||||
TestableHttpServletRequest testrequest = new TestableHttpServletRequest();
|
||||
testrequest.setMethod( "GET" );
|
||||
testrequest.setServletPath( "/repository" );
|
||||
testrequest.setUrl( url );
|
||||
|
||||
WrappedRepositoryRequest wraprequest = new WrappedRepositoryRequest( testrequest );
|
||||
MultiplexedDavServerRequest multirequest = new MultiplexedDavServerRequest( wraprequest );
|
||||
|
||||
assertEquals( expectedPrefix, multirequest.getPrefix() );
|
||||
assertEquals( expectedLogicalResource, multirequest.getLogicalResource() );
|
||||
}
|
||||
|
||||
public void testNormalUsage()
|
||||
throws MalformedURLException
|
||||
{
|
||||
assertMultiURL( "corporate", "/", "http://localhost:9091/repository/corporate" );
|
||||
assertMultiURL( "corporate", "/dom4j/dom4j/1.4", "http://localhost:9091/repository/corporate/dom4j/dom4j/1.4" );
|
||||
}
|
||||
|
||||
public void testHacker()
|
||||
throws MalformedURLException
|
||||
{
|
||||
assertMultiURL( "corporate", "/etc/passwd", "http://localhost:9091/repository/corporate//etc/passwd" );
|
||||
// Since the double ".." puts the path outside of the /corporate/, it will return "/" as a hack fallback.
|
||||
assertMultiURL( "corporate", "/", "http://localhost:9091/repository/corporate/dom4j/../../etc/passwd" );
|
||||
assertMultiURL( "corporate", "/", "http://localhost:9091/repository/corporate/../.." );
|
||||
}
|
||||
}
|
|
@ -1,38 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.simple;
|
||||
|
||||
import org.apache.maven.archiva.webdav.test.AbstractBasicWebdavProviderTestCase;
|
||||
|
||||
/**
|
||||
* SimpleDavServerComponentBasicTest
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: SimpleDavServerComponentBasicTest.java 5408 2007-01-12 19:42:37Z joakime $
|
||||
*/
|
||||
public class SimpleDavServerComponentBasicTest
|
||||
extends AbstractBasicWebdavProviderTestCase
|
||||
{
|
||||
public SimpleDavServerComponentBasicTest()
|
||||
{
|
||||
super();
|
||||
setProviderHint( "simple" );
|
||||
}
|
||||
}
|
|
@ -1,38 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.simple;
|
||||
|
||||
import org.apache.maven.archiva.webdav.test.AbstractWebdavIndexHtmlTestCase;
|
||||
|
||||
/**
|
||||
* SimpleDavServerComponentIndexHtmlTest
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: SimpleDavServerComponentIndexHtmlTest.java 6000 2007-03-04 22:01:49Z joakime $
|
||||
*/
|
||||
public class SimpleDavServerComponentIndexHtmlTest
|
||||
extends AbstractWebdavIndexHtmlTestCase
|
||||
{
|
||||
public SimpleDavServerComponentIndexHtmlTest()
|
||||
{
|
||||
super();
|
||||
setProviderHint( "simple" );
|
||||
}
|
||||
}
|
|
@ -1,38 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.simple;
|
||||
|
||||
import org.apache.maven.archiva.webdav.test.AbstractMultiWebdavProviderTestCase;
|
||||
|
||||
/**
|
||||
* SimpleDavServerComponentCrossTest
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: SimpleDavServerComponentMultiTest.java 5408 2007-01-12 19:42:37Z joakime $
|
||||
*/
|
||||
public class SimpleDavServerComponentMultiTest
|
||||
extends AbstractMultiWebdavProviderTestCase
|
||||
{
|
||||
public SimpleDavServerComponentMultiTest()
|
||||
{
|
||||
super();
|
||||
setProviderHint( "simple" );
|
||||
}
|
||||
}
|
|
@ -1,50 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.simple;
|
||||
|
||||
import org.apache.maven.archiva.webdav.test.AbstractWebdavServer;
|
||||
|
||||
/**
|
||||
* SimpleWebdavServer
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: SimpleWebdavServer.java 5379 2007-01-07 22:54:41Z joakime $
|
||||
*/
|
||||
public class SimpleWebdavServer
|
||||
extends AbstractWebdavServer
|
||||
{
|
||||
public static void main( String[] args )
|
||||
{
|
||||
try
|
||||
{
|
||||
SimpleWebdavServer server = new SimpleWebdavServer();
|
||||
server.startServer();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected String getProviderHint()
|
||||
{
|
||||
return "simple";
|
||||
}
|
||||
}
|
|
@ -1,255 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.test;
|
||||
|
||||
import org.apache.commons.httpclient.HttpURL;
|
||||
import org.apache.maven.archiva.webdav.servlet.basic.BasicWebDavServlet;
|
||||
import org.apache.webdav.lib.WebdavResource;
|
||||
import org.codehaus.plexus.util.IOUtil;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.ServletHandler;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
import org.mortbay.jetty.webapp.WebAppContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* AbstractBasicWebdavProviderTestCase
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: AbstractBasicWebdavProviderTestCase.java 6000 2007-03-04 22:01:49Z joakime $
|
||||
*/
|
||||
public abstract class AbstractBasicWebdavProviderTestCase
|
||||
extends AbstractWebdavProviderTestCase
|
||||
{
|
||||
private File serverRepoDir;
|
||||
|
||||
private WebdavResource davRepo;
|
||||
|
||||
/** The Jetty Server. */
|
||||
private Server server;
|
||||
|
||||
protected void setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
// Initialize server contents directory.
|
||||
|
||||
serverRepoDir = getTestDir( "sandbox" );
|
||||
|
||||
// Setup the Jetty Server.
|
||||
|
||||
System.setProperty( "DEBUG", "" );
|
||||
System.setProperty( "org.mortbay.log.class", "org.slf4j.impl.SimpleLogger" );
|
||||
|
||||
server = new Server( PORT );
|
||||
WebAppContext webAppConfig = new WebAppContext( server, getTestFile( "src/test/webapp" ).getCanonicalPath(), "/" );
|
||||
|
||||
ServletHandler servletHandler = webAppConfig.getServletHandler();
|
||||
|
||||
ServletHolder holder = servletHandler.addServletWithMapping( BasicWebDavServlet.class, CONTEXT + "/*" );
|
||||
|
||||
holder.setInitParameter( "dav.root", serverRepoDir.getAbsolutePath() );
|
||||
|
||||
server.start();
|
||||
|
||||
// Setup Client Side
|
||||
|
||||
HttpURL httpSandboxUrl = new HttpURL( "http://localhost:" + PORT + CONTEXT + "/" );
|
||||
|
||||
try
|
||||
{
|
||||
davRepo = new WebdavResource( httpSandboxUrl );
|
||||
|
||||
davRepo.setDebug( 8 );
|
||||
|
||||
davRepo.setPath( CONTEXT );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
tearDown();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
serverRepoDir = null;
|
||||
|
||||
if ( server != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
server = null;
|
||||
}
|
||||
|
||||
if ( davRepo != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
davRepo.close();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
davRepo = null;
|
||||
}
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Actual Test Cases.
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public void testPutGet()
|
||||
throws Exception
|
||||
{
|
||||
// Quote: Rocky
|
||||
String contents = "yo!\n";
|
||||
|
||||
assertDavTouchFile( davRepo, CONTEXT, "data.txt", contents );
|
||||
|
||||
InputStream inputStream = davRepo.getMethodData( CONTEXT + "/data.txt" );
|
||||
|
||||
assertEquals( contents, IOUtil.toString( inputStream ) );
|
||||
}
|
||||
|
||||
public void testCollectionTasks()
|
||||
throws Exception
|
||||
{
|
||||
// Create a few collections.
|
||||
assertDavMkDir( davRepo, CONTEXT + "/bar" );
|
||||
assertDavMkDir( davRepo, CONTEXT + "/bar/foo" );
|
||||
|
||||
// Remove a collection
|
||||
davRepo.setPath( CONTEXT );
|
||||
if ( !davRepo.deleteMethod( CONTEXT + "/bar/foo" ) )
|
||||
{
|
||||
fail( "Unable to remove <" + CONTEXT + "/bar/foo> on <" + davRepo.getHttpURL().toString() + "> due to <"
|
||||
+ davRepo.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
assertDavDirNotExists( davRepo, CONTEXT + "/bar/foo" );
|
||||
}
|
||||
|
||||
public void testResourceCopy()
|
||||
throws Exception
|
||||
{
|
||||
// Lyrics: Cool and the Gang - Celebrate Good Times
|
||||
String contents = "we're gonna have a good time tonite. lets celebrate. it's a celebration. "
|
||||
+ "cel-e-brate good times, come on!";
|
||||
|
||||
// Create a few collections.
|
||||
assertDavMkDir( davRepo, CONTEXT + "/bar" );
|
||||
assertDavMkDir( davRepo, CONTEXT + "/foo" );
|
||||
|
||||
// Create a resource
|
||||
assertDavTouchFile( davRepo, CONTEXT + "/bar", "data.txt", contents );
|
||||
|
||||
// Test for existance of resource
|
||||
assertDavFileExists( davRepo, CONTEXT + "/bar", "data.txt" );
|
||||
assertDavFileNotExists( davRepo, CONTEXT + "/foo", "data.txt" );
|
||||
|
||||
// Copy resource
|
||||
String source = CONTEXT + "/bar/data.txt";
|
||||
String dest = CONTEXT + "/foo/data.txt";
|
||||
if ( !davRepo.copyMethod( source, dest ) )
|
||||
{
|
||||
fail( "Unable to copy <" + source + "> to <" + dest + "> on <" + davRepo.getHttpURL().toString()
|
||||
+ "> due to <" + davRepo.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
// Test for existance of resource
|
||||
assertDavFileExists( davRepo, CONTEXT + "/bar", "data.txt" );
|
||||
assertDavFileExists( davRepo, CONTEXT + "/foo", "data.txt" );
|
||||
}
|
||||
|
||||
public void testResourceMove()
|
||||
throws Exception
|
||||
{
|
||||
// Lyrics: Men At Work - Who Can It Be Now
|
||||
String contents = "Who can it be knocking at my door?\n" + "Make no sound, tip-toe across the floor.\n"
|
||||
+ "If he hears, he'll knock all day,\n" + "I'll be trapped, and here I'll have to stay.\n"
|
||||
+ "I've done no harm, I keep to myself;\n" + "There's nothing wrong with my state of mental health.\n"
|
||||
+ "I like it here with my childhood friend;\n" + "Here they come, those feelings again!\n";
|
||||
|
||||
// Create a few collections.
|
||||
assertDavMkDir( davRepo, CONTEXT + "/bar" );
|
||||
assertDavMkDir( davRepo, CONTEXT + "/foo" );
|
||||
|
||||
// Create a resource
|
||||
assertDavTouchFile( davRepo, CONTEXT + "/bar", "data.txt", contents );
|
||||
|
||||
// Test for existance of resource
|
||||
assertDavFileExists( davRepo, CONTEXT + "/bar", "data.txt" );
|
||||
assertDavFileNotExists( davRepo, CONTEXT + "/foo", "data.txt" );
|
||||
|
||||
// Copy resource
|
||||
String source = CONTEXT + "/bar/data.txt";
|
||||
String dest = CONTEXT + "/foo/data.txt";
|
||||
if ( !davRepo.moveMethod( source, dest ) )
|
||||
{
|
||||
fail( "Unable to move <" + source + "> to <" + dest + "> on <" + davRepo.getHttpURL().toString()
|
||||
+ "> due to <" + davRepo.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
// Test for existance of resource
|
||||
assertDavFileNotExists( davRepo, CONTEXT + "/bar", "data.txt" );
|
||||
assertDavFileExists( davRepo, CONTEXT + "/foo", "data.txt" );
|
||||
}
|
||||
|
||||
public void testResourceDelete()
|
||||
throws Exception
|
||||
{
|
||||
// Lyrics: Men At Work - Down Under
|
||||
String contents = "Lying in a den in Bombay\n" + "With a slack jaw, and not much to say\n"
|
||||
+ "I said to the man, \"Are you trying to tempt me\"\n" + "Because I come from the land of plenty?\n";
|
||||
|
||||
// Create a few collections.
|
||||
assertDavMkDir( davRepo, CONTEXT + "/bar" );
|
||||
|
||||
// Create a resource
|
||||
assertDavTouchFile( davRepo, CONTEXT + "/bar", "data.txt", contents );
|
||||
|
||||
// Move resource
|
||||
davRepo.setPath( CONTEXT );
|
||||
if ( !davRepo.deleteMethod( CONTEXT + "/bar/data.txt" ) )
|
||||
{
|
||||
fail( "Unable to remove <" + CONTEXT + "/bar/data.txt> on <" + davRepo.getHttpURL().toString()
|
||||
+ "> due to <" + davRepo.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
// Test for existance via webdav interface.
|
||||
assertDavFileNotExists( davRepo, CONTEXT + "/bar", "data.txt" );
|
||||
}
|
||||
}
|
|
@ -1,203 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.test;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.httpclient.HttpURL;
|
||||
import org.apache.webdav.lib.WebdavResource;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.ServletHandler;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
import org.mortbay.jetty.webapp.WebAppContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* AbstractMultiWebdavProviderTestCase
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: AbstractMultiWebdavProviderTestCase.java 5997 2007-03-04 19:41:15Z joakime $
|
||||
*/
|
||||
public abstract class AbstractMultiWebdavProviderTestCase
|
||||
extends AbstractWebdavProviderTestCase
|
||||
{
|
||||
File serverSandboxDir;
|
||||
|
||||
File serverSnapshotsDir;
|
||||
|
||||
/** The Jetty Server. */
|
||||
private Server server;
|
||||
|
||||
private WebdavResource davSnapshots;
|
||||
|
||||
private WebdavResource davSandbox;
|
||||
|
||||
protected void setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
// Initialize server contents directory.
|
||||
|
||||
serverSandboxDir = getTestDir( "sandbox" );
|
||||
serverSnapshotsDir = getTestDir( "snapshots" );
|
||||
|
||||
// Setup the Jetty Server.
|
||||
|
||||
System.setProperty( "DEBUG", "" );
|
||||
System.setProperty( "org.mortbay.log.class", "org.slf4j.impl.SimpleLogger" );
|
||||
|
||||
server = new Server( PORT );
|
||||
|
||||
WebAppContext webAppConfig = new WebAppContext( server, getTestFile( "src/test/webapp" ).getCanonicalPath(), "/" );
|
||||
ServletHandler servletHandler = webAppConfig.getServletHandler();
|
||||
|
||||
ServletHolder holder = servletHandler.addServletWithMapping( TestMultiWebDavServlet.class, CONTEXT + "/*" );
|
||||
holder.setInitParameter( "root.sandbox", serverSandboxDir.getAbsolutePath() );
|
||||
holder.setInitParameter( "root.snapshots", serverSnapshotsDir.getAbsolutePath() );
|
||||
|
||||
System.out.println( "root.sandbox = " + serverSandboxDir.getAbsolutePath() );
|
||||
System.out.println( "root.snapshots = " + serverSnapshotsDir.getAbsolutePath() );
|
||||
|
||||
server.start();
|
||||
|
||||
// Setup Client Side
|
||||
|
||||
HttpURL httpSandboxUrl = new HttpURL( "http://localhost:" + PORT + CONTEXT + "/sandbox/" );
|
||||
HttpURL httpSnapshotsUrl = new HttpURL( "http://localhost:" + PORT + CONTEXT + "/snapshots/" );
|
||||
|
||||
try
|
||||
{
|
||||
davSandbox = new WebdavResource( httpSandboxUrl );
|
||||
davSnapshots = new WebdavResource( httpSnapshotsUrl );
|
||||
|
||||
davSandbox.setDebug( 8 );
|
||||
davSnapshots.setDebug( 8 );
|
||||
|
||||
davSandbox.setPath( CONTEXT + "/sandbox/" );
|
||||
davSnapshots.setPath( CONTEXT + "/snapshots/" );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
tearDown();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
serverRootDir = null;
|
||||
|
||||
if ( server != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
server = null;
|
||||
}
|
||||
|
||||
if ( davSandbox != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
davSandbox.close();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
davSandbox = null;
|
||||
}
|
||||
|
||||
if ( davSnapshots != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
davSnapshots.close();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
davSnapshots = null;
|
||||
}
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testResourceMoveCrossWebdav()
|
||||
throws Exception
|
||||
{
|
||||
// Create a few collections.
|
||||
assertDavMkDir( davSandbox, CONTEXT + "/sandbox/bar" );
|
||||
assertDavMkDir( davSnapshots, CONTEXT + "/snapshots/foo" );
|
||||
|
||||
// Create a resource
|
||||
assertDavTouchFile( davSandbox, CONTEXT + "/sandbox/bar", "data.txt", "yo!" );
|
||||
|
||||
// Move resource URL to URL (Across the WebDav Servlets)
|
||||
davSandbox.setPath( CONTEXT + "/sandbox/bar" );
|
||||
String source = CONTEXT + "/sandbox/bar/data.txt";
|
||||
String dest = "http://localhost:" + PORT + CONTEXT + "/snapshots/foo/data.txt";
|
||||
if ( !davSandbox.moveMethod( source, dest ) )
|
||||
{
|
||||
// TODO: remove when fully implemented.
|
||||
if ( davSandbox.getStatusCode() == HttpStatus.SC_NOT_IMPLEMENTED )
|
||||
{
|
||||
// return quietly, as the server reported no support for this method.
|
||||
return;
|
||||
}
|
||||
|
||||
fail( "Unable to move <" + source + "> to <" + dest + "> on <" + davSandbox.getHttpURL().toString()
|
||||
+ "> due to <" + davSandbox.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
assertDavFileNotExists( davSandbox, CONTEXT + "/sandbox/bar", "data.txt" );
|
||||
assertDavFileExists( davSnapshots, CONTEXT + "/snapshots/foo", "data.txt" );
|
||||
}
|
||||
|
||||
public void testResourceDoesNotExist()
|
||||
throws Exception
|
||||
{
|
||||
// Create a few collections.
|
||||
assertDavMkDir( davSandbox, CONTEXT + "/sandbox/bar" );
|
||||
assertDavMkDir( davSnapshots, CONTEXT + "/snapshots/foo" );
|
||||
|
||||
// Create a resource
|
||||
assertDavTouchFile( davSandbox, CONTEXT + "/sandbox/bar", "data.txt", "yo!" );
|
||||
|
||||
// Get bad resources URLs
|
||||
String urlPrefix = "http://localhost:" + PORT + CONTEXT;
|
||||
assertGet404( urlPrefix + "/sandbox/a/resource/that/does/not/exist.html" );
|
||||
assertGet404( urlPrefix + "/" );
|
||||
assertGet404( urlPrefix + "/snapshots/foo/index.html" );
|
||||
assertGet404( urlPrefix + "/sandbox/bar.html" );
|
||||
assertGet404( urlPrefix + "/nonexistant/index.html" );
|
||||
}
|
||||
}
|
|
@ -1,148 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.test;
|
||||
|
||||
import org.apache.commons.httpclient.HttpURL;
|
||||
import org.apache.maven.archiva.webdav.servlet.basic.BasicWebDavServlet;
|
||||
import org.apache.webdav.lib.WebdavResource;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.ServletHandler;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
import org.mortbay.jetty.webapp.WebAppContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class AbstractWebdavIndexHtmlTestCase
|
||||
extends AbstractWebdavProviderTestCase
|
||||
{
|
||||
private File serverRepoDir;
|
||||
|
||||
private WebdavResource davRepo;
|
||||
|
||||
/** The Jetty Server. */
|
||||
private Server server;
|
||||
|
||||
protected void setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
// Initialize server contents directory.
|
||||
|
||||
serverRepoDir = getTestDir( "sandbox" );
|
||||
|
||||
// Setup the Jetty Server.
|
||||
|
||||
System.setProperty( "DEBUG", "" );
|
||||
System.setProperty( "org.mortbay.log.class", "org.slf4j.impl.SimpleLogger" );
|
||||
|
||||
server = new Server( PORT );
|
||||
WebAppContext webAppConfig = new WebAppContext( server, getTestFile( "src/test/webapp" ).getCanonicalPath(), "/" );
|
||||
|
||||
ServletHandler servletHandler = webAppConfig.getServletHandler();
|
||||
|
||||
ServletHolder holder = servletHandler.addServletWithMapping( BasicWebDavServlet.class, CONTEXT + "/*" );
|
||||
|
||||
holder.setInitParameter( BasicWebDavServlet.INIT_ROOT_DIRECTORY, serverRepoDir.getAbsolutePath() );
|
||||
holder.setInitParameter( BasicWebDavServlet.INIT_USE_INDEX_HTML, "true" );
|
||||
|
||||
server.start();
|
||||
|
||||
// Setup Client Side
|
||||
|
||||
HttpURL httpSandboxUrl = new HttpURL( "http://localhost:" + PORT + CONTEXT + "/" );
|
||||
|
||||
try
|
||||
{
|
||||
davRepo = new WebdavResource( httpSandboxUrl );
|
||||
|
||||
davRepo.setDebug( 8 );
|
||||
|
||||
davRepo.setPath( CONTEXT );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
tearDown();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
serverRepoDir = null;
|
||||
|
||||
if ( server != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
server = null;
|
||||
}
|
||||
|
||||
if ( davRepo != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
davRepo.close();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
davRepo = null;
|
||||
}
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testCollectionIndexHtml()
|
||||
throws Exception
|
||||
{
|
||||
// Lyrics: Colin Hay - Overkill
|
||||
String contents = "I cant get to sleep\n" + "I think about the implications\n" + "Of diving in too deep\n"
|
||||
+ "And possibly the complications\n" + "Especially at night\n" + "I worry over situations\n"
|
||||
+ "I know will be alright\n" + "Perahaps its just my imagination\n" + "Day after day it reappears\n"
|
||||
+ "Night after night my heartbeat, shows the fear\n" + "Ghosts appear and fade away";
|
||||
|
||||
// Create a few collections.
|
||||
assertDavMkDir( davRepo, CONTEXT + "/bar" );
|
||||
assertDavMkDir( davRepo, CONTEXT + "/foo" );
|
||||
|
||||
// Create a resource
|
||||
assertDavTouchFile( davRepo, CONTEXT + "/bar", "index.html", contents );
|
||||
|
||||
// Test for existance of resource
|
||||
assertDavFileExists( davRepo, CONTEXT + "/bar", "index.html" );
|
||||
assertDavFileNotExists( davRepo, CONTEXT + "/foo", "index.html" );
|
||||
|
||||
// Copy resource
|
||||
String actual = davRepo.getMethodDataAsString( CONTEXT + "/bar/" );
|
||||
|
||||
assertEquals( contents, actual );
|
||||
}
|
||||
}
|
|
@ -1,401 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.test;
|
||||
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.HttpException;
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.maven.archiva.webdav.DavServerManager;
|
||||
import org.apache.webdav.lib.WebdavResource;
|
||||
import org.apache.webdav.lib.WebdavResources;
|
||||
import org.codehaus.plexus.spring.PlexusInSpringTestCase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* AbstractWebdavProviderTestCase
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: AbstractWebdavProviderTestCase.java 5997 2007-03-04 19:41:15Z joakime $
|
||||
*/
|
||||
public abstract class AbstractWebdavProviderTestCase
|
||||
extends PlexusInSpringTestCase
|
||||
{
|
||||
public static final int PORT = 4321;
|
||||
|
||||
public static final String CONTEXT = "/repos";
|
||||
|
||||
protected File serverRootDir = null;
|
||||
|
||||
private DavServerManager manager;
|
||||
|
||||
private String providerHint = "simple";
|
||||
|
||||
public DavServerManager getManager()
|
||||
{
|
||||
return manager;
|
||||
}
|
||||
|
||||
public String getProviderHint()
|
||||
{
|
||||
return providerHint;
|
||||
}
|
||||
|
||||
public void setManager( DavServerManager manager )
|
||||
{
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void setProviderHint( String providerHint )
|
||||
{
|
||||
this.providerHint = providerHint;
|
||||
}
|
||||
|
||||
protected void setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
try
|
||||
{
|
||||
manager = (DavServerManager) lookup( DavServerManager.ROLE, getProviderHint() );
|
||||
serverRootDir = getRootDir();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
tearDown();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
serverRootDir = null;
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected void dumpCollection( WebdavResource webdavResource, String path )
|
||||
throws Exception
|
||||
{
|
||||
webdavResource.setPath( path );
|
||||
WebdavResource resources[] = webdavResource.listWebdavResources();
|
||||
|
||||
System.out.println( "Dump Collection [" + path + "]: " + resources.length + " hits." );
|
||||
|
||||
dumpCollectionRecursive( "", webdavResource, path );
|
||||
}
|
||||
|
||||
protected void dumpCollectionRecursive( String indent, WebdavResource webdavResource, String path )
|
||||
throws Exception
|
||||
{
|
||||
if ( indent.length() > 12 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebdavResource resources[] = webdavResource.listWebdavResources();
|
||||
|
||||
for ( int i = 0; i < resources.length; i++ )
|
||||
{
|
||||
System.out.println( indent + "WebDavResource[" + path + "|" + i + "]: "
|
||||
+ ( resources[i].isCollection() ? "(collection) " : "" ) + resources[i].getName() );
|
||||
|
||||
if ( resources[i].isCollection() )
|
||||
{
|
||||
dumpCollectionRecursive( indent + " ", resources[i], path + "/" + resources[i].getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Actual Test Cases.
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public void assertNotExists( File basedir, String relativePath )
|
||||
{
|
||||
assertNotExists( new File( basedir, relativePath ) );
|
||||
}
|
||||
|
||||
public void assertNotExists( File file )
|
||||
{
|
||||
if ( file.exists() )
|
||||
{
|
||||
fail( "Unexpected path <" + file.getAbsolutePath() + "> should not exist." );
|
||||
}
|
||||
}
|
||||
|
||||
public void assertExists( File basedir, String relativePath )
|
||||
{
|
||||
assertExists( new File( basedir, relativePath ) );
|
||||
}
|
||||
|
||||
public void assertExists( File file )
|
||||
{
|
||||
if ( !file.exists() )
|
||||
{
|
||||
fail( "Expected path <" + file.getAbsolutePath() + "> does not exist." );
|
||||
}
|
||||
}
|
||||
|
||||
private void resetDirectory( File dir )
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtils.deleteDirectory( dir );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
fail( "Unable to delete test directory [" + dir.getAbsolutePath() + "]." );
|
||||
}
|
||||
|
||||
if ( dir.exists() )
|
||||
{
|
||||
fail( "Unable to execute test, test directory [" + dir.getAbsolutePath()
|
||||
+ "] exists, and cannot be deleted by the test case." );
|
||||
}
|
||||
|
||||
if ( !dir.mkdirs() )
|
||||
{
|
||||
fail( "Unable to execute test, test directory [" + dir.getAbsolutePath() + "] cannot be created." );
|
||||
}
|
||||
}
|
||||
|
||||
private File getRootDir()
|
||||
{
|
||||
if ( this.serverRootDir == null )
|
||||
{
|
||||
String clazz = this.getClass().getName();
|
||||
clazz = clazz.substring( clazz.lastIndexOf( "." ) + 1 );
|
||||
serverRootDir = new File( "target/test-contents-" + clazz + "/" + getName() );
|
||||
|
||||
resetDirectory( serverRootDir );
|
||||
}
|
||||
|
||||
return serverRootDir;
|
||||
}
|
||||
|
||||
protected File getTestDir( String subdir )
|
||||
{
|
||||
File testDir = new File( getRootDir(), subdir );
|
||||
resetDirectory( testDir );
|
||||
return testDir;
|
||||
}
|
||||
|
||||
public boolean isHttpStatusOk( WebdavResource webdavResource )
|
||||
{
|
||||
int statusCode = webdavResource.getStatusCode();
|
||||
|
||||
if ( statusCode == HttpStatus.SC_MULTI_STATUS )
|
||||
{
|
||||
// TODO: find out multi-status values.
|
||||
}
|
||||
|
||||
return ( statusCode >= 200 ) && ( statusCode < 300 );
|
||||
}
|
||||
|
||||
public void assertDavMkDir( WebdavResource webdavResource, String collectionName )
|
||||
throws Exception
|
||||
{
|
||||
String httpurl = webdavResource.getHttpURL().toString();
|
||||
|
||||
if ( !webdavResource.mkcolMethod( collectionName ) )
|
||||
{
|
||||
fail( "Unable to create collection/dir <" + collectionName + "> against <" + httpurl + "> due to <"
|
||||
+ webdavResource.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
assertDavDirExists( webdavResource, collectionName );
|
||||
}
|
||||
|
||||
public void assertDavFileExists( WebdavResource webdavResource, String path, String filename )
|
||||
throws Exception
|
||||
{
|
||||
String httpurl = webdavResource.getHttpURL().toString();
|
||||
|
||||
if ( !webdavResource.headMethod( path + "/" + filename ) )
|
||||
{
|
||||
fail( "Unable to verify that file/contents <" + path + "/" + filename + "> exists against <" + httpurl
|
||||
+ "> due to <" + webdavResource.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
String oldPath = webdavResource.getPath();
|
||||
try
|
||||
{
|
||||
webdavResource.setPath( path );
|
||||
|
||||
WebdavResources resources = webdavResource.getChildResources();
|
||||
|
||||
WebdavResource testResource = resources.getResource( filename );
|
||||
|
||||
if ( testResource == null )
|
||||
{
|
||||
fail( "The file/contents <" + path + "/" + filename + "> does not exist in <" + httpurl + ">" );
|
||||
}
|
||||
|
||||
if ( testResource.isCollection() )
|
||||
{
|
||||
fail( "The file/contents <" + path + "/" + filename
|
||||
+ "> is incorrectly being reported as a collection." );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
webdavResource.setPath( oldPath );
|
||||
}
|
||||
}
|
||||
|
||||
public void assertDavFileNotExists( WebdavResource webdavResource, String path, String filename )
|
||||
throws Exception
|
||||
{
|
||||
String httpurl = webdavResource.getHttpURL().toString();
|
||||
|
||||
if ( webdavResource.headMethod( path + "/" + filename ) )
|
||||
{
|
||||
fail( "Encountered unexpected file/contents <" + path + "/" + filename + "> at <" + httpurl + ">" );
|
||||
}
|
||||
|
||||
String oldPath = webdavResource.getPath();
|
||||
try
|
||||
{
|
||||
webdavResource.setPath( path );
|
||||
|
||||
WebdavResources resources = webdavResource.getChildResources();
|
||||
|
||||
WebdavResource testResource = resources.getResource( filename );
|
||||
|
||||
if ( testResource == null )
|
||||
{
|
||||
// Nothing found. we're done.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !testResource.isCollection() )
|
||||
{
|
||||
fail( "Encountered unexpected file/contents <" + path + "/" + filename + "> at <" + httpurl + ">" );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
webdavResource.setPath( oldPath );
|
||||
}
|
||||
}
|
||||
|
||||
public void assertDavDirExists( WebdavResource webdavResource, String path )
|
||||
throws Exception
|
||||
{
|
||||
String httpurl = webdavResource.getHttpURL().toString();
|
||||
|
||||
String oldPath = webdavResource.getPath();
|
||||
try
|
||||
{
|
||||
webdavResource.setPath( path );
|
||||
|
||||
if ( !webdavResource.isCollection() )
|
||||
{
|
||||
if ( !isHttpStatusOk( webdavResource ) )
|
||||
{
|
||||
fail( "Unable to verify that path <" + path + "> is really a collection against <" + httpurl
|
||||
+ "> due to <" + webdavResource.getStatusMessage() + ">" );
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
webdavResource.setPath( oldPath );
|
||||
}
|
||||
}
|
||||
|
||||
public void assertDavDirNotExists( WebdavResource webdavResource, String path )
|
||||
throws Exception
|
||||
{
|
||||
String httpurl = webdavResource.getHttpURL().toString();
|
||||
|
||||
String oldPath = webdavResource.getPath();
|
||||
try
|
||||
{
|
||||
webdavResource.setPath( path );
|
||||
|
||||
if ( webdavResource.isCollection() )
|
||||
{
|
||||
fail( "Encountered unexpected collection <" + path + "> at <" + httpurl + ">" );
|
||||
}
|
||||
}
|
||||
catch ( HttpException e )
|
||||
{
|
||||
if ( e.getReasonCode() == HttpStatus.SC_NOT_FOUND )
|
||||
{
|
||||
// Expected path.
|
||||
return;
|
||||
}
|
||||
|
||||
fail( "Unable to set path due to HttpException: " + e.getReasonCode() + ":" + e.getReason() );
|
||||
}
|
||||
finally
|
||||
{
|
||||
webdavResource.setPath( oldPath );
|
||||
}
|
||||
}
|
||||
|
||||
public void assertDavTouchFile( WebdavResource webdavResource, String path, String filename, String contents )
|
||||
throws Exception
|
||||
{
|
||||
String httpurl = webdavResource.getHttpURL().toString();
|
||||
|
||||
webdavResource.setPath( path );
|
||||
|
||||
if ( !webdavResource.putMethod( path + "/" + filename, contents ) )
|
||||
{
|
||||
fail( "Unable to create file/contents <" + path + "/" + filename + "> against <" + httpurl + "> due to <"
|
||||
+ webdavResource.getStatusMessage() + ">" );
|
||||
}
|
||||
|
||||
assertDavFileExists( webdavResource, path, filename );
|
||||
}
|
||||
|
||||
protected void assertGet404( String url )
|
||||
throws IOException
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
GetMethod method = new GetMethod( url );
|
||||
|
||||
try
|
||||
{
|
||||
client.executeMethod( method );
|
||||
|
||||
if ( method.getStatusCode() == 404 )
|
||||
{
|
||||
// Expected path.
|
||||
return;
|
||||
}
|
||||
|
||||
fail( "Request for resource " + url + " should have resulted in an HTTP 404 (Not Found) response, "
|
||||
+ "instead got code " + method.getStatusCode() + " <" + method.getStatusText() + ">." );
|
||||
}
|
||||
catch ( HttpException e )
|
||||
{
|
||||
System.err.println( "HTTP Response: " + e.getReasonCode() + " " + e.getReason() );
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,163 +0,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.
|
||||
*/
|
||||
|
||||
package org.apache.maven.archiva.webdav.test;
|
||||
|
||||
import org.apache.maven.archiva.webdav.DavServerManager;
|
||||
import org.apache.maven.archiva.webdav.servlet.basic.BasicWebDavServlet;
|
||||
import org.codehaus.plexus.PlexusConstants;
|
||||
import org.codehaus.plexus.PlexusContainer;
|
||||
import org.codehaus.plexus.PlexusContainerException;
|
||||
import org.codehaus.plexus.spring.PlexusContainerAdapter;
|
||||
import org.codehaus.plexus.util.FileUtils;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.Context;
|
||||
import org.mortbay.jetty.servlet.ServletHandler;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AbstractWebdavServer - Baseline server for starting up a BasicWebDavServlet to allow experimentation with.
|
||||
*
|
||||
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
|
||||
* @version $Id: AbstractWebdavServer.java 5407 2007-01-12 19:41:09Z joakime $
|
||||
*/
|
||||
public abstract class AbstractWebdavServer
|
||||
{
|
||||
public static final int PORT = 14541;
|
||||
|
||||
protected PlexusContainer container;
|
||||
|
||||
protected String basedir;
|
||||
|
||||
/** the jetty server */
|
||||
protected Server server;
|
||||
|
||||
private DavServerManager manager;
|
||||
|
||||
public String getBasedir()
|
||||
{
|
||||
if ( basedir != null )
|
||||
{
|
||||
return basedir;
|
||||
}
|
||||
|
||||
basedir = System.getProperty( "basedir" );
|
||||
if ( basedir == null )
|
||||
{
|
||||
basedir = new File( "" ).getAbsolutePath();
|
||||
}
|
||||
|
||||
return basedir;
|
||||
}
|
||||
|
||||
public File getTestFile( String path )
|
||||
{
|
||||
return new File( getBasedir(), path );
|
||||
}
|
||||
|
||||
protected abstract String getProviderHint();
|
||||
|
||||
public void startServer()
|
||||
throws Exception
|
||||
{
|
||||
container = createContainerInstance();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Create the DavServerManager
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
manager = (DavServerManager) container.lookup( DavServerManager.ROLE, getProviderHint() );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Create the jetty server
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
System.setProperty( "DEBUG", "" );
|
||||
System.setProperty( "org.mortbay.log.class", "org.slf4j.impl.SimpleLogger" );
|
||||
|
||||
server = new Server( PORT );
|
||||
Context root = new Context( server, "/", Context.SESSIONS );
|
||||
ServletHandler servletHandler = root.getServletHandler();
|
||||
root.setContextPath( "/" );
|
||||
root.setAttribute( PlexusConstants.PLEXUS_KEY, container );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Configure the webdav servlet
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
ServletHolder holder = servletHandler.addServletWithMapping( BasicWebDavServlet.class, "/projects/*" );
|
||||
|
||||
// Initialize server contents directory.
|
||||
File serverContentsDir = new File( "target/test-server/" );
|
||||
|
||||
FileUtils.deleteDirectory( serverContentsDir );
|
||||
if ( serverContentsDir.exists() )
|
||||
{
|
||||
throw new IllegalStateException( "Unable to execute test, server contents test directory ["
|
||||
+ serverContentsDir.getAbsolutePath() + "] exists, and cannot be deleted by the test case." );
|
||||
}
|
||||
|
||||
if ( !serverContentsDir.mkdirs() )
|
||||
{
|
||||
throw new IllegalStateException( "Unable to execute test, server contents test directory ["
|
||||
+ serverContentsDir.getAbsolutePath() + "] cannot be created." );
|
||||
}
|
||||
|
||||
holder.setInitParameter( "dav.root", serverContentsDir.getAbsolutePath() );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start the jetty server
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
protected PlexusContainer createContainerInstance()
|
||||
throws PlexusContainerException
|
||||
{
|
||||
return new PlexusContainerAdapter();
|
||||
}
|
||||
|
||||
public void stopServer()
|
||||
{
|
||||
if ( server != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if ( container != null )
|
||||
{
|
||||
container.dispose();
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue