/**
 *  Copyright (C) 2008 Progress Software, Inc. All rights reserved.
 *  http://fusesource.com
 *
 *  The software in this package is published under the terms of the AGPL license
 *  a copy of which has been included with this distribution in the license.txt file.
 */
package org.fusesource.cloudmix.common.spring;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.spi.container.servlet.ServletContainer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fusesource.cloudmix.common.HttpAuthenticator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * @version $Revision: 1.1 $
 */
public class SpringServlet extends ServletContainer {
	
    private static final transient Log LOG = LogFactory.getLog(SpringServlet.class);

    private ApplicationContext applicationContext;
	private HttpAuthenticator authenticator;

    public SpringServlet() {
        super();
    }
    
    public SpringServlet(ApplicationContext ctx, HttpAuthenticator ca) {
        applicationContext = ctx;
        authenticator = ca;
    }
  
    @Override
    protected void initiate(ResourceConfig rc, WebApplication wa) {
        ServletContext servletContext = getServletContext();
        ApplicationContext ctx;

        if (applicationContext != null) {
            ctx = applicationContext;
        } else {
            ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
        }

        wa.initiate(rc, getComponentProvider((ConfigurableApplicationContext) ctx));
    }

    protected SpringComponentProvider getComponentProvider(ConfigurableApplicationContext ctx) {
        return new SpringComponentProvider(ctx);
    }
    
    /**
     * Overriding service method to provide a authentication filter.  This calls the authenticator
     * if there is one to perform authentication.
     */
    @Override
    public void service(final ServletRequest request, final ServletResponse response) throws ServletException, IOException {
    	    	
    	if (authenticator != null) {
        	if (!(request instanceof HttpServletRequest)) {
    			throw new ServletException("Need a HttpServletRequest for authentication");
    		}
        	if (!(response instanceof HttpServletResponse)) {
    			throw new ServletException("Need a HttpServletRequest for authentication");
    		}
    		HttpServletRequest httpRequest = (HttpServletRequest) request;
    		HttpServletResponse httpResponse = (HttpServletResponse) response;
    		
    		try {
    			LOG.info("Controller request " + httpRequest.getMethod() + " " + httpRequest.getRequestURI());
    			if (authenticator.authenticate(httpRequest)) {
        			super.service(request, response);
    			} else {
        			LOG.error("Authentication failed for request " + httpRequest.getMethod() + " " + httpRequest.getRequestURI());
        			httpResponse.sendError(401, "Cannot authenticate request " + httpRequest.getMethod() + " " + httpRequest.getRequestURI());
    			}
    		} finally {
    			// TODO - would like to log the response status here.
    		}
    		
    	} else {
    		super.service(request, response);	
    	}

    }
}

@@ -1361,16 +1361,54 @@
 ticator;
+%0A%09private boolean initialized = false;
 %0A%0A    pu
@@ -1601,17 +1601,19 @@
     %7D%0A  
+  
 %0A
-
     @Ove
@@ -2064,24 +2064,52 @@
 ext) ctx));%0A
+        initialized = true;%0A
     %7D%0A%0A    p
@@ -2256,24 +2256,29 @@
 %0A    %7D%0A    %0A
+    %0A
     /**%0A    
@@ -2577,20 +2577,17 @@
     
-%09
+%0A
     
-%09%0A
     
-%09
 if (
@@ -2611,33 +2611,36 @@
 null) %7B%0A        
-%09
+    
 if (!(request in
@@ -2667,35 +2667,44 @@
 Request)) %7B%0A    
-%09%09%09
+            
 throw new Servle
@@ -2771,20 +2771,28 @@
     
-%09%09%7D%0A
+        %7D%0A  
         
 %09if 
@@ -2787,17 +2787,18 @@
         
-%09
+  
 if (!(re
@@ -2843,19 +2843,28 @@
 ) %7B%0A    
-%09%09%09
+            
 throw ne
@@ -2935,26 +2935,38 @@
 %22);%0A    
-%09%09%7D%0A    %09%09
+        %7D%0A            
 HttpServ
@@ -3024,18 +3024,24 @@
 st;%0A    
-%09%09
+        
 HttpServ
@@ -3099,16 +3099,508 @@
 sponse;%0A
+            %0A            // Check for race condition where are request arrives before this %0A            // application context has been initialized.%0A            if (!initialized) %7B%0A                LOG.info(%22Application context not initialized; returning 503 for request %22 + httpRequest.getRequestURI());                %0A                httpResponse.sendError(503, %22Service not initialized%22);%0A                httpResponse.addHeader(%22Retry-After%22, %2210%22);%0A                return;%0A            %7D%0A%0A
     %09%09%0A 

Fix for race condition where a request is processed before the application context is initialized (REPO-766).