View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.ksb.messaging.servlet;
17  
18  import org.apache.cxf.Bus;
19  import org.apache.cxf.interceptor.Interceptor;
20  import org.apache.cxf.message.Message;
21  import org.apache.cxf.transport.servlet.ServletController;
22  import org.apache.cxf.transport.servlet.ServletTransportFactory;
23  import org.apache.log4j.Logger;
24  import org.kuali.rice.core.api.config.property.ConfigContext;
25  import org.kuali.rice.core.api.exception.RiceRuntimeException;
26  import org.kuali.rice.core.api.util.ClassLoaderUtils;
27  import org.kuali.rice.ksb.api.KsbApiServiceLocator;
28  import org.kuali.rice.ksb.api.bus.Endpoint;
29  import org.kuali.rice.ksb.api.bus.ServiceConfiguration;
30  import org.kuali.rice.ksb.api.bus.support.SoapServiceConfiguration;
31  import org.kuali.rice.ksb.security.SignatureSigningResponseWrapper;
32  import org.kuali.rice.ksb.security.SignatureVerifyingRequestWrapper;
33  import org.kuali.rice.ksb.service.KSBServiceLocator;
34  import org.springframework.beans.BeansException;
35  import org.springframework.web.HttpRequestHandler;
36  import org.springframework.web.context.WebApplicationContext;
37  import org.springframework.web.servlet.DispatcherServlet;
38  import org.springframework.web.servlet.HandlerAdapter;
39  import org.springframework.web.servlet.HandlerExecutionChain;
40  import org.springframework.web.servlet.ModelAndView;
41  import org.springframework.web.servlet.mvc.Controller;
42  import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
43  import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
44  
45  import javax.servlet.ServletException;
46  import javax.servlet.http.HttpServletRequest;
47  import javax.servlet.http.HttpServletResponse;
48  import javax.xml.namespace.QName;
49  import java.io.IOException;
50  import java.util.List;
51  
52  
53  /**
54   * A {@link DispatcherServlet} which dispatches incoming requests to the appropriate
55   * service endpoint.
56   *
57   * @author Kuali Rice Team (rice.collab@kuali.org)
58   */
59  public class KSBDispatcherServlet extends DispatcherServlet {
60  
61  	private static final Logger LOG = Logger.getLogger(KSBDispatcherServlet.class);
62  	private static final long serialVersionUID = 6790121225857950019L;
63      private static final String REMOTING_SERVLET_CONFIG_LOCATION = "classpath:org/kuali/rice/ksb/config/remoting-servlet.xml";
64  
65  	private KSBHttpInvokerHandler httpInvokerHandler;
66  	private ServletController cxfServletController;
67  
68      @Override
69  	protected void initFrameworkServlet() throws ServletException, BeansException {
70  		this.httpInvokerHandler = new KSBHttpInvokerHandler();
71  		
72          Bus bus = KSBServiceLocator.getCXFBus();
73  
74          List<Interceptor<? extends Message>> inInterceptors = KSBServiceLocator.getInInterceptors();
75          if(inInterceptors != null) {
76          	List<Interceptor<? extends Message>> busInInterceptors = bus.getInInterceptors();
77          	busInInterceptors.addAll(inInterceptors);
78          }
79         
80          List<Interceptor<? extends Message>> outInterceptors = KSBServiceLocator.getOutInterceptors();
81          if(outInterceptors != null) {
82          	List<Interceptor<? extends Message>> busOutInterceptors = bus.getOutInterceptors();
83          	busOutInterceptors.addAll(outInterceptors);
84          }
85          
86  		ServletTransportFactory servletTransportFactory = KSBServiceLocator.getCXFServletTransportFactory();
87  				
88  		this.cxfServletController = new ServletController(servletTransportFactory, this.getServletConfig(), this.getServletContext(), bus);
89  		
90  		if (!ConfigContext.getCurrentContextConfig().getDevMode()) {
91  		    // disable handling of URLs ending in /services which display CXF generated service lists
92  		    this.cxfServletController.setHideServiceList(true);
93  		}
94  		
95  		this.setPublishEvents(false);
96  	}
97  
98      @Override
99  	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
100 		if (handler instanceof HttpRequestHandler) {
101 			return new HttpRequestHandlerAdapter();
102 		} else if (handler instanceof Controller) {
103 			Object unwrappedHandler = ClassLoaderUtils.unwrapFromProxy(handler);
104 			if (unwrappedHandler instanceof CXFServletControllerAdapter) {
105 				// TODO this just seems weird as this controller is initially null when it's created, does there need to be some synchronization here?
106 				((CXFServletControllerAdapter)unwrappedHandler).setController(cxfServletController);
107 			}			
108 			return new SimpleControllerHandlerAdapter();
109 		}
110 		throw new RiceRuntimeException("handler of type " + handler.getClass().getName() + " is not known and can't be used by " + KSBDispatcherServlet.class.getName());
111 	}
112 
113     @Override
114 	protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
115 		return this.httpInvokerHandler.getHandler(request);
116 	}
117 
118 	@Override
119 	protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
120 		try {
121 			QName serviceName = this.httpInvokerHandler.getServiceNameFromRequest(request);
122 			LOG.info("Caught Exception from service " + serviceName, ex);
123 		} catch (Throwable throwable) {
124 			LOG.warn("Caught exception attempting to log exception thrown from remotely accessed service", throwable);
125 		}
126 		return null;
127 	}
128 
129 	/**
130 	 * Overrides the service method to replace the request and responses with one which will provide input and output streams for
131 	 * verifying and signing the data.
132 	 */
133 	@Override
134 	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
135 		if (isSecure(request)) {
136 			super.service(new SignatureVerifyingRequestWrapper(request), new SignatureSigningResponseWrapper(response));
137 		} else {
138 			super.service(request, response);
139 		}
140 	}
141 
142     @Override
143     protected WebApplicationContext initWebApplicationContext() {
144         setContextConfigLocation(REMOTING_SERVLET_CONFIG_LOCATION);
145         return super.initWebApplicationContext();
146     }
147 
148 	protected boolean isSecure(HttpServletRequest request) {
149 		QName serviceName = this.httpInvokerHandler.getServiceNameFromRequest(request);
150 		if (LOG.isDebugEnabled()) {
151 		    LOG.debug("Checking service " + serviceName + " for security enabled");
152 		}
153 		Endpoint endpoint = KsbApiServiceLocator.getServiceBus().getEndpoint(serviceName);
154 		if (endpoint == null) {
155 			LOG.error("Attempting to acquire non-existent service " + request.getRequestURI());
156 		    throw new RiceRuntimeException("Attempting to acquire non-existent service.");
157 		}
158 		ServiceConfiguration serviceConfiguration = endpoint.getServiceConfiguration();
159 		if (serviceConfiguration instanceof SoapServiceConfiguration) {
160 		    return false;
161 		}
162 		return serviceConfiguration.getBusSecurity();
163 	}
164 
165 }