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.util.xml.pull.XmlPullParserException;
40 import org.codehaus.plexus.webdav.AbstractDavServerComponent;
41 import org.codehaus.plexus.webdav.DavServerComponent;
42 import org.codehaus.plexus.webdav.DavServerException;
43 import org.codehaus.plexus.webdav.servlet.DavServerRequest;
44 import org.codehaus.plexus.webdav.util.WebdavMethodUtil;
47 import java.io.FileNotFoundException;
48 import java.io.FileReader;
49 import java.io.IOException;
50 import java.io.PrintWriter;
52 import javax.servlet.ServletConfig;
53 import javax.servlet.ServletException;
54 import javax.servlet.http.HttpServletResponse;
59 * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
61 * @plexus.component role="org.codehaus.plexus.webdav.DavServerComponent"
62 * role-hint="proxied" instantiation-strategy="per-lookup"
64 public class ProxiedDavServer
65 extends AbstractDavServerComponent
68 * @plexus.requirement role-hint="simple"
70 private DavServerComponent davServer;
75 private RepositoryContentFactory repositoryFactory;
80 private RepositoryRequest repositoryRequest;
83 * @plexus.requirement role-hint="default"
85 private RepositoryProxyConnectors connectors;
90 private MetadataTools metadataTools;
92 private ManagedRepositoryContent managedRepository;
94 public String getPrefix()
96 return davServer.getPrefix();
99 public File getRootDirectory()
101 return davServer.getRootDirectory();
104 public void setPrefix( String prefix )
106 davServer.setPrefix( prefix );
109 public void setRootDirectory( File rootDirectory )
111 davServer.setRootDirectory( rootDirectory );
114 public void init( ServletConfig servletConfig )
115 throws DavServerException
117 davServer.init( servletConfig );
121 managedRepository = repositoryFactory.getManagedRepositoryContent( getPrefix() );
123 catch ( RepositoryNotFoundException e )
125 throw new DavServerException( e.getMessage(), e );
127 catch ( RepositoryException e )
129 throw new DavServerException( e.getMessage(), e );
133 public void process( DavServerRequest request, HttpServletResponse response )
134 throws DavServerException, ServletException, IOException
136 boolean isGet = WebdavMethodUtil.isReadMethod( request.getRequest().getMethod() );
137 boolean isPut = WebdavMethodUtil.isWriteMethod( request.getRequest().getMethod() );
141 fetchContentFromProxies( request );
146 /* Create parent directories that don't exist when writing a file
147 * This actually makes this implementation not compliant to the
148 * WebDAV RFC - but we have enough knowledge
149 * about how the collection is being used to do this reasonably and
150 * some versions of Maven's WebDAV don't
151 * correctly create the collections themselves.
154 File rootDirectory = getRootDirectory();
155 if ( rootDirectory != null )
157 new File( rootDirectory, request.getLogicalResource() ).getParentFile().mkdirs();
163 if ( resourceExists( request ) )
165 // [MRM-503] - Metadata file need Pragma:no-cache response header.
166 if ( request.getLogicalResource().endsWith( "/maven-metadata.xml" ) )
168 response.addHeader( "Pragma", "no-cache" );
169 response.addHeader( "Cache-Control", "no-cache" );
172 // TODO: [MRM-524] determine http caching options for other types of files (artifacts, sha1, md5, snapshots)
174 davServer.process( request, response );
178 respondResourceMissing( request, response );
184 davServer.process( request, response );
188 private void respondResourceMissing( DavServerRequest request, HttpServletResponse response )
190 response.setStatus( HttpServletResponse.SC_NOT_FOUND );
194 StringBuffer missingUrl = new StringBuffer();
195 missingUrl.append( request.getRequest().getScheme() ).append( "://" );
196 missingUrl.append( request.getRequest().getServerName() ).append( ":" );
197 missingUrl.append( request.getRequest().getServerPort() );
198 missingUrl.append( request.getRequest().getServletPath() );
199 // missingUrl.append( request.getRequest().getPathInfo() );
201 String message = "Error 404 Not Found";
203 PrintWriter out = new PrintWriter( response.getOutputStream() );
205 response.setContentType( "text/html; charset=\"UTF-8\"" );
207 out.println( "<html>" );
208 out.println( "<head><title>" + message + "</title></head>" );
209 out.println( "<body>" );
211 out.print( "<p><h1>" );
212 out.print( message );
213 out.println( "</h1></p>" );
215 out.print( "<p>The following resource does not exist: <a href=\"" );
216 out.print( missingUrl.toString() );
217 out.println( "\">" );
218 out.print( missingUrl.toString() );
219 out.println( "</a></p>" );
221 out.println( "</body></html>" );
225 catch ( IOException e )
231 private boolean resourceExists( DavServerRequest request )
233 String resource = request.getLogicalResource();
234 File resourceFile = new File( managedRepository.getRepoRoot(), resource );
235 return resourceFile.exists();
238 private void fetchContentFromProxies( DavServerRequest request )
239 throws ServletException
241 String resource = request.getLogicalResource();
243 // Cleanup bad requests from maven 1.
244 // Often seen is a double slash.
245 // example: http://hostname:8080/archiva/repository/internal//pmd/jars/pmd-3.0.jar
246 if ( resource.startsWith( "/" ) )
248 resource = resource.substring( 1 );
251 if ( resource.endsWith( ".sha1" ) || resource.endsWith( ".md5" ) )
253 // Checksums are fetched with artifact / metadata.
257 // Is it a Metadata resource?
258 if ( resource.endsWith( "/" + MetadataTools.MAVEN_METADATA ) )
260 ProjectReference project;
261 VersionedReference versioned;
266 versioned = metadataTools.toVersionedReference( resource );
267 if ( versioned != null )
269 connectors.fetchFromProxies( managedRepository, versioned );
270 request.getRequest().setPathInfo( metadataTools.toPath( versioned ) );
274 catch ( RepositoryMetadataException e )
278 catch ( ProxyException e )
280 throw new ServletException( "Unable to fetch versioned metadata resource.", e );
285 project = metadataTools.toProjectReference( resource );
286 if ( project != null )
288 connectors.fetchFromProxies( managedRepository, project );
289 request.getRequest().setPathInfo( metadataTools.toPath( project ) );
292 catch ( RepositoryMetadataException e )
296 catch ( ProxyException e )
298 throw new ServletException( "Unable to fetch project metadata resource.", e );
302 // Not any of the above? Then it's gotta be an artifact reference.
305 // Get the artifact reference in a layout neutral way.
306 ArtifactReference artifact = repositoryRequest.toArtifactReference( resource );
308 if ( artifact != null )
310 applyServerSideRelocation( artifact );
312 connectors.fetchFromProxies( managedRepository, artifact );
314 // Set the path to the resource using managed repository specific layout format.
315 request.getRequest().setPathInfo( managedRepository.toPath( artifact ) );
319 catch ( LayoutException e )
323 catch ( ProxyException e )
325 throw new ServletException( "Unable to fetch artifact resource.", e );
330 * A relocation capable client will request the POM prior to the artifact,
331 * and will then read meta-data and do client side relocation. A simplier
332 * client (like maven 1) will only request the artifact and not use the
335 * For such clients, archiva does server-side relocation by reading itself
336 * the <relocation> element in metadatas and serving the expected
339 protected void applyServerSideRelocation( ArtifactReference artifact )
340 throws ProxyException
342 if ( "pom".equals( artifact.getType() ) )
347 // Build the artifact POM reference
348 ArtifactReference pomReference = new ArtifactReference();
349 pomReference.setGroupId( artifact.getGroupId() );
350 pomReference.setArtifactId( artifact.getArtifactId() );
351 pomReference.setVersion( artifact.getVersion() );
352 pomReference.setType( "pom" );
354 // Get the artifact POM from proxied repositories if needed
355 connectors.fetchFromProxies( managedRepository, pomReference );
357 // Open and read the POM from the managed repo
358 File pom = managedRepository.toFile( pomReference );
367 Model model = new MavenXpp3Reader().read( new FileReader( pom ) );
368 DistributionManagement dist = model.getDistributionManagement();
371 Relocation relocation = dist.getRelocation();
372 if ( relocation != null )
374 // artifact is relocated : update the repositoryPath
375 if ( relocation.getGroupId() != null )
377 artifact.setGroupId( relocation.getGroupId() );
379 if ( relocation.getArtifactId() != null )
381 artifact.setArtifactId( relocation.getArtifactId() );
383 if ( relocation.getVersion() != null )
385 artifact.setVersion( relocation.getVersion() );
390 catch ( FileNotFoundException e )
392 // Artifact has no POM in repo : ignore
394 catch ( IOException e )
396 // Unable to read POM : ignore.
398 catch ( XmlPullParserException e )
400 // Invalid POM : ignore
404 public ManagedRepositoryContent getRepository()
406 return managedRepository;