View Javadoc

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