001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.net.rpc.server; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.PrintWriter; 024import java.lang.reflect.InvocationTargetException; 025import java.lang.reflect.Method; 026import java.util.Enumeration; 027import java.util.HashMap; 028import java.util.Iterator; 029import java.util.Map; 030import java.util.WeakHashMap; 031 032import javax.servlet.ServletContext; 033import javax.servlet.ServletException; 034import javax.servlet.http.HttpServletRequest; 035import javax.servlet.http.HttpServletResponse; 036import javax.servlet.http.HttpUtils; 037import javax.xml.namespace.QName; 038import javax.xml.soap.MimeHeader; 039import javax.xml.soap.MimeHeaders; 040import javax.xml.soap.SOAPException; 041import javax.xml.soap.SOAPMessage; 042 043import lucee.commons.io.IOUtil; 044import lucee.commons.lang.ClassException; 045import lucee.commons.lang.ClassUtil; 046import lucee.commons.lang.ExceptionUtil; 047import lucee.runtime.Component; 048import lucee.runtime.exp.PageException; 049import lucee.runtime.exp.PageServletException; 050import lucee.runtime.net.http.ReqRspUtil; 051import lucee.runtime.net.rpc.AxisCaster; 052import lucee.runtime.net.rpc.TypeMappingUtil; 053import lucee.runtime.op.Caster; 054 055import org.apache.axis.AxisEngine; 056import org.apache.axis.AxisFault; 057import org.apache.axis.ConfigurationException; 058import org.apache.axis.Constants; 059import org.apache.axis.Handler; 060import org.apache.axis.Message; 061import org.apache.axis.MessageContext; 062import org.apache.axis.SimpleChain; 063import org.apache.axis.SimpleTargetedChain; 064import org.apache.axis.components.logger.LogFactory; 065import org.apache.axis.management.ServiceAdmin; 066import org.apache.axis.security.servlet.ServletSecurityProvider; 067import org.apache.axis.server.AxisServer; 068import org.apache.axis.transport.http.AxisHttpSession; 069import org.apache.axis.transport.http.FilterPrintWriter; 070import org.apache.axis.transport.http.HTTPConstants; 071import org.apache.axis.transport.http.ServletEndpointContextImpl; 072import org.apache.axis.utils.Messages; 073import org.apache.commons.logging.Log; 074import org.w3c.dom.Element; 075 076/** 077 * xdoclet tags are not active yet; keep web.xml in sync. 078 * To change the location of the services, change url-pattern in web.xml and 079 * set parameter axis.servicesPath in server-config.wsdd. For more information see 080 * <a href="http://ws.apache.org/axis/java/reference.html">Axis Reference Guide</a>. 081 */ 082public final class RPCServer{ 083 084 protected static Log log =LogFactory.getLog(RPCServer.class.getName()); 085 private static Log tlog =LogFactory.getLog(Constants.TIME_LOG_CATEGORY); 086 private static Log exceptionLog =LogFactory.getLog(Constants.EXCEPTION_LOG_CATEGORY); 087 088 public static final String INIT_PROPERTY_TRANSPORT_NAME ="transport.name"; 089 public static final String INIT_PROPERTY_USE_SECURITY ="use-servlet-security"; 090 public static final String INIT_PROPERTY_ENABLE_LIST ="axis.enableListQuery"; 091 public static final String INIT_PROPERTY_JWS_CLASS_DIR ="axis.jws.servletClassDir"; 092 public static final String INIT_PROPERTY_DISABLE_SERVICES_LIST ="axis.disableServiceList"; 093 public static final String INIT_PROPERTY_SERVICES_PATH ="axis.servicesPath"; 094 095 private Handler transport; 096 private ServletSecurityProvider securityProvider = null; 097 private ServletContext context; 098 private String webInfPath; 099 private String homeDir; 100 private AxisServer axisServer; 101 //private org.apache.axis.encoding.TypeMapping typeMapping; 102 103 private static boolean isDevelopment=false; 104 private static boolean isDebug = false; 105 private static Map servers=new WeakHashMap(); 106 107 108 /** 109 * Initialization method. 110 * @throws AxisFault 111 */ 112 private RPCServer(ServletContext context) throws AxisFault { 113 this.context=context; 114 115 initQueryStringHandlers(); 116 ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo()); 117 118 webInfPath = context.getRealPath("/WEB-INF"); 119 homeDir = ReqRspUtil.getRootPath(context); 120 121 } 122 123 124 125 126 /** 127 * Process GET requests. This includes handoff of pseudo-SOAP requests 128 * 129 * @param request request in 130 * @param response request out 131 * @throws ServletException 132 */ 133 public void doGet(HttpServletRequest request, HttpServletResponse response, Component component) throws ServletException { 134 PrintWriter writer = new FilterPrintWriter(response); 135 136 try { 137 if (!doGet(request, response, writer,component)) { 138 response.setContentType("text/html; charset=utf-8"); 139 writer.println("<html><h1>Lucee Webservice</h1>"); 140 writer.println(Messages.getMessage("reachedServlet00")); 141 writer.println("<p>" + Messages.getMessage("transportName00","<b>http</b>")); 142 writer.println("</html>"); 143 } 144 } 145 catch (Throwable e) { 146 ExceptionUtil.rethrowIfNecessary(e); 147 if(e instanceof InvocationTargetException) 148 e= ((InvocationTargetException)e).getTargetException(); 149 if(e instanceof PageException) 150 throw new PageServletException((PageException)e); 151 throw new ServletException(e); 152 } 153 } 154 155 /** 156 * routine called whenever an axis fault is caught; where they 157 * are logged and any other business. The method may modify the fault 158 * in the process 159 * @param fault what went wrong. 160 */ 161 private void processAxisFault(AxisFault fault) { 162 //log the fault 163 Element runtimeException = fault.lookupFaultDetail( 164 Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); 165 if (runtimeException != null) { 166 exceptionLog.info(Messages.getMessage("axisFault00"), fault); 167 //strip runtime details 168 fault.removeFaultDetail(Constants. 169 QNAME_FAULTDETAIL_RUNTIMEEXCEPTION); 170 } else if (exceptionLog.isDebugEnabled()) { 171 exceptionLog.debug(Messages.getMessage("axisFault00"), fault); 172 } 173 //dev systems only give fault dumps 174 //if (!isDevelopment()) { 175 //strip out the stack trace 176 fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE); 177 //} 178 } 179 180 /** 181 * log any exception to our output log, at our chosen level 182 * @param e what went wrong 183 */ 184 private void logException(Throwable e) { 185 exceptionLog.info(Messages.getMessage("exception00"), e); 186 } 187 188 /* * 189 * print a snippet of service info. 190 * @param service service 191 * @param writer output channel 192 * @param serviceName where to put stuff 193 * / 194 private void reportServiceInfo(HttpServletResponse response, 195 PrintWriter writer, SOAPService service, 196 String serviceName) { 197 response.setContentType("text/html; charset=utf-8"); 198 199 writer.println("<h1>" 200 + service.getName() 201 + "</h1>"); 202 writer.println( 203 "<p>" + 204 Messages.getMessage("axisService00") + 205 "</p>"); 206 writer.println( 207 "<i>" + 208 Messages.getMessage("perhaps00") + 209 "</i>"); 210 }*/ 211 212 213 214 215 216 /** 217 * Process a POST to the servlet by handing it off to the Axis Engine. 218 * Here is where SOAP messages are received 219 * @param req posted request 220 * @param res respose 221 * @throws ServletException trouble 222 * @throws IOException different trouble 223 */ 224 public void doPost(HttpServletRequest req, HttpServletResponse res, Component component) throws 225 ServletException, IOException { 226 long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0; 227 String soapAction = null; 228 MessageContext msgContext = null; 229 230 Message rspMsg = null; 231 String contentType = null; 232 InputStream is=null; 233 try { 234 AxisEngine engine = getEngine(); 235 236 if (engine == null) { 237 // !!! should return a SOAP fault... 238 ServletException se = 239 new ServletException(Messages.getMessage("noEngine00")); 240 log.debug("No Engine!", se); 241 throw se; 242 } 243 244 res.setBufferSize(1024 * 8); // provide performance boost. 245 246 /** get message context w/ various properties set 247 */ 248 msgContext = createMessageContext(engine, req, res,component); 249 ComponentController.set(msgContext); 250 251 // ? OK to move this to 'getMessageContext', 252 // ? where it would also be picked up for 'doGet()' ? 253 if (securityProvider != null) { 254 if (isDebug) { 255 log.debug("securityProvider:" + securityProvider); 256 } 257 msgContext.setProperty(MessageContext.SECURITY_PROVIDER, 258 securityProvider); 259 } 260 261 is=req.getInputStream(); 262 Message requestMsg = 263 new Message(is, 264 false, 265 req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE), 266 req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION)); 267 // Transfer HTTP headers to MIME headers for request message. 268 MimeHeaders requestMimeHeaders = requestMsg.getMimeHeaders(); 269 for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) { 270 String headerName = (String) e.nextElement(); 271 for (Enumeration f = req.getHeaders(headerName); 272 f.hasMoreElements(); ) { 273 String headerValue = (String) f.nextElement(); 274 requestMimeHeaders.addHeader(headerName, headerValue); 275 } 276 } 277 278 if (isDebug) { 279 log.debug("Request Message:" + requestMsg); 280 281 /* Set the request(incoming) message field in the context */ 282 /**********************************************************/ 283 } 284 msgContext.setRequestMessage(requestMsg); 285 String url = HttpUtils.getRequestURL(req).toString().toLowerCase(); 286 msgContext.setProperty(MessageContext.TRANS_URL, url); 287 // put character encoding of request to message context 288 // in order to reuse it during the whole process. 289 290 try { 291 String reqEnc = (String) requestMsg.getProperty(SOAPMessage.CHARACTER_SET_ENCODING); 292 if (reqEnc!=null) msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,reqEnc); 293 } 294 catch (SOAPException e1) {} 295 296 try { 297 /** 298 * Save the SOAPAction header in the MessageContext bag. 299 * This will be used to tell the Axis Engine which service 300 * is being invoked. This will save us the trouble of 301 * having to parse the Request message - although we will 302 * need to double-check later on that the SOAPAction header 303 * does in fact match the URI in the body. 304 */ 305 // (is this last stmt true??? (I don't think so - Glen)) 306 /********************************************************/ 307 soapAction = getSoapAction(req); 308 if (soapAction != null) { 309 msgContext.setUseSOAPAction(true); 310 msgContext.setSOAPActionURI(soapAction); 311 } 312 313 // Create a Session wrapper for the HTTP session. 314 // These can/should be pooled at some point. 315 // (Sam is Watching! :-) 316 msgContext.setSession(new AxisHttpSession(req)); 317 318 if (tlog.isDebugEnabled()) { 319 t1 = System.currentTimeMillis(); 320 } 321 /* Invoke the Axis engine... */ 322 /*****************************/ 323 if (isDebug) { 324 log.debug("Invoking Axis Engine."); 325 //here we run the message by the engine 326 } 327 //msgContext.setProperty("disablePrettyXML", "false"); 328 engine.invoke(msgContext); 329 if (isDebug) { 330 log.debug("Return from Axis Engine."); 331 } 332 if (tlog.isDebugEnabled()) { 333 t2 = System.currentTimeMillis(); 334 } 335 336 rspMsg = msgContext.getResponseMessage(); 337 338 339 340 // We used to throw exceptions on null response messages. 341 // They are actually OK in certain situations (asynchronous 342 // services), so fall through here and return an ACCEPTED 343 // status code below. Might want to install a configurable 344 // error check for this later. 345 } 346 catch (AxisFault fault) { 347 348 //log and sanitize 349 processAxisFault(fault); 350 configureResponseFromAxisFault(res, fault); 351 rspMsg = msgContext.getResponseMessage(); 352 if (rspMsg == null) { 353 rspMsg = new Message(fault); 354 ((org.apache.axis.SOAPPart) rspMsg.getSOAPPart()). 355 getMessage().setMessageContext(msgContext); 356 } 357 } catch (Throwable t) { 358 ExceptionUtil.rethrowIfNecessary(t); 359 if(t instanceof InvocationTargetException) 360 t=((InvocationTargetException)t).getTargetException(); 361 // Exception 362 if(t instanceof Exception) { 363 Exception e=(Exception) t; 364 //other exceptions are internal trouble 365 rspMsg = msgContext.getResponseMessage(); 366 res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 367 rspMsg = convertExceptionToAxisFault(e, rspMsg); 368 ((org.apache.axis.SOAPPart) rspMsg.getSOAPPart()). 369 getMessage().setMessageContext(msgContext); 370 371 } 372 // throwable 373 else { 374 logException(t); 375 //other exceptions are internal trouble 376 rspMsg = msgContext.getResponseMessage(); 377 res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 378 rspMsg = new Message(new AxisFault(t.toString(),t)); 379 ((org.apache.axis.SOAPPart) rspMsg.getSOAPPart()). 380 getMessage().setMessageContext(msgContext); 381 } 382 } 383 } catch (AxisFault fault) { 384 385 processAxisFault(fault); 386 configureResponseFromAxisFault(res, fault); 387 rspMsg = msgContext.getResponseMessage(); 388 if (rspMsg == null) { 389 rspMsg = new Message(fault); 390 ((org.apache.axis.SOAPPart) rspMsg.getSOAPPart()). 391 getMessage().setMessageContext(msgContext); 392 } 393 } 394 finally { 395 IOUtil.closeEL(is); 396 } 397 398 if (tlog.isDebugEnabled()) { 399 t3 = System.currentTimeMillis(); 400 } 401 402 // Send response back along the wire... 403 if (rspMsg != null) { 404 405 // Transfer MIME headers to HTTP headers for response message. 406 MimeHeaders responseMimeHeaders = rspMsg.getMimeHeaders(); 407 for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) { 408 MimeHeader responseMimeHeader = (MimeHeader) i.next(); 409 res.addHeader(responseMimeHeader.getName(), responseMimeHeader.getValue()); 410 } 411 // synchronize the character encoding of request and response 412 String responseEncoding = (String) msgContext.getProperty(SOAPMessage.CHARACTER_SET_ENCODING); 413 if (responseEncoding != null) { 414 try { 415 rspMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,responseEncoding); 416 } 417 catch (SOAPException e) {} 418 } 419 420 //determine content type from message response 421 contentType = rspMsg.getContentType(msgContext.getSOAPConstants()); 422 if (isDebug) log.debug("Returned Content-Type:" + contentType); 423 424 // write result to response stream 425 try { 426 res.setContentType(contentType); 427 rspMsg.writeTo(res.getOutputStream()); 428 } 429 catch (SOAPException e) { 430 logException(e); 431 } 432 433 if (!res.isCommitted()) res.flushBuffer(); // Force it right now. 434 } 435 else { 436 // No content, so just indicate accepted 437 res.setStatus(202); 438 } 439 440 if (isDebug) { 441 log.debug("Response sent."); 442 log.debug("Exit: doPost()"); 443 } 444 if (tlog.isDebugEnabled()) { 445 t4 = System.currentTimeMillis(); 446 tlog.debug("axisServlet.doPost: " + soapAction + 447 " pre=" + (t1 - t0) + 448 " invoke=" + (t2 - t1) + 449 " post=" + (t3 - t2) + 450 " send=" + (t4 - t3) + 451 " " + msgContext.getTargetService() + "." + 452 ((msgContext.getOperation() == null) ? 453 "" : msgContext.getOperation().getName())); 454 } 455 456 } 457 458 /** 459 * Configure the servlet response status code and maybe other headers 460 * from the fault info. 461 * @param response response to configure 462 * @param fault what went wrong 463 */ 464 private void configureResponseFromAxisFault(HttpServletResponse response, 465 AxisFault fault) { 466 // then get the status code 467 // It's been suggested that a lack of SOAPAction 468 // should produce some other error code (in the 400s)... 469 int status = getHttpServletResponseStatus(fault); 470 if (status == HttpServletResponse.SC_UNAUTHORIZED) { 471 response.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\""); 472 } 473 response.setStatus(status); 474 } 475 476 /** 477 * turn any Exception into an AxisFault, log it, set the response 478 * status code according to what the specifications say and 479 * return a response message for posting. This will be the response 480 * message passed in if non-null; one generated from the fault otherwise. 481 * 482 * @param exception what went wrong 483 * @param responseMsg what response we have (if any) 484 * @return a response message to send to the user 485 */ 486 private Message convertExceptionToAxisFault(Exception exception, 487 Message responseMsg) { 488 logException(exception); 489 if (responseMsg == null) { 490 AxisFault fault = AxisFault.makeFault(exception); 491 processAxisFault(fault); 492 responseMsg = new Message(fault); 493 } 494 return responseMsg; 495 } 496 497 /** 498 * Extract information from AxisFault and map it to a HTTP Status code. 499 * 500 * @param af Axis Fault 501 * @return HTTP Status code. 502 */ 503 private int getHttpServletResponseStatus(AxisFault af) { 504 // subclasses... --Glen 505 return af.getFaultCode().getLocalPart().startsWith("Server.Unauth") 506 ? HttpServletResponse.SC_UNAUTHORIZED 507 : HttpServletResponse.SC_INTERNAL_SERVER_ERROR; 508 // This will raise a 401 for both 509 // "Unauthenticated" & "Unauthorized"... 510 } 511 512 /** 513 * write a message to the response, set appropriate headers for content 514 * type..etc. 515 * @param res response 516 * @param responseMsg message to write 517 * @throws AxisFault 518 * @throws IOException if the response stream can not be written to 519 */ 520 private void sendResponseX(String contentType, 521 HttpServletResponse res, 522 Message responseMsg) throws AxisFault, 523 IOException { 524 if (responseMsg == null) { 525 res.setStatus(HttpServletResponse.SC_NO_CONTENT); 526 if (isDebug) { 527 log.debug("NO AXIS MESSAGE TO RETURN!"); 528 } 529 } else { 530 if (isDebug) { 531 log.debug("Returned Content-Type:" + contentType); 532 } 533 534 try { 535 536 res.setContentType(contentType); 537 responseMsg.writeTo(res.getOutputStream()); 538 } catch (SOAPException e) { 539 logException(e); 540 } 541 } 542 543 if (!res.isCommitted()) { 544 res.flushBuffer(); // Force it right now. 545 } 546 } 547 548 /** 549 * Place the Request message in the MessagContext object - notice 550 * that we just leave it as a 'ServletRequest' object and let the 551 * Message processing routine convert it - we don't do it since we 552 * don't know how it's going to be used - perhaps it might not 553 * even need to be parsed. 554 * @return a message context 555 */ 556 private MessageContext createMessageContext(AxisEngine engine, HttpServletRequest req, HttpServletResponse res, Component component) { 557 MessageContext msgContext = new MessageContext(engine); 558 559 String requestPath = getRequestPath(req); 560 561 if (isDebug) { 562 log.debug("MessageContext:" + msgContext); 563 log.debug("HEADER_CONTENT_TYPE:" + 564 req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE)); 565 log.debug("HEADER_CONTENT_LOCATION:" + 566 req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION)); 567 log.debug("Constants.MC_HOME_DIR:" + String.valueOf(homeDir)); 568 log.debug("Constants.MC_RELATIVE_PATH:" + requestPath); 569 log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" +String.valueOf(webInfPath)); 570 log.debug("HTTPConstants.MC_HTTP_SERVLETPATHINFO:" +req.getPathInfo()); 571 log.debug("HTTPConstants.HEADER_AUTHORIZATION:" +req.getHeader(HTTPConstants.HEADER_AUTHORIZATION)); 572 log.debug("Constants.MC_REMOTE_ADDR:" + req.getRemoteAddr()); 573 log.debug("configPath:" + String.valueOf(webInfPath)); 574 } 575 576 /* Set the Transport */ 577 /*********************/ 578 msgContext.setTransportName("http"); 579 580 /* Save some HTTP specific info in the bag in case someone needs it */ 581 /********************************************************************/ 582 //msgContext.setProperty(Constants.MC_JWS_CLASSDIR, jwsClassDir); 583 msgContext.setProperty(Constants.MC_HOME_DIR, homeDir); 584 msgContext.setProperty(Constants.MC_RELATIVE_PATH, requestPath); 585 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLET, this); 586 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, req); 587 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, res); 588 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETLOCATION,webInfPath); 589 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO,req.getPathInfo()); 590 msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION,req.getHeader(HTTPConstants.HEADER_AUTHORIZATION)); 591 msgContext.setProperty(lucee.runtime.net.rpc.server.Constants.COMPONENT, component); 592 msgContext.setProperty(Constants.MC_REMOTE_ADDR, req.getRemoteAddr()); 593 594 // Set up a javax.xml.rpc.server.ServletEndpointContext 595 ServletEndpointContextImpl sec = new ServletEndpointContextImpl(); 596 597 msgContext.setProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT, sec); 598 /* Save the real path */ 599 /**********************/ 600 String relpath = context.getRealPath(requestPath); 601 602 if (relpath != null) { 603 msgContext.setProperty(Constants.MC_REALPATH, relpath); 604 } 605 606 msgContext.setProperty(Constants.MC_CONFIGPATH, webInfPath); 607 608 return msgContext; 609 } 610 611 /** 612 * Extract the SOAPAction header. 613 * if SOAPAction is null then we'll we be forced to scan the body for it. 614 * if SOAPAction is "" then use the URL 615 * @param req incoming request 616 * @return the action 617 * @throws AxisFault 618 */ 619 private String getSoapAction(HttpServletRequest req) throws AxisFault { 620 String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION); 621 if (soapAction == null) { 622 String contentType = req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE); 623 if(contentType != null) { 624 int index = contentType.indexOf("action"); 625 if(index != -1){ 626 soapAction = contentType.substring(index + 7); 627 } 628 } 629 } 630 631 if (isDebug) { 632 log.debug("HEADER_SOAP_ACTION:" + soapAction); 633 634 /** 635 * Technically, if we don't find this header, we should probably fault. 636 * It's required in the SOAP HTTP binding. 637 */ 638 } 639 if (soapAction == null) { 640 AxisFault af = new AxisFault("Client.NoSOAPAction", 641 Messages.getMessage("noHeader00", 642 "SOAPAction"), 643 null, null); 644 645 exceptionLog.error(Messages.getMessage("genFault00"), af); 646 647 throw af; 648 } 649 // the SOAP 1.1 spec & WS-I 1.0 says: 650 // soapaction = "SOAPAction" ":" [ <"> URI-reference <"> ] 651 // some implementations leave off the quotes 652 // we strip them if they are present 653 if (soapAction.startsWith("\"") && soapAction.endsWith("\"") 654 && soapAction.length() >= 2) { 655 int end = soapAction.length() - 1; 656 soapAction = soapAction.substring(1, end); 657 } 658 659 if (soapAction.length() == 0) { 660 soapAction = req.getContextPath(); // Is this right? 661 662 } 663 return soapAction; 664 } 665 666 667 /** 668 * Initialize a Handler for the transport defined in the Axis server config. 669 * This includes optionally filling in query string handlers. 670 */ 671 672 public void initQueryStringHandlers() { 673 this.transport = new SimpleTargetedChain(); 674 this.transport.setOption("qs.list","org.apache.axis.transport.http.QSListHandler"); 675 this.transport.setOption("qs.method","org.apache.axis.transport.http.QSMethodHandler"); 676 this.transport.setOption("qs.wsdl","org.apache.axis.transport.http.QSWSDLHandler"); 677 678 } 679 680 private boolean doGet(HttpServletRequest request,HttpServletResponse response,PrintWriter writer,Component component) throws AxisFault, ClassException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { 681 682 String path = request.getServletPath(); 683 String queryString = request.getQueryString(); 684 685 AxisEngine engine = getEngine(); 686 687 Iterator i = this.transport.getOptions().keySet().iterator(); 688 689 if (queryString == null) { 690 return false; 691 } 692 693 String servletURI = request.getContextPath() + path; 694 String reqURI = request.getRequestURI(); 695 696 // service name 697 String serviceName; 698 if (servletURI.length() + 1 < reqURI.length()) { 699 serviceName = reqURI.substring(servletURI.length() + 1); 700 } else { 701 serviceName = ""; 702 } 703 704 while (i.hasNext()) { 705 String queryHandler = (String) i.next(); 706 if (queryHandler.startsWith("qs.")) { 707 // Only attempt to match the query string with transport 708 // parameters prefixed with "qs:". 709 710 String handlerName = queryHandler.substring 711 (queryHandler.indexOf(".") + 1). 712 toLowerCase(); 713 // Determine the name of the plugin to invoke by using all text 714 // in the query string up to the first occurence of &, =, or the 715 // whole string if neither is present. 716 717 int length = 0; 718 boolean firstParamFound = false; 719 720 while (firstParamFound == false && length < queryString.length()) { 721 char ch = queryString.charAt(length++); 722 723 if (ch == '&' || ch == '=') { 724 firstParamFound = true; 725 726 --length; 727 } 728 } 729 730 if (length < queryString.length()) { 731 queryString = queryString.substring(0, length); 732 } 733 734 if (queryString.toLowerCase().equals(handlerName) == true) { 735 // Query string matches a defined query string handler name. 736 737 // If the defined class name for this query string handler is blank, 738 // just return (the handler is "turned off" in effect). 739 740 if (this.transport.getOption(queryHandler).equals("")) { 741 return false; 742 } 743 744 // Attempt to dynamically load the query string handler 745 // and its "invoke" method. 746 747 MessageContext msgContext = createMessageContext(engine,request, response,component); 748 Class plugin=ClassUtil.loadClass((String)this.transport.getOption(queryHandler)); 749 Method pluginMethod = plugin.getDeclaredMethod("invoke", new Class[] {msgContext.getClass()}); 750 751 msgContext.setProperty(MessageContext.TRANS_URL, HttpUtils.getRequestURL(request).toString().toLowerCase()); 752 //msgContext.setProperty(MessageContext.TRANS_URL, "http://DefaultNamespace"); 753 msgContext.setProperty(HTTPConstants.PLUGIN_SERVICE_NAME, serviceName); 754 msgContext.setProperty(HTTPConstants.PLUGIN_NAME,handlerName); 755 msgContext.setProperty(HTTPConstants.PLUGIN_IS_DEVELOPMENT,Caster.toBoolean(isDevelopment)); 756 msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,Boolean.FALSE); 757 msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE,engine); 758 msgContext.setProperty(HTTPConstants.PLUGIN_WRITER,writer); 759 msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log); 760 msgContext.setProperty(HTTPConstants.PLUGIN_EXCEPTION_LOG,exceptionLog); 761 762 // Invoke the plugin. 763 pluginMethod.invoke(ClassUtil.loadInstance(plugin),new Object[] {msgContext}); 764 writer.close(); 765 766 return true; 767 768 } 769 } 770 } 771 772 return false; 773 } 774 775 776 /** 777 * getRequestPath a returns request path for web service padded with 778 * request.getPathInfo for web services served from /services directory. 779 * This is a required to support serving .jws web services from /services 780 * URL. See AXIS-843 for more information. 781 * 782 * @param request HttpServletRequest 783 * @return String 784 */ 785 private static String getRequestPath(HttpServletRequest request) { 786 return request.getServletPath() + ((request.getPathInfo() != null) ? 787 request.getPathInfo() : ""); 788 } 789 790 791 /** 792 * get the engine for this Server from cache or context 793 * @return 794 * @throws AxisFault 795 */ 796 public AxisServer getEngine() throws AxisFault { 797 if (axisServer == null) { 798 synchronized (context) { 799 Map environment = new HashMap(); 800 environment.put(AxisEngine.ENV_SERVLET_CONTEXT, context); 801 axisServer = AxisServer.getServer(environment); 802 axisServer.setName("LuceeServer"); 803 } 804 805 // add Component Handler 806 try { 807 SimpleChain sc=(SimpleChain) axisServer.getGlobalRequest(); 808 sc.addHandler(new ComponentHandler()); 809 } 810 catch (ConfigurationException e) { 811 throw AxisFault.makeFault(e); 812 } 813 TypeMappingUtil.registerDefaults(axisServer.getTypeMappingRegistry()); 814 815 } 816 return axisServer; 817 } 818 819 public static RPCServer getInstance(int id, ServletContext servletContext) throws AxisFault { 820 RPCServer server=(RPCServer) servers.get(Caster.toString(id)); 821 if(server==null){ 822 servers.put(Caster.toString(id), server=new RPCServer(servletContext)); 823 } 824 return server; 825 } 826 827 828 829 830 public void registerTypeMapping(Class clazz) { 831 String fullname = clazz.getName();//,name,packages; 832 //registerTypeMapping(clazz, new QName(AxisCaster.getRequestNameSpace(),fullname)); 833 registerTypeMapping(clazz, new QName(AxisCaster.getRequestDefaultNameSpace(),fullname)); 834 } 835 836 private void registerTypeMapping(Class clazz,QName qname) { 837 838 org.apache.axis.encoding.TypeMapping tm = TypeMappingUtil.getServerTypeMapping(axisServer); 839 TypeMappingUtil.registerBeanTypeMapping(tm,clazz, qname); 840 } 841}