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.Constants; 036 import org.apache.axis2.addressing.AddressingHelper; 037 import org.apache.axis2.context.ConfigurationContext; 038 import org.apache.axis2.context.ConfigurationContextFactory; 039 import org.apache.axis2.context.MessageContext; 040 import org.apache.axis2.context.OperationContext; 041 import org.apache.axis2.description.AxisService; 042 import org.apache.axis2.description.TransportInDescription; 043 import org.apache.axis2.description.TransportOutDescription; 044 import org.apache.axis2.engine.AxisEngine; 045 import org.apache.axis2.engine.Handler.InvocationResponse; 046 import org.apache.axis2.jaxws.binding.BindingImpl; 047 import org.apache.axis2.jaxws.binding.BindingUtils; 048 import org.apache.axis2.jaxws.description.EndpointDescription; 049 import org.apache.axis2.jaxws.description.impl.DescriptionUtils; 050 import org.apache.axis2.jaxws.description.xml.handler.HandlerChainType; 051 import org.apache.axis2.jaxws.description.xml.handler.HandlerChainsType; 052 import org.apache.axis2.jaxws.description.xml.handler.HandlerType; 053 import org.apache.axis2.jaxws.handler.lifecycle.factory.HandlerLifecycleManagerFactory; 054 import org.apache.axis2.jaxws.registry.FactoryRegistry; 055 import org.apache.axis2.jaxws.server.JAXWSMessageReceiver; 056 import org.apache.axis2.transport.OutTransportInfo; 057 import org.apache.axis2.transport.RequestResponseTransport; 058 import org.apache.axis2.transport.http.HTTPConstants; 059 import org.apache.axis2.transport.http.HTTPTransportReceiver; 060 import org.apache.axis2.transport.http.HTTPTransportUtils; 061 import org.apache.axis2.transport.http.TransportHeaders; 062 import org.apache.axis2.transport.http.util.RESTUtil; 063 import org.apache.axis2.util.MessageContextBuilder; 064 import org.apache.commons.logging.Log; 065 import org.apache.commons.logging.LogFactory; 066 import org.apache.geronimo.axis2.client.Axis2ConfigGBean; 067 import org.apache.geronimo.jaxws.JAXWSAnnotationProcessor; 068 import org.apache.geronimo.jaxws.JAXWSUtils; 069 import org.apache.geronimo.jaxws.JNDIResolver; 070 import org.apache.geronimo.jaxws.PortInfo; 071 import org.apache.geronimo.jaxws.ServerJNDIResolver; 072 import org.apache.geronimo.jaxws.annotations.AnnotationException; 073 import org.apache.geronimo.webservices.WebServiceContainer; 074 import org.apache.geronimo.webservices.saaj.SAAJUniverse; 075 076 /** 077 * @version $Rev$ $Date$ 078 */ 079 public abstract class Axis2WebServiceContainer implements WebServiceContainer { 080 081 private static final Log LOG = LogFactory.getLog(Axis2WebServiceContainer.class); 082 083 public static final String REQUEST = Axis2WebServiceContainer.class.getName() + "@Request"; 084 public static final String RESPONSE = Axis2WebServiceContainer.class.getName() + "@Response"; 085 086 private transient final ClassLoader classLoader; 087 088 protected String endpointClassName; 089 protected org.apache.geronimo.jaxws.PortInfo portInfo; 090 protected ConfigurationContext configurationContext; 091 protected JNDIResolver jndiResolver; 092 protected Class endpointClass; 093 protected AxisService service; 094 protected URL configurationBaseUrl; 095 protected WSDLQueryHandler wsdlQueryHandler; 096 protected Binding binding; 097 protected JAXWSAnnotationProcessor annotationProcessor; 098 099 public Axis2WebServiceContainer(PortInfo portInfo, 100 String endpointClassName, 101 ClassLoader classLoader, 102 Context context, 103 URL configurationBaseUrl) { 104 this.classLoader = classLoader; 105 this.endpointClassName = endpointClassName; 106 this.portInfo = portInfo; 107 this.configurationBaseUrl = configurationBaseUrl; 108 this.jndiResolver = new ServerJNDIResolver(context); 109 } 110 111 public void init() throws Exception { 112 this.endpointClass = classLoader.loadClass(this.endpointClassName); 113 114 Axis2ConfigGBean.registerClientConfigurationFactory(); 115 116 configurationContext = ConfigurationContextFactory.createBasicConfigurationContext("META-INF/geronimo-axis2.xml"); 117 118 // check to see if the wsdlLocation property is set in portInfo, 119 // if not checking if wsdlLocation exists in annotation 120 // if already set, annotation should not overwrite it. 121 if (portInfo.getWsdlFile() == null || portInfo.getWsdlFile().equals("")) { 122 // getwsdllocation from annotation if it exists 123 if (JAXWSUtils.containsWsdlLocation(this.endpointClass, classLoader)) { 124 portInfo.setWsdlFile(JAXWSUtils.getServiceWsdlLocation(this.endpointClass, classLoader)); 125 } 126 } 127 128 AxisServiceGenerator serviceGen = createServiceGenerator(); 129 if (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().equals("")) { 130 // WSDL file has been provided 131 service = serviceGen.getServiceFromWSDL(portInfo, endpointClass, configurationBaseUrl); 132 } else { 133 // No WSDL, let Axis2 handle it. 134 service = serviceGen.getServiceFromClass(this.endpointClass); 135 } 136 137 service.setScope(Constants.SCOPE_APPLICATION); 138 configurationContext.getAxisConfiguration().addService(service); 139 140 this.wsdlQueryHandler = new WSDLQueryHandler(this.service); 141 142 /* 143 * This replaces HandlerLifecycleManagerFactory for all web services. 144 * This should be ok as we do our own handler instance managment and injection. 145 * Also, this does not affect service-ref clients, as we install our own 146 * HandlerResolver. 147 */ 148 FactoryRegistry.setFactory(HandlerLifecycleManagerFactory.class, 149 new GeronimoHandlerLifecycleManagerFactory()); 150 } 151 152 protected AxisServiceGenerator createServiceGenerator() { 153 return new AxisServiceGenerator(); 154 } 155 156 public void getWsdl(Request request, Response response) throws Exception { 157 doService(request, response); 158 } 159 160 public void invoke(Request request, Response response) throws Exception { 161 SAAJUniverse universe = new SAAJUniverse(); 162 universe.set(SAAJUniverse.AXIS2); 163 try { 164 doService(request, response); 165 } finally { 166 universe.unset(); 167 } 168 } 169 170 protected void doService(final Request request, final Response response) 171 throws Exception { 172 initContextRoot(request); 173 174 if (LOG.isDebugEnabled()) { 175 LOG.debug("Target URI: " + request.getURI()); 176 } 177 178 MessageContext msgContext = new MessageContext(); 179 msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTP); 180 msgContext.setProperty(MessageContext.REMOTE_ADDR, request.getRemoteAddr()); 181 182 try { 183 TransportOutDescription transportOut = this.configurationContext.getAxisConfiguration() 184 .getTransportOut(Constants.TRANSPORT_HTTP); 185 TransportInDescription transportIn = this.configurationContext.getAxisConfiguration() 186 .getTransportIn(Constants.TRANSPORT_HTTP); 187 188 msgContext.setConfigurationContext(this.configurationContext); 189 190 //TODO: Port this segment for session support. 191 // String sessionKey = (String) this.httpcontext.getAttribute(HTTPConstants.COOKIE_STRING); 192 // if (this.configurationContext.getAxisConfiguration().isManageTransportSession()) { 193 // SessionContext sessionContext = this.sessionManager.getSessionContext(sessionKey); 194 // msgContext.setSessionContext(sessionContext); 195 // } 196 msgContext.setTransportIn(transportIn); 197 msgContext.setTransportOut(transportOut); 198 msgContext.setServiceGroupContextId(UUIDGenerator.getUUID()); 199 msgContext.setServerSide(true); 200 msgContext.setAxisService(this.service); 201 202 doService2(request, response, msgContext); 203 } catch (Throwable e) { 204 String msg = "Exception occurred while trying to invoke service method doService()"; 205 LOG.error(msg, e); 206 try { 207 AxisEngine engine = new AxisEngine(this.configurationContext); 208 209 msgContext.setProperty(MessageContext.TRANSPORT_OUT, response.getOutputStream()); 210 msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, new Axis2TransportInfo(response)); 211 212 MessageContext faultContext = MessageContextBuilder.createFaultMessageContext(msgContext, e); 213 // If the fault is not going along the back channel we should be 202ing 214 if (AddressingHelper.isFaultRedirected(msgContext)) { 215 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED); 216 } else { 217 response.setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR); 218 } 219 engine.sendFault(faultContext); 220 } catch (Exception ex) { 221 if (AddressingHelper.isFaultRedirected(msgContext)) { 222 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED); 223 } else { 224 response.setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR); 225 response.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, "text/plain"); 226 PrintWriter pw = new PrintWriter(response.getOutputStream()); 227 ex.printStackTrace(pw); 228 pw.flush(); 229 LOG.error(msg, ex); 230 } 231 } 232 } 233 234 } 235 236 protected abstract void initContextRoot(Request request); 237 238 public void doService2(Request request, 239 Response response, 240 MessageContext msgContext) throws Exception { 241 242 if (request.getMethod() == Request.GET) { 243 processGETRequest(request, response, this.service, msgContext); 244 } else if (request.getMethod() == Request.POST) { 245 processPOSTRequest(request, response, this.service, msgContext); 246 } else { 247 throw new UnsupportedOperationException("[" + request.getMethod() + " ] method not supported"); 248 } 249 250 // Finalize response 251 OperationContext operationContext = msgContext.getOperationContext(); 252 Object contextWritten = null; 253 Object isTwoChannel = null; 254 if (operationContext != null) { 255 contextWritten = operationContext.getProperty(Constants.RESPONSE_WRITTEN); 256 isTwoChannel = operationContext.getProperty(Constants.DIFFERENT_EPR); 257 } 258 259 if ((contextWritten != null) && Constants.VALUE_TRUE.equals(contextWritten)) { 260 if ((isTwoChannel != null) && Constants.VALUE_TRUE.equals(isTwoChannel)) { 261 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED); 262 return; 263 } 264 response.setStatusCode(HttpURLConnection.HTTP_OK); 265 } else { 266 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED); 267 } 268 } 269 270 public void destroy() { 271 } 272 273 public static class Axis2TransportInfo implements OutTransportInfo { 274 private Response response; 275 276 public Axis2TransportInfo(Response response) { 277 this.response = response; 278 } 279 280 public void setContentType(String contentType) { 281 response.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, contentType); 282 } 283 } 284 285 protected void processGETRequest(Request request, Response response, AxisService service, MessageContext msgContext) throws Exception{ 286 if (request.getURI().getQuery() != null && 287 (request.getURI().getQuery().startsWith("wsdl") || 288 request.getURI().getQuery().startsWith("xsd"))) { 289 // wsdl or xsd request 290 291 if (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().equals("")) { 292 URL wsdlURL = AxisServiceGenerator.getWsdlURL(portInfo.getWsdlFile(), 293 configurationBaseUrl, 294 classLoader); 295 this.wsdlQueryHandler.writeResponse(request.getURI().toString(), 296 wsdlURL.toString(), 297 response.getOutputStream()); 298 } else { 299 service.printWSDL(response.getOutputStream()); 300 } 301 } else { 302 // REST request 303 304 msgContext.setProperty(MessageContext.TRANSPORT_OUT, response.getOutputStream()); 305 msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, new Axis2TransportInfo(response)); 306 307 InvocationResponse processed = RESTUtil.processURLRequest(msgContext, 308 response.getOutputStream(), 309 null); 310 311 if (!processed.equals(InvocationResponse.CONTINUE)) { 312 response.setStatusCode(HttpURLConnection.HTTP_OK); 313 String s = HTTPTransportReceiver.getServicesHTML(configurationContext); 314 PrintWriter pw = new PrintWriter(response.getOutputStream()); 315 pw.write(s); 316 pw.flush(); 317 } 318 } 319 } 320 321 protected void setMsgContextProperties(Request request, Response response, AxisService service, MessageContext msgContext) { 322 msgContext.setProperty(MessageContext.TRANSPORT_OUT, response.getOutputStream()); 323 msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, new Axis2TransportInfo(response)); 324 msgContext.setProperty(RequestResponseTransport.TRANSPORT_CONTROL, 325 new Axis2RequestResponseTransport(response)); 326 msgContext.setProperty(Constants.Configuration.TRANSPORT_IN_URL, request.getURI().toString()); 327 msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTP); 328 329 HttpServletRequest servletRequest = 330 (HttpServletRequest)request.getAttribute(WebServiceContainer.SERVLET_REQUEST); 331 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, servletRequest); 332 333 HttpServletResponse servletResponse = 334 (HttpServletResponse)request.getAttribute(WebServiceContainer.SERVLET_RESPONSE); 335 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, servletResponse); 336 337 ServletContext servletContext = 338 (ServletContext)request.getAttribute(WebServiceContainer.SERVLET_CONTEXT); 339 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETCONTEXT, servletContext); 340 341 if (servletRequest != null) { 342 msgContext.setProperty(MessageContext.TRANSPORT_HEADERS, 343 new TransportHeaders(servletRequest)); 344 } 345 346 if (this.binding != null) { 347 msgContext.setProperty(JAXWSMessageReceiver.PARAM_BINDING, this.binding); 348 } 349 } 350 351 protected void processPOSTRequest(Request request, Response response, AxisService service, MessageContext msgContext) throws Exception { 352 String contentType = request.getHeader(HTTPConstants.HEADER_CONTENT_TYPE); 353 String soapAction = request.getHeader(HTTPConstants.HEADER_SOAP_ACTION); 354 if (soapAction == null) { 355 soapAction = "\"\""; 356 } 357 358 ConfigurationContext configurationContext = msgContext.getConfigurationContext(); 359 configurationContext.fillServiceContextAndServiceGroupContext(msgContext); 360 361 setMsgContextProperties(request, response, service, msgContext); 362 363 HTTPTransportUtils.processHTTPPostRequest(msgContext, 364 request.getInputStream(), 365 response.getOutputStream(), 366 contentType, 367 soapAction, 368 request.getURI().getPath()); 369 } 370 371 /* 372 * Gets the right handlers for the port/service/bindings and performs injection. 373 */ 374 protected void configureHandlers() throws Exception { 375 EndpointDescription desc = AxisServiceGenerator.getEndpointDescription(this.service); 376 if (desc == null) { 377 this.binding = new BindingImpl(""); 378 } else { 379 String xml = this.portInfo.getHandlersAsXML(); 380 HandlerChainsType handlerChains = null; 381 if (xml != null) { 382 ByteArrayInputStream in = new ByteArrayInputStream(xml.getBytes("UTF-8")); 383 handlerChains = DescriptionUtils.loadHandlerChains(in); 384 desc.setHandlerChain(handlerChains); 385 } 386 387 if (LOG.isDebugEnabled()) { 388 logHandlers(desc.getHandlerChain()); 389 } 390 391 this.binding = BindingUtils.createBinding(desc); 392 393 DescriptionUtils.registerHandlerHeaders(desc.getAxisService(), this.binding.getHandlerChain()); 394 } 395 } 396 397 private void logHandlers(HandlerChainsType handlerChains) { 398 if (handlerChains == null || handlerChains.getHandlerChain() == null 399 || handlerChains.getHandlerChain().isEmpty()) { 400 LOG.debug("No handlers"); 401 return; 402 } 403 404 for (HandlerChainType chains : handlerChains.getHandlerChain()) { 405 LOG.debug("Handler chain: " + chains.getServiceNamePattern() + " " + 406 chains.getPortNamePattern() + " " + chains.getProtocolBindings()); 407 if (chains.getHandler() != null) { 408 for (HandlerType chain : chains.getHandler()) { 409 LOG.debug(" Handler: " + chain.getHandlerName().getValue() + " " + 410 chain.getHandlerClass().getValue()); 411 } 412 } 413 } 414 } 415 416 protected void injectHandlers() { 417 List<Handler> handlers = this.binding.getHandlerChain(); 418 try { 419 for (Handler handler : handlers) { 420 injectResources(handler); 421 } 422 } catch (AnnotationException e) { 423 throw new WebServiceException("Handler annotation failed", e); 424 } 425 } 426 427 protected void destroyHandlers() { 428 if (this.annotationProcessor != null) { 429 // call handlers preDestroy 430 List<Handler> handlers = this.binding.getHandlerChain(); 431 for (Handler handler : handlers) { 432 this.annotationProcessor.invokePreDestroy(handler); 433 } 434 } 435 } 436 437 protected void injectResources(Object instance) throws AnnotationException { 438 this.annotationProcessor.processAnnotations(instance); 439 this.annotationProcessor.invokePostConstruct(instance); 440 } 441 442 }