content: package org.apache.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.archiva.admin.model.RepositoryAdminException;
  import org.apache.archiva.configuration.provider.ArchivaConfiguration;
  import org.apache.archiva.configuration.provider.ConfigurationEvent;
  import org.apache.archiva.configuration.provider.ConfigurationListener;
  import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
  import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
  import org.apache.archiva.repository.ManagedRepository;
  import org.apache.archiva.repository.RepositoryRegistry;
  import org.apache.archiva.security.ServletAuthenticator;
  import org.apache.jackrabbit.webdav.DavException;
  import org.apache.jackrabbit.webdav.DavLocatorFactory;
  import org.apache.jackrabbit.webdav.DavMethods;
  import org.apache.jackrabbit.webdav.DavResource;
  import org.apache.jackrabbit.webdav.DavResourceFactory;
  import org.apache.jackrabbit.webdav.DavServletResponse;
  import org.apache.jackrabbit.webdav.DavSessionProvider;
  import org.apache.jackrabbit.webdav.WebdavRequest;
  import org.apache.jackrabbit.webdav.WebdavRequestImpl;
  import org.apache.jackrabbit.webdav.WebdavResponse;
  import org.apache.jackrabbit.webdav.WebdavResponseImpl;
  import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.context.ConfigurableApplicationContext;
  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.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import java.io.IOException;
  import java.util.concurrent.locks.ReentrantReadWriteLock;
  
  /**
   * RepositoryServlet
   */
  public class RepositoryServlet
      extends AbstractWebdavServlet
      implements ConfigurationListener
  {
      private Logger log = LoggerFactory.getLogger( RepositoryServlet.class );
  
      private ArchivaConfiguration configuration;
  
      RepositoryRegistry repositoryRegistry;
  
      private DavLocatorFactory locatorFactory;
  
      private DavResourceFactory resourceFactory;
  
      private DavSessionProvider sessionProvider;
  
      protected final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
  
      @Override
      public void init( ServletConfig servletConfig )
          throws ServletException
      {
          super.init( servletConfig );
          initServers( servletConfig );
      }
  
      /**
       * Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
       * to support different realms
       *
       * @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 );
          DavResource resource = null;
  
          try
          {
              // make sure there is a authenticated user
              if ( !getDavSessionProvider().attachSession( webdavRequest ) )
              {
                  return;
              }
  
              // check matching if=header for lock-token relevant operations
              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 ( BrowserRedirectException e )
          {
              response.sendRedirect( e.getLocation() );
          }
          catch ( DavException e )
          {
              if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
              {
                  final String msg = "Should throw " + UnauthorizedDavException.class.getName();
                  log.error( msg );
                  webdavResponse.sendError( e.getErrorCode(), msg );
              }
              else if ( e.getCause() != null )
              {
                  webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
              }
              else
              {
                  webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
              }
          }
          finally
          {
              getDavSessionProvider().releaseSession( webdavRequest );
          }
      }
  
      public void initServers( ServletConfig servletConfig ) {
  
          long start = System.currentTimeMillis();
  
          WebApplicationContext wac =
              WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
  
          rwLock.writeLock().lock();
          try {
              configuration = wac.getBean("archivaConfiguration#default", ArchivaConfiguration.class);
              configuration.addListener(this);
  
              repositoryRegistry = wac.getBean( ArchivaRepositoryRegistry.class);
              resourceFactory = wac.getBean("davResourceFactory#archiva", DavResourceFactory.class);
              locatorFactory = new ArchivaDavLocatorFactory();
  
              ServletAuthenticator servletAuth = wac.getBean(ServletAuthenticator.class);
              HttpAuthenticator httpAuth = wac.getBean("httpAuthenticator#basic", HttpAuthenticator.class);
  
              sessionProvider = new ArchivaDavSessionProvider(servletAuth, httpAuth);
          } finally {
              rwLock.writeLock().unlock();
          }
          long end = System.currentTimeMillis();
  
          log.debug( "initServers done in {} ms", (end - start) );
      }
  
      @Override
      public void configurationEvent( ConfigurationEvent event )
      {
          if ( event.getType() == ConfigurationEvent.SAVED )
          {
              try
              {
                  initRepositories();
              }
              catch ( RepositoryAdminException e )
              {
                  log.error( e.getMessage(), e );
                  throw new RuntimeException( e.getMessage(), e );
              }
          }
      }
  
      private void initRepositories()
          throws RepositoryAdminException
      {
              initServers( getServletConfig() );
      }
  
      public ManagedRepository getRepository( String prefix )
          throws RepositoryAdminException
      {
          return repositoryRegistry.getManagedRepository( prefix );
      }
  
      ArchivaConfiguration getConfiguration()
      {
          return configuration;
      }
  
      @Override
      protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
      {
          // check for read or write access to the resource when resource-based permission is implemented
  
          return true;
      }
  
      @Override
      public DavSessionProvider getDavSessionProvider()
      {
          return sessionProvider;
      }
  
      @Override
      public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
      {
          this.sessionProvider = davSessionProvider;
      }
  
      @Override
      public DavLocatorFactory getLocatorFactory()
      {
          return locatorFactory;
      }
  
      @Override
      public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
      {
          locatorFactory = davLocatorFactory;
      }
  
      @Override
      public DavResourceFactory getResourceFactory()
      {
          return resourceFactory;
      }
  
      @Override
      public void setResourceFactory( final DavResourceFactory davResourceFactory )
      {
          resourceFactory = davResourceFactory;
      }
  
      @Override
      public String getAuthenticateHeaderValue()
      {
          throw new UnsupportedOperationException();
      }
  
      public String getAuthenticateHeaderValue( String repository )
      {
          return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
      }
  
      @Override
      public void destroy()
      {
          rwLock.writeLock().lock();
          try {
              configuration.removeListener(this);
  
              resourceFactory = null;
              configuration = null;
              locatorFactory = null;
              sessionProvider = null;
  
              WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
  
              if (wac instanceof ConfigurableApplicationContext) {
                  ((ConfigurableApplicationContext) wac).close();
              }
              super.destroy();
          } finally {
              rwLock.writeLock().unlock();
          }
      }
  }
  