1 package org.apache.maven.archiva.web.repository;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.maven.archiva.model.ArtifactReference;
23 import org.apache.maven.archiva.model.ProjectReference;
24 import org.apache.maven.archiva.model.VersionedReference;
25 import org.apache.maven.archiva.proxy.ProxyException;
26 import org.apache.maven.archiva.proxy.RepositoryProxyConnectors;
27 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
28 import org.apache.maven.archiva.repository.RepositoryContentFactory;
29 import org.apache.maven.archiva.repository.RepositoryException;
30 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
31 import org.apache.maven.archiva.repository.content.RepositoryRequest;
32 import org.apache.maven.archiva.repository.layout.LayoutException;
33 import org.apache.maven.archiva.repository.metadata.MetadataTools;
34 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
35 import org.apache.maven.model.DistributionManagement;
36 import org.apache.maven.model.Model;
37 import org.apache.maven.model.Relocation;
38 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
39 import org.codehaus.plexus.webdav.AbstractDavServerComponent;
40 import org.codehaus.plexus.webdav.DavServerComponent;
41 import org.codehaus.plexus.webdav.DavServerException;
42 import org.codehaus.plexus.webdav.servlet.DavServerRequest;
43 import org.codehaus.plexus.webdav.util.WebdavMethodUtil;
46 import java.io.FileNotFoundException;
47 import java.io.FileReader;
48 import java.io.IOException;
49 import java.io.PrintWriter;
51 import javax.servlet.ServletConfig;
52 import javax.servlet.ServletException;
53 import javax.servlet.http.HttpServletResponse;
58 * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
60 * @plexus.component role="org.codehaus.plexus.webdav.DavServerComponent"
61 * role-hint="proxied" instantiation-strategy="per-lookup"
63 public class ProxiedDavServer
64 extends AbstractDavServerComponent
67 * @plexus.requirement role-hint="simple"
69 private DavServerComponent davServer;
74 private RepositoryContentFactory repositoryFactory;
79 private RepositoryRequest repositoryRequest;
82 * @plexus.requirement role-hint="default"
84 private RepositoryProxyConnectors connectors;
89 private MetadataTools metadataTools;
91 private ManagedRepositoryContent managedRepository;
93 public String getPrefix()
95 return davServer.getPrefix();
98 public File getRootDirectory()
100 return davServer.getRootDirectory();
103 public void setPrefix( String prefix )
105 davServer.setPrefix( prefix );
108 public void setRootDirectory( File rootDirectory )
110 davServer.setRootDirectory( rootDirectory );
113 public void init( ServletConfig servletConfig )
114 throws DavServerException
116 davServer.init( servletConfig );
120 managedRepository = repositoryFactory.getManagedRepositoryContent( getPrefix() );
122 catch ( RepositoryNotFoundException e )
124 throw new DavServerException( e.getMessage(), e );
126 catch ( RepositoryException e )
128 throw new DavServerException( e.getMessage(), e );
132 public void process( DavServerRequest request, HttpServletResponse response )
133 throws DavServerException, ServletException, IOException
135 if ( WebdavMethodUtil.isReadMethod( request.getRequest().getMethod() ) )
137 fetchContentFromProxies( request );
141 /* Create parent directories that don't exist when writing a file
142 * This actually makes this implementation not compliant to the
143 * WebDAV RFC - but we have enough knowledge
144 * about how the collection is being used to do this reasonably and
145 * some versions of Maven's WebDAV don't
146 * correctly create the collections themselves.
149 File rootDirectory = getRootDirectory();
150 if ( rootDirectory != null )
152 new File( rootDirectory, request.getLogicalResource() ).getParentFile().mkdirs();
156 // [MRM-503] - Metadata file need Pragma:no-cache response header.
157 if ( request.getLogicalResource().endsWith( "/maven-metadata.xml" ) )
159 response.addHeader( "Pragma", "no-cache" );
160 response.addHeader( "Cache-Control", "no-cache" );
163 // TODO: [MRM-524] determine http caching options for other types of files (artifacts, sha1, md5, snapshots)
165 if( resourceExists( request ) )
167 davServer.process( request, response );
171 respondResourceMissing( request, response );
175 private void respondResourceMissing( DavServerRequest request, HttpServletResponse response )
177 response.setStatus( HttpServletResponse.SC_NOT_FOUND );
181 StringBuffer missingUrl = new StringBuffer();
182 missingUrl.append( request.getRequest().getScheme() ).append( "://" );
183 missingUrl.append( request.getRequest().getServerName() ).append( ":" );
184 missingUrl.append( request.getRequest().getServerPort() );
185 missingUrl.append( request.getRequest().getServletPath() );
186 // missingUrl.append( request.getRequest().getPathInfo() );
188 String message = "Error 404 Not Found";
190 PrintWriter out = new PrintWriter( response.getOutputStream() );
192 response.setContentType( "text/html; charset=\"UTF-8\"" );
194 out.println( "<html>" );
195 out.println( "<head><title>" + message + "</title></head>" );
196 out.println( "<body>" );
198 out.print( "<p><h1>" );
199 out.print( message );
200 out.println( "</h1></p>" );
202 out.print( "<p>The following resource does not exist: <a href=\"" );
203 out.print( missingUrl.toString() );
204 out.println( "\">" );
205 out.print( missingUrl.toString() );
206 out.println( "</a></p>" );
208 out.println( "</body></html>" );
212 catch ( IOException e )
218 private boolean resourceExists( DavServerRequest request )
220 String resource = request.getLogicalResource();
221 File resourceFile = new File( managedRepository.getRepoRoot(), resource );
222 return resourceFile.exists();
225 private void fetchContentFromProxies( DavServerRequest request )
226 throws ServletException
228 String resource = request.getLogicalResource();
230 // Cleanup bad requests from maven 1.
231 // Often seen is a double slash.
232 // example: http://hostname:8080/archiva/repository/internal//pmd/jars/pmd-3.0.jar
233 if ( resource.startsWith( "/" ) )
235 resource = resource.substring( 1 );
238 if ( resource.endsWith( ".sha1" ) || resource.endsWith( ".md5" ) )
240 // Checksums are fetched with artifact / metadata.
244 // Is it a Metadata resource?
245 if ( resource.endsWith( "/" + MetadataTools.MAVEN_METADATA ) )
247 ProjectReference project;
248 VersionedReference versioned;
253 versioned = metadataTools.toVersionedReference( resource );
254 if ( versioned != null )
256 connectors.fetchFromProxies( managedRepository, versioned );
257 request.getRequest().setPathInfo( metadataTools.toPath( versioned ) );
261 catch ( RepositoryMetadataException e )
265 catch ( ProxyException e )
267 throw new ServletException( "Unable to fetch versioned metadata resource.", e );
272 project = metadataTools.toProjectReference( resource );
273 if ( project != null )
275 connectors.fetchFromProxies( managedRepository, project );
276 request.getRequest().setPathInfo( metadataTools.toPath( project ) );
279 catch ( RepositoryMetadataException e )
283 catch ( ProxyException e )
285 throw new ServletException( "Unable to fetch project metadata resource.", e );
289 // Not any of the above? Then it's gotta be an artifact reference.
292 // Get the artifact reference in a layout neutral way.
293 ArtifactReference artifact = repositoryRequest.toArtifactReference( resource );
295 if ( artifact != null )
297 applyServerSideRelocation( artifact );
299 connectors.fetchFromProxies( managedRepository, artifact );
301 // Set the path to the resource using managed repository specific layout format.
302 request.getRequest().setPathInfo( managedRepository.toPath( artifact ) );
306 catch ( LayoutException e )
310 catch ( ProxyException e )
312 throw new ServletException( "Unable to fetch artifact resource.", e );
317 * A relocation capable client will request the POM prior to the artifact,
318 * and will then read meta-data and do client side relocation. A simplier
319 * client (like maven 1) will only request the artifact and not use the
322 * For such clients, archiva does server-side relocation by reading itself
323 * the <relocation> element in metadatas and serving the expected
326 protected void applyServerSideRelocation( ArtifactReference artifact )
327 throws ProxyException
329 if ( "pom".equals( artifact.getType() ) )
334 // Build the artifact POM reference
335 ArtifactReference pomReference = new ArtifactReference();
336 pomReference.setGroupId( artifact.getGroupId() );
337 pomReference.setArtifactId( artifact.getArtifactId() );
338 pomReference.setVersion( artifact.getVersion() );
339 pomReference.setType( "pom" );
341 // Get the artifact POM from proxied repositories if needed
342 connectors.fetchFromProxies( managedRepository, pomReference );
344 // Open and read the POM from the managed repo
345 File pom = managedRepository.toFile( pomReference );
348 Model model = new MavenXpp3Reader().read( new FileReader( pom ) );
349 DistributionManagement dist = model.getDistributionManagement();
352 Relocation relocation = dist.getRelocation();
353 if ( relocation != null )
355 // artifact is relocated : update the repositoryPath
356 if ( relocation.getGroupId() != null )
358 artifact.setGroupId( relocation.getGroupId() );
360 if ( relocation.getArtifactId() != null )
362 artifact.setArtifactId( relocation.getArtifactId() );
364 if ( relocation.getVersion() != null )
366 artifact.setVersion( relocation.getVersion() );
371 catch ( FileNotFoundException e )
373 // Artifact has no POM in repo : ignore
375 catch ( Exception e )
377 // invalid POM : ignore
381 public ManagedRepositoryContent getRepository()
383 return managedRepository;