001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.axis2; 019 020 import java.io.ByteArrayInputStream; 021 import java.io.PrintWriter; 022 import java.net.HttpURLConnection; 023 import java.net.URL; 024 import java.util.List; 025 026 import javax.naming.Context; 027 import javax.servlet.ServletContext; 028 import javax.servlet.http.HttpServletRequest; 029 import javax.servlet.http.HttpServletResponse; 030 import javax.xml.ws.Binding; 031 import javax.xml.ws.WebServiceException; 032 import javax.xml.ws.handler.Handler; 033 034 import org.apache.axiom.om.util.UUIDGenerator; 035 import org.apache.axis2.AxisFault; 036 import org.apache.axis2.Constants; 037 import org.apache.axis2.addressing.AddressingHelper; 038 import org.apache.axis2.addressing.EndpointReference; 039 import org.apache.axis2.context.ConfigurationContext; 040 import org.apache.axis2.context.ConfigurationContextFactory; 041 import org.apache.axis2.context.MessageContext; 042 import org.apache.axis2.context.OperationContext; 043 import org.apache.axis2.description.AxisService; 044 import org.apache.axis2.description.TransportInDescription; 045 import org.apache.axis2.description.TransportOutDescription; 046 import org.apache.axis2.engine.AxisEngine; 047 import org.apache.axis2.engine.Handler.InvocationResponse; 048 import org.apache.axis2.jaxws.binding.BindingImpl; 049 import org.apache.axis2.jaxws.binding.BindingUtils; 050 import org.apache.axis2.jaxws.description.EndpointDescription; 051 import org.apache.axis2.jaxws.description.impl.DescriptionUtils; 052 import org.apache.axis2.jaxws.description.xml.handler.HandlerChainType; 053 import org.apache.axis2.jaxws.description.xml.handler.HandlerChainsType; 054 import org.apache.axis2.jaxws.description.xml.handler.HandlerType; 055 import org.apache.axis2.jaxws.handler.lifecycle.factory.HandlerLifecycleManagerFactory; 056 import org.apache.axis2.jaxws.registry.FactoryRegistry; 057 import org.apache.axis2.jaxws.server.JAXWSMessageReceiver; 058 import org.apache.axis2.transport.OutTransportInfo; 059 import org.apache.axis2.transport.RequestResponseTransport; 060 import org.apache.axis2.transport.http.HTTPConstants; 061 import org.apache.axis2.transport.http.HTTPTransportReceiver; 062 import org.apache.axis2.transport.http.HTTPTransportUtils; 063 import org.apache.axis2.transport.http.TransportHeaders; 064 import org.apache.axis2.transport.http.util.RESTUtil; 065 import org.apache.axis2.util.MessageContextBuilder; 066 import org.apache.commons.logging.Log; 067 import org.apache.commons.logging.LogFactory; 068 import org.apache.geronimo.axis2.client.Axis2ConfigGBean; 069 import org.apache.geronimo.jaxws.JAXWSAnnotationProcessor; 070 import org.apache.geronimo.jaxws.JAXWSUtils; 071 import org.apache.geronimo.jaxws.JNDIResolver; 072 import org.apache.geronimo.jaxws.PortInfo; 073 import org.apache.geronimo.jaxws.ServerJNDIResolver; 074 import org.apache.geronimo.jaxws.annotations.AnnotationException; 075 import org.apache.geronimo.webservices.WebServiceContainer; 076 import org.apache.geronimo.webservices.saaj.SAAJUniverse; 077 078 /** 079 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 080 */ 081 public abstract class Axis2WebServiceContainer implements WebServiceContainer { 082 083 private static final Log LOG = LogFactory.getLog(Axis2WebServiceContainer.class); 084 085 public static final String REQUEST = Axis2WebServiceContainer.class.getName() + "@Request"; 086 public static final String RESPONSE = Axis2WebServiceContainer.class.getName() + "@Response"; 087 088 private transient final ClassLoader classLoader; 089 090 protected String endpointClassName; 091 protected org.apache.geronimo.jaxws.PortInfo portInfo; 092 protected ConfigurationContext configurationContext; 093 protected JNDIResolver jndiResolver; 094 protected Class endpointClass; 095 protected AxisService service; 096 protected URL configurationBaseUrl; 097 protected WSDLQueryHandler wsdlQueryHandler; 098 protected Binding binding; 099 protected JAXWSAnnotationProcessor annotationProcessor; 100 protected Context context; 101 102 public Axis2WebServiceContainer(PortInfo portInfo, 103 String endpointClassName, 104 ClassLoader classLoader, 105 Context context, 106 URL configurationBaseUrl) { 107 this.classLoader = classLoader; 108 this.endpointClassName = endpointClassName; 109 this.portInfo = portInfo; 110 this.configurationBaseUrl = configurationBaseUrl; 111 this.context = context; 112 this.jndiResolver = new ServerJNDIResolver(context); 113 } 114 115 public void init() throws Exception { 116 this.endpointClass = classLoader.loadClass(this.endpointClassName); 117 118 Axis2ConfigGBean.registerClientConfigurationFactory(); 119 120 configurationContext = ConfigurationContextFactory.createBasicConfigurationContext("META-INF/geronimo-axis2.xml"); 121 122 // check to see if the wsdlLocation property is set in portInfo, 123 // if not checking if wsdlLocation exists in annotation 124 // if already set, annotation should not overwrite it. 125 if (portInfo.getWsdlFile() == null || portInfo.getWsdlFile().equals("")) { 126 // getwsdllocation from annotation if it exists 127 if (JAXWSUtils.containsWsdlLocation(this.endpointClass, classLoader)) { 128 portInfo.setWsdlFile(JAXWSUtils.getServiceWsdlLocation(this.endpointClass, classLoader)); 129 } 130 } 131 132 AxisServiceGenerator serviceGen = createServiceGenerator(); 133 if (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().equals("")) { 134 // WSDL file has been provided 135 service = serviceGen.getServiceFromWSDL(portInfo, endpointClass, configurationBaseUrl); 136 } else { 137 // No WSDL, let Axis2 handle it. 138 service = serviceGen.getServiceFromClass(this.endpointClass); 139 } 140 141 service.setScope(Constants.SCOPE_APPLICATION); 142 configurationContext.getAxisConfiguration().addService(service); 143 144 this.wsdlQueryHandler = new WSDLQueryHandler(this.service); 145 146 /* 147 * This replaces HandlerLifecycleManagerFactory for all web services. 148 * This should be ok as we do our own handler instance managment and injection. 149 * Also, this does not affect service-ref clients, as we install our own 150 * HandlerResolver. 151 */ 152 FactoryRegistry.setFactory(HandlerLifecycleManagerFactory.class, 153 new GeronimoHandlerLifecycleManagerFactory()); 154 } 155 156 protected AxisServiceGenerator createServiceGenerator() { 157 return new AxisServiceGenerator(); 158 } 159 160 public void getWsdl(Request request, Response response) throws Exception { 161 doService(request, response); 162 } 163 164 public void invoke(Request request, Response response) throws Exception { 165 SAAJUniverse universe = new SAAJUniverse(); 166 universe.set(SAAJUniverse.AXIS2); 167 try { 168 doService(request, response); 169 } finally { 170 universe.unset(); 171 } 172 } 173 174 protected void doService(final Request request, final Response response) 175 throws Exception { 176 177 if (LOG.isDebugEnabled()) { 178 LOG.debug("Target URI: " + request.getURI()); 179 } 180 181 MessageContext msgContext = new MessageContext(); 182 msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTP); 183 msgContext.setProperty(MessageContext.REMOTE_ADDR, request.getRemoteAddr()); 184 185 try { 186 TransportOutDescription transportOut = this.configurationContext.getAxisConfiguration() 187 .getTransportOut(Constants.TRANSPORT_HTTP); 188 TransportInDescription transportIn = this.configurationContext.getAxisConfiguration() 189 .getTransportIn(Constants.TRANSPORT_HTTP); 190 191 msgContext.setConfigurationContext(this.configurationContext); 192 193 //TODO: Port this segment for session support. 194 // String sessionKey = (String) this.httpcontext.getAttribute(HTTPConstants.COOKIE_STRING); 195 // if (this.configurationContext.getAxisConfiguration().isManageTransportSession()) { 196 // SessionContext sessionContext = this.sessionManager.getSessionContext(sessionKey); 197 // msgContext.setSessionContext(sessionContext); 198 // } 199 msgContext.setTransportIn(transportIn); 200 msgContext.setTransportOut(transportOut); 201 msgContext.setServiceGroupContextId(UUIDGenerator.getUUID()); 202 msgContext.setServerSide(true); 203 msgContext.setAxisService(this.service); 204 205 doService2(request, response, msgContext); 206 } catch (AxisFault e) { 207 LOG.debug(e.getMessage(), e); 208 handleFault(msgContext, response, e); 209 } catch (Throwable e) { 210 String msg = "Exception occurred while trying to invoke service method doService()"; 211 LOG.error(msg, e); 212 handleFault(msgContext, response, new AxisFault(msg, e)); 213 } 214 215 } 216 217 private void handleFault(MessageContext msgContext, Response response, AxisFault e) { 218 // If the fault is not going along the back channel we should be 202ing 219 if (AddressingHelper.isFaultRedirected(msgContext)) { 220 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED); 221 } else { 222 response.setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR); 223 } 224 225 msgContext.setProperty(MessageContext.TRANSPORT_OUT, response.getOutputStream()); 226 msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, new Axis2TransportInfo(response)); 227 228 try { 229 MessageContext faultContext = MessageContextBuilder.createFaultMessageContext(msgContext, e); 230 AxisEngine.sendFault(faultContext); 231 } catch (Exception ex) { 232 LOG.warn("Error sending fault", ex); 233 if (!AddressingHelper.isFaultRedirected(msgContext)) { 234 response.setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR); 235 response.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, "text/plain"); 236 PrintWriter pw = new PrintWriter(response.getOutputStream()); 237 ex.printStackTrace(pw); 238 pw.flush(); 239 } 240 } 241 } 242 243 protected String getServicePath(String contextRoot) { 244 String location = this.portInfo.getLocation(); 245 if (location != null && location.startsWith(contextRoot)) { 246 return location.substring(contextRoot.length()); 247 } 248 return null; 249 } 250 251 public static String trimContext(String contextPath) { 252 if (contextPath != null) { 253 if (contextPath.startsWith("/")) { 254 contextPath = contextPath.substring(1); 255 } 256 if (contextPath.endsWith("/")) { 257 contextPath = contextPath.substring(0, contextPath.length() - 1); 258 } 259 } 260 return contextPath; 261 } 262 263 public void doService2(Request request, 264 Response response, 265 MessageContext msgContext) throws Exception { 266 267 if (request.getMethod() == Request.GET) { 268 processGETRequest(request, response, this.service, msgContext); 269 } else if (request.getMethod() == Request.POST) { 270 processPOSTRequest(request, response, this.service, msgContext); 271 } else { 272 throw new UnsupportedOperationException("[" + request.getMethod() + " ] method not supported"); 273 } 274 275 // Finalize response 276 OperationContext operationContext = msgContext.getOperationContext(); 277 Object contextWritten = null; 278 Object isTwoChannel = null; 279 if (operationContext != null) { 280 contextWritten = operationContext.getProperty(Constants.RESPONSE_WRITTEN); 281 isTwoChannel = operationContext.getProperty(Constants.DIFFERENT_EPR); 282 } 283 284 if ((contextWritten != null) && Constants.VALUE_TRUE.equals(contextWritten)) { 285 if ((isTwoChannel != null) && Constants.VALUE_TRUE.equals(isTwoChannel)) { 286 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED); 287 return; 288 } 289 response.setStatusCode(HttpURLConnection.HTTP_OK); 290 } else { 291 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED); 292 } 293 } 294 295 public void destroy() { 296 } 297 298 public static class Axis2TransportInfo implements OutTransportInfo { 299 private Response response; 300 301 public Axis2TransportInfo(Response response) { 302 this.response = response; 303 } 304 305 public void setContentType(String contentType) { 306 response.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, contentType); 307 } 308 } 309 310 protected void processGETRequest(Request request, Response response, AxisService service, MessageContext msgContext) throws Exception{ 311 String query = request.getURI().getQuery(); 312 if (query != null && 313 (query.startsWith("wsdl") || query.startsWith("WSDL") || 314 query.startsWith("xsd") || query.startsWith("XSD"))) { 315 // wsdl or xsd request 316 317 if (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().equals("")) { 318 URL wsdlURL = AxisServiceGenerator.getWsdlURL(portInfo.getWsdlFile(), 319 configurationBaseUrl, 320 classLoader); 321 this.wsdlQueryHandler.writeResponse(request.getURI().toString(), 322 wsdlURL.toString(), 323 response.getOutputStream()); 324 } else { 325 throw new Exception("Service does not have WSDL"); 326 } 327 } else if (AxisServiceGenerator.isSOAP11(service)) { 328 response.setContentType("text/html"); 329 PrintWriter pw = new PrintWriter(response.getOutputStream()); 330 pw.write("<html><title>Web Service</title><body>"); 331 pw.write("Hi, this is '" + service.getName() + "' web service."); 332 pw.write("</body></html>"); 333 pw.flush(); 334 } else { 335 // REST request 336 processURLRequest(request, response, service, msgContext); 337 } 338 } 339 340 protected void processPOSTRequest(Request request, Response response, AxisService service, MessageContext msgContext) throws Exception { 341 processXMLRequest(request, response, service, msgContext); 342 } 343 344 protected void setMsgContextProperties(Request request, Response response, AxisService service, MessageContext msgContext) { 345 msgContext.setProperty(MessageContext.TRANSPORT_OUT, response.getOutputStream()); 346 msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, new Axis2TransportInfo(response)); 347 msgContext.setProperty(RequestResponseTransport.TRANSPORT_CONTROL, 348 new Axis2RequestResponseTransport(response)); 349 msgContext.setProperty(Constants.Configuration.TRANSPORT_IN_URL, request.getURI().toString()); 350 msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTP); 351 352 HttpServletRequest servletRequest = 353 (HttpServletRequest)request.getAttribute(WebServiceContainer.SERVLET_REQUEST); 354 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, servletRequest); 355 356 HttpServletResponse servletResponse = 357 (HttpServletResponse)request.getAttribute(WebServiceContainer.SERVLET_RESPONSE); 358 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, servletResponse); 359 360 ServletContext servletContext = 361 (ServletContext)request.getAttribute(WebServiceContainer.SERVLET_CONTEXT); 362 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETCONTEXT, servletContext); 363 364 if (servletRequest != null) { 365 msgContext.setProperty(MessageContext.TRANSPORT_HEADERS, 366 new TransportHeaders(servletRequest)); 367 } 368 369 if (this.binding != null) { 370 msgContext.setProperty(JAXWSMessageReceiver.PARAM_BINDING, this.binding); 371 } 372 373 msgContext.setTo(new EndpointReference(request.getURI().toString())); 374 } 375 376 protected void processXMLRequest(Request request, 377 Response response, 378 AxisService service, 379 MessageContext msgContext) throws Exception { 380 String contentType = request.getHeader(HTTPConstants.HEADER_CONTENT_TYPE); 381 String soapAction = request.getHeader(HTTPConstants.HEADER_SOAP_ACTION); 382 if (soapAction == null) { 383 soapAction = "\"\""; 384 } 385 386 ConfigurationContext configurationContext = msgContext.getConfigurationContext(); 387 configurationContext.fillServiceContextAndServiceGroupContext(msgContext); 388 389 setMsgContextProperties(request, response, service, msgContext); 390 391 if (!HTTPTransportUtils.isRESTRequest(contentType)) { 392 HTTPTransportUtils.processHTTPPostRequest(msgContext, 393 request.getInputStream(), 394 response.getOutputStream(), 395 contentType, 396 soapAction, 397 request.getURI().getPath()); 398 } else { 399 RESTUtil.processXMLRequest(msgContext, 400 request.getInputStream(), 401 response.getOutputStream(), 402 contentType); 403 } 404 } 405 406 protected void processURLRequest(Request request, 407 Response response, 408 AxisService service, 409 MessageContext msgContext) throws Exception { 410 String contentType = request.getHeader(HTTPConstants.HEADER_CONTENT_TYPE); 411 412 ConfigurationContext configurationContext = msgContext.getConfigurationContext(); 413 configurationContext.fillServiceContextAndServiceGroupContext(msgContext); 414 415 setMsgContextProperties(request, response, service, msgContext); 416 417 InvocationResponse processed = RESTUtil.processURLRequest(msgContext, 418 response.getOutputStream(), 419 contentType); 420 421 if (!processed.equals(InvocationResponse.CONTINUE)) { 422 response.setStatusCode(HttpURLConnection.HTTP_OK); 423 String s = HTTPTransportReceiver.getServicesHTML(configurationContext); 424 PrintWriter pw = new PrintWriter(response.getOutputStream()); 425 pw.write(s); 426 pw.flush(); 427 } 428 } 429 430 /* 431 * Gets the right handlers for the port/service/bindings and performs injection. 432 */ 433 protected void configureHandlers() throws Exception { 434 EndpointDescription desc = AxisServiceGenerator.getEndpointDescription(this.service); 435 if (desc == null) { 436 this.binding = new BindingImpl(""); 437 } else { 438 String xml = this.portInfo.getHandlersAsXML(); 439 HandlerChainsType handlerChains = null; 440 if (xml != null) { 441 ByteArrayInputStream in = new ByteArrayInputStream(xml.getBytes("UTF-8")); 442 handlerChains = DescriptionUtils.loadHandlerChains(in); 443 desc.setHandlerChain(handlerChains); 444 } 445 446 if (LOG.isDebugEnabled()) { 447 logHandlers(desc.getHandlerChain()); 448 } 449 450 this.binding = BindingUtils.createBinding(desc); 451 452 DescriptionUtils.registerHandlerHeaders(desc.getAxisService(), this.binding.getHandlerChain()); 453 } 454 } 455 456 private void logHandlers(HandlerChainsType handlerChains) { 457 if (handlerChains == null || handlerChains.getHandlerChain() == null 458 || handlerChains.getHandlerChain().isEmpty()) { 459 LOG.debug("No handlers"); 460 return; 461 } 462 463 for (HandlerChainType chains : handlerChains.getHandlerChain()) { 464 LOG.debug("Handler chain: " + chains.getServiceNamePattern() + " " + 465 chains.getPortNamePattern() + " " + chains.getProtocolBindings()); 466 if (chains.getHandler() != null) { 467 for (HandlerType chain : chains.getHandler()) { 468 LOG.debug(" Handler: " + chain.getHandlerName().getValue() + " " + 469 chain.getHandlerClass().getValue()); 470 } 471 } 472 } 473 } 474 475 protected void injectHandlers() { 476 List<Handler> handlers = this.binding.getHandlerChain(); 477 try { 478 for (Handler handler : handlers) { 479 injectResources(handler); 480 } 481 } catch (AnnotationException e) { 482 throw new WebServiceException("Handler annotation failed", e); 483 } 484 } 485 486 protected void destroyHandlers() { 487 if (this.annotationProcessor != null) { 488 // call handlers preDestroy 489 List<Handler> handlers = this.binding.getHandlerChain(); 490 for (Handler handler : handlers) { 491 this.annotationProcessor.invokePreDestroy(handler); 492 } 493 } 494 } 495 496 protected void injectResources(Object instance) throws AnnotationException { 497 this.annotationProcessor.processAnnotations(instance); 498 this.annotationProcessor.invokePostConstruct(instance); 499 } 500 501 }