This project has retired. For details please refer to its Attic page.
RepositoryServlet xref
View Javadoc
1   package org.apache.archiva.webdav;
2   
3   /*
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
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
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
19   * under the License.
20   */
21  
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.DavException;
31  import org.apache.jackrabbit.webdav.DavLocatorFactory;
32  import org.apache.jackrabbit.webdav.DavMethods;
33  import org.apache.jackrabbit.webdav.DavResource;
34  import org.apache.jackrabbit.webdav.DavResourceFactory;
35  import org.apache.jackrabbit.webdav.DavServletResponse;
36  import org.apache.jackrabbit.webdav.DavSessionProvider;
37  import org.apache.jackrabbit.webdav.WebdavRequest;
38  import org.apache.jackrabbit.webdav.WebdavRequestImpl;
39  import org.apache.jackrabbit.webdav.WebdavResponse;
40  import org.apache.jackrabbit.webdav.WebdavResponseImpl;
41  import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  import org.springframework.context.ConfigurableApplicationContext;
45  import org.springframework.web.context.WebApplicationContext;
46  import org.springframework.web.context.support.WebApplicationContextUtils;
47  
48  import javax.servlet.ServletConfig;
49  import javax.servlet.ServletException;
50  import javax.servlet.http.HttpServletRequest;
51  import javax.servlet.http.HttpServletResponse;
52  import java.io.File;
53  import java.io.IOException;
54  import java.util.Map;
55  
56  /**
57   * RepositoryServlet
58   */
59  public class RepositoryServlet
60      extends AbstractWebdavServlet
61      implements ConfigurationListener
62  {
63      private Logger log = LoggerFactory.getLogger( RepositoryServlet.class );
64  
65      private ArchivaConfiguration configuration;
66  
67      private ManagedRepositoryAdmin managedRepositoryAdmin;
68  
69      private Map<String, ManagedRepository> repositoryMap;
70  
71      private DavLocatorFactory locatorFactory;
72  
73      private DavResourceFactory resourceFactory;
74  
75      private DavSessionProvider sessionProvider;
76  
77      private final Object reloadLock = new Object();
78  
79      @Override
80      public void init( ServletConfig servletConfig )
81          throws ServletException
82      {
83          super.init( servletConfig );
84          try
85          {
86              initServers( servletConfig );
87          }
88          catch ( RepositoryAdminException e )
89          {
90              log.error( e.getMessage(), e );
91              throw new ServletException( e.getMessage(), e );
92          }
93      }
94  
95      /**
96       * Service the given request. This method has been overridden and copy/pasted to allow better exception handling and
97       * to support different realms
98       *
99       * @param request
100      * @param response
101      * @throws ServletException
102      * @throws java.io.IOException
103      */
104     @Override
105     protected void service( HttpServletRequest request, HttpServletResponse response )
106         throws ServletException, IOException
107     {
108         WebdavRequest webdavRequest = new WebdavRequestImpl( request, getLocatorFactory() );
109         // DeltaV requires 'Cache-Control' header for all methods except 'VERSION-CONTROL' and 'REPORT'.
110         int methodCode = DavMethods.getMethodCode( request.getMethod() );
111         boolean noCache = DavMethods.isDeltaVMethod( webdavRequest ) && !( DavMethods.DAV_VERSION_CONTROL == methodCode
112             || DavMethods.DAV_REPORT == methodCode );
113         WebdavResponse webdavResponse = new WebdavResponseImpl( response, noCache );
114         DavResource resource = null;
115 
116         try
117         {
118             // make sure there is a authenticated user
119             if ( !getDavSessionProvider().attachSession( webdavRequest ) )
120             {
121                 return;
122             }
123 
124             // check matching if=header for lock-token relevant operations
125             resource =
126                 getResourceFactory().createResource( webdavRequest.getRequestLocator(), webdavRequest, webdavResponse );
127 
128             if ( !isPreconditionValid( webdavRequest, resource ) )
129             {
130                 webdavResponse.sendError( DavServletResponse.SC_PRECONDITION_FAILED );
131                 return;
132             }
133             if ( !execute( webdavRequest, webdavResponse, methodCode, resource ) )
134             {
135                 super.service( request, response );
136             }
137 
138         }
139         catch ( UnauthorizedDavException e )
140         {
141             webdavResponse.setHeader( "WWW-Authenticate", getAuthenticateHeaderValue( e.getRepositoryName() ) );
142             webdavResponse.sendError( e.getErrorCode(), e.getStatusPhrase() );
143         }
144         catch ( BrowserRedirectException e )
145         {
146             response.sendRedirect( e.getLocation() );
147         }
148         catch ( DavException e )
149         {
150             if ( e.getErrorCode() == HttpServletResponse.SC_UNAUTHORIZED )
151             {
152                 final String msg = "Should throw " + UnauthorizedDavException.class.getName();
153                 log.error( msg );
154                 webdavResponse.sendError( e.getErrorCode(), msg );
155             }
156             else if ( e.getCause() != null )
157             {
158                 webdavResponse.sendError( e.getErrorCode(), e.getCause().getMessage() );
159             }
160             else
161             {
162                 webdavResponse.sendError( e.getErrorCode(), e.getMessage() );
163             }
164         }
165         finally
166         {
167             getDavSessionProvider().releaseSession( webdavRequest );
168         }
169     }
170 
171     public synchronized void initServers( ServletConfig servletConfig )
172         throws RepositoryAdminException
173     {
174 
175         long start = System.currentTimeMillis();
176 
177         WebApplicationContext wac =
178             WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
179 
180         configuration = wac.getBean( "archivaConfiguration#default", ArchivaConfiguration.class );
181         configuration.addListener( this );
182 
183         managedRepositoryAdmin = wac.getBean( ManagedRepositoryAdmin.class );
184 
185         repositoryMap = managedRepositoryAdmin.getManagedRepositoriesAsMap();
186 
187         for ( ManagedRepository repo : repositoryMap.values() )
188         {
189             File repoDir = new File( repo.getLocation() );
190 
191             if ( !repoDir.exists() )
192             {
193                 if ( !repoDir.mkdirs() )
194                 {
195                     // Skip invalid directories.
196                     log.info( "Unable to create missing directory for {}", repo.getLocation() );
197                     continue;
198                 }
199             }
200         }
201 
202         resourceFactory = wac.getBean( "davResourceFactory#archiva", DavResourceFactory.class );
203         locatorFactory = new ArchivaDavLocatorFactory();
204 
205         ServletAuthenticator servletAuth = wac.getBean( ServletAuthenticator.class );
206         HttpAuthenticator httpAuth = wac.getBean( "httpAuthenticator#basic", HttpAuthenticator.class );
207 
208         sessionProvider = new ArchivaDavSessionProvider( servletAuth, httpAuth );
209 
210         long end = System.currentTimeMillis();
211 
212         log.info( "initServers done in {} ms", (end - start) );
213     }
214 
215     @Override
216     public void configurationEvent( ConfigurationEvent event )
217     {
218         if ( event.getType() == ConfigurationEvent.SAVED )
219         {
220             try
221             {
222                 initRepositories();
223             }
224             catch ( RepositoryAdminException e )
225             {
226                 log.error( e.getMessage(), e );
227                 throw new RuntimeException( e.getMessage(), e );
228             }
229         }
230     }
231 
232     private void initRepositories()
233         throws RepositoryAdminException
234     {
235         synchronized ( repositoryMap )
236         {
237             repositoryMap.clear();
238             repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
239         }
240 
241         synchronized ( reloadLock )
242         {
243             initServers( getServletConfig() );
244         }
245     }
246 
247     public synchronized ManagedRepository getRepository( String prefix )
248         throws RepositoryAdminException
249     {
250         if ( repositoryMap.isEmpty() )
251         {
252             repositoryMap.putAll( managedRepositoryAdmin.getManagedRepositoriesAsMap() );
253         }
254         return repositoryMap.get( prefix );
255     }
256 
257     ArchivaConfiguration getConfiguration()
258     {
259         return configuration;
260     }
261 
262     @Override
263     protected boolean isPreconditionValid( final WebdavRequest request, final DavResource davResource )
264     {
265         // check for read or write access to the resource when resource-based permission is implemented
266 
267         return true;
268     }
269 
270     @Override
271     public DavSessionProvider getDavSessionProvider()
272     {
273         return sessionProvider;
274     }
275 
276     @Override
277     public void setDavSessionProvider( final DavSessionProvider davSessionProvider )
278     {
279         this.sessionProvider = davSessionProvider;
280     }
281 
282     @Override
283     public DavLocatorFactory getLocatorFactory()
284     {
285         return locatorFactory;
286     }
287 
288     @Override
289     public void setLocatorFactory( final DavLocatorFactory davLocatorFactory )
290     {
291         locatorFactory = davLocatorFactory;
292     }
293 
294     @Override
295     public DavResourceFactory getResourceFactory()
296     {
297         return resourceFactory;
298     }
299 
300     @Override
301     public void setResourceFactory( final DavResourceFactory davResourceFactory )
302     {
303         resourceFactory = davResourceFactory;
304     }
305 
306     @Override
307     public String getAuthenticateHeaderValue()
308     {
309         throw new UnsupportedOperationException();
310     }
311 
312     public String getAuthenticateHeaderValue( String repository )
313     {
314         return "Basic realm=\"Repository Archiva Managed " + repository + " Repository\"";
315     }
316 
317     @Override
318     public void destroy()
319     {
320         configuration.removeListener( this );
321 
322         resourceFactory = null;
323         configuration = null;
324         locatorFactory = null;
325         sessionProvider = null;
326         repositoryMap.clear();
327         repositoryMap = null;
328 
329         WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( getServletContext() );
330 
331         if ( wac instanceof ConfigurableApplicationContext )
332         {
333             ( (ConfigurableApplicationContext) wac ).close();
334         }
335         super.destroy();
336     }
337 }