在Axis源码分析-Web服务部署(二)中
http://dead-knight.iteye.com/blog/732961
已经将两种web部署方式进行了分析
其中涉及了服务端AxisServlet初始化。以及对get、post请求的监听。
服务端处理请求实际上就是AxisServlet中doPost所做的事情。
AxisServlet中doPost源码:
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()");
}
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
Message responseMsg = null;
String contentType = null;
try {
//获取服务端引擎。初始化工作在init方法已完成
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
*/
//MessageContext初始化以及属性设置
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
*/
//构造请求消息体。req.getInputStream()即为请求输入流
//http request header+xml(soap格式)
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 {
soapAction = getSoapAction(req);
if (soapAction != null) {
msgContext.setUseSOAPAction(true);
msgContext.setSOAPActionURI(soapAction);
}
msgContext.setSession(new AxisHttpSession(req));
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
if (isDebug) {
log.debug("Invoking Axis Engine.");
//here we run the message by the engine
}
//AxisServer执行invoke
engine.invoke(msgContext);
if (isDebug) {
log.debug("Return from Axis Engine.");
}
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
}
responseMsg = msgContext.getResponseMessage();
} 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);
}
}
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);
}
}
doPost主要任务为:
1.构造MessageContext并进行初始化
通过createMessageContext方法完成MessageContext构造,通过setProperty完成属性设置;
2.构造请求消息体
通过Message requestMsg =new Message(req.getInputStream(),false,
req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION));
完成;其构造方法依赖SOAPPart实例,并将请求输入流req.getInputStream()即:org.apache.catalina.connector.CoyoteInputStream(Tomcat环境)设置为SOAPPart的currentMessage;
3.AxisServer引擎调用
通过invoke方法完成对各Handler链的一次调用;后面详细分析。
4.将处理完成的响应消息体发送至客户端。
AxisServer引擎invoke调用分析
public void invoke(MessageContext msgContext) throws AxisFault {
String hName = null ;
Handler h = null ;
MessageContext previousContext = getCurrentMessageContext();
try {
setCurrentMessageContext(msgContext);
hName = msgContext.getStrProp( MessageContext.ENGINE_HANDLER );
if ( hName != null ) {
if ( (h = getHandler(hName)) == null ) {
ClassLoader cl = msgContext.getClassLoader();
try {
log.debug( Messages.getMessage("tryingLoad00", hName) );
Class cls = ClassUtils.forName(hName, true, cl);
h = (Handler) cls.newInstance();
}
catch( Exception e ) {
h = null ;
}
}
if( tlog.isDebugEnabled() ) {
t1=System.currentTimeMillis();
}
if ( h != null )
h.invoke(msgContext);
else
throw new AxisFault( "Server.error",
Messages.getMessage("noHandler00", hName),
null, null );
}
}
else {
hName = msgContext.getStrProp(MessageContext.TRANSPORT);
if ( hName != null ) {
if ((h = hr.find( hName )) != null ) {
h.invoke(msgContext);
} else {
log.error(Messages.getMessage("noTransport02", hName));
}
} else {
defaultTransport.invoke(msgContext);
}
//首先对server-config.wsdd中http传输协议配置的requestFlow
//handler进行处理,如:URLMapper、HTTPAuthHandler
hName = msgContext.getTransportName();
SimpleTargetedChain transportChain = null;
if ( hName != null && (h = getTransport( hName )) != null ) {
if (h instanceof SimpleTargetedChain) {
transportChain = (SimpleTargetedChain)h;
h = transportChain.getRequestHandler();
if (h != null)
h.invoke(msgContext);
}
}
//处理全局请求handler chain
if ((h = getGlobalRequest()) != null ) {
h.invoke(msgContext);
}
//处理所配置接口服务中的requestflow请求handler chain
h = msgContext.getService();
if (h == null) {
Message rm = msgContext.getRequestMessage();
rm.getSOAPEnvelope().getFirstBody();
h = msgContext.getService();
if (h == null)
throw new AxisFault("Server.NoService",
Messages.getMessage("noService05",
"" + msgContext.getTargetService()),
null, null );
}
initSOAPConstants(msgContext);
try {
h.invoke(msgContext);
} catch (AxisFault ae) {
if ((h = getGlobalRequest()) != null ) {
h.onFault(msgContext);
}
throw ae;
}
//处理全局响应handler chain
if ((h = getGlobalResponse()) != null)
h.invoke(msgContext);
//处理http传输的响应handler chain
if (transportChain != null) {
h = transportChain.getResponseHandler();
if (h != null)
h.invoke(msgContext);
}
}
} catch (AxisFault e) {
throw e;
} catch (Exception e) {
// Should we even bother catching it ?
throw AxisFault.makeFault(e);
} finally {
// restore previous state
setCurrentMessageContext(previousContext);
}
if (log.isDebugEnabled()) {
log.debug("Exit: AxisServer::invoke");
}
}
通过以上代码可见、整个Axis引擎处理是通过一系列的handler chain进行invoke。其处理顺序为http requestFlow(URLMapper、HTTPAuthHandler)----global requestFlow(JWSHandler)----service requestFlow responseFlow(接口服务)
----global responseFlow----http responseFlow
那么依次分析各Handler处理过程。
一、transport配置Handler
1.org.apache.axis.handlers.http.URLMapper:
public void invoke(MessageContext msgContext) throws AxisFault
{
log.debug("Enter: URLMapper::invoke");
if ( msgContext.getService() == null ) {
String path = (String)msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO);
if ((path != null) && (path.length() >= 1)) { //rules out the cases of path="", path=null
if(path.startsWith("/"))
path = path.substring(1);
//设置此次请求目标服务
msgContext.setTargetService( path );
}
}
log.debug("Exit: URLMapper::invoke");
}
URLMapper主要任务将客户端调用服务对应的SOAPService设置到MessageContext中
public void setTargetService(String tServ) throws AxisFault {
log.debug("MessageContext: setTargetService(" + tServ+")");
if (tServ == null) {
setService(null);
}
else {
try {
//首先从AxisEngine获取SOAPService服务
//通过SOAPService设置对应的MessageContext属性
setService(getAxisEngine().getService(tServ));
} catch (AxisFault fault) {
// If we're on the client, don't throw this fault...
if (!isClient()) {
throw fault;
}
}
}
targetService = tServ;
}
AxisEngine:
public SOAPService getService(String name) throws AxisFault
{
try {
//委托至FileProvider返回SOAPService
return config.getService(new QName(null, name));
} catch (ConfigurationException e) {
try {
return config.getServiceByNamespaceURI(name);
} catch (ConfigurationException e1) {
throw new AxisFault(e);
}
}
}
由于在初始化AxisServlet已经对server-config.wsdd配置进行实例化至WSDDDeployment中,并由FileProvider引用。
FileProvider实际上将getService任务交给deployment完成:
public SOAPService getService(QName qname) throws ConfigurationException {
SOAPService service = deployment.getService(qname);
if (service == null) {
throw new ConfigurationException(Messages.getMessage("noService10",
qname.toString()));
}
return service;
}
deployment在AxisEngine初始化时已经持有server-config.wsdd中各种配置信息,如:transport、handler、globalConfiguration、service,并将各类配置存储至HashMap缓存中。
WSDDDeployment:
public SOAPService getService(QName name) throws ConfigurationException {
//从缓存中取出WSDDService
WSDDService s = (WSDDService) services.get(name);
if (s != null) {
//通过WSDDService结构返回SOAPService实例
return (SOAPService) s.getInstance(this);
}
return null;
}
可见,deployment只是从存储service信息的HashMap(services)中取出WSDDServie实例(该实例在初始化时即WSDDDeployment构造函数中,已经对配置总所有service服务进行了注册),然后通过WSDDService返回SOAPService。WSDDService只是一种数据结构,用于保存service配置的属性信息;SOAPService是一种Handler,可参与整个Handler Chain中,并对MessageContext进行处理。
(SOAPService) s.getInstance(this)实现如下(实现类为:WSDDDeployableItem):
public final Handler getInstance(EngineConfiguration registry)
throws ConfigurationException
{
//是否为单态实例
if (scope == SCOPE_SINGLETON) {
synchronized (this) {
if (singletonInstance == null)
singletonInstance = getNewInstance(registry);
}
return singletonInstance;
}
return getNewInstance(registry);
}
private Handler getNewInstance(EngineConfiguration registry)
throws ConfigurationException
{
QName type = getType();
if (type == null ||
WSDDConstants.URI_WSDD_JAVA.equals(type.getNamespaceURI())) {
//该任务交给具体子类完成
return makeNewInstance(registry);
} else {
return registry.getHandler(type);
}
}
WSDDservice是WSDDDeployableItem的子类,WSDDservice的getInstance方法由父类WSDDDeployableItem完成。
WSDDservice-makeNewInstance:
public Handler makeNewInstance(EngineConfiguration registry)
throws ConfigurationException
{
if (cachedService != null) {
return cachedService;
}
// 初始化类型映射.
initTMR();
Handler reqHandler = null;
//获取Service中配置的requestFlow Handler
WSDDChain request = getRequestFlow();
if (request != null) {
//存在requestFlow时,返回对应的Handler
//具体操作如WSDDService.getInstance方法
reqHandler = request.getInstance(registry);
}
Handler providerHandler = null;
if (providerQName != null) {
try {
//此处重要!!!在配置service时,
//<service name="Version" provider="java:RPC">
//其中的provider即为处理Messagecontext实现方式
//RPC:org.apache.axis.providers.java.RPCProvider
providerHandler = WSDDProvider.getInstance(providerQName,this,registry);
} catch (Exception e) {
throw new ConfigurationException(e);
}
if (providerHandler == null)
throw new WSDDException(
Messages.getMessage("couldntConstructProvider00"));
}
Handler respHandler = null;
WSDDChain response = getResponseFlow();
if (response != null) {
//存在requestFlow时,返回对应的Handler
respHandler = response.getInstance(registry);
}
//构造SOAPService实例,实际上SOAPService为SimpleTargetedChain子类
SOAPService service = new SOAPService(reqHandler, providerHandler,respHandler);
//设置SOAPService属性
service.setStyle(style);
service.setUse(use);
service.setServiceDescription(desc);
service.setHighFidelityRecording(!streaming);
service.setSendType(sendType);
if ( getQName() != null )
service.setName(getQName().getLocalPart());
service.setOptions(getParametersTable());
service.setRoles(roles);
service.setEngine(((WSDDDeployment)registry).getEngine());
if (use != Use.ENCODED) {
// If not encoded, turn off multi-refs and prefer
// not to sent xsi:type and xsi:nil
service.setOption(AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
service.setOption(AxisEngine.PROP_SEND_XSI, Boolean.FALSE);
}
// Set handlerInfoChain
if (_wsddHIchain != null) {
HandlerInfoChainFactory hiChainFactory = _wsddHIchain.getHandlerChainFactory();
service.setOption(Constants.ATTR_HANDLERINFOCHAIN, hiChainFactory);
}
AxisEngine.normaliseOptions(service);
WSDDFaultFlow [] faultFlows = getFaultFlows();
if (faultFlows != null && faultFlows.length > 0) {
FaultableHandler wrapper = new FaultableHandler(service);
for (int i = 0; i < faultFlows.length; i++) {
WSDDFaultFlow flow = faultFlows[i];
Handler faultHandler = flow.getInstance(registry);
wrapper.setOption("fault-" + flow.getQName().getLocalPart(),
faultHandler);
}
}
try {
service.getInitializedServiceDesc(MessageContext.getCurrentContext());
} catch (AxisFault axisFault) {
throw new ConfigurationException(axisFault);
}
cachedService = service;
return service;
}
至此,整个URLMapper的Handler已经处理完成。其重要任务就是将缓存中的service信息构造成SOAPService Handler,并设置到Messagecontext中。SOAPService实际上是个Handler Chain即:SimpleTargetedChain,该链中包含了service中配置的requestFlow、provider、responseFlow。当执行SOAPService的invoke方法时,通过配置依次执行handler。
2.org.apache.axis.handlers.http.HTTPAuthHandler:
public void invoke(MessageContext msgContext) throws AxisFault
{
log.debug("Enter: HTTPAuthHandler::invoke");
/* Process the Basic Auth stuff in the headers */
/***********************************************/
String tmp = (String)msgContext.getProperty(HTTPConstants.HEADER_AUTHORIZATION);
if ( tmp != null ) tmp = tmp.trim();
if ( tmp != null && tmp.startsWith("Basic ") ) {
String user=null ;
int i ;
tmp = new String( Base64.decode( tmp.substring(6) ) );
i = tmp.indexOf( ':' );
if ( i == -1 ) user = tmp ;
else user = tmp.substring( 0, i);
msgContext.setUsername( user );
log.debug( Messages.getMessage("httpUser00", user) );
if ( i != -1 ) {
String pwd = tmp.substring(i+1);
if ( pwd != null && pwd.equals("") ) pwd = null ;
if ( pwd != null ) {
msgContext.setPassword( pwd );
log.debug( Messages.getMessage("httpPassword00", pwd) );
}
}
}
log.debug("Exit: HTTPAuthHandler::invoke");
}
HTTPAuthHandler主要是处理针对Basic验证方式的web应用,简单地将http请求中的用户名、密码信息设置到MessageContext中。
二、globalConfiguration配置handler
//AxisServer中执行global invoke
if ((h = getGlobalRequest()) != null ) {
h.invoke(msgContext);
}
WSDDDeployment中的getGlobalRequest方法
public Handler getGlobalRequest() throws ConfigurationException {
if (globalConfig != null) {
//取出当前requestFlow
WSDDRequestFlow reqFlow = globalConfig.getRequestFlow();
if (reqFlow != null)
//返回Handler Chain
return reqFlow.getInstance(this);
}
return null;
}
WSDDRequestFlow中的makeNewInstance由父类WSDDChain实现
public Handler makeNewInstance(EngineConfiguration registry)
throws ConfigurationException
{
//new SimpleChain
Chain c = new org.apache.axis.SimpleChain();
for (int n = 0; n < handlers.size(); n++) {
WSDDHandler handler = (WSDDHandler)handlers.get(n);
Handler h = handler.getInstance(registry);
if ( h != null )
//向chain中添加handler
c.addHandler(h);
else
throw new ConfigurationException("……");
}
return c;
}
org.apache.axis.handlers.JWSHandler
在上一篇中已经分析了JWSHandler的用途,主要是针对jws部署方式的处理。
由于JWS部署方式是没有service配置信息的,无法在WSDDDeployment缓存中获取,故通过JWSHandler进行特殊处理。
由于jws方式没有service信息,则通过这个handler完成SOAPService的构造。
//先从jws的soapservices缓存中获取
SOAPService rpc = (SOAPService)soapServices.get(clsName);
if (rpc == null) {
//构造SOAPService,provider为:RPCProvider
rpc = new SOAPService(new RPCProvider());
rpc.setName(clsName);
rpc.setOption(RPCProvider.OPTION_CLASSNAME, clsName );
rpc.setEngine(msgContext.getAxisEngine());
String allowed = (String)getOption(RPCProvider.OPTION_ALLOWEDMETHODS);
if (allowed == null) allowed = "*";
rpc.setOption(RPCProvider.OPTION_ALLOWEDMETHODS, allowed);
String scope = (String)getOption(RPCProvider.OPTION_SCOPE);
if (scope == null) scope = Scope.DEFAULT.getName();
rpc.setOption(RPCProvider.OPTION_SCOPE, scope);
rpc.getInitializedServiceDesc(msgContext);
//缓存当前SOAPService
soapServices.put(clsName, rpc);
}
rpc.setEngine(msgContext.getAxisEngine());
rpc.init(); // ??
msgContext.setService( rpc );
三、service配置handler
回到AxisServer中
//将URLMapper 或者JWSHandler handler中设置的service取出
h = msgContext.getService();
if (h == null) {
Message rm = msgContext.getRequestMessage();
rm.getSOAPEnvelope().getFirstBody();
if (h == null)
……;
}
if( tlog.isDebugEnabled() ) {
t3=System.currentTimeMillis();
}
//初始化soap信息
//比较复杂,通过sax解析request Inputstream。
//有空时再补充说明
initSOAPConstants(msgContext);
try {
//执行service handler chain,包含provider
h.invoke(msgContext);
} catch (AxisFault ae) {
if ((h = getGlobalRequest()) != null ) {
h.onFault(msgContext);
}
throw ae;
}
如果在service中配置了requestFlow,则先执行request handler 的invoke
如果部署的service未配置handler,则直接执行provider handler的invoke
RPCProvider是JavaProvider子类,其invoke由父类JavaProvider实现。
JavaProvider:
public void invoke(MessageContext msgContext) throws AxisFault {
if (log.isDebugEnabled())
log.debug("Enter: JavaProvider::invoke (" + this + ")");
String serviceName = msgContext.getTargetService();
Handler service = msgContext.getService();
//service对应的类名
//jws:即通过javac编译后加载的class类
//wsdd:即通过className配置的class类
String clsName = getServiceClassName(service);
if ((clsName == null) || clsName.equals("")) {
throw new AxisFault("Server.NoClassForService",
Messages.getMessage("noOption00", getServiceClassNameOptionName(), serviceName),
null, null);
}
IntHolder scope = new IntHolder();
Object serviceObject = null;
try {
//通过clsName新建service对应的class实例对象
//未配置scope属性,则默认为request 生命周期
//scope为session属性,则将该对象存储至session中
serviceObject = getServiceObject(msgContext, service, clsName, scope);
SOAPEnvelope resEnv = null;
OperationDesc operation = msgContext.getOperation();
if (operation != null &&
OperationType.ONE_WAY.equals(operation.getMep())) {
msgContext.setResponseMessage(null);
} else {
Message resMsg = msgContext.getResponseMessage();
if (resMsg == null) {
resEnv = new SOAPEnvelope(msgContext.getSOAPConstants(),msgContext.getSchemaVersion());
//构造响应消息体response Message
resMsg = new Message(resEnv);
String encoding = XMLUtils.getEncoding(msgContext);
resMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding);
msgContext.setResponseMessage( resMsg );
} else {
resEnv = resMsg.getSOAPEnvelope();
}
}
Message reqMsg = msgContext.getRequestMessage();
SOAPEnvelope reqEnv = reqMsg.getSOAPEnvelope();
//实际处理交给子类RPCProvider实现
processMessage(msgContext, reqEnv, resEnv, serviceObject);
} catch( SAXException exp ) {
entLog.debug( Messages.getMessage("toAxisFault00"), exp);
Exception real = exp.getException();
if (real == null) {
real = exp;
}
throw AxisFault.makeFault(real);
} catch( Exception exp ) {
entLog.debug( Messages.getMessage("toAxisFault00"), exp);
AxisFault fault = AxisFault.makeFault(exp);
//make a note if this was a runtime fault, for better logging
if (exp instanceof RuntimeException) {
fault.addFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION,
"true");
}
throw fault;
} finally {
// If this is a request scoped service object which implements
// ServiceLifecycle, let it know that it's being destroyed now.
if (serviceObject != null &&
scope.value == Scope.REQUEST.getValue() &&
serviceObject instanceof ServiceLifecycle)
{
((ServiceLifecycle)serviceObject).destroy();
}
}
if (log.isDebugEnabled())
log.debug("Exit: JavaProvider::invoke (" + this + ")");
}
RPCProvider:
public void processMessage(MessageContext msgContext,
SOAPEnvelope reqEnv,
SOAPEnvelope resEnv,
Object obj)
throws Exception {
if (log.isDebugEnabled()) {
log.debug("Enter: RPCProvider.processMessage()");
}
SOAPService service = msgContext.getService();
ServiceDesc serviceDesc = service.getServiceDescription();
RPCElement body = getBody(reqEnv, msgContext);
Vector args = null;
try {
args = body.getParams();
} catch (SAXException e) {
if(e.getException() != null)
throw e.getException();
throw e;
}
int numArgs = args.size();
OperationDesc operation = getOperationDesc(msgContext, body);
// Create the array we'll use to hold the actual parameter
// values. We know how big to make it from the metadata.
Object[] argValues = new Object[operation.getNumParams()];
// A place to keep track of the out params (INOUTs and OUTs)
ArrayList outs = new ArrayList();
// Put the values contained in the RPCParams into an array
// suitable for passing to java.lang.reflect.Method.invoke()
// Make sure we respect parameter ordering if we know about it
// from metadata, and handle whatever conversions are necessary
// (values -> Holders, etc)
for (int i = 0; i < numArgs; i++) {
RPCParam rpcParam = (RPCParam) args.get(i);
Object value = rpcParam.getObjectValue();
// first check the type on the paramter
ParameterDesc paramDesc = rpcParam.getParamDesc();
// if we found some type info try to make sure the value type is
// correct. For instance, if we deserialized a xsd:dateTime in
// to a Calendar and the service takes a Date, we need to convert
if (paramDesc != null && paramDesc.getJavaType() != null) {
// Get the type in the signature (java type or its holder)
Class sigType = paramDesc.getJavaType();
// Convert the value into the expected type in the signature
value = JavaUtils.convert(value, sigType);
rpcParam.setObjectValue(value);
if (paramDesc.getMode() == ParameterDesc.INOUT) {
outs.add(rpcParam);
}
}
// Put the value (possibly converted) in the argument array
// make sure to use the parameter order if we have it
if (paramDesc == null || paramDesc.getOrder() == -1) {
argValues[i] = value;
} else {
argValues[paramDesc.getOrder()] = value;
}
if (log.isDebugEnabled()) {
log.debug(" " + Messages.getMessage("value00",
"" + argValues[i]));
}
}
// See if any subclasses want a crack at faulting on a bad operation
// FIXME : Does this make sense here???
String allowedMethods = (String) service.getOption("allowedMethods");
checkMethodName(msgContext, allowedMethods, operation.getName());
// Now create any out holders we need to pass in
int count = numArgs;
for (int i = 0; i < argValues.length; i++) {
// We are interested only in OUT/INOUT
ParameterDesc param = operation.getParameter(i);
if(param.getMode() == ParameterDesc.IN)
continue;
Class holderClass = param.getJavaType();
if (holderClass != null &&
Holder.class.isAssignableFrom(holderClass)) {
int index = count;
// Use the parameter order if specified or just stick them to the end.
if (param.getOrder() != -1) {
index = param.getOrder();
} else {
count++;
}
// If it's already filled, don't muck with it
if (argValues[index] != null) {
continue;
}
argValues[index] = holderClass.newInstance();
// Store an RPCParam in the outs collection so we
// have an easy and consistent way to write these
// back to the client below
RPCParam p = new RPCParam(param.getQName(),
argValues[index]);
p.setParamDesc(param);
outs.add(p);
} else {
throw new AxisFault(Messages.getMessage("badOutParameter00",
"" + param.getQName(),
operation.getName()));
}
}
// OK! Now we can invoke the method
Object objRes = null;
try {
//该方法完成服务调用
//即通过反射调用执行service中className、以及客户端指定的operation指定的操作名称
//obj:className所对应的实例
//argValues:操作方法包含的参数
objRes = invokeMethod(msgContext,
operation.getMethod(),
obj, argValues);
} catch (IllegalArgumentException e) {
String methodSig = operation.getMethod().toString();
String argClasses = "";
for (int i = 0; i < argValues.length; i++) {
if (argValues[i] == null) {
argClasses += "null";
} else {
argClasses += argValues[i].getClass().getName();
}
if (i + 1 < argValues.length) {
argClasses += ",";
}
}
log.info(Messages.getMessage("dispatchIAE00",
new String[]{methodSig, argClasses}),
e);
throw new AxisFault(Messages.getMessage("dispatchIAE00",
new String[]{methodSig, argClasses}),
e);
}
/** If this is a one-way operation, there is nothing more to do.
*/
if (OperationType.ONE_WAY.equals(operation.getMep()))
return;
//根据返回值构造响应消息体
RPCElement resBody = createResponseBody(body, msgContext, operation, serviceDesc, objRes, resEnv, outs);
resEnv.addBodyElement(resBody);
}
由于时间问题,后面部分分析的比较粗糙
希望以后看到这个,还能记得。