1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.ksb.messaging.servlet;
17
18 import org.apache.commons.collections.EnumerationUtils;
19 import org.apache.cxf.Bus;
20 import org.apache.cxf.interceptor.Interceptor;
21 import org.apache.cxf.message.Message;
22 import org.apache.cxf.transport.http.DestinationRegistry;
23 import org.apache.cxf.transport.http.HTTPTransportFactory;
24 import org.apache.cxf.transport.servlet.ServletController;
25 import org.apache.cxf.transport.servlet.servicelist.ServiceListGeneratorServlet;
26 import org.apache.log4j.Logger;
27 import org.kuali.rice.core.api.config.property.ConfigContext;
28 import org.kuali.rice.core.api.exception.RiceRuntimeException;
29 import org.kuali.rice.core.api.util.ClassLoaderUtils;
30 import org.kuali.rice.ksb.api.KsbApiServiceLocator;
31 import org.kuali.rice.ksb.api.bus.Endpoint;
32 import org.kuali.rice.ksb.api.bus.ServiceConfiguration;
33 import org.kuali.rice.ksb.api.bus.support.SoapServiceConfiguration;
34 import org.kuali.rice.ksb.security.SignatureSigningResponseWrapper;
35 import org.kuali.rice.ksb.security.SignatureVerifyingRequestWrapper;
36 import org.kuali.rice.ksb.service.KSBServiceLocator;
37 import org.springframework.beans.BeansException;
38 import org.springframework.web.HttpRequestHandler;
39 import org.springframework.web.context.WebApplicationContext;
40 import org.springframework.web.servlet.DispatcherServlet;
41 import org.springframework.web.servlet.HandlerAdapter;
42 import org.springframework.web.servlet.HandlerExecutionChain;
43 import org.springframework.web.servlet.ModelAndView;
44 import org.springframework.web.servlet.mvc.Controller;
45 import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
46 import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
47
48 import javax.servlet.ServletConfig;
49 import javax.servlet.ServletContext;
50 import javax.servlet.ServletException;
51 import javax.servlet.http.HttpServletRequest;
52 import javax.servlet.http.HttpServletResponse;
53 import javax.xml.namespace.QName;
54 import java.io.IOException;
55 import java.util.Enumeration;
56 import java.util.List;
57 import java.util.Vector;
58
59
60
61
62
63
64
65 public class KSBDispatcherServlet extends DispatcherServlet {
66
67 private static final Logger LOG = Logger.getLogger(KSBDispatcherServlet.class);
68 private static final long serialVersionUID = 6790121225857950019L;
69 private static final String REMOTING_SERVLET_CONFIG_LOCATION = "classpath:org/kuali/rice/ksb/config/remoting-servlet.xml";
70
71 private KSBHttpInvokerHandler httpInvokerHandler;
72 private ServletController cxfServletController;
73
74 @Override
75 protected void initFrameworkServlet() throws ServletException, BeansException {
76 this.httpInvokerHandler = new KSBHttpInvokerHandler();
77
78 Bus bus = KSBServiceLocator.getCXFBus();
79
80 List<Interceptor<? extends Message>> inInterceptors = KSBServiceLocator.getInInterceptors();
81 if(inInterceptors != null) {
82 List<Interceptor<? extends Message>> busInInterceptors = bus.getInInterceptors();
83 busInInterceptors.addAll(inInterceptors);
84 }
85
86 List<Interceptor<? extends Message>> outInterceptors = KSBServiceLocator.getOutInterceptors();
87 if(outInterceptors != null) {
88 List<Interceptor<? extends Message>> busOutInterceptors = bus.getOutInterceptors();
89 busOutInterceptors.addAll(outInterceptors);
90 }
91
92
93 HTTPTransportFactory transportFactory = bus.getExtension(HTTPTransportFactory.class);
94 if (transportFactory == null) {
95 throw new IllegalStateException("Failed to locate HTTPTransportFactory extension on Apache CXF Bus");
96 }
97
98 DestinationRegistry destinationRegistry = transportFactory.getRegistry();
99
100
101 this.cxfServletController = new ServletController(destinationRegistry, getCXFServletConfig(
102 this.getServletConfig()), new ServiceListGeneratorServlet(destinationRegistry, bus));
103
104 this.setPublishEvents(false);
105 }
106
107
108
109
110
111
112 protected ServletConfig getCXFServletConfig(final ServletConfig baseServletConfig) {
113
114 final String shouldHide = Boolean.toString(!ConfigContext.getCurrentContextConfig().getDevMode().booleanValue());
115 return new ServletConfig() {
116 private static final String HIDE_SERVICE_LIST_PAGE_PARAM = "hide-service-list-page";
117 @Override
118 public String getServletName() {
119 return baseServletConfig.getServletName();
120 }
121 @Override
122 public ServletContext getServletContext() {
123 return baseServletConfig.getServletContext();
124 }
125 @Override
126 public String getInitParameter(String parameter) {
127 if (HIDE_SERVICE_LIST_PAGE_PARAM.equals(parameter)) {
128 return shouldHide;
129 }
130 return baseServletConfig.getInitParameter(parameter);
131 }
132 @Override
133 public Enumeration<String> getInitParameterNames() {
134 List<String> initParameterNames = EnumerationUtils.toList(baseServletConfig.getInitParameterNames());
135 initParameterNames.add(HIDE_SERVICE_LIST_PAGE_PARAM);
136 return new Vector<String>(initParameterNames).elements();
137 }
138 };
139 }
140
141 @Override
142 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
143 if (handler instanceof HttpRequestHandler) {
144 return new HttpRequestHandlerAdapter();
145 } else if (handler instanceof Controller) {
146 Object unwrappedHandler = ClassLoaderUtils.unwrapFromProxy(handler);
147 if (unwrappedHandler instanceof CXFServletControllerAdapter) {
148
149 ((CXFServletControllerAdapter)unwrappedHandler).setController(cxfServletController);
150 }
151 return new SimpleControllerHandlerAdapter();
152 }
153 throw new RiceRuntimeException("handler of type " + handler.getClass().getName() + " is not known and can't be used by " + KSBDispatcherServlet.class.getName());
154 }
155
156 @Override
157 protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
158 return this.httpInvokerHandler.getHandler(request);
159 }
160
161 @Override
162 protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
163 try {
164 QName serviceName = this.httpInvokerHandler.getServiceNameFromRequest(request);
165 LOG.info("Caught Exception from service " + serviceName, ex);
166 } catch (Throwable throwable) {
167 LOG.warn("Caught exception attempting to log exception thrown from remotely accessed service", throwable);
168 }
169 return null;
170 }
171
172
173
174
175
176 @Override
177 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
178
179
180 long startTime = System.currentTimeMillis();
181 try {
182 if (isSecure(request)) {
183 super.service(new SignatureVerifyingRequestWrapper(request), new SignatureSigningResponseWrapper(response));
184 } else {
185 super.service(request, response);
186 }
187 }finally {
188 long endTime = System.currentTimeMillis();
189 LOG.info("Service call took " + (endTime - startTime) + "ms");
190 }
191 }
192
193 @Override
194 protected WebApplicationContext initWebApplicationContext() {
195 setContextConfigLocation(REMOTING_SERVLET_CONFIG_LOCATION);
196 return super.initWebApplicationContext();
197 }
198
199 protected boolean isSecure(HttpServletRequest request) {
200 QName serviceName = this.httpInvokerHandler.getServiceNameFromRequest(request);
201 if (LOG.isDebugEnabled()) {
202 LOG.debug("Checking service " + serviceName + " for security enabled");
203 }
204 Endpoint endpoint = KsbApiServiceLocator.getServiceBus().getEndpoint(serviceName);
205 if (endpoint == null) {
206 LOG.error("Attempting to acquire non-existent service " + request.getRequestURI());
207 throw new RiceRuntimeException("Attempting to acquire non-existent service.");
208 }
209 ServiceConfiguration serviceConfiguration = endpoint.getServiceConfiguration();
210 if (serviceConfiguration instanceof SoapServiceConfiguration) {
211 return false;
212 }
213 return serviceConfiguration.getBusSecurity();
214 }
215
216 }