1 package org.apache.archiva.webdav;
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.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.beans.ManagedRepository;
24 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
25 import org.apache.archiva.configuration.ArchivaConfiguration;
26 import org.apache.archiva.configuration.ConfigurationEvent;
27 import org.apache.archiva.configuration.ConfigurationListener;
28 import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
29 import org.apache.archiva.security.ServletAuthenticator;
30 import org.apache.jackrabbit.webdav.*;
31 import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.springframework.context.ConfigurableApplicationContext;
35 import org.springframework.web.context.WebApplicationContext;
36 import org.springframework.web.context.support.WebApplicationContextUtils;
38 import javax.servlet.ServletConfig;
39 import javax.servlet.ServletException;
40 import javax.servlet.http.HttpServletRequest;
41 import javax.servlet.http.HttpServletResponse;
42 import java.io.IOException;
43 import java.nio.file.Files;
44 import java.nio.file.Path;
45 import java.nio.file.Paths;
51 public class RepositoryServlet
52 extends AbstractWebdavServlet
53 implements ConfigurationListener
55 private Logger log = LoggerFactory.getLogger( RepositoryServlet.class );
57 private ArchivaConfiguration configuration;
59 private ManagedRepositoryAdmin managedRepositoryAdmin;
61 private Map<String, ManagedRepository> repositoryMap;
63 private DavLocatorFactory locatorFactory;
65 private DavResourceFactory resourceFactory;
67 private DavSessionProvider sessionProvider;
69 private final Object reloadLock = new Object();
72 public void init( ServletConfig servletConfig )
73 throws ServletException
75 super.init( servletConfig );
78 initServers( servletConfig );
80 catch ( RepositoryAdminException e )
82 log.error( e.getMessage(), e );
83 throw new ServletException( e.getMessage(), e );
88 * Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
89 * to support different realms
93 * @throws ServletException
94 * @throws java.io.IOException
97 protected void service( HttpServletRequest request, HttpServletResponse response )
98 throws ServletException, IOException
100 WebdavRequest webdavRequest = new WebdavRequestImpl( request, getLocatorFactory() );
101 // DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
102 int methodCode = DavMethods.getMethodCode( request.getMethod() );
103 boolean noCache = DavMethods.isDeltaVMethod( webdavRequest ) && !( DavMethods.DAV_VERSION_CONTROL == methodCode
104 || DavMethods.DAV_REPORT == methodCode );
105 WebdavResponse webdavResponse = new WebdavResponseImpl( response, noCache );
106 DavResource resource = null;
110 // make sure there is a authenticated user
111 if ( !getDavSessionProvider().attachSession( webdavRequest ) )
116 // check matching if=header for lock-token relevant operations
118 getResourceFactory().createResource( webdavRequest.getRequestLocator(), webdavRequest, webdavResponse );
120 if ( !isPreconditionValid( webdavRequest, resource ) )
122 webdavResponse.sendError( DavServletResponse.SC_PRECONDITION_FAILED );
125 if ( !execute( webdavRequest, webdavResponse, methodCode, resource ) )
127 super.service( request, response );
131 catch ( UnauthorizedDavException e )
133 webdavResponse.setHeader( "WWW-Authenticate", getAuthenticateHeaderValue( e.getRepositoryName() ) );
134 webdavResponse.sendError( e.getErrorCode(), e.getStatusPhrase() );
136 catch ( BrowserRedirectException e )
138 response.sendRedirect( e.getLocation() );
140 catch ( DavException e )
142 if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
144 final String msg = "Should throw " + UnauthorizedDavException.class.getName();
146 webdavResponse.sendError( e.getErrorCode(), msg );
148 else if ( e.getCause() != null )
150 webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
154 webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
159 getDavSessionProvider().releaseSession( webdavRequest );
163 public synchronized void initServers( ServletConfig servletConfig )
164 throws RepositoryAdminException
167 long start = System.currentTimeMillis();
169 WebApplicationContext wac =
170 WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
172 configuration = wac.getBean( "archivaConfiguration#default", ArchivaConfiguration.class );
173 configuration.addListener( this );
175 managedRepositoryAdmin = wac.getBean( ManagedRepositoryAdmin.class );
177 repositoryMap = managedRepositoryAdmin.getManagedRepositoriesAsMap();
179 for ( ManagedRepository repo : repositoryMap.values() )
181 Path repoDir = Paths.get( repo.getLocation() );
183 if ( !Files.exists(repoDir) )
187 Files.createDirectories( repoDir );
189 catch ( IOException e )
191 log.info( "Unable to create missing directory for {}", repo.getLocation() );
197 resourceFactory = wac.getBean( "davResourceFactory#archiva", DavResourceFactory.class );
198 locatorFactory = new ArchivaDavLocatorFactory();
200 ServletAuthenticator servletAuth = wac.getBean( ServletAuthenticator.class );
201 HttpAuthenticator httpAuth = wac.getBean( "httpAuthenticator#basic", HttpAuthenticator.class );
203 sessionProvider = new ArchivaDavSessionProvider( servletAuth, httpAuth );
205 long end = System.currentTimeMillis();
207 log.info( "initServers done in {} ms", (end - start) );
211 public void configurationEvent( ConfigurationEvent event )
213 if ( event.getType() == ConfigurationEvent.SAVED )
219 catch ( RepositoryAdminException e )
221 log.error( e.getMessage(), e );
222 throw new RuntimeException( e.getMessage(), e );
227 private void initRepositories()
228 throws RepositoryAdminException
230 synchronized ( repositoryMap )
232 repositoryMap.clear();
233 repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
236 synchronized ( reloadLock )
238 initServers( getServletConfig() );
242 public synchronized ManagedRepository getRepository( String prefix )
243 throws RepositoryAdminException
245 if ( repositoryMap.isEmpty() )
247 repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
249 return repositoryMap.get( prefix );
252 ArchivaConfiguration getConfiguration()
254 return configuration;
258 protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
260 // check for read or write access to the resource when resource-based permission is implemented
266 public DavSessionProvider getDavSessionProvider()
268 return sessionProvider;
272 public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
274 this.sessionProvider = davSessionProvider;
278 public DavLocatorFactory getLocatorFactory()
280 return locatorFactory;
284 public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
286 locatorFactory = davLocatorFactory;
290 public DavResourceFactory getResourceFactory()
292 return resourceFactory;
296 public void setResourceFactory( final DavResourceFactory davResourceFactory )
298 resourceFactory = davResourceFactory;
302 public String getAuthenticateHeaderValue()
304 throw new UnsupportedOperationException();
307 public String getAuthenticateHeaderValue( String repository )
309 return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
313 public void destroy()
315 configuration.removeListener( this );
317 resourceFactory = null;
318 configuration = null;
319 locatorFactory = null;
320 sessionProvider = null;
321 repositoryMap.clear();
322 repositoryMap = null;
324 WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
326 if ( wac instanceof ConfigurableApplicationContext )
328 ( (ConfigurableApplicationContext) wac ).close();