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