You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-user@axis.apache.org by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com> on 2007/07/23 12:06:38 UTC
RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to measure
the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to response
time? I created a handler in the requestFlow to store
System.currentTimeMillis in messageContext and another handler in the
responseFlow that retrieved this value and subtracts it from
System.currentTimeMillis(), when I use these classes in the global conf
or transport (server side) I am getting values that correspond to the
response time the client is getting so it looks like it is not
calculating the Axix overhead on the server side, when I put these
handlers in the requestFlow and responseFlow in the service section in
server-conf.wsdd it gives differnt time which seem right but I am nti
sure if this is the Axix engine overhead? Any suggestions? other ways to
do this? please reply back to me or CC me if you are sending to the list
since I am not yet a member in this list.
Regards,
Firas Khasawneh
Re: measuring Axix 1.4 overhead
Posted by Deepal Jayasinghe <de...@opensource.lk>.
As I know in WSO2 WSAS you can deploy Axis1 services inside Axis2
without having any pain. So that you do not need to re-write anything to
use Axis2 , if you are an Axis1 user.
Thanks
Deepal
> Please see this
> http://ws.apache.org/axis2/1_2/migration.html
> -jaliya
>
> ----- Original Message -----
> *From:* Firas Khasawneh (fkhasawn) <ma...@cisco.com>
> *To:* Jaliya Ekanayake <ma...@apache.org>
> *Cc:* axis-dev@ws.apache.org <ma...@ws.apache.org>
> *Sent:* Tuesday, July 24, 2007 12:22 PM
> *Subject:* RE: measuring Axix 1.4 overhead
>
> Hi Jaliya,
>
> To use Axis2 do I need to change anything in my service code or
> rebuild it or can I just replace the library jars?
>
> Thanks,
> Firas
>
> ------------------------------------------------------------------------
> *From:* Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
> *Sent:* Tuesday, July 24, 2007 10:44 AM
> *To:* Firas Khasawneh (fkhasawn)
> *Cc:* axis-dev@ws.apache.org <ma...@ws.apache.org>
> *Subject:* Re: measuring Axix 1.4 overhead
>
> Hi Firas,
>
> Did you try Axis2 http://ws.apache.org/axis2/ ?
> In axis2 processing starts without fully building the soap envelope.
> And the performance figures for Axis2 is
> http://www.wso2.org/library/588
>
> Thanks,
> -jaliya
>
>
> ----- Original Message -----
> *From:* Firas Khasawneh (fkhasawn) <ma...@cisco.com>
> *To:* Jaliya Ekanayake <ma...@apache.org>
> *Sent:* Tuesday, July 24, 2007 8:48 AM
> *Subject:* RE: measuring Axix 1.4 overhead
>
> Hi Jaliya,
>
> I tested with small size messages and 1 mb messages and there
> is big difference, looks like Axis takes long time to process
> large messages, but t4-t0 should give the processing time and
> not the transport time. Also invoke time t3-t0 should give
> only Axis engine overhead.
>
> Thanks,
> Firas
>
> ------------------------------------------------------------------------
> *From:* Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
> *Sent:* Monday, July 23, 2007 4:34 PM
> *To:* Firas Khasawneh (fkhasawn)
> *Subject:* Re: measuring Axix 1.4 overhead
>
> Hi Firas,
>
> Yes, t4-t0 should give you the results.
> However the problem is that you use large message size.
> My guess is that the processing happens before the total
> retrieval of the message and hence it include the time it
> takes to transfer the message as well.
> Did you try with a small message sizes?
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: axis-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-dev-help@ws.apache.org
Re: measuring Axix 1.4 overhead
Posted by Jaliya Ekanayake <jn...@gmail.com>.
Please see this
http://ws.apache.org/axis2/1_2/migration.html
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake
Cc: axis-dev@ws.apache.org
Sent: Tuesday, July 24, 2007 12:22 PM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
To use Axis2 do I need to change anything in my service code or rebuild it or can I just replace the library jars?
Thanks,
Firas
------------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Tuesday, July 24, 2007 10:44 AM
To: Firas Khasawneh (fkhasawn)
Cc: axis-dev@ws.apache.org
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Did you try Axis2 http://ws.apache.org/axis2/ ?
In axis2 processing starts without fully building the soap envelope.
And the performance figures for Axis2 is http://www.wso2.org/library/588
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake
Sent: Tuesday, July 24, 2007 8:48 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I tested with small size messages and 1 mb messages and there is big difference, looks like Axis takes long time to process large messages, but t4-t0 should give the processing time and not the transport time. Also invoke time t3-t0 should give only Axis engine overhead.
Thanks,
Firas
----------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 4:34 PM
To: Firas Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Yes, t4-t0 should give you the results.
However the problem is that you use large message size.
My guess is that the processing happens before the total retrieval of the message and hence it include the time it takes to transfer the message as well.
Did you try with a small message sizes?
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 3:49 PM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I am attaching the AxisServlet.java after adding benchmark times, if you look at line 791 in the doPost method, the invoke shoudl calculate the invokation time for the Axis engine without the network time but for some reason it looks like it is including this time in the invokation time which does not make any sense. I am testing with 1 MB size files so I am not sure. below is AxisServlet.java, sorry for cuttin and pasting it here but I was not sure if this email list allows attachments:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.transport.http;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.apache.axis.AxisEngine;
import org.apache.axis.AxisFault;
import org.apache.axis.ConfigurationException;
import org.apache.axis.Constants;
import org.apache.axis.Handler;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.SimpleTargetedChain;
import org.apache.axis.client.Service;
import org.apache.axis.management.ServiceAdmin;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ServiceDesc;
import org.apache.axis.handlers.soap.SOAPService;
import org.apache.axis.security.servlet.ServletSecurityProvider;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import org.apache.commons.logging.Log;
import org.w3c.dom.Element;
/**
*
* @author Doug Davis (dug@us.ibm.com)
* @author Steve Loughran
* xdoclet tags are not active yet; keep web.xml in sync.
* To change the location of the services, change url-pattern in web.xml and
* set parameter axis.servicesPath in server-config.wsdd. For more information see
* <a href="http://ws.apache.org/axis/java/reference.html">Axis Reference Guide</a>.
*
* @web.servlet name="AxisServlet" display-name="Apache-Axis Servlet"
* @web.servlet-mapping url-pattern="/servlet/AxisServlet"
* @web.servlet-mapping url-pattern="*.jws"
* @web.servlet-mapping url-pattern="/services/*"
*/
public class AxisServlet extends AxisServletBase {
protected static Log log =
LogFactory.getLog(AxisServlet.class.getName());
/**
* this log is for timing
*/
private static Log tlog =
LogFactory.getLog(Constants.TIME_LOG_CATEGORY);
/**
* a separate log for exceptions lets users route them
* differently from general low level debug info
*/
private static Log exceptionLog =
LogFactory.getLog(Constants.EXCEPTION_LOG_CATEGORY);
public static final String INIT_PROPERTY_TRANSPORT_NAME =
"transport.name";
public static final String INIT_PROPERTY_USE_SECURITY =
"use-servlet-security";
public static final String INIT_PROPERTY_ENABLE_LIST =
"axis.enableListQuery";
public static final String INIT_PROPERTY_JWS_CLASS_DIR =
"axis.jws.servletClassDir";
// This will turn off the list of available services
public static final String INIT_PROPERTY_DISABLE_SERVICES_LIST =
"axis.disableServiceList";
// Location of the services as defined by the servlet-mapping in web.xml
public static final String INIT_PROPERTY_SERVICES_PATH =
"axis.servicesPath";
// These have default values.
private String transportName;
private Handler transport;
private ServletSecurityProvider securityProvider = null;
private String servicesPath;
/**
* cache of logging debug option; only evaluated at init time.
* So no dynamic switching of logging options with this servlet.
*/
private static boolean isDebug = false;
/**
* Should we enable the "?list" functionality on GETs? (off by
* default because deployment information is a potential security
* hole)
*/
private boolean enableList = false;
/**
* Should we turn off the list of services when we receive a GET
* at the servlet root?
*/
private boolean disableServicesList = false;
/**
* Cached path to JWS output directory
*/
private String jwsClassDir = null;
protected String getJWSClassDir() {return jwsClassDir;
}
/**
* create a new servlet instance
*/
public AxisServlet() {
}
/**
* Initialization method.
*/
public void init() throws javax.servlet.ServletException {
super.init();
ServletContext context = getServletConfig().getServletContext();
isDebug = log.isDebugEnabled();
if (isDebug) {
log.debug("In servlet init");
}
transportName = getOption(context,
INIT_PROPERTY_TRANSPORT_NAME,
HTTPTransport.DEFAULT_TRANSPORT_NAME);
if (JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_USE_SECURITY, null))) {
securityProvider = new ServletSecurityProvider();
}
enableList =
JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_ENABLE_LIST, null));
jwsClassDir = getOption(context, INIT_PROPERTY_JWS_CLASS_DIR, null);
// Should we list services?
disableServicesList = JavaUtils.isTrue(getOption(context,
INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));
servicesPath = getOption(context, INIT_PROPERTY_SERVICES_PATH,
"/services/");
/**
* There are DEFINATE problems here if
* getHomeDir and/or getDefaultJWSClassDir return null
* (as they could with WebLogic).
* This needs to be reexamined in the future, but this
* should fix any NPE's in the mean time.
*/
if (jwsClassDir != null) {
if (getHomeDir() != null) {
jwsClassDir = getHomeDir() + jwsClassDir;
}
} else {
jwsClassDir = getDefaultJWSClassDir();
}
initQueryStringHandlers();
// Setup the service admin
try {
ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo());
} catch (AxisFault af) {
exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " +
af);
}
}
/**
* Process GET requests. This includes handoff of pseudo-SOAP requests
*
* @param request request in
* @param response request out
* @throws ServletException
* @throws IOException
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
if (isDebug) {
log.debug("Enter: doGet()");
}
PrintWriter writer = new FilterPrintWriter(response);
try {
AxisEngine engine = getEngine();
ServletContext servletContext =
getServletConfig().getServletContext();
String pathInfo = request.getPathInfo();
String realpath = servletContext.getRealPath(request.getServletPath());
if (realpath == null) {
realpath = request.getServletPath();
}
//JWS pages are special; they are the servlet path and there
//is no pathinfo...we map the pathinfo to the servlet path to keep
//it happy
boolean isJWSPage = request.getRequestURI().endsWith(".jws");
if (isJWSPage) {
pathInfo = request.getServletPath();
}
// Try to execute a query string plugin and return upon success.
if (processQuery(request, response, writer) == true) {
long reqout = System.currentTimeMillis();
return;
}
boolean hasNoPath = (pathInfo == null || pathInfo.equals(""));
if (!disableServicesList) {
if(hasNoPath) {
// If the user requested the servlet (i.e. /axis/servlet/AxisServlet)
// with no service name, present the user with a list of deployed
// services to be helpful
// Don't do this if has been turned off
reportAvailableServices(response, writer, request);
} else if (realpath != null) {
// We have a pathname, so now we perform WSDL or list operations
// get message context w/ various properties set
MessageContext msgContext = createMessageContext(engine,
request, response);
// NOTE: HttpUtils.getRequestURL has been deprecated.
// This line SHOULD be:
// String url = req.getRequestURL().toString()
// HOWEVER!!!! DON'T REPLACE IT! There's a bug in
// req.getRequestURL that is not in HttpUtils.getRequestURL
// req.getRequestURL returns "localhost" in the remote
// scenario rather than the actual host name.
//
// But more importantly, getRequestURL() is a servlet 2.3
// API and to support servlet 2.2 (aka WebSphere 4)
// we need to leave this in for a while longer. tomj 10/14/2004
//
String url = HttpUtils.getRequestURL(request).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// See if we can locate the desired service. If we
// can't, return a 404 Not Found. Otherwise, just
// print the placeholder message.
String serviceName;
if (pathInfo.startsWith("/")) {
serviceName = pathInfo.substring(1);
} else {
serviceName = pathInfo;
}
SOAPService s = engine.getService(serviceName);
if (s == null) {
//no service: report it
if (isJWSPage) {
reportCantGetJWSService(request, response, writer);
} else {
reportCantGetAxisService(request, response, writer);
}
} else {
//print a snippet of service info.
reportServiceInfo(response, writer, s, serviceName);
}
}
} else {
// We didn't have a real path in the request, so just
// print a message informing the user that they reached
// the servlet.
response.setContentType("text/html; charset=utf-8");
writer.println("<html><h1>Axis HTTP Servlet</h1>");
writer.println(Messages.getMessage("reachedServlet00"));
writer.println("<p>" +
Messages.getMessage("transportName00",
"<b>" + transportName + "</b>"));
writer.println("</html>");
}
} catch (AxisFault fault) {
reportTroubleInGet(fault, response, writer);
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
} finally {
writer.close();
if (isDebug) {
log.debug("Exit: doGet()");
}
}
}
/**
* when we get an exception or an axis fault in a GET, we handle
* it almost identically: we go 'something went wrong', set the response
* code to 500 and then dump info. But we dump different info for an axis fault
* or subclass thereof.
* @param exception what went wrong
* @param response current response
* @param writer open writer to response
*/
private void reportTroubleInGet(Throwable exception,
HttpServletResponse response,
PrintWriter writer) {
response.setContentType("text/html; charset=utf-8");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
writer.println("<h2>" +
Messages.getMessage("error00") +
"</h2>");
writer.println("<p>" +
Messages.getMessage("somethingWrong00") +
"</p>");
if (exception instanceof AxisFault) {
AxisFault fault = (AxisFault) exception;
processAxisFault(fault);
writeFault(writer, fault);
} else {
logException(exception);
writer.println("<pre>Exception - " + exception + "<br>");
//dev systems only give fault dumps
if (isDevelopment()) {
writer.println(JavaUtils.stackToString(exception));
}
writer.println("</pre>");
}
}
/**
* routine called whenever an axis fault is caught; where they
* are logged and any other business. The method may modify the fault
* in the process
* @param fault what went wrong.
*/
protected void processAxisFault(AxisFault fault) {
//log the fault
Element runtimeException = fault.lookupFaultDetail(
Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
if (runtimeException != null) {
exceptionLog.info(Messages.getMessage("axisFault00"), fault);
//strip runtime details
fault.removeFaultDetail(Constants.
QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
} else if (exceptionLog.isDebugEnabled()) {
exceptionLog.debug(Messages.getMessage("axisFault00"), fault);
}
//dev systems only give fault dumps
if (!isDevelopment()) {
//strip out the stack trace
fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE);
}
}
/**
* log any exception to our output log, at our chosen level
* @param e what went wrong
*/
protected void logException(Throwable e) {
exceptionLog.info(Messages.getMessage("exception00"), e);
}
/**
* this method writes a fault out to an HTML stream. This includes
* escaping the strings to defend against cross-site scripting attacks
* @param writer
* @param axisFault
*/
private void writeFault(PrintWriter writer, AxisFault axisFault) {
String localizedMessage = XMLUtils.xmlEncodeString(axisFault.
getLocalizedMessage());
writer.println("<pre>Fault - " + localizedMessage + "<br>");
writer.println(axisFault.dumpToString());
writer.println("</pre>");
}
/**
* print a snippet of service info.
* @param service service
* @param writer output channel
* @param serviceName where to put stuff
*/
protected void reportServiceInfo(HttpServletResponse response,
PrintWriter writer, SOAPService service,
String serviceName) {
response.setContentType("text/html; charset=utf-8");
writer.println("<h1>"
+ service.getName()
+ "</h1>");
writer.println(
"<p>" +
Messages.getMessage("axisService00") +
"</p>");
writer.println(
"<i>" +
Messages.getMessage("perhaps00") +
"</i>");
}
/**
* report that we have no WSDL
*
* This method was moved to the querystring handler QSWSDLHandler. The
* method reportNoWSDL in AxisServlet is never called. Perhaps the method
* is overwritten in subclasses of AxisServlet so the method wasn't
* removed. See the discussion in
*
* http://nagoya.apache.org/bugzilla/show_bug.cgi?id=23845
*
* @param res
* @param writer
* @param moreDetailCode optional name of a message to provide more detail
* @param axisFault optional fault string, for extra info at debug time only
*/
protected void reportNoWSDL(HttpServletResponse res, PrintWriter writer,
String moreDetailCode, AxisFault axisFault) {
}
/**
* This method lists the available services; it is called when there is
* nothing to execute on a GET
* @param response
* @param writer
* @param request
* @throws ConfigurationException
* @throws AxisFault
*/
protected void reportAvailableServices(HttpServletResponse response,
PrintWriter writer,
HttpServletRequest request) throws
ConfigurationException, AxisFault {
AxisEngine engine = getEngine();
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>And now... Some Services</h2>");
Iterator i;
try {
i = engine.getConfig().getDeployedServices();
} catch (ConfigurationException configException) {
//turn any internal configuration exceptions back into axis faults
//if that is what they are
if (configException.getContainedException() instanceof AxisFault) {
throw (AxisFault) configException.getContainedException();
} else {
throw configException;
}
}
// baseURL may change if <endpointURL> tag is used for
// custom deployment at a different location
String defaultBaseURL = getWebappBase(request) + servicesPath;
writer.println("<ul>");
while (i.hasNext()) {
ServiceDesc sd = (ServiceDesc) i.next();
StringBuffer sb = new StringBuffer();
sb.append("<li>");
String name = sd.getName();
sb.append(name);
sb.append(" <a href=\"");
String endpointURL = sd.getEndpointURL();
String baseURL = (endpointURL == null) ? defaultBaseURL :
endpointURL;
sb.append(baseURL);
sb.append(name);
sb.append("?wsdl\"><i>(wsdl)</i></a></li>");
writer.println(sb.toString());
ArrayList operations = sd.getOperations();
if (!operations.isEmpty()) {
writer.println("<ul>");
for (Iterator it = operations.iterator(); it.hasNext(); ) {
OperationDesc desc = (OperationDesc) it.next();
writer.println("<li>" + desc.getName());
}
writer.println("</ul>");
}
}
writer.println("</ul>");
}
/**
* generate the error response to indicate that there is apparently no endpoint there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void reportCantGetAxisService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// no such service....
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>" +
Messages.getMessage("error00") + "</h2>");
writer.println("<p>" +
Messages.getMessage("noService06") +
"</p>");
}
/**
* probe for a JWS page and report 'no service' if one is not found there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void reportCantGetJWSService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// first look to see if there is a service
// requestPath is a work around to support serving .jws web services
// from services URL - see AXIS-843 for more information
String requestPath = request.getServletPath() + ((request.getPathInfo() != null) ?
request.getPathInfo() : "");
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
log.debug("JWS real path: " + realpath);
boolean foundJWSFile = (new File(realpath).exists()) &&
(realpath.endsWith(Constants.
JWS_DEFAULT_FILE_EXTENSION));
response.setContentType("text/html; charset=utf-8");
if (foundJWSFile) {
response.setStatus(HttpURLConnection.HTTP_OK);
writer.println(Messages.getMessage("foundJWS00") + "<p>");
String url = request.getRequestURI();
String urltext = Messages.getMessage("foundJWS01");
writer.println("<a href='" + url + "?wsdl'>" + urltext + "</a>");
} else {
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
writer.println(Messages.getMessage("noService06"));
}
}
/**
* Process a POST to the servlet by handing it off to the Axis Engine.
* Here is where SOAP messages are received
* @param req posted request
* @param res respose
* @throws ServletException trouble
* @throws IOException different trouble
*/
public void doPost(HttpServletRequest req, HttpServletResponse res) throws
ServletException, IOException {
long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
String soapAction = null;
MessageContext msgContext = null;
if (isDebug) {
log.debug("Enter: doPost()");
}
t0 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
Message responseMsg = null;
String contentType = null;
try {
AxisEngine engine = getEngine();
if (engine == null) {
// !!! should return a SOAP fault...
ServletException se =
new ServletException(Messages.getMessage("noEngine00"));
log.debug("No Engine!", se);
throw se;
}
res.setBufferSize(1024 * 8); // provide performance boost.
/** get message context w/ various properties set
*/
msgContext = createMessageContext(engine, req, res);
// ? OK to move this to 'getMessageContext',
// ? where it would also be picked up for 'doGet()' ?
if (securityProvider != null) {
if (isDebug) {
log.debug("securityProvider:" + securityProvider);
}
msgContext.setProperty(MessageContext.SECURITY_PROVIDER,
securityProvider);
}
/* Get request message
*/
Message requestMsg =
new Message(req.getInputStream(),
false,
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
req.getHeader(HTTPConstants.
HEADER_CONTENT_LOCATION));
// Transfer HTTP headers to MIME headers for request message.
MimeHeaders requestMimeHeaders = requestMsg.getMimeHeaders();
for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) {
String headerName = (String) e.nextElement();
for (Enumeration f = req.getHeaders(headerName);
f.hasMoreElements(); ) {
String headerValue = (String) f.nextElement();
requestMimeHeaders.addHeader(headerName, headerValue);
}
}
if (isDebug) {
log.debug("Request Message:" + requestMsg);
/* Set the request(incoming) message field in the context */
/**********************************************************/
}
msgContext.setRequestMessage(requestMsg);
String url = HttpUtils.getRequestURL(req).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// put character encoding of request to message context
// in order to reuse it during the whole process.
String requestEncoding;
try {
requestEncoding = (String) requestMsg.getProperty(SOAPMessage.
CHARACTER_SET_ENCODING);
if (requestEncoding != null) {
msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
requestEncoding);
}
} catch (SOAPException e1) {
}
try {
/**
* Save the SOAPAction header in the MessageContext bag.
* This will be used to tell the Axis Engine which service
* is being invoked. This will save us the trouble of
* having to parse the Request message - although we will
* need to double-check later on that the SOAPAction header
* does in fact match the URI in the body.
*/
// (is this last stmt true??? (I don't think so - Glen))
/********************************************************/
soapAction = getSoapAction(req);
if (soapAction != null) {
msgContext.setUseSOAPAction(true);
msgContext.setSOAPActionURI(soapAction);
}
// Create a Session wrapper for the HTTP session.
// These can/should be pooled at some point.
// (Sam is Watching! :-)
msgContext.setSession(new AxisHttpSession(req));
t1 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
/* Invoke the Axis engine... */
/*****************************/
if (isDebug) {
log.debug("Invoking Axis Engine.");
//here we run the message by the engine
}
engine.invoke(msgContext);
if (isDebug) {
log.debug("Return from Axis Engine.");
}
t2 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
}
responseMsg = msgContext.getResponseMessage();
// We used to throw exceptions on null response messages.
// They are actually OK in certain situations (asynchronous
// services), so fall through here and return an ACCEPTED
// status code below. Might want to install a configurable
// error check for this later.
} catch (AxisFault fault) {
//log and sanitize
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (Exception e) {
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = convertExceptionToAxisFault(e, responseMsg);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
} catch (Throwable t) {
logException(t);
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = new Message(new AxisFault(t.toString(),t));
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (AxisFault fault) {
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
}
t3 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t3 = System.currentTimeMillis();
}
/* Send response back along the wire... */
/***********************************/
if (responseMsg != null) {
// Transfer MIME headers to HTTP headers for response message.
MimeHeaders responseMimeHeaders = responseMsg.getMimeHeaders();
for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) {
MimeHeader responseMimeHeader = (MimeHeader) i.next();
res.addHeader(responseMimeHeader.getName(),
responseMimeHeader.getValue());
}
// synchronize the character encoding of request and response
String responseEncoding = (String) msgContext.getProperty(
SOAPMessage.CHARACTER_SET_ENCODING);
if (responseEncoding != null) {
try {
responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
responseEncoding);
} catch (SOAPException e) {
}
}
//determine content type from message response
contentType = responseMsg.getContentType(msgContext.
getSOAPConstants());
sendResponse(contentType, res, responseMsg);
} else {
// No content, so just indicate accepted
res.setStatus(202);
}
if (isDebug) {
log.debug("Response sent.");
log.debug("Exit: doPost()");
}
t4 = System.currentTimeMillis();
System.out.println("Axis stats: " +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" total=" + (t4 - t0));
if (tlog.isDebugEnabled()) {
t4 = System.currentTimeMillis();
tlog.debug("axisServlet.doPost: " + soapAction +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" " + msgContext.getTargetService() + "." +
((msgContext.getOperation() == null) ?
"" : msgContext.getOperation().getName()));
}
}
/**
* Configure the servlet response status code and maybe other headers
* from the fault info.
* @param response response to configure
* @param fault what went wrong
*/
private void configureResponseFromAxisFault(HttpServletResponse response,
AxisFault fault) {
// then get the status code
// It's been suggested that a lack of SOAPAction
// should produce some other error code (in the 400s)...
int status = getHttpServletResponseStatus(fault);
if (status == HttpServletResponse.SC_UNAUTHORIZED) {
// unauth access results in authentication request
// TODO: less generic realm choice?
response.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\"");
}
response.setStatus(status);
}
/**
* turn any Exception into an AxisFault, log it, set the response
* status code according to what the specifications say and
* return a response message for posting. This will be the response
* message passed in if non-null; one generated from the fault otherwise.
*
* @param exception what went wrong
* @param responseMsg what response we have (if any)
* @return a response message to send to the user
*/
private Message convertExceptionToAxisFault(Exception exception,
Message responseMsg) {
logException(exception);
if (responseMsg == null) {
AxisFault fault = AxisFault.makeFault(exception);
processAxisFault(fault);
responseMsg = new Message(fault);
}
return responseMsg;
}
/**
* Extract information from AxisFault and map it to a HTTP Status code.
*
* @param af Axis Fault
* @return HTTP Status code.
*/
protected int getHttpServletResponseStatus(AxisFault af) {
// TODO: Should really be doing this with explicit AxisFault
// subclasses... --Glen
return af.getFaultCode().getLocalPart().startsWith("Server.Unauth")
? HttpServletResponse.SC_UNAUTHORIZED
: HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
// This will raise a 401 for both
// "Unauthenticated" & "Unauthorized"...
}
/**
* write a message to the response, set appropriate headers for content
* type..etc.
* @param res response
* @param responseMsg message to write
* @throws AxisFault
* @throws IOException if the response stream can not be written to
*/
private void sendResponse(String contentType,
HttpServletResponse res,
Message responseMsg) throws AxisFault,
IOException {
if (responseMsg == null) {
res.setStatus(HttpServletResponse.SC_NO_CONTENT);
if (isDebug) {
log.debug("NO AXIS MESSAGE TO RETURN!");
//String resp = Messages.getMessage("noData00");
//res.setContentLength((int) resp.getBytes().length);
//res.getWriter().print(resp);
}
} else {
if (isDebug) {
log.debug("Returned Content-Type:" +
contentType);
// log.debug("Returned Content-Length:" +
// responseMsg.getContentLength());
}
try {
res.setContentType(contentType);
/* My understand of Content-Length
* HTTP 1.0
* -Required for requests, but optional for responses.
* HTTP 1.1
* - Either Content-Length or HTTP Chunking is required.
* Most servlet engines will do chunking if content-length is not specified.
*
*
*/
//if(clientVersion == HTTPConstants.HEADER_PROTOCOL_V10) //do chunking if necessary.
// res.setContentLength(responseMsg.getContentLength());
responseMsg.writeTo(res.getOutputStream());
} catch (SOAPException e) {
logException(e);
}
}
if (!res.isCommitted()) {
res.flushBuffer(); // Force it right now.
}
}
/**
* Place the Request message in the MessagContext object - notice
* that we just leave it as a 'ServletRequest' object and let the
* Message processing routine convert it - we don't do it since we
* don't know how it's going to be used - perhaps it might not
* even need to be parsed.
* @return a message context
*/
private MessageContext createMessageContext(AxisEngine engine,
HttpServletRequest req,
HttpServletResponse res) {
MessageContext msgContext = new MessageContext(engine);
String requestPath = getRequestPath(req);
if (isDebug) {
log.debug("MessageContext:" + msgContext);
log.debug("HEADER_CONTENT_TYPE:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
log.debug("HEADER_CONTENT_LOCATION:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION));
log.debug("Constants.MC_HOME_DIR:" + String.valueOf(getHomeDir()));
log.debug("Constants.MC_RELATIVE_PATH:" + requestPath);
log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" +
String.valueOf(getWebInfPath()));
log.debug("HTTPConstants.MC_HTTP_SERVLETPATHINFO:" +
req.getPathInfo());
log.debug("HTTPConstants.HEADER_AUTHORIZATION:" +
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
log.debug("Constants.MC_REMOTE_ADDR:" + req.getRemoteAddr());
log.debug("configPath:" + String.valueOf(getWebInfPath()));
}
/* Set the Transport */
/*********************/
msgContext.setTransportName(transportName);
/* Save some HTTP specific info in the bag in case someone needs it */
/********************************************************************/
msgContext.setProperty(Constants.MC_JWS_CLASSDIR, jwsClassDir);
msgContext.setProperty(Constants.MC_HOME_DIR, getHomeDir());
msgContext.setProperty(Constants.MC_RELATIVE_PATH, requestPath);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLET, this);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, req);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, res);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETLOCATION,
getWebInfPath());
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO,
req.getPathInfo());
msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION,
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
msgContext.setProperty(Constants.MC_REMOTE_ADDR, req.getRemoteAddr());
// Set up a javax.xml.rpc.server.ServletEndpointContext
ServletEndpointContextImpl sec = new ServletEndpointContextImpl();
msgContext.setProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT, sec);
/* Save the real path */
/**********************/
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
if (realpath != null) {
msgContext.setProperty(Constants.MC_REALPATH, realpath);
}
msgContext.setProperty(Constants.MC_CONFIGPATH, getWebInfPath());
return msgContext;
}
/**
* Extract the SOAPAction header.
* if SOAPAction is null then we'll we be forced to scan the body for it.
* if SOAPAction is "" then use the URL
* @param req incoming request
* @return the action
* @throws AxisFault
*/
private String getSoapAction(HttpServletRequest req) throws AxisFault {
String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
if (soapAction == null) {
String contentType = req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
if(contentType != null) {
int index = contentType.indexOf("action");
if(index != -1){
soapAction = contentType.substring(index + 7);
}
}
}
if (isDebug) {
log.debug("HEADER_SOAP_ACTION:" + soapAction);
/**
* Technically, if we don't find this header, we should probably fault.
* It's required in the SOAP HTTP binding.
*/
}
if (soapAction == null) {
AxisFault af = new AxisFault("Client.NoSOAPAction",
Messages.getMessage("noHeader00",
"SOAPAction"),
null, null);
exceptionLog.error(Messages.getMessage("genFault00"), af);
throw af;
}
// the SOAP 1.1 spec & WS-I 1.0 says:
// soapaction = "SOAPAction" ":" [ <"> URI-reference <"> ]
// some implementations leave off the quotes
// we strip them if they are present
if (soapAction.startsWith("\"") && soapAction.endsWith("\"")
&& soapAction.length() >= 2) {
int end = soapAction.length() - 1;
soapAction = soapAction.substring(1, end);
}
if (soapAction.length() == 0) {
soapAction = req.getContextPath(); // Is this right?
}
return soapAction;
}
/**
* Provided to allow overload of default JWSClassDir
* by derived class.
* @return directory for JWS files
*/
protected String getDefaultJWSClassDir() {
return (getWebInfPath() == null)
? null // ??? what is a good FINAL default for WebLogic?
: getWebInfPath() + File.separator + "jwsClasses";
}
/**
* Initialize a Handler for the transport defined in the Axis server config.
* This includes optionally filling in query string handlers.
*/
public void initQueryStringHandlers() {
try {
this.transport = getEngine().getTransport(this.transportName);
if (this.transport == null) {
// No transport by this name is defined. Therefore, fill in default
// query string handlers.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
else {
// See if we should use the default query string handlers.
// By default, set this to true (for backwards compatibility).
boolean defaultQueryStrings = true;
String useDefaults = (String)this.transport.getOption(
"useDefaultQueryStrings");
if ((useDefaults != null) &&
useDefaults.toLowerCase().equals("false")) {
defaultQueryStrings = false;
}
if (defaultQueryStrings == true) {
// We should use defaults, so fill them in.
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
}
}
}
catch (AxisFault e) {
// Some sort of problem occurred, let's just make a default transport.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
}
/**
* Attempts to invoke a plugin for the query string supplied in the URL.
*
* @param request the servlet's HttpServletRequest object.
* @param response the servlet's HttpServletResponse object.
* @param writer the servlet's PrintWriter object.
*/
private boolean processQuery(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) throws AxisFault {
// Attempt to instantiate a plug-in handler class for the query string
// handler classes defined in the HTTP transport.
String path = request.getServletPath();
String queryString = request.getQueryString();
String serviceName;
AxisEngine engine = getEngine();
Iterator i = this.transport.getOptions().keySet().iterator();
if (queryString == null) {
return false;
}
String servletURI = request.getContextPath() + path;
String reqURI = request.getRequestURI();
// chop off '/'.
if (servletURI.length() + 1 < reqURI.length()) {
serviceName = reqURI.substring(servletURI.length() + 1);
} else {
serviceName = "";
} while (i.hasNext() == true) {
String queryHandler = (String) i.next();
if (queryHandler.startsWith("qs.") == true) {
// Only attempt to match the query string with transport
// parameters prefixed with "qs:".
String handlerName = queryHandler.substring
(queryHandler.indexOf(".") + 1).
toLowerCase();
// Determine the name of the plugin to invoke by using all text
// in the query string up to the first occurence of &, =, or the
// whole string if neither is present.
int length = 0;
boolean firstParamFound = false;
while (firstParamFound == false && length < queryString.length()) {
char ch = queryString.charAt(length++);
if (ch == '&' || ch == '=') {
firstParamFound = true;
--length;
}
}
if (length < queryString.length()) {
queryString = queryString.substring(0, length);
}
if (queryString.toLowerCase().equals(handlerName) == true) {
// Query string matches a defined query string handler name.
// If the defined class name for this query string handler is blank,
// just return (the handler is "turned off" in effect).
if (this.transport.getOption(queryHandler).equals("")) {
return false;
}
try {
// Attempt to dynamically load the query string handler
// and its "invoke" method.
MessageContext msgContext = createMessageContext(engine,
request, response);
Class plugin = Class.forName((String)this.transport.
getOption(queryHandler));
Method pluginMethod = plugin.getDeclaredMethod("invoke",
new Class[] {msgContext.getClass()});
String url = HttpUtils.getRequestURL(request).toString();
// Place various useful servlet-related objects in
// the MessageContext object being delivered to the
// plugin.
msgContext.setProperty(MessageContext.TRANS_URL, url);
msgContext.setProperty(HTTPConstants.
PLUGIN_SERVICE_NAME, serviceName);
msgContext.setProperty(HTTPConstants.PLUGIN_NAME,
handlerName);
msgContext.setProperty(HTTPConstants.
PLUGIN_IS_DEVELOPMENT,
new Boolean(isDevelopment()));
msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,
new Boolean(enableList));
msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE,
engine);
msgContext.setProperty(HTTPConstants.PLUGIN_WRITER,
writer);
msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log);
msgContext.setProperty(HTTPConstants.
PLUGIN_EXCEPTION_LOG,
exceptionLog);
// Invoke the plugin.
pluginMethod.invoke(plugin.newInstance(),
new Object[] {msgContext});
writer.close();
return true;
} catch (InvocationTargetException ie) {
reportTroubleInGet(ie.getTargetException(), response,
writer);
// return true to prevent any further processing
return true;
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
// return true to prevent any further processing
return true;
}
}
}
}
return false;
}
/**
* getRequestPath a returns request path for web service padded with
* request.getPathInfo for web services served from /services directory.
* This is a required to support serving .jws web services from /services
* URL. See AXIS-843 for more information.
*
* @param request HttpServletRequest
* @return String
*/
private static String getRequestPath(HttpServletRequest request) {
return request.getServletPath() + ((request.getPathInfo() != null) ?
request.getPathInfo() : "");
}
}
--------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 12:36 PM
To: Firas Khasawneh (fkhasawn); axis-user@ws.apache.org
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
The order of processing in the case of HTTP is;
AxisServlet->AxisEngine->HandlerChain->MessageProcessor->Service and come back.
If you placed the server in a different machine, then your RTT should definitely include the network time so it should be larger than the processing time.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake ; axis-dev@ws.apache.org ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 11:27 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
Do you know if response coming back from transport handler after the request is processed in the Axis engine also hits AxisServlet and uses doGet?
Thanks,
Firas
------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same machine? If you put the handler in transport section, then what you will measure is the time it takes inside the engine from transport handlers ->service -> transport handlers. One other possibility is to keep track of the time in AxisServlet. Measure the time in AxisServlet before it calls AxisEngine's invoke(..) method and after it is returned and you will get the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to measure the overhead Axis adds?
----------------------------------------------------------------------
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to response time? I created a handler in the requestFlow to store System.currentTimeMillis in messageContext and another handler in the responseFlow that retrieved this value and subtracts it from System.currentTimeMillis(), when I use these classes in the global conf or transport (server side) I am getting values that correspond to the response time the client is getting so it looks like it is not calculating the Axix overhead on the server side, when I put these handlers in the requestFlow and responseFlow in the service section in server-conf.wsdd it gives differnt time which seem right but I am nti sure if this is the Axix engine overhead? Any suggestions? other ways to do this? please reply back to me or CC me if you are sending to the list since I am not yet a member in this list.
Regards,
Firas Khasawneh
RE: measuring Axix 1.4 overhead
Posted by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com>.
Hi Jaliya,
To use Axis2 do I need to change anything in my service code or rebuild
it or can I just replace the library jars?
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Tuesday, July 24, 2007 10:44 AM
To: Firas Khasawneh (fkhasawn)
Cc: axis-dev@ws.apache.org
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Did you try Axis2 http://ws.apache.org/axis2/ ?
In axis2 processing starts without fully building the soap envelope.
And the performance figures for Axis2 is http://www.wso2.org/library/588
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn) <ma...@cisco.com>
To: Jaliya Ekanayake <ma...@apache.org>
Sent: Tuesday, July 24, 2007 8:48 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I tested with small size messages and 1 mb messages and there is
big difference, looks like Axis takes long time to process large
messages, but t4-t0 should give the processing time and not the
transport time. Also invoke time t3-t0 should give only Axis engine
overhead.
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 4:34 PM
To: Firas Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Yes, t4-t0 should give you the results.
However the problem is that you use large message size.
My guess is that the processing happens before the total
retrieval of the message and hence it include the time it takes to
transfer the message as well.
Did you try with a small message sizes?
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
<ma...@cisco.com>
To: Jaliya Ekanayake <ma...@apache.org> ;
axis-user@ws.apache.org
Sent: Monday, July 23, 2007 3:49 PM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I am attaching the AxisServlet.java after adding
benchmark times, if you look at line 791 in the doPost method, the
invoke shoudl calculate the invokation time for the Axis engine without
the network time but for some reason it looks like it is including this
time in the invokation time which does not make any sense. I am testing
with 1 MB size files so I am not sure. below is AxisServlet.java, sorry
for cuttin and pasting it here but I was not sure if this email list
allows attachments:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the
"License");
* you may not use this file except in compliance with
the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in
writing, software
* distributed under the License is distributed on an "AS
IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied.
* See the License for the specific language governing
permissions and
* limitations under the License.
*/
package org.apache.axis.transport.http;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.apache.axis.AxisEngine;
import org.apache.axis.AxisFault;
import org.apache.axis.ConfigurationException;
import org.apache.axis.Constants;
import org.apache.axis.Handler;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.SimpleTargetedChain;
import org.apache.axis.client.Service;
import org.apache.axis.management.ServiceAdmin;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ServiceDesc;
import org.apache.axis.handlers.soap.SOAPService;
import
org.apache.axis.security.servlet.ServletSecurityProvider;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import org.apache.commons.logging.Log;
import org.w3c.dom.Element;
/**
*
* @author Doug Davis (dug@us.ibm.com)
* @author Steve Loughran
* xdoclet tags are not active yet; keep web.xml in sync.
* To change the location of the services, change
url-pattern in web.xml and
* set parameter axis.servicesPath in server-config.wsdd.
For more information see
* <a
href="http://ws.apache.org/axis/java/reference.html">Axis Reference
Guide</a>.
*
* @web.servlet name="AxisServlet"
display-name="Apache-Axis Servlet"
* @web.servlet-mapping
url-pattern="/servlet/AxisServlet"
* @web.servlet-mapping url-pattern="*.jws"
* @web.servlet-mapping url-pattern="/services/*"
*/
public class AxisServlet extends AxisServletBase {
protected static Log log =
LogFactory.getLog(AxisServlet.class.getName());
/**
* this log is for timing
*/
private static Log tlog =
LogFactory.getLog(Constants.TIME_LOG_CATEGORY);
/**
* a separate log for exceptions lets users route them
* differently from general low level debug info
*/
private static Log exceptionLog =
LogFactory.getLog(Constants.EXCEPTION_LOG_CATEGORY);
public static final String INIT_PROPERTY_TRANSPORT_NAME
=
"transport.name";
public static final String INIT_PROPERTY_USE_SECURITY =
"use-servlet-security";
public static final String INIT_PROPERTY_ENABLE_LIST =
"axis.enableListQuery";
public static final String INIT_PROPERTY_JWS_CLASS_DIR =
"axis.jws.servletClassDir";
// This will turn off the list of available services
public static final String
INIT_PROPERTY_DISABLE_SERVICES_LIST =
"axis.disableServiceList";
// Location of the services as defined by the
servlet-mapping in web.xml
public static final String INIT_PROPERTY_SERVICES_PATH =
"axis.servicesPath";
// These have default values.
private String transportName;
private Handler transport;
private ServletSecurityProvider securityProvider = null;
private String servicesPath;
/**
* cache of logging debug option; only evaluated at init
time.
* So no dynamic switching of logging options with this
servlet.
*/
private static boolean isDebug = false;
/**
* Should we enable the "?list" functionality on GETs?
(off by
* default because deployment information is a potential
security
* hole)
*/
private boolean enableList = false;
/**
* Should we turn off the list of services when we
receive a GET
* at the servlet root?
*/
private boolean disableServicesList = false;
/**
* Cached path to JWS output directory
*/
private String jwsClassDir = null;
protected String getJWSClassDir() {return jwsClassDir;
}
/**
* create a new servlet instance
*/
public AxisServlet() {
}
/**
* Initialization method.
*/
public void init() throws javax.servlet.ServletException
{
super.init();
ServletContext context =
getServletConfig().getServletContext();
isDebug = log.isDebugEnabled();
if (isDebug) {
log.debug("In servlet init");
}
transportName = getOption(context,
INIT_PROPERTY_TRANSPORT_NAME,
HTTPTransport.DEFAULT_TRANSPORT_NAME);
if (JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_USE_SECURITY, null))) {
securityProvider = new ServletSecurityProvider();
}
enableList =
JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_ENABLE_LIST, null));
jwsClassDir = getOption(context,
INIT_PROPERTY_JWS_CLASS_DIR, null);
// Should we list services?
disableServicesList =
JavaUtils.isTrue(getOption(context,
INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));
servicesPath = getOption(context,
INIT_PROPERTY_SERVICES_PATH,
"/services/");
/**
* There are DEFINATE problems here if
* getHomeDir and/or getDefaultJWSClassDir return null
* (as they could with WebLogic).
* This needs to be reexamined in the future, but this
* should fix any NPE's in the mean time.
*/
if (jwsClassDir != null) {
if (getHomeDir() != null) {
jwsClassDir = getHomeDir() + jwsClassDir;
}
} else {
jwsClassDir = getDefaultJWSClassDir();
}
initQueryStringHandlers();
// Setup the service admin
try {
ServiceAdmin.setEngine(this.getEngine(),
context.getServerInfo());
} catch (AxisFault af) {
exceptionLog.info("Exception setting AxisEngine on
ServiceAdmin " +
af);
}
}
/**
* Process GET requests. This includes handoff of
pseudo-SOAP requests
*
* @param request request in
* @param response request out
* @throws ServletException
* @throws IOException
*/
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws
ServletException, IOException {
if (isDebug) {
log.debug("Enter: doGet()");
}
PrintWriter writer = new FilterPrintWriter(response);
try {
AxisEngine engine = getEngine();
ServletContext servletContext =
getServletConfig().getServletContext();
String pathInfo = request.getPathInfo();
String realpath =
servletContext.getRealPath(request.getServletPath());
if (realpath == null) {
realpath = request.getServletPath();
}
//JWS pages are special; they are the servlet path and
there
//is no pathinfo...we map the pathinfo to the servlet
path to keep
//it happy
boolean isJWSPage =
request.getRequestURI().endsWith(".jws");
if (isJWSPage) {
pathInfo = request.getServletPath();
}
// Try to execute a query string plugin and return upon
success.
if (processQuery(request, response, writer) == true) {
long reqout = System.currentTimeMillis();
return;
}
boolean hasNoPath = (pathInfo == null ||
pathInfo.equals(""));
if (!disableServicesList) {
if(hasNoPath) {
// If the user requested the servlet (i.e.
/axis/servlet/AxisServlet)
// with no service name, present the user with a list of
deployed
// services to be helpful
// Don't do this if has been turned off
reportAvailableServices(response, writer, request);
} else if (realpath != null) {
// We have a pathname, so now we perform WSDL or list
operations
// get message context w/ various properties set
MessageContext msgContext = createMessageContext(engine,
request, response);
// NOTE: HttpUtils.getRequestURL has been deprecated.
// This line SHOULD be:
// String url = req.getRequestURL().toString()
// HOWEVER!!!! DON'T REPLACE IT! There's a bug in
// req.getRequestURL that is not in
HttpUtils.getRequestURL
// req.getRequestURL returns "localhost" in the remote
// scenario rather than the actual host name.
//
// But more importantly, getRequestURL() is a servlet
2.3
// API and to support servlet 2.2 (aka WebSphere 4)
// we need to leave this in for a while longer. tomj
10/14/2004
//
String url =
HttpUtils.getRequestURL(request).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// See if we can locate the desired service. If we
// can't, return a 404 Not Found. Otherwise, just
// print the placeholder message.
String serviceName;
if (pathInfo.startsWith("/")) {
serviceName = pathInfo.substring(1);
} else {
serviceName = pathInfo;
}
SOAPService s = engine.getService(serviceName);
if (s == null) {
//no service: report it
if (isJWSPage) {
reportCantGetJWSService(request, response, writer);
} else {
reportCantGetAxisService(request, response, writer);
}
} else {
//print a snippet of service info.
reportServiceInfo(response, writer, s, serviceName);
}
}
} else {
// We didn't have a real path in the request, so just
// print a message informing the user that they reached
// the servlet.
response.setContentType("text/html; charset=utf-8");
writer.println("<html><h1>Axis HTTP Servlet</h1>");
writer.println(Messages.getMessage("reachedServlet00"));
writer.println("<p>" +
Messages.getMessage("transportName00",
"<b>" + transportName + "</b>"));
writer.println("</html>");
}
} catch (AxisFault fault) {
reportTroubleInGet(fault, response, writer);
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
} finally {
writer.close();
if (isDebug) {
log.debug("Exit: doGet()");
}
}
}
/**
* when we get an exception or an axis fault in a GET, we
handle
* it almost identically: we go 'something went wrong',
set the response
* code to 500 and then dump info. But we dump different
info for an axis fault
* or subclass thereof.
* @param exception what went wrong
* @param response current response
* @param writer open writer to response
*/
private void reportTroubleInGet(Throwable exception,
HttpServletResponse response,
PrintWriter writer) {
response.setContentType("text/html; charset=utf-8");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
writer.println("<h2>" +
Messages.getMessage("error00") +
"</h2>");
writer.println("<p>" +
Messages.getMessage("somethingWrong00") +
"</p>");
if (exception instanceof AxisFault) {
AxisFault fault = (AxisFault) exception;
processAxisFault(fault);
writeFault(writer, fault);
} else {
logException(exception);
writer.println("<pre>Exception - " + exception +
"<br>");
//dev systems only give fault dumps
if (isDevelopment()) {
writer.println(JavaUtils.stackToString(exception));
}
writer.println("</pre>");
}
}
/**
* routine called whenever an axis fault is caught; where
they
* are logged and any other business. The method may
modify the fault
* in the process
* @param fault what went wrong.
*/
protected void processAxisFault(AxisFault fault) {
//log the fault
Element runtimeException = fault.lookupFaultDetail(
Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
if (runtimeException != null) {
exceptionLog.info(Messages.getMessage("axisFault00"),
fault);
//strip runtime details
fault.removeFaultDetail(Constants.
QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
} else if (exceptionLog.isDebugEnabled()) {
exceptionLog.debug(Messages.getMessage("axisFault00"),
fault);
}
//dev systems only give fault dumps
if (!isDevelopment()) {
//strip out the stack trace
fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE);
}
}
/**
* log any exception to our output log, at our chosen
level
* @param e what went wrong
*/
protected void logException(Throwable e) {
exceptionLog.info(Messages.getMessage("exception00"),
e);
}
/**
* this method writes a fault out to an HTML stream. This
includes
* escaping the strings to defend against cross-site
scripting attacks
* @param writer
* @param axisFault
*/
private void writeFault(PrintWriter writer, AxisFault
axisFault) {
String localizedMessage =
XMLUtils.xmlEncodeString(axisFault.
getLocalizedMessage());
writer.println("<pre>Fault - " + localizedMessage +
"<br>");
writer.println(axisFault.dumpToString());
writer.println("</pre>");
}
/**
* print a snippet of service info.
* @param service service
* @param writer output channel
* @param serviceName where to put stuff
*/
protected void reportServiceInfo(HttpServletResponse
response,
PrintWriter writer, SOAPService service,
String serviceName) {
response.setContentType("text/html; charset=utf-8");
writer.println("<h1>"
+ service.getName()
+ "</h1>");
writer.println(
"<p>" +
Messages.getMessage("axisService00") +
"</p>");
writer.println(
"<i>" +
Messages.getMessage("perhaps00") +
"</i>");
}
/**
* report that we have no WSDL
*
* This method was moved to the querystring handler
QSWSDLHandler. The
* method reportNoWSDL in AxisServlet is never called.
Perhaps the method
* is overwritten in subclasses of AxisServlet so the
method wasn't
* removed. See the discussion in
*
*
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=23845
*
* @param res
* @param writer
* @param moreDetailCode optional name of a message to
provide more detail
* @param axisFault optional fault string, for extra info
at debug time only
*/
protected void reportNoWSDL(HttpServletResponse res,
PrintWriter writer,
String moreDetailCode, AxisFault axisFault) {
}
/**
* This method lists the available services; it is called
when there is
* nothing to execute on a GET
* @param response
* @param writer
* @param request
* @throws ConfigurationException
* @throws AxisFault
*/
protected void
reportAvailableServices(HttpServletResponse response,
PrintWriter writer,
HttpServletRequest request) throws
ConfigurationException, AxisFault {
AxisEngine engine = getEngine();
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>And now... Some Services</h2>");
Iterator i;
try {
i = engine.getConfig().getDeployedServices();
} catch (ConfigurationException configException) {
//turn any internal configuration exceptions back into
axis faults
//if that is what they are
if (configException.getContainedException() instanceof
AxisFault) {
throw (AxisFault)
configException.getContainedException();
} else {
throw configException;
}
}
// baseURL may change if <endpointURL> tag is used for
// custom deployment at a different location
String defaultBaseURL = getWebappBase(request) +
servicesPath;
writer.println("<ul>");
while (i.hasNext()) {
ServiceDesc sd = (ServiceDesc) i.next();
StringBuffer sb = new StringBuffer();
sb.append("<li>");
String name = sd.getName();
sb.append(name);
sb.append(" <a href=\"");
String endpointURL = sd.getEndpointURL();
String baseURL = (endpointURL == null) ? defaultBaseURL
:
endpointURL;
sb.append(baseURL);
sb.append(name);
sb.append("?wsdl\"><i>(wsdl)</i></a></li>");
writer.println(sb.toString());
ArrayList operations = sd.getOperations();
if (!operations.isEmpty()) {
writer.println("<ul>");
for (Iterator it = operations.iterator(); it.hasNext();
) {
OperationDesc desc = (OperationDesc) it.next();
writer.println("<li>" + desc.getName());
}
writer.println("</ul>");
}
}
writer.println("</ul>");
}
/**
* generate the error response to indicate that there is
apparently no endpoint there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void
reportCantGetAxisService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// no such service....
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>" +
Messages.getMessage("error00") + "</h2>");
writer.println("<p>" +
Messages.getMessage("noService06") +
"</p>");
}
/**
* probe for a JWS page and report 'no service' if one is
not found there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void
reportCantGetJWSService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// first look to see if there is a service
// requestPath is a work around to support serving .jws
web services
// from services URL - see AXIS-843 for more information
String requestPath = request.getServletPath() +
((request.getPathInfo() != null) ?
request.getPathInfo() : "");
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
log.debug("JWS real path: " + realpath);
boolean foundJWSFile = (new File(realpath).exists()) &&
(realpath.endsWith(Constants.
JWS_DEFAULT_FILE_EXTENSION));
response.setContentType("text/html; charset=utf-8");
if (foundJWSFile) {
response.setStatus(HttpURLConnection.HTTP_OK);
writer.println(Messages.getMessage("foundJWS00") +
"<p>");
String url = request.getRequestURI();
String urltext = Messages.getMessage("foundJWS01");
writer.println("<a href='" + url + "?wsdl'>" + urltext +
"</a>");
} else {
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
writer.println(Messages.getMessage("noService06"));
}
}
/**
* Process a POST to the servlet by handing it off to the
Axis Engine.
* Here is where SOAP messages are received
* @param req posted request
* @param res respose
* @throws ServletException trouble
* @throws IOException different trouble
*/
public void doPost(HttpServletRequest req,
HttpServletResponse res) throws
ServletException, IOException {
long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
String soapAction = null;
MessageContext msgContext = null;
if (isDebug) {
log.debug("Enter: doPost()");
}
t0 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
Message responseMsg = null;
String contentType = null;
try {
AxisEngine engine = getEngine();
if (engine == null) {
// !!! should return a SOAP fault...
ServletException se =
new ServletException(Messages.getMessage("noEngine00"));
log.debug("No Engine!", se);
throw se;
}
res.setBufferSize(1024 * 8); // provide performance
boost.
/** get message context w/ various properties set
*/
msgContext = createMessageContext(engine, req, res);
// ? OK to move this to 'getMessageContext',
// ? where it would also be picked up for 'doGet()' ?
if (securityProvider != null) {
if (isDebug) {
log.debug("securityProvider:" + securityProvider);
}
msgContext.setProperty(MessageContext.SECURITY_PROVIDER,
securityProvider);
}
/* Get request message
*/
Message requestMsg =
new Message(req.getInputStream(),
false,
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
req.getHeader(HTTPConstants.
HEADER_CONTENT_LOCATION));
// Transfer HTTP headers to MIME headers for request
message.
MimeHeaders requestMimeHeaders =
requestMsg.getMimeHeaders();
for (Enumeration e = req.getHeaderNames();
e.hasMoreElements(); ) {
String headerName = (String) e.nextElement();
for (Enumeration f = req.getHeaders(headerName);
f.hasMoreElements(); ) {
String headerValue = (String) f.nextElement();
requestMimeHeaders.addHeader(headerName, headerValue);
}
}
if (isDebug) {
log.debug("Request Message:" + requestMsg);
/* Set the request(incoming) message field in the
context */
/**********************************************************/
}
msgContext.setRequestMessage(requestMsg);
String url = HttpUtils.getRequestURL(req).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// put character encoding of request to message context
// in order to reuse it during the whole process.
String requestEncoding;
try {
requestEncoding = (String)
requestMsg.getProperty(SOAPMessage.
CHARACTER_SET_ENCODING);
if (requestEncoding != null) {
msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
requestEncoding);
}
} catch (SOAPException e1) {
}
try {
/**
* Save the SOAPAction header in the MessageContext bag.
* This will be used to tell the Axis Engine which
service
* is being invoked. This will save us the trouble of
* having to parse the Request message - although we will
* need to double-check later on that the SOAPAction
header
* does in fact match the URI in the body.
*/
// (is this last stmt true??? (I don't think so - Glen))
/********************************************************/
soapAction = getSoapAction(req);
if (soapAction != null) {
msgContext.setUseSOAPAction(true);
msgContext.setSOAPActionURI(soapAction);
}
// Create a Session wrapper for the HTTP session.
// These can/should be pooled at some point.
// (Sam is Watching! :-)
msgContext.setSession(new AxisHttpSession(req));
t1 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
/* Invoke the Axis engine... */
/*****************************/
if (isDebug) {
log.debug("Invoking Axis Engine.");
//here we run the message by the engine
}
engine.invoke(msgContext);
if (isDebug) {
log.debug("Return from Axis Engine.");
}
t2 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
}
responseMsg = msgContext.getResponseMessage();
// We used to throw exceptions on null response
messages.
// They are actually OK in certain situations
(asynchronous
// services), so fall through here and return an
ACCEPTED
// status code below. Might want to install a
configurable
// error check for this later.
} catch (AxisFault fault) {
//log and sanitize
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (Exception e) {
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = convertExceptionToAxisFault(e,
responseMsg);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
} catch (Throwable t) {
logException(t);
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = new Message(new
AxisFault(t.toString(),t));
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (AxisFault fault) {
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
}
t3 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t3 = System.currentTimeMillis();
}
/* Send response back along the wire... */
/***********************************/
if (responseMsg != null) {
// Transfer MIME headers to HTTP headers for response
message.
MimeHeaders responseMimeHeaders =
responseMsg.getMimeHeaders();
for (Iterator i = responseMimeHeaders.getAllHeaders();
i.hasNext(); ) {
MimeHeader responseMimeHeader = (MimeHeader) i.next();
res.addHeader(responseMimeHeader.getName(),
responseMimeHeader.getValue());
}
// synchronize the character encoding of request and
response
String responseEncoding = (String)
msgContext.getProperty(
SOAPMessage.CHARACTER_SET_ENCODING);
if (responseEncoding != null) {
try {
responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
responseEncoding);
} catch (SOAPException e) {
}
}
//determine content type from message response
contentType = responseMsg.getContentType(msgContext.
getSOAPConstants());
sendResponse(contentType, res, responseMsg);
} else {
// No content, so just indicate accepted
res.setStatus(202);
}
if (isDebug) {
log.debug("Response sent.");
log.debug("Exit: doPost()");
}
t4 = System.currentTimeMillis();
System.out.println("Axis stats: " +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" total=" + (t4 - t0));
if (tlog.isDebugEnabled()) {
t4 = System.currentTimeMillis();
tlog.debug("axisServlet.doPost: " + soapAction +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" " + msgContext.getTargetService() + "." +
((msgContext.getOperation() == null) ?
"" : msgContext.getOperation().getName()));
}
}
/**
* Configure the servlet response status code and maybe
other headers
* from the fault info.
* @param response response to configure
* @param fault what went wrong
*/
private void
configureResponseFromAxisFault(HttpServletResponse response,
AxisFault fault) {
// then get the status code
// It's been suggested that a lack of SOAPAction
// should produce some other error code (in the 400s)...
int status = getHttpServletResponseStatus(fault);
if (status == HttpServletResponse.SC_UNAUTHORIZED) {
// unauth access results in authentication request
// TODO: less generic realm choice?
response.setHeader("WWW-Authenticate", "Basic
realm=\"AXIS\"");
}
response.setStatus(status);
}
/**
* turn any Exception into an AxisFault, log it, set the
response
* status code according to what the specifications say
and
* return a response message for posting. This will be
the response
* message passed in if non-null; one generated from the
fault otherwise.
*
* @param exception what went wrong
* @param responseMsg what response we have (if any)
* @return a response message to send to the user
*/
private Message convertExceptionToAxisFault(Exception
exception,
Message responseMsg) {
logException(exception);
if (responseMsg == null) {
AxisFault fault = AxisFault.makeFault(exception);
processAxisFault(fault);
responseMsg = new Message(fault);
}
return responseMsg;
}
/**
* Extract information from AxisFault and map it to a
HTTP Status code.
*
* @param af Axis Fault
* @return HTTP Status code.
*/
protected int getHttpServletResponseStatus(AxisFault af)
{
// TODO: Should really be doing this with explicit
AxisFault
// subclasses... --Glen
return
af.getFaultCode().getLocalPart().startsWith("Server.Unauth")
? HttpServletResponse.SC_UNAUTHORIZED
: HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
// This will raise a 401 for both
// "Unauthenticated" & "Unauthorized"...
}
/**
* write a message to the response, set appropriate
headers for content
* type..etc.
* @param res response
* @param responseMsg message to write
* @throws AxisFault
* @throws IOException if the response stream can not be
written to
*/
private void sendResponse(String contentType,
HttpServletResponse res,
Message responseMsg) throws AxisFault,
IOException {
if (responseMsg == null) {
res.setStatus(HttpServletResponse.SC_NO_CONTENT);
if (isDebug) {
log.debug("NO AXIS MESSAGE TO RETURN!");
//String resp = Messages.getMessage("noData00");
//res.setContentLength((int) resp.getBytes().length);
//res.getWriter().print(resp);
}
} else {
if (isDebug) {
log.debug("Returned Content-Type:" +
contentType);
// log.debug("Returned Content-Length:" +
// responseMsg.getContentLength());
}
try {
res.setContentType(contentType);
/* My understand of Content-Length
* HTTP 1.0
* -Required for requests, but optional for responses.
* HTTP 1.1
* - Either Content-Length or HTTP Chunking is required.
* Most servlet engines will do chunking if
content-length is not specified.
*
*
*/
//if(clientVersion == HTTPConstants.HEADER_PROTOCOL_V10)
//do chunking if necessary.
// res.setContentLength(responseMsg.getContentLength());
responseMsg.writeTo(res.getOutputStream());
} catch (SOAPException e) {
logException(e);
}
}
if (!res.isCommitted()) {
res.flushBuffer(); // Force it right now.
}
}
/**
* Place the Request message in the MessagContext object
- notice
* that we just leave it as a 'ServletRequest' object and
let the
* Message processing routine convert it - we don't do it
since we
* don't know how it's going to be used - perhaps it
might not
* even need to be parsed.
* @return a message context
*/
private MessageContext createMessageContext(AxisEngine
engine,
HttpServletRequest req,
HttpServletResponse res) {
MessageContext msgContext = new MessageContext(engine);
String requestPath = getRequestPath(req);
if (isDebug) {
log.debug("MessageContext:" + msgContext);
log.debug("HEADER_CONTENT_TYPE:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
log.debug("HEADER_CONTENT_LOCATION:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION));
log.debug("Constants.MC_HOME_DIR:" +
String.valueOf(getHomeDir()));
log.debug("Constants.MC_RELATIVE_PATH:" + requestPath);
log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" +
String.valueOf(getWebInfPath()));
log.debug("HTTPConstants.MC_HTTP_SERVLETPATHINFO:" +
req.getPathInfo());
log.debug("HTTPConstants.HEADER_AUTHORIZATION:" +
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
log.debug("Constants.MC_REMOTE_ADDR:" +
req.getRemoteAddr());
log.debug("configPath:" +
String.valueOf(getWebInfPath()));
}
/* Set the Transport */
/*********************/
msgContext.setTransportName(transportName);
/* Save some HTTP specific info in the bag in case
someone needs it */
/********************************************************************/
msgContext.setProperty(Constants.MC_JWS_CLASSDIR,
jwsClassDir);
msgContext.setProperty(Constants.MC_HOME_DIR,
getHomeDir());
msgContext.setProperty(Constants.MC_RELATIVE_PATH,
requestPath);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLET,
this);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, req);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, res);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETLOCATION,
getWebInfPath());
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO,
req.getPathInfo());
msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION,
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
msgContext.setProperty(Constants.MC_REMOTE_ADDR,
req.getRemoteAddr());
// Set up a javax.xml.rpc.server.ServletEndpointContext
ServletEndpointContextImpl sec = new
ServletEndpointContextImpl();
msgContext.setProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT, sec);
/* Save the real path */
/**********************/
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
if (realpath != null) {
msgContext.setProperty(Constants.MC_REALPATH, realpath);
}
msgContext.setProperty(Constants.MC_CONFIGPATH,
getWebInfPath());
return msgContext;
}
/**
* Extract the SOAPAction header.
* if SOAPAction is null then we'll we be forced to scan
the body for it.
* if SOAPAction is "" then use the URL
* @param req incoming request
* @return the action
* @throws AxisFault
*/
private String getSoapAction(HttpServletRequest req)
throws AxisFault {
String soapAction =
req.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
if (soapAction == null) {
String contentType =
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
if(contentType != null) {
int index = contentType.indexOf("action");
if(index != -1){
soapAction = contentType.substring(index + 7);
}
}
}
if (isDebug) {
log.debug("HEADER_SOAP_ACTION:" + soapAction);
/**
* Technically, if we don't find this header, we should
probably fault.
* It's required in the SOAP HTTP binding.
*/
}
if (soapAction == null) {
AxisFault af = new AxisFault("Client.NoSOAPAction",
Messages.getMessage("noHeader00",
"SOAPAction"),
null, null);
exceptionLog.error(Messages.getMessage("genFault00"),
af);
throw af;
}
// the SOAP 1.1 spec & WS-I 1.0 says:
// soapaction = "SOAPAction" ":" [ <"> URI-reference <">
]
// some implementations leave off the quotes
// we strip them if they are present
if (soapAction.startsWith("\"") &&
soapAction.endsWith("\"")
&& soapAction.length() >= 2) {
int end = soapAction.length() - 1;
soapAction = soapAction.substring(1, end);
}
if (soapAction.length() == 0) {
soapAction = req.getContextPath(); // Is this right?
}
return soapAction;
}
/**
* Provided to allow overload of default JWSClassDir
* by derived class.
* @return directory for JWS files
*/
protected String getDefaultJWSClassDir() {
return (getWebInfPath() == null)
? null // ??? what is a good FINAL default for WebLogic?
: getWebInfPath() + File.separator + "jwsClasses";
}
/**
* Initialize a Handler for the transport defined in the
Axis server config.
* This includes optionally filling in query string
handlers.
*/
public void initQueryStringHandlers() {
try {
this.transport =
getEngine().getTransport(this.transportName);
if (this.transport == null) {
// No transport by this name is defined. Therefore, fill
in default
// query string handlers.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
else {
// See if we should use the default query string
handlers.
// By default, set this to true (for backwards
compatibility).
boolean defaultQueryStrings = true;
String useDefaults = (String)this.transport.getOption(
"useDefaultQueryStrings");
if ((useDefaults != null) &&
useDefaults.toLowerCase().equals("false")) {
defaultQueryStrings = false;
}
if (defaultQueryStrings == true) {
// We should use defaults, so fill them in.
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
}
}
}
catch (AxisFault e) {
// Some sort of problem occurred, let's just make a
default transport.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
}
/**
* Attempts to invoke a plugin for the query string
supplied in the URL.
*
* @param request the servlet's HttpServletRequest
object.
* @param response the servlet's HttpServletResponse
object.
* @param writer the servlet's PrintWriter object.
*/
private boolean processQuery(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) throws AxisFault {
// Attempt to instantiate a plug-in handler class for
the query string
// handler classes defined in the HTTP transport.
String path = request.getServletPath();
String queryString = request.getQueryString();
String serviceName;
AxisEngine engine = getEngine();
Iterator i =
this.transport.getOptions().keySet().iterator();
if (queryString == null) {
return false;
}
String servletURI = request.getContextPath() + path;
String reqURI = request.getRequestURI();
// chop off '/'.
if (servletURI.length() + 1 < reqURI.length()) {
serviceName = reqURI.substring(servletURI.length() + 1);
} else {
serviceName = "";
} while (i.hasNext() == true) {
String queryHandler = (String) i.next();
if (queryHandler.startsWith("qs.") == true) {
// Only attempt to match the query string with transport
// parameters prefixed with "qs:".
String handlerName = queryHandler.substring
(queryHandler.indexOf(".") + 1).
toLowerCase();
// Determine the name of the plugin to invoke by using
all text
// in the query string up to the first occurence of &,
=, or the
// whole string if neither is present.
int length = 0;
boolean firstParamFound = false;
while (firstParamFound == false && length <
queryString.length()) {
char ch = queryString.charAt(length++);
if (ch == '&' || ch == '=') {
firstParamFound = true;
--length;
}
}
if (length < queryString.length()) {
queryString = queryString.substring(0, length);
}
if (queryString.toLowerCase().equals(handlerName) ==
true) {
// Query string matches a defined query string handler
name.
// If the defined class name for this query string
handler is blank,
// just return (the handler is "turned off" in effect).
if (this.transport.getOption(queryHandler).equals("")) {
return false;
}
try {
// Attempt to dynamically load the query string handler
// and its "invoke" method.
MessageContext msgContext = createMessageContext(engine,
request, response);
Class plugin = Class.forName((String)this.transport.
getOption(queryHandler));
Method pluginMethod = plugin.getDeclaredMethod("invoke",
new Class[] {msgContext.getClass()});
String url =
HttpUtils.getRequestURL(request).toString();
// Place various useful servlet-related objects in
// the MessageContext object being delivered to the
// plugin.
msgContext.setProperty(MessageContext.TRANS_URL, url);
msgContext.setProperty(HTTPConstants.
PLUGIN_SERVICE_NAME, serviceName);
msgContext.setProperty(HTTPConstants.PLUGIN_NAME,
handlerName);
msgContext.setProperty(HTTPConstants.
PLUGIN_IS_DEVELOPMENT,
new Boolean(isDevelopment()));
msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,
new Boolean(enableList));
msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE,
engine);
msgContext.setProperty(HTTPConstants.PLUGIN_WRITER,
writer);
msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log);
msgContext.setProperty(HTTPConstants.
PLUGIN_EXCEPTION_LOG,
exceptionLog);
// Invoke the plugin.
pluginMethod.invoke(plugin.newInstance(),
new Object[] {msgContext});
writer.close();
return true;
} catch (InvocationTargetException ie) {
reportTroubleInGet(ie.getTargetException(), response,
writer);
// return true to prevent any further processing
return true;
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
// return true to prevent any further processing
return true;
}
}
}
}
return false;
}
/**
* getRequestPath a returns request path for web service
padded with
* request.getPathInfo for web services served from
/services directory.
* This is a required to support serving .jws web
services from /services
* URL. See AXIS-843 for more information.
*
* @param request HttpServletRequest
* @return String
*/
private static String getRequestPath(HttpServletRequest
request) {
return request.getServletPath() +
((request.getPathInfo() != null) ?
request.getPathInfo() : "");
}
}
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 12:36 PM
To: Firas Khasawneh (fkhasawn); axis-user@ws.apache.org
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
The order of processing in the case of HTTP is;
AxisServlet->AxisEngine->HandlerChain->MessageProcessor->Service and
come back.
If you placed the server in a different machine, then
your RTT should definitely include the network time so it should be
larger than the processing time.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
<ma...@cisco.com>
To: Jaliya Ekanayake <ma...@apache.org>
; axis-dev@ws.apache.org ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 11:27 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
Do you know if response coming back from
transport handler after the request is processed in the Axis engine also
hits AxisServlet and uses doGet?
Thanks,
Firas
________________________________
From: Jaliya Ekanayake
[mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org;
axis-user@ws.apache.org; Firas Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client
in a same machine? If you put the handler in transport section, then
what you will measure is the time it takes inside the engine from
transport handlers ->service -> transport handlers. One other
possibility is to keep track of the time in AxisServlet. Measure the
time in AxisServlet before it calls AxisEngine's invoke(..) method and
after it is returned and you will get the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
<ma...@cisco.com>
To: axis-user@ws.apache.org ;
axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any
suggestions on how to measure the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the
overhead Axis 1.4 adds to response time? I created a handler in the
requestFlow to store System.currentTimeMillis in messageContext and
another handler in the responseFlow that retrieved this value and
subtracts it from System.currentTimeMillis(), when I use these classes
in the global conf or transport (server side) I am getting values that
correspond to the response time the client is getting so it looks like
it is not calculating the Axix overhead on the server side, when I put
these handlers in the requestFlow and responseFlow in the service
section in server-conf.wsdd it gives differnt time which seem right but
I am nti sure if this is the Axix engine overhead? Any suggestions?
other ways to do this? please reply back to me or CC me if you are
sending to the list since I am not yet a member in this list.
Regards,
Firas Khasawneh
Re: measuring Axix 1.4 overhead
Posted by Jaliya Ekanayake <jn...@gmail.com>.
Hi Firas,
Did you try Axis2 http://ws.apache.org/axis2/ ?
In axis2 processing starts without fully building the soap envelope.
And the performance figures for Axis2 is http://www.wso2.org/library/588
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake
Sent: Tuesday, July 24, 2007 8:48 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I tested with small size messages and 1 mb messages and there is big difference, looks like Axis takes long time to process large messages, but t4-t0 should give the processing time and not the transport time. Also invoke time t3-t0 should give only Axis engine overhead.
Thanks,
Firas
------------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 4:34 PM
To: Firas Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Yes, t4-t0 should give you the results.
However the problem is that you use large message size.
My guess is that the processing happens before the total retrieval of the message and hence it include the time it takes to transfer the message as well.
Did you try with a small message sizes?
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 3:49 PM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I am attaching the AxisServlet.java after adding benchmark times, if you look at line 791 in the doPost method, the invoke shoudl calculate the invokation time for the Axis engine without the network time but for some reason it looks like it is including this time in the invokation time which does not make any sense. I am testing with 1 MB size files so I am not sure. below is AxisServlet.java, sorry for cuttin and pasting it here but I was not sure if this email list allows attachments:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.transport.http;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.apache.axis.AxisEngine;
import org.apache.axis.AxisFault;
import org.apache.axis.ConfigurationException;
import org.apache.axis.Constants;
import org.apache.axis.Handler;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.SimpleTargetedChain;
import org.apache.axis.client.Service;
import org.apache.axis.management.ServiceAdmin;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ServiceDesc;
import org.apache.axis.handlers.soap.SOAPService;
import org.apache.axis.security.servlet.ServletSecurityProvider;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import org.apache.commons.logging.Log;
import org.w3c.dom.Element;
/**
*
* @author Doug Davis (dug@us.ibm.com)
* @author Steve Loughran
* xdoclet tags are not active yet; keep web.xml in sync.
* To change the location of the services, change url-pattern in web.xml and
* set parameter axis.servicesPath in server-config.wsdd. For more information see
* <a href="http://ws.apache.org/axis/java/reference.html">Axis Reference Guide</a>.
*
* @web.servlet name="AxisServlet" display-name="Apache-Axis Servlet"
* @web.servlet-mapping url-pattern="/servlet/AxisServlet"
* @web.servlet-mapping url-pattern="*.jws"
* @web.servlet-mapping url-pattern="/services/*"
*/
public class AxisServlet extends AxisServletBase {
protected static Log log =
LogFactory.getLog(AxisServlet.class.getName());
/**
* this log is for timing
*/
private static Log tlog =
LogFactory.getLog(Constants.TIME_LOG_CATEGORY);
/**
* a separate log for exceptions lets users route them
* differently from general low level debug info
*/
private static Log exceptionLog =
LogFactory.getLog(Constants.EXCEPTION_LOG_CATEGORY);
public static final String INIT_PROPERTY_TRANSPORT_NAME =
"transport.name";
public static final String INIT_PROPERTY_USE_SECURITY =
"use-servlet-security";
public static final String INIT_PROPERTY_ENABLE_LIST =
"axis.enableListQuery";
public static final String INIT_PROPERTY_JWS_CLASS_DIR =
"axis.jws.servletClassDir";
// This will turn off the list of available services
public static final String INIT_PROPERTY_DISABLE_SERVICES_LIST =
"axis.disableServiceList";
// Location of the services as defined by the servlet-mapping in web.xml
public static final String INIT_PROPERTY_SERVICES_PATH =
"axis.servicesPath";
// These have default values.
private String transportName;
private Handler transport;
private ServletSecurityProvider securityProvider = null;
private String servicesPath;
/**
* cache of logging debug option; only evaluated at init time.
* So no dynamic switching of logging options with this servlet.
*/
private static boolean isDebug = false;
/**
* Should we enable the "?list" functionality on GETs? (off by
* default because deployment information is a potential security
* hole)
*/
private boolean enableList = false;
/**
* Should we turn off the list of services when we receive a GET
* at the servlet root?
*/
private boolean disableServicesList = false;
/**
* Cached path to JWS output directory
*/
private String jwsClassDir = null;
protected String getJWSClassDir() {return jwsClassDir;
}
/**
* create a new servlet instance
*/
public AxisServlet() {
}
/**
* Initialization method.
*/
public void init() throws javax.servlet.ServletException {
super.init();
ServletContext context = getServletConfig().getServletContext();
isDebug = log.isDebugEnabled();
if (isDebug) {
log.debug("In servlet init");
}
transportName = getOption(context,
INIT_PROPERTY_TRANSPORT_NAME,
HTTPTransport.DEFAULT_TRANSPORT_NAME);
if (JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_USE_SECURITY, null))) {
securityProvider = new ServletSecurityProvider();
}
enableList =
JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_ENABLE_LIST, null));
jwsClassDir = getOption(context, INIT_PROPERTY_JWS_CLASS_DIR, null);
// Should we list services?
disableServicesList = JavaUtils.isTrue(getOption(context,
INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));
servicesPath = getOption(context, INIT_PROPERTY_SERVICES_PATH,
"/services/");
/**
* There are DEFINATE problems here if
* getHomeDir and/or getDefaultJWSClassDir return null
* (as they could with WebLogic).
* This needs to be reexamined in the future, but this
* should fix any NPE's in the mean time.
*/
if (jwsClassDir != null) {
if (getHomeDir() != null) {
jwsClassDir = getHomeDir() + jwsClassDir;
}
} else {
jwsClassDir = getDefaultJWSClassDir();
}
initQueryStringHandlers();
// Setup the service admin
try {
ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo());
} catch (AxisFault af) {
exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " +
af);
}
}
/**
* Process GET requests. This includes handoff of pseudo-SOAP requests
*
* @param request request in
* @param response request out
* @throws ServletException
* @throws IOException
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
if (isDebug) {
log.debug("Enter: doGet()");
}
PrintWriter writer = new FilterPrintWriter(response);
try {
AxisEngine engine = getEngine();
ServletContext servletContext =
getServletConfig().getServletContext();
String pathInfo = request.getPathInfo();
String realpath = servletContext.getRealPath(request.getServletPath());
if (realpath == null) {
realpath = request.getServletPath();
}
//JWS pages are special; they are the servlet path and there
//is no pathinfo...we map the pathinfo to the servlet path to keep
//it happy
boolean isJWSPage = request.getRequestURI().endsWith(".jws");
if (isJWSPage) {
pathInfo = request.getServletPath();
}
// Try to execute a query string plugin and return upon success.
if (processQuery(request, response, writer) == true) {
long reqout = System.currentTimeMillis();
return;
}
boolean hasNoPath = (pathInfo == null || pathInfo.equals(""));
if (!disableServicesList) {
if(hasNoPath) {
// If the user requested the servlet (i.e. /axis/servlet/AxisServlet)
// with no service name, present the user with a list of deployed
// services to be helpful
// Don't do this if has been turned off
reportAvailableServices(response, writer, request);
} else if (realpath != null) {
// We have a pathname, so now we perform WSDL or list operations
// get message context w/ various properties set
MessageContext msgContext = createMessageContext(engine,
request, response);
// NOTE: HttpUtils.getRequestURL has been deprecated.
// This line SHOULD be:
// String url = req.getRequestURL().toString()
// HOWEVER!!!! DON'T REPLACE IT! There's a bug in
// req.getRequestURL that is not in HttpUtils.getRequestURL
// req.getRequestURL returns "localhost" in the remote
// scenario rather than the actual host name.
//
// But more importantly, getRequestURL() is a servlet 2.3
// API and to support servlet 2.2 (aka WebSphere 4)
// we need to leave this in for a while longer. tomj 10/14/2004
//
String url = HttpUtils.getRequestURL(request).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// See if we can locate the desired service. If we
// can't, return a 404 Not Found. Otherwise, just
// print the placeholder message.
String serviceName;
if (pathInfo.startsWith("/")) {
serviceName = pathInfo.substring(1);
} else {
serviceName = pathInfo;
}
SOAPService s = engine.getService(serviceName);
if (s == null) {
//no service: report it
if (isJWSPage) {
reportCantGetJWSService(request, response, writer);
} else {
reportCantGetAxisService(request, response, writer);
}
} else {
//print a snippet of service info.
reportServiceInfo(response, writer, s, serviceName);
}
}
} else {
// We didn't have a real path in the request, so just
// print a message informing the user that they reached
// the servlet.
response.setContentType("text/html; charset=utf-8");
writer.println("<html><h1>Axis HTTP Servlet</h1>");
writer.println(Messages.getMessage("reachedServlet00"));
writer.println("<p>" +
Messages.getMessage("transportName00",
"<b>" + transportName + "</b>"));
writer.println("</html>");
}
} catch (AxisFault fault) {
reportTroubleInGet(fault, response, writer);
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
} finally {
writer.close();
if (isDebug) {
log.debug("Exit: doGet()");
}
}
}
/**
* when we get an exception or an axis fault in a GET, we handle
* it almost identically: we go 'something went wrong', set the response
* code to 500 and then dump info. But we dump different info for an axis fault
* or subclass thereof.
* @param exception what went wrong
* @param response current response
* @param writer open writer to response
*/
private void reportTroubleInGet(Throwable exception,
HttpServletResponse response,
PrintWriter writer) {
response.setContentType("text/html; charset=utf-8");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
writer.println("<h2>" +
Messages.getMessage("error00") +
"</h2>");
writer.println("<p>" +
Messages.getMessage("somethingWrong00") +
"</p>");
if (exception instanceof AxisFault) {
AxisFault fault = (AxisFault) exception;
processAxisFault(fault);
writeFault(writer, fault);
} else {
logException(exception);
writer.println("<pre>Exception - " + exception + "<br>");
//dev systems only give fault dumps
if (isDevelopment()) {
writer.println(JavaUtils.stackToString(exception));
}
writer.println("</pre>");
}
}
/**
* routine called whenever an axis fault is caught; where they
* are logged and any other business. The method may modify the fault
* in the process
* @param fault what went wrong.
*/
protected void processAxisFault(AxisFault fault) {
//log the fault
Element runtimeException = fault.lookupFaultDetail(
Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
if (runtimeException != null) {
exceptionLog.info(Messages.getMessage("axisFault00"), fault);
//strip runtime details
fault.removeFaultDetail(Constants.
QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
} else if (exceptionLog.isDebugEnabled()) {
exceptionLog.debug(Messages.getMessage("axisFault00"), fault);
}
//dev systems only give fault dumps
if (!isDevelopment()) {
//strip out the stack trace
fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE);
}
}
/**
* log any exception to our output log, at our chosen level
* @param e what went wrong
*/
protected void logException(Throwable e) {
exceptionLog.info(Messages.getMessage("exception00"), e);
}
/**
* this method writes a fault out to an HTML stream. This includes
* escaping the strings to defend against cross-site scripting attacks
* @param writer
* @param axisFault
*/
private void writeFault(PrintWriter writer, AxisFault axisFault) {
String localizedMessage = XMLUtils.xmlEncodeString(axisFault.
getLocalizedMessage());
writer.println("<pre>Fault - " + localizedMessage + "<br>");
writer.println(axisFault.dumpToString());
writer.println("</pre>");
}
/**
* print a snippet of service info.
* @param service service
* @param writer output channel
* @param serviceName where to put stuff
*/
protected void reportServiceInfo(HttpServletResponse response,
PrintWriter writer, SOAPService service,
String serviceName) {
response.setContentType("text/html; charset=utf-8");
writer.println("<h1>"
+ service.getName()
+ "</h1>");
writer.println(
"<p>" +
Messages.getMessage("axisService00") +
"</p>");
writer.println(
"<i>" +
Messages.getMessage("perhaps00") +
"</i>");
}
/**
* report that we have no WSDL
*
* This method was moved to the querystring handler QSWSDLHandler. The
* method reportNoWSDL in AxisServlet is never called. Perhaps the method
* is overwritten in subclasses of AxisServlet so the method wasn't
* removed. See the discussion in
*
* http://nagoya.apache.org/bugzilla/show_bug.cgi?id=23845
*
* @param res
* @param writer
* @param moreDetailCode optional name of a message to provide more detail
* @param axisFault optional fault string, for extra info at debug time only
*/
protected void reportNoWSDL(HttpServletResponse res, PrintWriter writer,
String moreDetailCode, AxisFault axisFault) {
}
/**
* This method lists the available services; it is called when there is
* nothing to execute on a GET
* @param response
* @param writer
* @param request
* @throws ConfigurationException
* @throws AxisFault
*/
protected void reportAvailableServices(HttpServletResponse response,
PrintWriter writer,
HttpServletRequest request) throws
ConfigurationException, AxisFault {
AxisEngine engine = getEngine();
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>And now... Some Services</h2>");
Iterator i;
try {
i = engine.getConfig().getDeployedServices();
} catch (ConfigurationException configException) {
//turn any internal configuration exceptions back into axis faults
//if that is what they are
if (configException.getContainedException() instanceof AxisFault) {
throw (AxisFault) configException.getContainedException();
} else {
throw configException;
}
}
// baseURL may change if <endpointURL> tag is used for
// custom deployment at a different location
String defaultBaseURL = getWebappBase(request) + servicesPath;
writer.println("<ul>");
while (i.hasNext()) {
ServiceDesc sd = (ServiceDesc) i.next();
StringBuffer sb = new StringBuffer();
sb.append("<li>");
String name = sd.getName();
sb.append(name);
sb.append(" <a href=\"");
String endpointURL = sd.getEndpointURL();
String baseURL = (endpointURL == null) ? defaultBaseURL :
endpointURL;
sb.append(baseURL);
sb.append(name);
sb.append("?wsdl\"><i>(wsdl)</i></a></li>");
writer.println(sb.toString());
ArrayList operations = sd.getOperations();
if (!operations.isEmpty()) {
writer.println("<ul>");
for (Iterator it = operations.iterator(); it.hasNext(); ) {
OperationDesc desc = (OperationDesc) it.next();
writer.println("<li>" + desc.getName());
}
writer.println("</ul>");
}
}
writer.println("</ul>");
}
/**
* generate the error response to indicate that there is apparently no endpoint there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void reportCantGetAxisService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// no such service....
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>" +
Messages.getMessage("error00") + "</h2>");
writer.println("<p>" +
Messages.getMessage("noService06") +
"</p>");
}
/**
* probe for a JWS page and report 'no service' if one is not found there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void reportCantGetJWSService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// first look to see if there is a service
// requestPath is a work around to support serving .jws web services
// from services URL - see AXIS-843 for more information
String requestPath = request.getServletPath() + ((request.getPathInfo() != null) ?
request.getPathInfo() : "");
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
log.debug("JWS real path: " + realpath);
boolean foundJWSFile = (new File(realpath).exists()) &&
(realpath.endsWith(Constants.
JWS_DEFAULT_FILE_EXTENSION));
response.setContentType("text/html; charset=utf-8");
if (foundJWSFile) {
response.setStatus(HttpURLConnection.HTTP_OK);
writer.println(Messages.getMessage("foundJWS00") + "<p>");
String url = request.getRequestURI();
String urltext = Messages.getMessage("foundJWS01");
writer.println("<a href='" + url + "?wsdl'>" + urltext + "</a>");
} else {
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
writer.println(Messages.getMessage("noService06"));
}
}
/**
* Process a POST to the servlet by handing it off to the Axis Engine.
* Here is where SOAP messages are received
* @param req posted request
* @param res respose
* @throws ServletException trouble
* @throws IOException different trouble
*/
public void doPost(HttpServletRequest req, HttpServletResponse res) throws
ServletException, IOException {
long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
String soapAction = null;
MessageContext msgContext = null;
if (isDebug) {
log.debug("Enter: doPost()");
}
t0 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
Message responseMsg = null;
String contentType = null;
try {
AxisEngine engine = getEngine();
if (engine == null) {
// !!! should return a SOAP fault...
ServletException se =
new ServletException(Messages.getMessage("noEngine00"));
log.debug("No Engine!", se);
throw se;
}
res.setBufferSize(1024 * 8); // provide performance boost.
/** get message context w/ various properties set
*/
msgContext = createMessageContext(engine, req, res);
// ? OK to move this to 'getMessageContext',
// ? where it would also be picked up for 'doGet()' ?
if (securityProvider != null) {
if (isDebug) {
log.debug("securityProvider:" + securityProvider);
}
msgContext.setProperty(MessageContext.SECURITY_PROVIDER,
securityProvider);
}
/* Get request message
*/
Message requestMsg =
new Message(req.getInputStream(),
false,
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
req.getHeader(HTTPConstants.
HEADER_CONTENT_LOCATION));
// Transfer HTTP headers to MIME headers for request message.
MimeHeaders requestMimeHeaders = requestMsg.getMimeHeaders();
for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) {
String headerName = (String) e.nextElement();
for (Enumeration f = req.getHeaders(headerName);
f.hasMoreElements(); ) {
String headerValue = (String) f.nextElement();
requestMimeHeaders.addHeader(headerName, headerValue);
}
}
if (isDebug) {
log.debug("Request Message:" + requestMsg);
/* Set the request(incoming) message field in the context */
/**********************************************************/
}
msgContext.setRequestMessage(requestMsg);
String url = HttpUtils.getRequestURL(req).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// put character encoding of request to message context
// in order to reuse it during the whole process.
String requestEncoding;
try {
requestEncoding = (String) requestMsg.getProperty(SOAPMessage.
CHARACTER_SET_ENCODING);
if (requestEncoding != null) {
msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
requestEncoding);
}
} catch (SOAPException e1) {
}
try {
/**
* Save the SOAPAction header in the MessageContext bag.
* This will be used to tell the Axis Engine which service
* is being invoked. This will save us the trouble of
* having to parse the Request message - although we will
* need to double-check later on that the SOAPAction header
* does in fact match the URI in the body.
*/
// (is this last stmt true??? (I don't think so - Glen))
/********************************************************/
soapAction = getSoapAction(req);
if (soapAction != null) {
msgContext.setUseSOAPAction(true);
msgContext.setSOAPActionURI(soapAction);
}
// Create a Session wrapper for the HTTP session.
// These can/should be pooled at some point.
// (Sam is Watching! :-)
msgContext.setSession(new AxisHttpSession(req));
t1 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
/* Invoke the Axis engine... */
/*****************************/
if (isDebug) {
log.debug("Invoking Axis Engine.");
//here we run the message by the engine
}
engine.invoke(msgContext);
if (isDebug) {
log.debug("Return from Axis Engine.");
}
t2 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
}
responseMsg = msgContext.getResponseMessage();
// We used to throw exceptions on null response messages.
// They are actually OK in certain situations (asynchronous
// services), so fall through here and return an ACCEPTED
// status code below. Might want to install a configurable
// error check for this later.
} catch (AxisFault fault) {
//log and sanitize
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (Exception e) {
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = convertExceptionToAxisFault(e, responseMsg);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
} catch (Throwable t) {
logException(t);
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = new Message(new AxisFault(t.toString(),t));
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (AxisFault fault) {
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
}
t3 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t3 = System.currentTimeMillis();
}
/* Send response back along the wire... */
/***********************************/
if (responseMsg != null) {
// Transfer MIME headers to HTTP headers for response message.
MimeHeaders responseMimeHeaders = responseMsg.getMimeHeaders();
for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) {
MimeHeader responseMimeHeader = (MimeHeader) i.next();
res.addHeader(responseMimeHeader.getName(),
responseMimeHeader.getValue());
}
// synchronize the character encoding of request and response
String responseEncoding = (String) msgContext.getProperty(
SOAPMessage.CHARACTER_SET_ENCODING);
if (responseEncoding != null) {
try {
responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
responseEncoding);
} catch (SOAPException e) {
}
}
//determine content type from message response
contentType = responseMsg.getContentType(msgContext.
getSOAPConstants());
sendResponse(contentType, res, responseMsg);
} else {
// No content, so just indicate accepted
res.setStatus(202);
}
if (isDebug) {
log.debug("Response sent.");
log.debug("Exit: doPost()");
}
t4 = System.currentTimeMillis();
System.out.println("Axis stats: " +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" total=" + (t4 - t0));
if (tlog.isDebugEnabled()) {
t4 = System.currentTimeMillis();
tlog.debug("axisServlet.doPost: " + soapAction +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" " + msgContext.getTargetService() + "." +
((msgContext.getOperation() == null) ?
"" : msgContext.getOperation().getName()));
}
}
/**
* Configure the servlet response status code and maybe other headers
* from the fault info.
* @param response response to configure
* @param fault what went wrong
*/
private void configureResponseFromAxisFault(HttpServletResponse response,
AxisFault fault) {
// then get the status code
// It's been suggested that a lack of SOAPAction
// should produce some other error code (in the 400s)...
int status = getHttpServletResponseStatus(fault);
if (status == HttpServletResponse.SC_UNAUTHORIZED) {
// unauth access results in authentication request
// TODO: less generic realm choice?
response.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\"");
}
response.setStatus(status);
}
/**
* turn any Exception into an AxisFault, log it, set the response
* status code according to what the specifications say and
* return a response message for posting. This will be the response
* message passed in if non-null; one generated from the fault otherwise.
*
* @param exception what went wrong
* @param responseMsg what response we have (if any)
* @return a response message to send to the user
*/
private Message convertExceptionToAxisFault(Exception exception,
Message responseMsg) {
logException(exception);
if (responseMsg == null) {
AxisFault fault = AxisFault.makeFault(exception);
processAxisFault(fault);
responseMsg = new Message(fault);
}
return responseMsg;
}
/**
* Extract information from AxisFault and map it to a HTTP Status code.
*
* @param af Axis Fault
* @return HTTP Status code.
*/
protected int getHttpServletResponseStatus(AxisFault af) {
// TODO: Should really be doing this with explicit AxisFault
// subclasses... --Glen
return af.getFaultCode().getLocalPart().startsWith("Server.Unauth")
? HttpServletResponse.SC_UNAUTHORIZED
: HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
// This will raise a 401 for both
// "Unauthenticated" & "Unauthorized"...
}
/**
* write a message to the response, set appropriate headers for content
* type..etc.
* @param res response
* @param responseMsg message to write
* @throws AxisFault
* @throws IOException if the response stream can not be written to
*/
private void sendResponse(String contentType,
HttpServletResponse res,
Message responseMsg) throws AxisFault,
IOException {
if (responseMsg == null) {
res.setStatus(HttpServletResponse.SC_NO_CONTENT);
if (isDebug) {
log.debug("NO AXIS MESSAGE TO RETURN!");
//String resp = Messages.getMessage("noData00");
//res.setContentLength((int) resp.getBytes().length);
//res.getWriter().print(resp);
}
} else {
if (isDebug) {
log.debug("Returned Content-Type:" +
contentType);
// log.debug("Returned Content-Length:" +
// responseMsg.getContentLength());
}
try {
res.setContentType(contentType);
/* My understand of Content-Length
* HTTP 1.0
* -Required for requests, but optional for responses.
* HTTP 1.1
* - Either Content-Length or HTTP Chunking is required.
* Most servlet engines will do chunking if content-length is not specified.
*
*
*/
//if(clientVersion == HTTPConstants.HEADER_PROTOCOL_V10) //do chunking if necessary.
// res.setContentLength(responseMsg.getContentLength());
responseMsg.writeTo(res.getOutputStream());
} catch (SOAPException e) {
logException(e);
}
}
if (!res.isCommitted()) {
res.flushBuffer(); // Force it right now.
}
}
/**
* Place the Request message in the MessagContext object - notice
* that we just leave it as a 'ServletRequest' object and let the
* Message processing routine convert it - we don't do it since we
* don't know how it's going to be used - perhaps it might not
* even need to be parsed.
* @return a message context
*/
private MessageContext createMessageContext(AxisEngine engine,
HttpServletRequest req,
HttpServletResponse res) {
MessageContext msgContext = new MessageContext(engine);
String requestPath = getRequestPath(req);
if (isDebug) {
log.debug("MessageContext:" + msgContext);
log.debug("HEADER_CONTENT_TYPE:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
log.debug("HEADER_CONTENT_LOCATION:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION));
log.debug("Constants.MC_HOME_DIR:" + String.valueOf(getHomeDir()));
log.debug("Constants.MC_RELATIVE_PATH:" + requestPath);
log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" +
String.valueOf(getWebInfPath()));
log.debug("HTTPConstants.MC_HTTP_SERVLETPATHINFO:" +
req.getPathInfo());
log.debug("HTTPConstants.HEADER_AUTHORIZATION:" +
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
log.debug("Constants.MC_REMOTE_ADDR:" + req.getRemoteAddr());
log.debug("configPath:" + String.valueOf(getWebInfPath()));
}
/* Set the Transport */
/*********************/
msgContext.setTransportName(transportName);
/* Save some HTTP specific info in the bag in case someone needs it */
/********************************************************************/
msgContext.setProperty(Constants.MC_JWS_CLASSDIR, jwsClassDir);
msgContext.setProperty(Constants.MC_HOME_DIR, getHomeDir());
msgContext.setProperty(Constants.MC_RELATIVE_PATH, requestPath);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLET, this);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, req);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, res);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETLOCATION,
getWebInfPath());
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO,
req.getPathInfo());
msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION,
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
msgContext.setProperty(Constants.MC_REMOTE_ADDR, req.getRemoteAddr());
// Set up a javax.xml.rpc.server.ServletEndpointContext
ServletEndpointContextImpl sec = new ServletEndpointContextImpl();
msgContext.setProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT, sec);
/* Save the real path */
/**********************/
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
if (realpath != null) {
msgContext.setProperty(Constants.MC_REALPATH, realpath);
}
msgContext.setProperty(Constants.MC_CONFIGPATH, getWebInfPath());
return msgContext;
}
/**
* Extract the SOAPAction header.
* if SOAPAction is null then we'll we be forced to scan the body for it.
* if SOAPAction is "" then use the URL
* @param req incoming request
* @return the action
* @throws AxisFault
*/
private String getSoapAction(HttpServletRequest req) throws AxisFault {
String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
if (soapAction == null) {
String contentType = req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
if(contentType != null) {
int index = contentType.indexOf("action");
if(index != -1){
soapAction = contentType.substring(index + 7);
}
}
}
if (isDebug) {
log.debug("HEADER_SOAP_ACTION:" + soapAction);
/**
* Technically, if we don't find this header, we should probably fault.
* It's required in the SOAP HTTP binding.
*/
}
if (soapAction == null) {
AxisFault af = new AxisFault("Client.NoSOAPAction",
Messages.getMessage("noHeader00",
"SOAPAction"),
null, null);
exceptionLog.error(Messages.getMessage("genFault00"), af);
throw af;
}
// the SOAP 1.1 spec & WS-I 1.0 says:
// soapaction = "SOAPAction" ":" [ <"> URI-reference <"> ]
// some implementations leave off the quotes
// we strip them if they are present
if (soapAction.startsWith("\"") && soapAction.endsWith("\"")
&& soapAction.length() >= 2) {
int end = soapAction.length() - 1;
soapAction = soapAction.substring(1, end);
}
if (soapAction.length() == 0) {
soapAction = req.getContextPath(); // Is this right?
}
return soapAction;
}
/**
* Provided to allow overload of default JWSClassDir
* by derived class.
* @return directory for JWS files
*/
protected String getDefaultJWSClassDir() {
return (getWebInfPath() == null)
? null // ??? what is a good FINAL default for WebLogic?
: getWebInfPath() + File.separator + "jwsClasses";
}
/**
* Initialize a Handler for the transport defined in the Axis server config.
* This includes optionally filling in query string handlers.
*/
public void initQueryStringHandlers() {
try {
this.transport = getEngine().getTransport(this.transportName);
if (this.transport == null) {
// No transport by this name is defined. Therefore, fill in default
// query string handlers.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
else {
// See if we should use the default query string handlers.
// By default, set this to true (for backwards compatibility).
boolean defaultQueryStrings = true;
String useDefaults = (String)this.transport.getOption(
"useDefaultQueryStrings");
if ((useDefaults != null) &&
useDefaults.toLowerCase().equals("false")) {
defaultQueryStrings = false;
}
if (defaultQueryStrings == true) {
// We should use defaults, so fill them in.
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
}
}
}
catch (AxisFault e) {
// Some sort of problem occurred, let's just make a default transport.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
}
/**
* Attempts to invoke a plugin for the query string supplied in the URL.
*
* @param request the servlet's HttpServletRequest object.
* @param response the servlet's HttpServletResponse object.
* @param writer the servlet's PrintWriter object.
*/
private boolean processQuery(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) throws AxisFault {
// Attempt to instantiate a plug-in handler class for the query string
// handler classes defined in the HTTP transport.
String path = request.getServletPath();
String queryString = request.getQueryString();
String serviceName;
AxisEngine engine = getEngine();
Iterator i = this.transport.getOptions().keySet().iterator();
if (queryString == null) {
return false;
}
String servletURI = request.getContextPath() + path;
String reqURI = request.getRequestURI();
// chop off '/'.
if (servletURI.length() + 1 < reqURI.length()) {
serviceName = reqURI.substring(servletURI.length() + 1);
} else {
serviceName = "";
} while (i.hasNext() == true) {
String queryHandler = (String) i.next();
if (queryHandler.startsWith("qs.") == true) {
// Only attempt to match the query string with transport
// parameters prefixed with "qs:".
String handlerName = queryHandler.substring
(queryHandler.indexOf(".") + 1).
toLowerCase();
// Determine the name of the plugin to invoke by using all text
// in the query string up to the first occurence of &, =, or the
// whole string if neither is present.
int length = 0;
boolean firstParamFound = false;
while (firstParamFound == false && length < queryString.length()) {
char ch = queryString.charAt(length++);
if (ch == '&' || ch == '=') {
firstParamFound = true;
--length;
}
}
if (length < queryString.length()) {
queryString = queryString.substring(0, length);
}
if (queryString.toLowerCase().equals(handlerName) == true) {
// Query string matches a defined query string handler name.
// If the defined class name for this query string handler is blank,
// just return (the handler is "turned off" in effect).
if (this.transport.getOption(queryHandler).equals("")) {
return false;
}
try {
// Attempt to dynamically load the query string handler
// and its "invoke" method.
MessageContext msgContext = createMessageContext(engine,
request, response);
Class plugin = Class.forName((String)this.transport.
getOption(queryHandler));
Method pluginMethod = plugin.getDeclaredMethod("invoke",
new Class[] {msgContext.getClass()});
String url = HttpUtils.getRequestURL(request).toString();
// Place various useful servlet-related objects in
// the MessageContext object being delivered to the
// plugin.
msgContext.setProperty(MessageContext.TRANS_URL, url);
msgContext.setProperty(HTTPConstants.
PLUGIN_SERVICE_NAME, serviceName);
msgContext.setProperty(HTTPConstants.PLUGIN_NAME,
handlerName);
msgContext.setProperty(HTTPConstants.
PLUGIN_IS_DEVELOPMENT,
new Boolean(isDevelopment()));
msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,
new Boolean(enableList));
msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE,
engine);
msgContext.setProperty(HTTPConstants.PLUGIN_WRITER,
writer);
msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log);
msgContext.setProperty(HTTPConstants.
PLUGIN_EXCEPTION_LOG,
exceptionLog);
// Invoke the plugin.
pluginMethod.invoke(plugin.newInstance(),
new Object[] {msgContext});
writer.close();
return true;
} catch (InvocationTargetException ie) {
reportTroubleInGet(ie.getTargetException(), response,
writer);
// return true to prevent any further processing
return true;
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
// return true to prevent any further processing
return true;
}
}
}
}
return false;
}
/**
* getRequestPath a returns request path for web service padded with
* request.getPathInfo for web services served from /services directory.
* This is a required to support serving .jws web services from /services
* URL. See AXIS-843 for more information.
*
* @param request HttpServletRequest
* @return String
*/
private static String getRequestPath(HttpServletRequest request) {
return request.getServletPath() + ((request.getPathInfo() != null) ?
request.getPathInfo() : "");
}
}
----------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 12:36 PM
To: Firas Khasawneh (fkhasawn); axis-user@ws.apache.org
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
The order of processing in the case of HTTP is;
AxisServlet->AxisEngine->HandlerChain->MessageProcessor->Service and come back.
If you placed the server in a different machine, then your RTT should definitely include the network time so it should be larger than the processing time.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake ; axis-dev@ws.apache.org ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 11:27 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
Do you know if response coming back from transport handler after the request is processed in the Axis engine also hits AxisServlet and uses doGet?
Thanks,
Firas
--------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same machine? If you put the handler in transport section, then what you will measure is the time it takes inside the engine from transport handlers ->service -> transport handlers. One other possibility is to keep track of the time in AxisServlet. Measure the time in AxisServlet before it calls AxisEngine's invoke(..) method and after it is returned and you will get the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to measure the overhead Axis adds?
------------------------------------------------------------------------
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to response time? I created a handler in the requestFlow to store System.currentTimeMillis in messageContext and another handler in the responseFlow that retrieved this value and subtracts it from System.currentTimeMillis(), when I use these classes in the global conf or transport (server side) I am getting values that correspond to the response time the client is getting so it looks like it is not calculating the Axix overhead on the server side, when I put these handlers in the requestFlow and responseFlow in the service section in server-conf.wsdd it gives differnt time which seem right but I am nti sure if this is the Axix engine overhead? Any suggestions? other ways to do this? please reply back to me or CC me if you are sending to the list since I am not yet a member in this list.
Regards,
Firas Khasawneh
RE: measuring Axix 1.4 overhead
Posted by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com>.
Hi Jaliya,
I am attaching the AxisServlet.java after adding benchmark times, if you
look at line 791 in the doPost method, the invoke shoudl calculate the
invokation time for the Axis engine without the network time but for
some reason it looks like it is including this time in the invokation
time which does not make any sense. I am testing with 1 MB size files so
I am not sure. below is AxisServlet.java, sorry for cuttin and pasting
it here but I was not sure if this email list allows attachments:
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.transport.http;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.apache.axis.AxisEngine;
import org.apache.axis.AxisFault;
import org.apache.axis.ConfigurationException;
import org.apache.axis.Constants;
import org.apache.axis.Handler;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.SimpleTargetedChain;
import org.apache.axis.client.Service;
import org.apache.axis.management.ServiceAdmin;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ServiceDesc;
import org.apache.axis.handlers.soap.SOAPService;
import org.apache.axis.security.servlet.ServletSecurityProvider;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import org.apache.commons.logging.Log;
import org.w3c.dom.Element;
/**
*
* @author Doug Davis (dug@us.ibm.com)
* @author Steve Loughran
* xdoclet tags are not active yet; keep web.xml in sync.
* To change the location of the services, change url-pattern in web.xml
and
* set parameter axis.servicesPath in server-config.wsdd. For more
information see
* <a href="http://ws.apache.org/axis/java/reference.html">Axis Reference
Guide</a>.
*
* @web.servlet name="AxisServlet" display-name="Apache-Axis Servlet"
* @web.servlet-mapping url-pattern="/servlet/AxisServlet"
* @web.servlet-mapping url-pattern="*.jws"
* @web.servlet-mapping url-pattern="/services/*"
*/
public class AxisServlet extends AxisServletBase {
protected static Log log =
LogFactory.getLog(AxisServlet.class.getName());
/**
* this log is for timing
*/
private static Log tlog =
LogFactory.getLog(Constants.TIME_LOG_CATEGORY);
/**
* a separate log for exceptions lets users route them
* differently from general low level debug info
*/
private static Log exceptionLog =
LogFactory.getLog(Constants.EXCEPTION_LOG_CATEGORY);
public static final String INIT_PROPERTY_TRANSPORT_NAME =
"transport.name";
public static final String INIT_PROPERTY_USE_SECURITY =
"use-servlet-security";
public static final String INIT_PROPERTY_ENABLE_LIST =
"axis.enableListQuery";
public static final String INIT_PROPERTY_JWS_CLASS_DIR =
"axis.jws.servletClassDir";
// This will turn off the list of available services
public static final String INIT_PROPERTY_DISABLE_SERVICES_LIST =
"axis.disableServiceList";
// Location of the services as defined by the servlet-mapping in web.xml
public static final String INIT_PROPERTY_SERVICES_PATH =
"axis.servicesPath";
// These have default values.
private String transportName;
private Handler transport;
private ServletSecurityProvider securityProvider = null;
private String servicesPath;
/**
* cache of logging debug option; only evaluated at init time.
* So no dynamic switching of logging options with this servlet.
*/
private static boolean isDebug = false;
/**
* Should we enable the "?list" functionality on GETs? (off by
* default because deployment information is a potential security
* hole)
*/
private boolean enableList = false;
/**
* Should we turn off the list of services when we receive a GET
* at the servlet root?
*/
private boolean disableServicesList = false;
/**
* Cached path to JWS output directory
*/
private String jwsClassDir = null;
protected String getJWSClassDir() {return jwsClassDir;
}
/**
* create a new servlet instance
*/
public AxisServlet() {
}
/**
* Initialization method.
*/
public void init() throws javax.servlet.ServletException {
super.init();
ServletContext context = getServletConfig().getServletContext();
isDebug = log.isDebugEnabled();
if (isDebug) {
log.debug("In servlet init");
}
transportName = getOption(context,
INIT_PROPERTY_TRANSPORT_NAME,
HTTPTransport.DEFAULT_TRANSPORT_NAME);
if (JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_USE_SECURITY, null))) {
securityProvider = new ServletSecurityProvider();
}
enableList =
JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_ENABLE_LIST, null));
jwsClassDir = getOption(context, INIT_PROPERTY_JWS_CLASS_DIR, null);
// Should we list services?
disableServicesList = JavaUtils.isTrue(getOption(context,
INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));
servicesPath = getOption(context, INIT_PROPERTY_SERVICES_PATH,
"/services/");
/**
* There are DEFINATE problems here if
* getHomeDir and/or getDefaultJWSClassDir return null
* (as they could with WebLogic).
* This needs to be reexamined in the future, but this
* should fix any NPE's in the mean time.
*/
if (jwsClassDir != null) {
if (getHomeDir() != null) {
jwsClassDir = getHomeDir() + jwsClassDir;
}
} else {
jwsClassDir = getDefaultJWSClassDir();
}
initQueryStringHandlers();
// Setup the service admin
try {
ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo());
} catch (AxisFault af) {
exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " +
af);
}
}
/**
* Process GET requests. This includes handoff of pseudo-SOAP requests
*
* @param request request in
* @param response request out
* @throws ServletException
* @throws IOException
*/
public void doGet(HttpServletRequest request, HttpServletResponse
response) throws
ServletException, IOException {
if (isDebug) {
log.debug("Enter: doGet()");
}
PrintWriter writer = new FilterPrintWriter(response);
try {
AxisEngine engine = getEngine();
ServletContext servletContext =
getServletConfig().getServletContext();
String pathInfo = request.getPathInfo();
String realpath = servletContext.getRealPath(request.getServletPath());
if (realpath == null) {
realpath = request.getServletPath();
}
//JWS pages are special; they are the servlet path and there
//is no pathinfo...we map the pathinfo to the servlet path to keep
//it happy
boolean isJWSPage = request.getRequestURI().endsWith(".jws");
if (isJWSPage) {
pathInfo = request.getServletPath();
}
// Try to execute a query string plugin and return upon success.
if (processQuery(request, response, writer) == true) {
long reqout = System.currentTimeMillis();
return;
}
boolean hasNoPath = (pathInfo == null || pathInfo.equals(""));
if (!disableServicesList) {
if(hasNoPath) {
// If the user requested the servlet (i.e. /axis/servlet/AxisServlet)
// with no service name, present the user with a list of deployed
// services to be helpful
// Don't do this if has been turned off
reportAvailableServices(response, writer, request);
} else if (realpath != null) {
// We have a pathname, so now we perform WSDL or list operations
// get message context w/ various properties set
MessageContext msgContext = createMessageContext(engine,
request, response);
// NOTE: HttpUtils.getRequestURL has been deprecated.
// This line SHOULD be:
// String url = req.getRequestURL().toString()
// HOWEVER!!!! DON'T REPLACE IT! There's a bug in
// req.getRequestURL that is not in HttpUtils.getRequestURL
// req.getRequestURL returns "localhost" in the remote
// scenario rather than the actual host name.
//
// But more importantly, getRequestURL() is a servlet 2.3
// API and to support servlet 2.2 (aka WebSphere 4)
// we need to leave this in for a while longer. tomj 10/14/2004
//
String url = HttpUtils.getRequestURL(request).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// See if we can locate the desired service. If we
// can't, return a 404 Not Found. Otherwise, just
// print the placeholder message.
String serviceName;
if (pathInfo.startsWith("/")) {
serviceName = pathInfo.substring(1);
} else {
serviceName = pathInfo;
}
SOAPService s = engine.getService(serviceName);
if (s == null) {
//no service: report it
if (isJWSPage) {
reportCantGetJWSService(request, response, writer);
} else {
reportCantGetAxisService(request, response, writer);
}
} else {
//print a snippet of service info.
reportServiceInfo(response, writer, s, serviceName);
}
}
} else {
// We didn't have a real path in the request, so just
// print a message informing the user that they reached
// the servlet.
response.setContentType("text/html; charset=utf-8");
writer.println("<html><h1>Axis HTTP Servlet</h1>");
writer.println(Messages.getMessage("reachedServlet00"));
writer.println("<p>" +
Messages.getMessage("transportName00",
"<b>" + transportName + "</b>"));
writer.println("</html>");
}
} catch (AxisFault fault) {
reportTroubleInGet(fault, response, writer);
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
} finally {
writer.close();
if (isDebug) {
log.debug("Exit: doGet()");
}
}
}
/**
* when we get an exception or an axis fault in a GET, we handle
* it almost identically: we go 'something went wrong', set the response
* code to 500 and then dump info. But we dump different info for an axis
fault
* or subclass thereof.
* @param exception what went wrong
* @param response current response
* @param writer open writer to response
*/
private void reportTroubleInGet(Throwable exception,
HttpServletResponse response,
PrintWriter writer) {
response.setContentType("text/html; charset=utf-8");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
writer.println("<h2>" +
Messages.getMessage("error00") +
"</h2>");
writer.println("<p>" +
Messages.getMessage("somethingWrong00") +
"</p>");
if (exception instanceof AxisFault) {
AxisFault fault = (AxisFault) exception;
processAxisFault(fault);
writeFault(writer, fault);
} else {
logException(exception);
writer.println("<pre>Exception - " + exception + "<br>");
//dev systems only give fault dumps
if (isDevelopment()) {
writer.println(JavaUtils.stackToString(exception));
}
writer.println("</pre>");
}
}
/**
* routine called whenever an axis fault is caught; where they
* are logged and any other business. The method may modify the fault
* in the process
* @param fault what went wrong.
*/
protected void processAxisFault(AxisFault fault) {
//log the fault
Element runtimeException = fault.lookupFaultDetail(
Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
if (runtimeException != null) {
exceptionLog.info(Messages.getMessage("axisFault00"), fault);
//strip runtime details
fault.removeFaultDetail(Constants.
QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
} else if (exceptionLog.isDebugEnabled()) {
exceptionLog.debug(Messages.getMessage("axisFault00"), fault);
}
//dev systems only give fault dumps
if (!isDevelopment()) {
//strip out the stack trace
fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE);
}
}
/**
* log any exception to our output log, at our chosen level
* @param e what went wrong
*/
protected void logException(Throwable e) {
exceptionLog.info(Messages.getMessage("exception00"), e);
}
/**
* this method writes a fault out to an HTML stream. This includes
* escaping the strings to defend against cross-site scripting attacks
* @param writer
* @param axisFault
*/
private void writeFault(PrintWriter writer, AxisFault axisFault) {
String localizedMessage = XMLUtils.xmlEncodeString(axisFault.
getLocalizedMessage());
writer.println("<pre>Fault - " + localizedMessage + "<br>");
writer.println(axisFault.dumpToString());
writer.println("</pre>");
}
/**
* print a snippet of service info.
* @param service service
* @param writer output channel
* @param serviceName where to put stuff
*/
protected void reportServiceInfo(HttpServletResponse response,
PrintWriter writer, SOAPService service,
String serviceName) {
response.setContentType("text/html; charset=utf-8");
writer.println("<h1>"
+ service.getName()
+ "</h1>");
writer.println(
"<p>" +
Messages.getMessage("axisService00") +
"</p>");
writer.println(
"<i>" +
Messages.getMessage("perhaps00") +
"</i>");
}
/**
* report that we have no WSDL
*
* This method was moved to the querystring handler QSWSDLHandler. The
* method reportNoWSDL in AxisServlet is never called. Perhaps the method
* is overwritten in subclasses of AxisServlet so the method wasn't
* removed. See the discussion in
*
* http://nagoya.apache.org/bugzilla/show_bug.cgi?id=23845
*
* @param res
* @param writer
* @param moreDetailCode optional name of a message to provide more
detail
* @param axisFault optional fault string, for extra info at debug time
only
*/
protected void reportNoWSDL(HttpServletResponse res, PrintWriter writer,
String moreDetailCode, AxisFault axisFault) {
}
/**
* This method lists the available services; it is called when there is
* nothing to execute on a GET
* @param response
* @param writer
* @param request
* @throws ConfigurationException
* @throws AxisFault
*/
protected void reportAvailableServices(HttpServletResponse response,
PrintWriter writer,
HttpServletRequest request) throws
ConfigurationException, AxisFault {
AxisEngine engine = getEngine();
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>And now... Some Services</h2>");
Iterator i;
try {
i = engine.getConfig().getDeployedServices();
} catch (ConfigurationException configException) {
//turn any internal configuration exceptions back into axis faults
//if that is what they are
if (configException.getContainedException() instanceof AxisFault) {
throw (AxisFault) configException.getContainedException();
} else {
throw configException;
}
}
// baseURL may change if <endpointURL> tag is used for
// custom deployment at a different location
String defaultBaseURL = getWebappBase(request) + servicesPath;
writer.println("<ul>");
while (i.hasNext()) {
ServiceDesc sd = (ServiceDesc) i.next();
StringBuffer sb = new StringBuffer();
sb.append("<li>");
String name = sd.getName();
sb.append(name);
sb.append(" <a href=\"");
String endpointURL = sd.getEndpointURL();
String baseURL = (endpointURL == null) ? defaultBaseURL :
endpointURL;
sb.append(baseURL);
sb.append(name);
sb.append("?wsdl\"><i>(wsdl)</i></a></li>");
writer.println(sb.toString());
ArrayList operations = sd.getOperations();
if (!operations.isEmpty()) {
writer.println("<ul>");
for (Iterator it = operations.iterator(); it.hasNext(); ) {
OperationDesc desc = (OperationDesc) it.next();
writer.println("<li>" + desc.getName());
}
writer.println("</ul>");
}
}
writer.println("</ul>");
}
/**
* generate the error response to indicate that there is apparently no
endpoint there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void reportCantGetAxisService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// no such service....
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
response.setContentType("text/html; charset=utf-8");
writer.println("<h2>" +
Messages.getMessage("error00") + "</h2>");
writer.println("<p>" +
Messages.getMessage("noService06") +
"</p>");
}
/**
* probe for a JWS page and report 'no service' if one is not found there
* @param request the request that didnt have an edpoint
* @param response response we are generating
* @param writer open writer for the request
*/
protected void reportCantGetJWSService(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) {
// first look to see if there is a service
// requestPath is a work around to support serving .jws web services
// from services URL - see AXIS-843 for more information
String requestPath = request.getServletPath() + ((request.getPathInfo()
!= null) ?
request.getPathInfo() : "");
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
log.debug("JWS real path: " + realpath);
boolean foundJWSFile = (new File(realpath).exists()) &&
(realpath.endsWith(Constants.
JWS_DEFAULT_FILE_EXTENSION));
response.setContentType("text/html; charset=utf-8");
if (foundJWSFile) {
response.setStatus(HttpURLConnection.HTTP_OK);
writer.println(Messages.getMessage("foundJWS00") + "<p>");
String url = request.getRequestURI();
String urltext = Messages.getMessage("foundJWS01");
writer.println("<a href='" + url + "?wsdl'>" + urltext + "</a>");
} else {
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
writer.println(Messages.getMessage("noService06"));
}
}
/**
* Process a POST to the servlet by handing it off to the Axis Engine.
* Here is where SOAP messages are received
* @param req posted request
* @param res respose
* @throws ServletException trouble
* @throws IOException different trouble
*/
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws
ServletException, IOException {
long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
String soapAction = null;
MessageContext msgContext = null;
if (isDebug) {
log.debug("Enter: doPost()");
}
t0 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
Message responseMsg = null;
String contentType = null;
try {
AxisEngine engine = getEngine();
if (engine == null) {
// !!! should return a SOAP fault...
ServletException se =
new ServletException(Messages.getMessage("noEngine00"));
log.debug("No Engine!", se);
throw se;
}
res.setBufferSize(1024 * 8); // provide performance boost.
/** get message context w/ various properties set
*/
msgContext = createMessageContext(engine, req, res);
// ? OK to move this to 'getMessageContext',
// ? where it would also be picked up for 'doGet()' ?
if (securityProvider != null) {
if (isDebug) {
log.debug("securityProvider:" + securityProvider);
}
msgContext.setProperty(MessageContext.SECURITY_PROVIDER,
securityProvider);
}
/* Get request message
*/
Message requestMsg =
new Message(req.getInputStream(),
false,
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
req.getHeader(HTTPConstants.
HEADER_CONTENT_LOCATION));
// Transfer HTTP headers to MIME headers for request message.
MimeHeaders requestMimeHeaders = requestMsg.getMimeHeaders();
for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) {
String headerName = (String) e.nextElement();
for (Enumeration f = req.getHeaders(headerName);
f.hasMoreElements(); ) {
String headerValue = (String) f.nextElement();
requestMimeHeaders.addHeader(headerName, headerValue);
}
}
if (isDebug) {
log.debug("Request Message:" + requestMsg);
/* Set the request(incoming) message field in the context */
/**********************************************************/
}
msgContext.setRequestMessage(requestMsg);
String url = HttpUtils.getRequestURL(req).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
// put character encoding of request to message context
// in order to reuse it during the whole process.
String requestEncoding;
try {
requestEncoding = (String) requestMsg.getProperty(SOAPMessage.
CHARACTER_SET_ENCODING);
if (requestEncoding != null) {
msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
requestEncoding);
}
} catch (SOAPException e1) {
}
try {
/**
* Save the SOAPAction header in the MessageContext bag.
* This will be used to tell the Axis Engine which service
* is being invoked. This will save us the trouble of
* having to parse the Request message - although we will
* need to double-check later on that the SOAPAction header
* does in fact match the URI in the body.
*/
// (is this last stmt true??? (I don't think so - Glen))
/********************************************************/
soapAction = getSoapAction(req);
if (soapAction != null) {
msgContext.setUseSOAPAction(true);
msgContext.setSOAPActionURI(soapAction);
}
// Create a Session wrapper for the HTTP session.
// These can/should be pooled at some point.
// (Sam is Watching! :-)
msgContext.setSession(new AxisHttpSession(req));
t1 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
/* Invoke the Axis engine... */
/*****************************/
if (isDebug) {
log.debug("Invoking Axis Engine.");
//here we run the message by the engine
}
engine.invoke(msgContext);
if (isDebug) {
log.debug("Return from Axis Engine.");
}
t2 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
}
responseMsg = msgContext.getResponseMessage();
// We used to throw exceptions on null response messages.
// They are actually OK in certain situations (asynchronous
// services), so fall through here and return an ACCEPTED
// status code below. Might want to install a configurable
// error check for this later.
} catch (AxisFault fault) {
//log and sanitize
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (Exception e) {
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = convertExceptionToAxisFault(e, responseMsg);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
} catch (Throwable t) {
logException(t);
//other exceptions are internal trouble
responseMsg = msgContext.getResponseMessage();
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
responseMsg = new Message(new AxisFault(t.toString(),t));
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
} catch (AxisFault fault) {
processAxisFault(fault);
configureResponseFromAxisFault(res, fault);
responseMsg = msgContext.getResponseMessage();
if (responseMsg == null) {
responseMsg = new Message(fault);
((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
getMessage().setMessageContext(msgContext);
}
}
t3 = System.currentTimeMillis();
if (tlog.isDebugEnabled()) {
t3 = System.currentTimeMillis();
}
/* Send response back along the wire... */
/***********************************/
if (responseMsg != null) {
// Transfer MIME headers to HTTP headers for response message.
MimeHeaders responseMimeHeaders = responseMsg.getMimeHeaders();
for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) {
MimeHeader responseMimeHeader = (MimeHeader) i.next();
res.addHeader(responseMimeHeader.getName(),
responseMimeHeader.getValue());
}
// synchronize the character encoding of request and response
String responseEncoding = (String) msgContext.getProperty(
SOAPMessage.CHARACTER_SET_ENCODING);
if (responseEncoding != null) {
try {
responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
responseEncoding);
} catch (SOAPException e) {
}
}
//determine content type from message response
contentType = responseMsg.getContentType(msgContext.
getSOAPConstants());
sendResponse(contentType, res, responseMsg);
} else {
// No content, so just indicate accepted
res.setStatus(202);
}
if (isDebug) {
log.debug("Response sent.");
log.debug("Exit: doPost()");
}
t4 = System.currentTimeMillis();
System.out.println("Axis stats: " +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" total=" + (t4 - t0));
if (tlog.isDebugEnabled()) {
t4 = System.currentTimeMillis();
tlog.debug("axisServlet.doPost: " + soapAction +
" pre=" + (t1 - t0) +
" invoke=" + (t2 - t1) +
" post=" + (t3 - t2) +
" send=" + (t4 - t3) +
" " + msgContext.getTargetService() + "." +
((msgContext.getOperation() == null) ?
"" : msgContext.getOperation().getName()));
}
}
/**
* Configure the servlet response status code and maybe other headers
* from the fault info.
* @param response response to configure
* @param fault what went wrong
*/
private void configureResponseFromAxisFault(HttpServletResponse
response,
AxisFault fault) {
// then get the status code
// It's been suggested that a lack of SOAPAction
// should produce some other error code (in the 400s)...
int status = getHttpServletResponseStatus(fault);
if (status == HttpServletResponse.SC_UNAUTHORIZED) {
// unauth access results in authentication request
// TODO: less generic realm choice?
response.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\"");
}
response.setStatus(status);
}
/**
* turn any Exception into an AxisFault, log it, set the response
* status code according to what the specifications say and
* return a response message for posting. This will be the response
* message passed in if non-null; one generated from the fault otherwise.
*
* @param exception what went wrong
* @param responseMsg what response we have (if any)
* @return a response message to send to the user
*/
private Message convertExceptionToAxisFault(Exception exception,
Message responseMsg) {
logException(exception);
if (responseMsg == null) {
AxisFault fault = AxisFault.makeFault(exception);
processAxisFault(fault);
responseMsg = new Message(fault);
}
return responseMsg;
}
/**
* Extract information from AxisFault and map it to a HTTP Status code.
*
* @param af Axis Fault
* @return HTTP Status code.
*/
protected int getHttpServletResponseStatus(AxisFault af) {
// TODO: Should really be doing this with explicit AxisFault
// subclasses... --Glen
return af.getFaultCode().getLocalPart().startsWith("Server.Unauth")
? HttpServletResponse.SC_UNAUTHORIZED
: HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
// This will raise a 401 for both
// "Unauthenticated" & "Unauthorized"...
}
/**
* write a message to the response, set appropriate headers for content
* type..etc.
* @param res response
* @param responseMsg message to write
* @throws AxisFault
* @throws IOException if the response stream can not be written to
*/
private void sendResponse(String contentType,
HttpServletResponse res,
Message responseMsg) throws AxisFault,
IOException {
if (responseMsg == null) {
res.setStatus(HttpServletResponse.SC_NO_CONTENT);
if (isDebug) {
log.debug("NO AXIS MESSAGE TO RETURN!");
//String resp = Messages.getMessage("noData00");
//res.setContentLength((int) resp.getBytes().length);
//res.getWriter().print(resp);
}
} else {
if (isDebug) {
log.debug("Returned Content-Type:" +
contentType);
// log.debug("Returned Content-Length:" +
// responseMsg.getContentLength());
}
try {
res.setContentType(contentType);
/* My understand of Content-Length
* HTTP 1.0
* -Required for requests, but optional for responses.
* HTTP 1.1
* - Either Content-Length or HTTP Chunking is required.
* Most servlet engines will do chunking if content-length is not
specified.
*
*
*/
//if(clientVersion == HTTPConstants.HEADER_PROTOCOL_V10) //do chunking
if necessary.
// res.setContentLength(responseMsg.getContentLength());
responseMsg.writeTo(res.getOutputStream());
} catch (SOAPException e) {
logException(e);
}
}
if (!res.isCommitted()) {
res.flushBuffer(); // Force it right now.
}
}
/**
* Place the Request message in the MessagContext object - notice
* that we just leave it as a 'ServletRequest' object and let the
* Message processing routine convert it - we don't do it since we
* don't know how it's going to be used - perhaps it might not
* even need to be parsed.
* @return a message context
*/
private MessageContext createMessageContext(AxisEngine engine,
HttpServletRequest req,
HttpServletResponse res) {
MessageContext msgContext = new MessageContext(engine);
String requestPath = getRequestPath(req);
if (isDebug) {
log.debug("MessageContext:" + msgContext);
log.debug("HEADER_CONTENT_TYPE:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
log.debug("HEADER_CONTENT_LOCATION:" +
req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION));
log.debug("Constants.MC_HOME_DIR:" + String.valueOf(getHomeDir()));
log.debug("Constants.MC_RELATIVE_PATH:" + requestPath);
log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" +
String.valueOf(getWebInfPath()));
log.debug("HTTPConstants.MC_HTTP_SERVLETPATHINFO:" +
req.getPathInfo());
log.debug("HTTPConstants.HEADER_AUTHORIZATION:" +
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
log.debug("Constants.MC_REMOTE_ADDR:" + req.getRemoteAddr());
log.debug("configPath:" + String.valueOf(getWebInfPath()));
}
/* Set the Transport */
/*********************/
msgContext.setTransportName(transportName);
/* Save some HTTP specific info in the bag in case someone needs it */
/********************************************************************/
msgContext.setProperty(Constants.MC_JWS_CLASSDIR, jwsClassDir);
msgContext.setProperty(Constants.MC_HOME_DIR, getHomeDir());
msgContext.setProperty(Constants.MC_RELATIVE_PATH, requestPath);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLET, this);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, req);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, res);
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETLOCATION,
getWebInfPath());
msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO,
req.getPathInfo());
msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION,
req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
msgContext.setProperty(Constants.MC_REMOTE_ADDR, req.getRemoteAddr());
// Set up a javax.xml.rpc.server.ServletEndpointContext
ServletEndpointContextImpl sec = new ServletEndpointContextImpl();
msgContext.setProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT, sec);
/* Save the real path */
/**********************/
String realpath = getServletConfig().getServletContext()
.getRealPath(requestPath);
if (realpath != null) {
msgContext.setProperty(Constants.MC_REALPATH, realpath);
}
msgContext.setProperty(Constants.MC_CONFIGPATH, getWebInfPath());
return msgContext;
}
/**
* Extract the SOAPAction header.
* if SOAPAction is null then we'll we be forced to scan the body for it.
* if SOAPAction is "" then use the URL
* @param req incoming request
* @return the action
* @throws AxisFault
*/
private String getSoapAction(HttpServletRequest req) throws AxisFault {
String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
if (soapAction == null) {
String contentType = req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
if(contentType != null) {
int index = contentType.indexOf("action");
if(index != -1){
soapAction = contentType.substring(index + 7);
}
}
}
if (isDebug) {
log.debug("HEADER_SOAP_ACTION:" + soapAction);
/**
* Technically, if we don't find this header, we should probably fault.
* It's required in the SOAP HTTP binding.
*/
}
if (soapAction == null) {
AxisFault af = new AxisFault("Client.NoSOAPAction",
Messages.getMessage("noHeader00",
"SOAPAction"),
null, null);
exceptionLog.error(Messages.getMessage("genFault00"), af);
throw af;
}
// the SOAP 1.1 spec & WS-I 1.0 says:
// soapaction = "SOAPAction" ":" [ <"> URI-reference <"> ]
// some implementations leave off the quotes
// we strip them if they are present
if (soapAction.startsWith("\"") && soapAction.endsWith("\"")
&& soapAction.length() >= 2) {
int end = soapAction.length() - 1;
soapAction = soapAction.substring(1, end);
}
if (soapAction.length() == 0) {
soapAction = req.getContextPath(); // Is this right?
}
return soapAction;
}
/**
* Provided to allow overload of default JWSClassDir
* by derived class.
* @return directory for JWS files
*/
protected String getDefaultJWSClassDir() {
return (getWebInfPath() == null)
? null // ??? what is a good FINAL default for WebLogic?
: getWebInfPath() + File.separator + "jwsClasses";
}
/**
* Initialize a Handler for the transport defined in the Axis server
config.
* This includes optionally filling in query string handlers.
*/
public void initQueryStringHandlers() {
try {
this.transport = getEngine().getTransport(this.transportName);
if (this.transport == null) {
// No transport by this name is defined. Therefore, fill in default
// query string handlers.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
else {
// See if we should use the default query string handlers.
// By default, set this to true (for backwards compatibility).
boolean defaultQueryStrings = true;
String useDefaults = (String)this.transport.getOption(
"useDefaultQueryStrings");
if ((useDefaults != null) &&
useDefaults.toLowerCase().equals("false")) {
defaultQueryStrings = false;
}
if (defaultQueryStrings == true) {
// We should use defaults, so fill them in.
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
}
}
}
catch (AxisFault e) {
// Some sort of problem occurred, let's just make a default transport.
this.transport = new SimpleTargetedChain();
this.transport.setOption("qs.list",
"org.apache.axis.transport.http.QSListHandler");
this.transport.setOption("qs.method",
"org.apache.axis.transport.http.QSMethodHandler");
this.transport.setOption("qs.wsdl",
"org.apache.axis.transport.http.QSWSDLHandler");
return;
}
}
/**
* Attempts to invoke a plugin for the query string supplied in the URL.
*
* @param request the servlet's HttpServletRequest object.
* @param response the servlet's HttpServletResponse object.
* @param writer the servlet's PrintWriter object.
*/
private boolean processQuery(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) throws AxisFault {
// Attempt to instantiate a plug-in handler class for the query string
// handler classes defined in the HTTP transport.
String path = request.getServletPath();
String queryString = request.getQueryString();
String serviceName;
AxisEngine engine = getEngine();
Iterator i = this.transport.getOptions().keySet().iterator();
if (queryString == null) {
return false;
}
String servletURI = request.getContextPath() + path;
String reqURI = request.getRequestURI();
// chop off '/'.
if (servletURI.length() + 1 < reqURI.length()) {
serviceName = reqURI.substring(servletURI.length() + 1);
} else {
serviceName = "";
} while (i.hasNext() == true) {
String queryHandler = (String) i.next();
if (queryHandler.startsWith("qs.") == true) {
// Only attempt to match the query string with transport
// parameters prefixed with "qs:".
String handlerName = queryHandler.substring
(queryHandler.indexOf(".") + 1).
toLowerCase();
// Determine the name of the plugin to invoke by using all text
// in the query string up to the first occurence of &, =, or the
// whole string if neither is present.
int length = 0;
boolean firstParamFound = false;
while (firstParamFound == false && length < queryString.length()) {
char ch = queryString.charAt(length++);
if (ch == '&' || ch == '=') {
firstParamFound = true;
--length;
}
}
if (length < queryString.length()) {
queryString = queryString.substring(0, length);
}
if (queryString.toLowerCase().equals(handlerName) == true) {
// Query string matches a defined query string handler name.
// If the defined class name for this query string handler is blank,
// just return (the handler is "turned off" in effect).
if (this.transport.getOption(queryHandler).equals("")) {
return false;
}
try {
// Attempt to dynamically load the query string handler
// and its "invoke" method.
MessageContext msgContext = createMessageContext(engine,
request, response);
Class plugin = Class.forName((String)this.transport.
getOption(queryHandler));
Method pluginMethod = plugin.getDeclaredMethod("invoke",
new Class[] {msgContext.getClass()});
String url = HttpUtils.getRequestURL(request).toString();
// Place various useful servlet-related objects in
// the MessageContext object being delivered to the
// plugin.
msgContext.setProperty(MessageContext.TRANS_URL, url);
msgContext.setProperty(HTTPConstants.
PLUGIN_SERVICE_NAME, serviceName);
msgContext.setProperty(HTTPConstants.PLUGIN_NAME,
handlerName);
msgContext.setProperty(HTTPConstants.
PLUGIN_IS_DEVELOPMENT,
new Boolean(isDevelopment()));
msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,
new Boolean(enableList));
msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE,
engine);
msgContext.setProperty(HTTPConstants.PLUGIN_WRITER,
writer);
msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log);
msgContext.setProperty(HTTPConstants.
PLUGIN_EXCEPTION_LOG,
exceptionLog);
// Invoke the plugin.
pluginMethod.invoke(plugin.newInstance(),
new Object[] {msgContext});
writer.close();
return true;
} catch (InvocationTargetException ie) {
reportTroubleInGet(ie.getTargetException(), response,
writer);
// return true to prevent any further processing
return true;
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
// return true to prevent any further processing
return true;
}
}
}
}
return false;
}
/**
* getRequestPath a returns request path for web service padded with
* request.getPathInfo for web services served from /services directory.
* This is a required to support serving .jws web services from /services
* URL. See AXIS-843 for more information.
*
* @param request HttpServletRequest
* @return String
*/
private static String getRequestPath(HttpServletRequest request) {
return request.getServletPath() + ((request.getPathInfo() != null) ?
request.getPathInfo() : "");
}
}
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 12:36 PM
To: Firas Khasawneh (fkhasawn); axis-user@ws.apache.org
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
The order of processing in the case of HTTP is;
AxisServlet->AxisEngine->HandlerChain->MessageProcessor->Service and
come back.
If you placed the server in a different machine, then your RTT should
definitely include the network time so it should be larger than the
processing time.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn) <ma...@cisco.com>
To: Jaliya Ekanayake <ma...@apache.org> ;
axis-dev@ws.apache.org ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 11:27 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
Do you know if response coming back from transport handler after
the request is processed in the Axis engine also hits AxisServlet and
uses doGet?
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas
Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same
machine? If you put the handler in transport section, then what you will
measure is the time it takes inside the engine from transport handlers
->service -> transport handlers. One other possibility is to keep track
of the time in AxisServlet. Measure the time in AxisServlet before it
calls AxisEngine's invoke(..) method and after it is returned and you
will get the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
<ma...@cisco.com>
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on
how to measure the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds
to response time? I created a handler in the requestFlow to store
System.currentTimeMillis in messageContext and another handler in the
responseFlow that retrieved this value and subtracts it from
System.currentTimeMillis(), when I use these classes in the global conf
or transport (server side) I am getting values that correspond to the
response time the client is getting so it looks like it is not
calculating the Axix overhead on the server side, when I put these
handlers in the requestFlow and responseFlow in the service section in
server-conf.wsdd it gives differnt time which seem right but I am nti
sure if this is the Axix engine overhead? Any suggestions? other ways to
do this? please reply back to me or CC me if you are sending to the list
since I am not yet a member in this list.
Regards,
Firas Khasawneh
RE: measuring Axix 1.4 overhead
Posted by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com>.
Hi Jaliya,
Do you know if response coming back from transport handler after the
request is processed in the Axis engine also hits AxisServlet and uses
doGet?
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas Khasawneh
(fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same machine? If you
put the handler in transport section, then what you will measure is the
time it takes inside the engine from transport handlers ->service ->
transport handlers. One other possibility is to keep track of the time
in AxisServlet. Measure the time in AxisServlet before it calls
AxisEngine's invoke(..) method and after it is returned and you will get
the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn) <ma...@cisco.com>
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to
measure the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to
response time? I created a handler in the requestFlow to store
System.currentTimeMillis in messageContext and another handler in the
responseFlow that retrieved this value and subtracts it from
System.currentTimeMillis(), when I use these classes in the global conf
or transport (server side) I am getting values that correspond to the
response time the client is getting so it looks like it is not
calculating the Axix overhead on the server side, when I put these
handlers in the requestFlow and responseFlow in the service section in
server-conf.wsdd it gives differnt time which seem right but I am nti
sure if this is the Axix engine overhead? Any suggestions? other ways to
do this? please reply back to me or CC me if you are sending to the list
since I am not yet a member in this list.
Regards,
Firas Khasawneh
RE: measuring Axix 1.4 overhead
Posted by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com>.
Hi Jaliya,
Yes I mean RTT by response time, the client is on a different machine. I
am not using client side Axis. I am using System.currentTimeMillis.
Regards,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 10:09 AM
To: Firas Khasawneh (fkhasawn); axis-dev@ws.apache.org
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
What do you mean by the response time at the client. Is it the Round
Trip Time(RTT) of the web service invocation?
The reasons you are getting the same time may be;
You are using the server and the client in the same machine and the time
it takes for processing at the server is not captured at milliseconds
resolution.
If you are in JDK1.5 or above try using, System.nanoTime();
You will get a higer RTT if you deploy the server in a differnt machine
than where you run the client.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn) <ma...@cisco.com>
To: Jaliya Ekanayake <ma...@apache.org> ;
axis-dev@ws.apache.org ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 9:45 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I am using only server side Axis, for client I am using SoapUI.
if I put the handler in transport for both response and request, I am
getting the response time I am measuring from my client so looks like it
is measuring from the client side (the time it gets the request till it
releases the http connection)
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas
Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same
machine? If you put the handler in transport section, then what you will
measure is the time it takes inside the engine from transport handlers
->service -> transport handlers. One other possibility is to keep track
of the time in AxisServlet. Measure the time in AxisServlet before it
calls AxisEngine's invoke(..) method and after it is returned and you
will get the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
<ma...@cisco.com>
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on
how to measure the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds
to response time? I created a handler in the requestFlow to store
System.currentTimeMillis in messageContext and another handler in the
responseFlow that retrieved this value and subtracts it from
System.currentTimeMillis(), when I use these classes in the global conf
or transport (server side) I am getting values that correspond to the
response time the client is getting so it looks like it is not
calculating the Axix overhead on the server side, when I put these
handlers in the requestFlow and responseFlow in the service section in
server-conf.wsdd it gives differnt time which seem right but I am nti
sure if this is the Axix engine overhead? Any suggestions? other ways to
do this? please reply back to me or CC me if you are sending to the list
since I am not yet a member in this list.
Regards,
Firas Khasawneh
Re: measuring Axix 1.4 overhead
Posted by Jaliya Ekanayake <jn...@gmail.com>.
Hi Firas,
What do you mean by the response time at the client. Is it the Round Trip Time(RTT) of the web service invocation?
The reasons you are getting the same time may be;
You are using the server and the client in the same machine and the time it takes for processing at the server is not captured at milliseconds resolution.
If you are in JDK1.5 or above try using, System.nanoTime();
You will get a higer RTT if you deploy the server in a differnt machine than where you run the client.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: Jaliya Ekanayake ; axis-dev@ws.apache.org ; axis-user@ws.apache.org
Sent: Monday, July 23, 2007 9:45 AM
Subject: RE: measuring Axix 1.4 overhead
Hi Jaliya,
I am using only server side Axis, for client I am using SoapUI. if I put the handler in transport for both response and request, I am getting the response time I am measuring from my client so looks like it is measuring from the client side (the time it gets the request till it releases the http connection)
Thanks,
Firas
------------------------------------------------------------------------------
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas Khasawneh (fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same machine? If you put the handler in transport section, then what you will measure is the time it takes inside the engine from transport handlers ->service -> transport handlers. One other possibility is to keep track of the time in AxisServlet. Measure the time in AxisServlet before it calls AxisEngine's invoke(..) method and after it is returned and you will get the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to measure the overhead Axis adds?
----------------------------------------------------------------------------
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to response time? I created a handler in the requestFlow to store System.currentTimeMillis in messageContext and another handler in the responseFlow that retrieved this value and subtracts it from System.currentTimeMillis(), when I use these classes in the global conf or transport (server side) I am getting values that correspond to the response time the client is getting so it looks like it is not calculating the Axix overhead on the server side, when I put these handlers in the requestFlow and responseFlow in the service section in server-conf.wsdd it gives differnt time which seem right but I am nti sure if this is the Axix engine overhead? Any suggestions? other ways to do this? please reply back to me or CC me if you are sending to the list since I am not yet a member in this list.
Regards,
Firas Khasawneh
RE: measuring Axix 1.4 overhead
Posted by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com>.
Hi Jaliya,
I am using only server side Axis, for client I am using SoapUI. if I put
the handler in transport for both response and request, I am getting the
response time I am measuring from my client so looks like it is
measuring from the client side (the time it gets the request till it
releases the http connection)
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas Khasawneh
(fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same machine? If you
put the handler in transport section, then what you will measure is the
time it takes inside the engine from transport handlers ->service ->
transport handlers. One other possibility is to keep track of the time
in AxisServlet. Measure the time in AxisServlet before it calls
AxisEngine's invoke(..) method and after it is returned and you will get
the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn) <ma...@cisco.com>
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to
measure the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to
response time? I created a handler in the requestFlow to store
System.currentTimeMillis in messageContext and another handler in the
responseFlow that retrieved this value and subtracts it from
System.currentTimeMillis(), when I use these classes in the global conf
or transport (server side) I am getting values that correspond to the
response time the client is getting so it looks like it is not
calculating the Axix overhead on the server side, when I put these
handlers in the requestFlow and responseFlow in the service section in
server-conf.wsdd it gives differnt time which seem right but I am nti
sure if this is the Axix engine overhead? Any suggestions? other ways to
do this? please reply back to me or CC me if you are sending to the list
since I am not yet a member in this list.
Regards,
Firas Khasawneh
RE: measuring Axix 1.4 overhead
Posted by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com>.
Hi Jaliya,
I am using only server side Axis, for client I am using SoapUI. if I put
the handler in transport for both response and request, I am getting the
response time I am measuring from my client so looks like it is
measuring from the client side (the time it gets the request till it
releases the http connection)
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas Khasawneh
(fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same machine? If you
put the handler in transport section, then what you will measure is the
time it takes inside the engine from transport handlers ->service ->
transport handlers. One other possibility is to keep track of the time
in AxisServlet. Measure the time in AxisServlet before it calls
AxisEngine's invoke(..) method and after it is returned and you will get
the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn) <ma...@cisco.com>
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to
measure the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to
response time? I created a handler in the requestFlow to store
System.currentTimeMillis in messageContext and another handler in the
responseFlow that retrieved this value and subtracts it from
System.currentTimeMillis(), when I use these classes in the global conf
or transport (server side) I am getting values that correspond to the
response time the client is getting so it looks like it is not
calculating the Axix overhead on the server side, when I put these
handlers in the requestFlow and responseFlow in the service section in
server-conf.wsdd it gives differnt time which seem right but I am nti
sure if this is the Axix engine overhead? Any suggestions? other ways to
do this? please reply back to me or CC me if you are sending to the list
since I am not yet a member in this list.
Regards,
Firas Khasawneh
RE: measuring Axix 1.4 overhead
Posted by "Firas Khasawneh (fkhasawn)" <fk...@cisco.com>.
Hi Jaliya,
Do you know if response coming back from transport handler after the
request is processed in the Axis engine also hits AxisServlet and uses
doGet?
Thanks,
Firas
________________________________
From: Jaliya Ekanayake [mailto:jnekanayake@gmail.com]
Sent: Monday, July 23, 2007 9:42 AM
To: axis-dev@ws.apache.org; axis-user@ws.apache.org; Firas Khasawneh
(fkhasawn)
Subject: Re: measuring Axix 1.4 overhead
Hi Firas,
Are you trying both axis server and the client in a same machine? If you
put the handler in transport section, then what you will measure is the
time it takes inside the engine from transport handlers ->service ->
transport handlers. One other possibility is to keep track of the time
in AxisServlet. Measure the time in AxisServlet before it calls
AxisEngine's invoke(..) method and after it is returned and you will get
the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn) <ma...@cisco.com>
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to
measure the overhead Axis adds?
________________________________
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to
response time? I created a handler in the requestFlow to store
System.currentTimeMillis in messageContext and another handler in the
responseFlow that retrieved this value and subtracts it from
System.currentTimeMillis(), when I use these classes in the global conf
or transport (server side) I am getting values that correspond to the
response time the client is getting so it looks like it is not
calculating the Axix overhead on the server side, when I put these
handlers in the requestFlow and responseFlow in the service section in
server-conf.wsdd it gives differnt time which seem right but I am nti
sure if this is the Axix engine overhead? Any suggestions? other ways to
do this? please reply back to me or CC me if you are sending to the list
since I am not yet a member in this list.
Regards,
Firas Khasawneh
Re: measuring Axix 1.4 overhead
Posted by Jaliya Ekanayake <jn...@gmail.com>.
Hi Firas,
Are you trying both axis server and the client in a same machine? If you put the handler in transport section, then what you will measure is the time it takes inside the engine from transport handlers ->service -> transport handlers. One other possibility is to keep track of the time in AxisServlet. Measure the time in AxisServlet before it calls AxisEngine's invoke(..) method and after it is returned and you will get the time for the total invocation.
Thanks,
-jaliya
----- Original Message -----
From: Firas Khasawneh (fkhasawn)
To: axis-user@ws.apache.org ; axis-dev@ws.apache.org
Sent: Monday, July 23, 2007 6:06 AM
Subject: RE: measuring Axix 1.4 overhead
Any help regarding the below please? any suggestions on how to measure the overhead Axis adds?
------------------------------------------------------------------------------
From: Firas Khasawneh (fkhasawn)
Sent: Sunday, July 22, 2007 11:50 PM
To: 'axis-user@ws.apache.org'
Subject: measuring Axix 1.4 overhead
Hi all,
Anybody knows how to measure the overhead Axis 1.4 adds to response time? I created a handler in the requestFlow to store System.currentTimeMillis in messageContext and another handler in the responseFlow that retrieved this value and subtracts it from System.currentTimeMillis(), when I use these classes in the global conf or transport (server side) I am getting values that correspond to the response time the client is getting so it looks like it is not calculating the Axix overhead on the server side, when I put these handlers in the requestFlow and responseFlow in the service section in server-conf.wsdd it gives differnt time which seem right but I am nti sure if this is the Axix engine overhead? Any suggestions? other ways to do this? please reply back to me or CC me if you are sending to the list since I am not yet a member in this list.
Regards,
Firas Khasawneh