1.服务部署:
1)即时发布
编写java类,去掉包名称,将.java文件类型改成jws。
通过浏览器打开url如:http://localhost:8888/axis/EchoHeaders.jws
点击“Click to see the WSDL”,即可查看所部署服务的WSDL描述文件
2)定制发布
通过deploy.wsdd部署,如:
<service name="AxisService" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="com.axis.service.AxisService"/>
</service>
2.源码解读:
1)初始化AxisEngine:
即所有以jws结尾或者services路径的的URL均由AxisServlet进行处理。
AxisServlet的init方法:
AxisServletBase.init():
AxisServer初始化工作由getOption触发
初始化AxisServer:
首先从当前上下文中获取AxisServer Engine,如果返回为null,则进行初始化并存储至上下文中。
EngineConfigurationFactoryFinder.newFactory(servlet)返回org.apache.axis.configuration.EngineConfigurationFactoryServlet工厂实例,并通过private static EngineConfiguration getServerEngineConfig(ServletConfig cfg)新建EngineConfiguration实现类:FileProvider对象(即server-config.wsdd的文件操作类)
AxisServer类getServer方法充当工厂方法,返回自身对象。但实际新建AxisServer Engine任务是委托AxisServerFactory工厂实例完成。
DefaultAxisServerFactory类getServer方法:
configureEngine完成的任务主要是解析server-config.wsdd服务配置。将配置文件中的各种属性(handler、globalConfiguration、service、transport……)缓存至WSDDDeployment类中。刷新global配置选项即将server-config.wsdd配置文件中globalConfiguration节点中的parameter属性集合由AxisEngine持有。
以上完成了所有初始化工作。
2)通过url打开服务:
在浏览器中打开
http://localhost:8888/axis/EchoHeaders.jws
AxisServlet的doGet方法:
如果是JWS服务,在返回的页面中,点击“Click to see the WSDL”,则产生服务描述XML信息。
该链接对应的url为:http://localhost:8888/axis/EchoHeaders.jws?wsdl
即带有查询条件的url。
上面代码注释中已说明此类url由processQuery(request, response, writer)处理
以上代码主要任务是根据查询条件字符串(即wsdl),通过与server-config.wsdd中transport节点parameter属性匹配,查找对应的handler(即:org.apache.axis.transport.http.QSWSDLHandler)。并通过反射执行QSWSDLHandler的invoke方法
QSWSDLHandler:
AxisEngine的generateWSDL方法:
以上代码主要将生成wsdl任务交给server-config.wsdd所配置的一系列Handler,其执行顺序为
transport【requestFlow】---->globalConfiguration【requestFlow】---->service【requestFlow】---->service【responseFlow】---->globalConfiguration【responseFlow】---->transport【responseFlow】
针对jws的服务通过JWSHandler处理
org.apache.axis.handlers.JWSHandler:
以上代码主要完成将jws转换成java文件,并临时存放至jwsClasses目录中,再通过jdk中的编译器sun.tools.javac.Main、com.sun.tools.javac.main.Main对java文件进行编译,将编译后的class文件存放至jwsClasses目录中,删除临时java文件,并将生成的class二进制文件加载至类加载器中。
rpc = new SOAPService(new RPCProvider());
增加Handler实例RPCProvider(继承BasicProvider)到当前handler链中
BasicProvider generateWSDL:
由于RPCProvider添加至handler链中,故也需完成generateWSDL任务。该任务由父类
BasicProvider完成。实际生成WSDL的任务委托至Emitter类处理
至此,整个服务部署以及WSDL描述算是梳理完毕。
1)即时发布
编写java类,去掉包名称,将.java文件类型改成jws。
通过浏览器打开url如:http://localhost:8888/axis/EchoHeaders.jws
点击“Click to see the WSDL”,即可查看所部署服务的WSDL描述文件
2)定制发布
通过deploy.wsdd部署,如:
<service name="AxisService" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="com.axis.service.AxisService"/>
</service>
2.源码解读:
1)初始化AxisEngine:
<servlet>
<servlet-name>AxisServlet</servlet-name>
<display-name>Apache-Axis Servlet</display-name>
<servlet-class>
org.apache.axis.transport.http.AxisServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
即所有以jws结尾或者services路径的的URL均由AxisServlet进行处理。
AxisServlet的init方法:
public void init() throws javax.servlet.ServletException {
//super.init()即执行父类AxisServletBase的init方法,完成AxisServer初始化工作
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);
disableServicesList = JavaUtils.isTrue(getOption(context,
INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));
servicesPath = getOption(context, INIT_PROPERTY_SERVICES_PATH,
"/services/");
if (jwsClassDir != null) {
if (getHomeDir() != null) {
jwsClassDir = getHomeDir() + jwsClassDir;
}
} else {
jwsClassDir = getDefaultJWSClassDir();
}
//初始化查询Handler,即wsdl对应的handler,用于wsdl文件生成
initQueryStringHandlers();
// Setup the service admin
try {
ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo());
} catch (AxisFault af) {
exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " +
af);
}
}
AxisServletBase.init():
public void init() throws javax.servlet.ServletException {
ServletContext context = getServletConfig().getServletContext();
webInfPath = context.getRealPath("/WEB-INF");
homeDir = context.getRealPath("/");
isDebug = log.isDebugEnabled();
if(log.isDebugEnabled()) log.debug("In AxisServletBase init");
//触发AxisServer的初始化
isDevelopment= JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_DEVELOPMENT_SYSTEM, null));
}
AxisServer初始化工作由getOption触发
protected String getOption(ServletContext context,
String param,
String dephault)
{
String value = AxisProperties.getProperty(param);
if (value == null)
value = getInitParameter(param);
if (value == null)
value = context.getInitParameter(param);
try {
//初始化AxisServer
AxisServer engine = getEngine(this);
if (value == null && engine != null)
value = (String) engine.getOption(param);
} catch (AxisFault axisFault) {
}
return (value != null) ? value : dephault;
}
初始化AxisServer:
public static AxisServer getEngine(HttpServlet servlet) throws AxisFault
{
AxisServer engine = null;
if (isDebug)
log.debug("Enter: getEngine()");
ServletContext context = servlet.getServletContext();
synchronized (context) {
engine = retrieveEngine(servlet);
if (engine == null) {
//配置Engine环境
Map environment = getEngineEnvironment(servlet);
//初始化AxisServer Engine
engine = AxisServer.getServer(environment);
engine.setName(servlet.getServletName());
//存储AxisServer Engine至上下文
storeEngine(servlet, engine);
}
}
if (isDebug)
log.debug("Exit: getEngine()");
return engine;
}
首先从当前上下文中获取AxisServer Engine,如果返回为null,则进行初始化并存储至上下文中。
protected static Map getEngineEnvironment(HttpServlet servlet) {
Map environment = new HashMap();
String attdir= servlet.getInitParameter(AxisEngine.ENV_ATTACHMENT_DIR);
if (attdir != null)
environment.put(AxisEngine.ENV_ATTACHMENT_DIR, attdir);
ServletContext context = servlet.getServletContext();
environment.put(AxisEngine.ENV_SERVLET_CONTEXT, context);
String webInfPath = context.getRealPath("/WEB-INF");
if (webInfPath != null)
environment.put(AxisEngine.ENV_SERVLET_REALPATH,
webInfPath + File.separator + "attachments");
EngineConfiguration config =
EngineConfigurationFactoryFinder.newFactory(servlet)
.getServerEngineConfig();
if (config != null) {
environment.put(EngineConfiguration.PROPERTY_NAME, config);
}
return environment;
}
EngineConfigurationFactoryFinder.newFactory(servlet)返回org.apache.axis.configuration.EngineConfigurationFactoryServlet工厂实例,并通过private static EngineConfiguration getServerEngineConfig(ServletConfig cfg)新建EngineConfiguration实现类:FileProvider对象(即server-config.wsdd的文件操作类)
AxisServer类getServer方法充当工厂方法,返回自身对象。但实际新建AxisServer Engine任务是委托AxisServerFactory工厂实例完成。
public static AxisServer getServer(Map environment) throws AxisFault
{
if (factory == null) {
String factoryClassName = AxisProperties.getProperty("axis.ServerFactory");
if (factoryClassName != null) {
try {
Class factoryClass = ClassUtils.forName(factoryClassName);
if (AxisServerFactory.class.isAssignableFrom(factoryClass))
factory = (AxisServerFactory)factoryClass.newInstance();
} catch (Exception e) {
// If something goes wrong here, should we just fall
// through and use the default one?
log.error(Messages.getMessage("exception00"), e);
}
}
if (factory == null) {
//通过默认工厂新建Server Engine
factory = new DefaultAxisServerFactory();
}
}
return factory.getServer(environment);
}
DefaultAxisServerFactory类getServer方法:
public AxisServer getServer(Map environment) throws AxisFault {
log.debug("Enter: DefaultAxisServerFactory::getServer");
AxisServer ret = createServer(environment);
if (ret != null) {
if (environment != null) {
ret.setOptionDefault(AxisEngine.PROP_ATTACHMENT_DIR,
(String)environment.get(AxisEngine.ENV_ATTACHMENT_DIR));
ret.setOptionDefault(AxisEngine.PROP_ATTACHMENT_DIR,
(String)environment.get(AxisEngine.ENV_SERVLET_REALPATH));
}
String attachmentsdir = (String)ret.getOption(AxisEngine.PROP_ATTACHMENT_DIR);
if (attachmentsdir != null) {
File attdirFile = new File(attachmentsdir);
if (!attdirFile.isDirectory()) {
attdirFile.mkdirs();
}
}
}
log.debug("Exit: DefaultAxisServerFactory::getServer");
return ret;
}
private static AxisServer createServer(Map environment) {
//从Map环境中取出FileProvider对象
EngineConfiguration config = getEngineConfiguration(environment);
//通过AxisServer(EngineConfiguration config)构造函数新建对象
return (config == null) ? new AxisServer() : new AxisServer(config);
}
public AxisServer(EngineConfiguration config)
{
//Engine的初始化由父类AxisEngine完成
super(config);
// 服务端默认是保存配置
setShouldSaveConfig(true);
}
public void init() {
if (log.isDebugEnabled()) {
log.debug("Enter: AxisEngine::init");
}
try {
//通过FileProvider类配置Engine
config.configureEngine(this);
} catch (Exception e) {
throw new InternalException(e);
}
setOptionDefault(PROP_ATTACHMENT_IMPLEMENTATION,
AxisProperties.getProperty("axis." + PROP_ATTACHMENT_IMPLEMENTATION ));
setOptionDefault(PROP_ATTACHMENT_IMPLEMENTATION, DEFAULT_ATTACHMENT_IMPL);
final Object dotnet = getOption(PROP_DOTNET_SOAPENC_FIX);
if (JavaUtils.isTrue(dotnet)) {
TypeMappingImpl.dotnet_soapenc_bugfix = true;
}
if (log.isDebugEnabled()) {
log.debug("Exit: AxisEngine::init");
}
}
public void configureEngine(AxisEngine engine)
throws ConfigurationException {
try {
if (getInputStream() == null) {
try {
setInputStream(new FileInputStream(configFile));
} catch (Exception e) {
if (searchClasspath)
setInputStream(ClassUtils.getResourceAsStream(engine.getClass(), filename, true));
}
}
if (getInputStream() == null) {
throw new ConfigurationException(
Messages.getMessage("noConfigFile"));
}
//初始化deployment
WSDDDocument doc = new WSDDDocument(XMLUtils.
newDocument(getInputStream()));
deployment = doc.getDeployment();
//deployment持有Engine引用
deployment.configureEngine(engine);
//刷新global配置选项
engine.refreshGlobalOptions();
setInputStream(null);
} catch (Exception e) {
throw new ConfigurationException(e);
}
}
configureEngine完成的任务主要是解析server-config.wsdd服务配置。将配置文件中的各种属性(handler、globalConfiguration、service、transport……)缓存至WSDDDeployment类中。刷新global配置选项即将server-config.wsdd配置文件中globalConfiguration节点中的parameter属性集合由AxisEngine持有。
以上完成了所有初始化工作。
2)通过url打开服务:
在浏览器中打开
http://localhost:8888/axis/EchoHeaders.jws
AxisServlet的doGet方法:
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();
}
boolean isJWSPage = request.getRequestURI().endsWith(".jws");
if (isJWSPage) {
pathInfo = request.getServletPath();
}
//判断是否存在查询。即server-config.wsdd的transport节点
//配置的parameter查询条件(list/method/wsdl)
//如url:http://localhost:8888/axis/EchoHeaders.jws?wsdl
//如url:http://localhost:8888/services/AxisService?wsdl
//这样doGet直接生成wsdl描述信息至浏览器端
if (processQuery(request, response, writer) == true) {
return;
}
boolean hasNoPath = (pathInfo == null || pathInfo.equals(""));
if (!disableServicesList) {
if(hasNoPath) {
reportAvailableServices(response, writer, request);
} else if (realpath != null) {
MessageContext msgContext = createMessageContext(engine,request, response);
String url = HttpUtils.getRequestURL(request).toString();
msgContext.setProperty(MessageContext.TRANS_URL, url);
String serviceName;
if (pathInfo.startsWith("/")) {
serviceName = pathInfo.substring(1);
} else {
serviceName = pathInfo;
}
//从WSDDDeployment的services缓存中取service
SOAPService s = engine.getService(serviceName);
if (s == null) {
if (isJWSPage) {
//生成Click to see the WSDL连接的页面
reportCantGetJWSService(request, response, writer);
} else {
reportCantGetAxisService(request, response, writer);
}
} else {
reportServiceInfo(response, writer, s, serviceName);
}
}
} else {
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()");
}
}
}
如果是JWS服务,在返回的页面中,点击“Click to see the WSDL”,则产生服务描述XML信息。
该链接对应的url为:http://localhost:8888/axis/EchoHeaders.jws?wsdl
即带有查询条件的url。
上面代码注释中已说明此类url由processQuery(request, response, writer)处理
private boolean processQuery(HttpServletRequest request,
HttpServletResponse response,
PrintWriter writer) throws AxisFault {
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) {
String handlerName = queryHandler.substring
(queryHandler.indexOf(".") + 1).
toLowerCase();
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) {
if (this.transport.getOption(queryHandler).equals("")) {
return false;
}
try {
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();
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);
pluginMethod.invoke(plugin.newInstance(),
new Object[] {msgContext});
writer.close();
return true;
} catch (InvocationTargetException ie) {
reportTroubleInGet(ie.getTargetException(), response,writer);
return true;
} catch (Exception e) {
reportTroubleInGet(e, response, writer);
return true;
}
}
}
}
return false;
}
以上代码主要任务是根据查询条件字符串(即wsdl),通过与server-config.wsdd中transport节点parameter属性匹配,查找对应的handler(即:org.apache.axis.transport.http.QSWSDLHandler)。并通过反射执行QSWSDLHandler的invoke方法
QSWSDLHandler:
public void invoke(MessageContext msgContext) throws AxisFault {
// Obtain objects relevant to the task at hand from the provided
// MessageContext's bag.
configureFromContext(msgContext);
AxisServer engine = (AxisServer) msgContext.getProperty
(HTTPConstants.PLUGIN_ENGINE);
PrintWriter writer = (PrintWriter) msgContext.getProperty
(HTTPConstants.PLUGIN_WRITER);
HttpServletResponse response = (HttpServletResponse)
msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE);
try {
//生成WSDL服务描述信息
engine.generateWSDL(msgContext);
Document wsdlDoc = (Document) msgContext.getProperty("WSDL");
if (wsdlDoc != null) {
try {
updateSoapAddressLocationURLs(wsdlDoc, msgContext);
} catch (RuntimeException re) {
log.warn(
"Failed to update soap:address location URL(s) in WSDL.",
re);
}
response.setContentType(
"text/xml; charset=" +
XMLUtils.getEncoding().toLowerCase());
//将描述信息XML通过writer输出至浏览器端
reportWSDL(wsdlDoc, writer);
} else {
if (log.isDebugEnabled()) {
log.debug("processWsdlRequest: failed to create WSDL");
}
reportNoWSDL(response, writer, "noWSDL02", null);
}
} catch (AxisFault axisFault) {
//the no-service fault is mapped to a no-wsdl error
if (axisFault.getFaultCode().equals
(Constants.QNAME_NO_SERVICE_FAULT_CODE)) {
//which we log
processAxisFault(axisFault);
//then report under a 404 error
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
reportNoWSDL(response, writer, "noWSDL01", axisFault);
} else {
//all other faults get thrown
throw axisFault;
}
}
}
AxisEngine的generateWSDL方法:
public void generateWSDL(MessageContext msgContext) throws AxisFault {
if (log.isDebugEnabled()) {
log.debug("Enter: AxisServer::generateWSDL");
}
if (!isRunning()) {
throw new AxisFault("Server.disabled",
Messages.getMessage("serverDisabled00"),
null, null);
}
String hName = null ;
Handler h = null ;
// save previous context
MessageContext previousContext = getCurrentMessageContext();
try {
// set active context
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 ) {
throw new AxisFault(
"Server.error",
Messages.getMessage("noHandler00", hName),
null, null );
}
}
h.generateWSDL(msgContext);
}
else {
hName = msgContext.getStrProp(MessageContext.TRANSPORT);
if ( hName != null ) {
if ((h = hr.find( hName )) != null ) {
h.generateWSDL(msgContext);
} else {
log.error(Messages.getMessage("noTransport02", hName));
}
} else {
defaultTransport.generateWSDL(msgContext);
}
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.generateWSDL(msgContext);
}
}
}
if ((h = getGlobalRequest()) != null )
h.generateWSDL(msgContext);
h = msgContext.getService();
if (h == null) {
Message rm = msgContext.getRequestMessage();
if (rm != null) {
rm.getSOAPEnvelope().getFirstBody();
h = msgContext.getService();
}
if (h == null) {
……
}
}
h.generateWSDL(msgContext);
if ((h = getGlobalResponse()) != null )
h.generateWSDL(msgContext);
if (transportChain != null) {
h = transportChain.getResponseHandler();
if (h != null) {
h.generateWSDL(msgContext);
}
}
}
} catch (AxisFault e) {
throw e;
} catch(Exception e) {
throw AxisFault.makeFault(e);
} finally {
setCurrentMessageContext(previousContext);
}
}
以上代码主要将生成wsdl任务交给server-config.wsdd所配置的一系列Handler,其执行顺序为
transport【requestFlow】---->globalConfiguration【requestFlow】---->service【requestFlow】---->service【responseFlow】---->globalConfiguration【responseFlow】---->transport【responseFlow】
针对jws的服务通过JWSHandler处理
org.apache.axis.handlers.JWSHandler:
public void generateWSDL(MessageContext msgContext) throws AxisFault {
try {
setupService(msgContext);
} catch (Exception e) {
log.error( Messages.getMessage("exception00"), e );
throw AxisFault.makeFault(e);
}
}
protected void setupService(MessageContext msgContext) throws Exception {
// FORCE the targetService to be JWS if the URL is right.
String realpath = msgContext.getStrProp(Constants.MC_REALPATH);
String extension = (String)getOption(OPTION_JWS_FILE_EXTENSION);
if (extension == null) extension = DEFAULT_JWS_FILE_EXTENSION;
if ((realpath!=null) && (realpath.endsWith(extension))) {
/* Grab the *.jws filename from the context - should have been */
/* placed there by another handler (ie. HTTPActionHandler) */
/***************************************************************/
String jwsFile = realpath;
String rel = msgContext.getStrProp(Constants.MC_RELATIVE_PATH);
// Check for file existance, report error with
// relative path to avoid giving out directory info.
File f2 = new File( jwsFile );
if (!f2.exists()) {
throw new FileNotFoundException(rel);
}
if (rel.charAt(0) == '/') {
rel = rel.substring(1);
}
int lastSlash = rel.lastIndexOf('/');
String dir = null;
if (lastSlash > 0) {
dir = rel.substring(0, lastSlash);
}
String file = rel.substring(lastSlash + 1);
String outdir = msgContext.getStrProp( Constants.MC_JWS_CLASSDIR );
if ( outdir == null ) outdir = "." ;
// Build matching directory structure under the output
// directory. In other words, if we have:
// /webroot/jws1/Foo.jws
//
// That will be compiled to:
// .../jwsOutputDirectory/jws1/Foo.class
if (dir != null) {
outdir = outdir + File.separator + dir;
}
// Confirm output directory exists. If not, create it IF we're
// allowed to.
// !!! TODO: add a switch to control this.
File outDirectory = new File(outdir);
if (!outDirectory.exists()) {
outDirectory.mkdirs();
}
if (log.isDebugEnabled())
log.debug("jwsFile: " + jwsFile );
String jFile = outdir + File.separator + file.substring(0, file.length()-extension.length()+1) +
"java" ;
String cFile = outdir + File.separator + file.substring(0, file.length()-extension.length()+1) +
"class" ;
if (log.isDebugEnabled()) {
log.debug("jFile: " + jFile );
log.debug("cFile: " + cFile );
log.debug("outdir: " + outdir);
}
File f1 = new File( cFile );
/* Get the class */
/*****************/
String clsName = null ;
//clsName = msgContext.getStrProp(Constants.MC_RELATIVE_PATH);
if ( clsName == null ) clsName = f2.getName();
if ( clsName != null && clsName.charAt(0) == '/' )
clsName = clsName.substring(1);
clsName = clsName.substring( 0, clsName.length()-extension.length() );
clsName = clsName.replace('/', '.');
if (log.isDebugEnabled())
log.debug("ClsName: " + clsName );
/* Check to see if we need to recompile */
/****************************************/
if ( !f1.exists() || f2.lastModified() > f1.lastModified() ) {
/* If the class file doesn't exist, or it's older than the */
/* java file then recompile the java file. */
/* Start by copying the *.jws file to *.java */
/***********************************************************/
log.debug(Messages.getMessage("compiling00", jwsFile) );
log.debug(Messages.getMessage("copy00", jwsFile, jFile) );
FileReader fr = new FileReader( jwsFile );
FileWriter fw = new FileWriter( jFile );
char[] buf = new char[4096];
int rc ;
while ( (rc = fr.read( buf, 0, 4095)) >= 0 )
fw.write( buf, 0, rc );
fw.close();
fr.close();
/* Now run javac on the *.java file */
/************************************/
log.debug("javac " + jFile );
// Process proc = rt.exec( "javac " + jFile );
// proc.waitFor();
//获取编译器(默认:sun.tools.javac.Main,com.sun.tools.javac.main.Main)
Compiler compiler = CompilerFactory.getCompiler();
compiler.setClasspath(ClasspathUtils.getDefaultClasspath(msgContext));
compiler.setDestination(outdir);
compiler.addFile(jFile);
boolean result = compiler.compile();
/* Delete the temporary *.java file and check return code */
/**********************************************************/
(new File(jFile)).delete();
if ( !result ) {
/* Delete the *class file - sometimes it gets created even */
/* when there are errors - so erase it so it doesn't */
/* confuse us. */
/***********************************************************/
(new File(cFile)).delete();
Document doc = XMLUtils.newDocument();
Element root = doc.createElementNS("", "Errors");
StringBuffer message = new StringBuffer("Error compiling ");
message.append(jFile);
message.append(":\n");
List errors = compiler.getErrors();
int count = errors.size();
for (int i = 0; i < count; i++) {
CompilerError error = (CompilerError) errors.get(i);
if (i > 0) message.append("\n");
message.append("Line ");
message.append(error.getStartLine());
message.append(", column ");
message.append(error.getStartColumn());
message.append(": ");
message.append(error.getMessage());
}
root.appendChild( doc.createTextNode( message.toString() ) );
throw new AxisFault( "Server.compileError",
Messages.getMessage("badCompile00", jFile),
null, new Element[] { root } );
}
ClassUtils.removeClassLoader( clsName );
// And clean out the cached service.
soapServices.remove(clsName);
}
ClassLoader cl = ClassUtils.getClassLoader(clsName);
if (cl == null) {
cl = new JWSClassLoader(clsName,
msgContext.getClassLoader(),
cFile);
}
msgContext.setClassLoader(cl);
/* Create a new RPCProvider - this will be the "service" */
/* that we invoke. */
/******************************************************************/
// Cache the rpc service created to handle the class. The cache
// is based on class name, so only one .jws/.jwr class can be active
// in the system at a time.
SOAPService rpc = (SOAPService)soapServices.get(clsName);
if (rpc == null) {
rpc = new SOAPService(new RPCProvider());
rpc.setName(clsName);
rpc.setOption(RPCProvider.OPTION_CLASSNAME, clsName );
rpc.setEngine(msgContext.getAxisEngine());
// Support specification of "allowedMethods" as a parameter.
String allowed = (String)getOption(RPCProvider.OPTION_ALLOWEDMETHODS);
if (allowed == null) allowed = "*";
rpc.setOption(RPCProvider.OPTION_ALLOWEDMETHODS, allowed);
// Take the setting for the scope option from the handler
// parameter named "scope"
String scope = (String)getOption(RPCProvider.OPTION_SCOPE);
if (scope == null) scope = Scope.DEFAULT.getName();
rpc.setOption(RPCProvider.OPTION_SCOPE, scope);
rpc.getInitializedServiceDesc(msgContext);
soapServices.put(clsName, rpc);
}
// Set engine, which hooks up type mappings.
rpc.setEngine(msgContext.getAxisEngine());
rpc.init(); // ??
// OK, this is now the destination service!
msgContext.setService( rpc );
}
if (log.isDebugEnabled()) {
log.debug("Exit: JWSHandler::invoke");
}
}
以上代码主要完成将jws转换成java文件,并临时存放至jwsClasses目录中,再通过jdk中的编译器sun.tools.javac.Main、com.sun.tools.javac.main.Main对java文件进行编译,将编译后的class文件存放至jwsClasses目录中,删除临时java文件,并将生成的class二进制文件加载至类加载器中。
rpc = new SOAPService(new RPCProvider());
增加Handler实例RPCProvider(继承BasicProvider)到当前handler链中
BasicProvider generateWSDL:
public void generateWSDL(MessageContext msgContext) throws AxisFault {
if (log.isDebugEnabled())
log.debug("Enter: BasicProvider::generateWSDL (" + this +")");
SOAPService service = msgContext.getService();
ServiceDesc serviceDesc = service.getInitializedServiceDesc(msgContext);
try {
// Location URL is whatever is explicitly set in the MC
String locationUrl = msgContext.getStrProp(MessageContext.WSDLGEN_SERV_LOC_URL);
if (locationUrl == null) {
// If nothing, try what's explicitly set in the ServiceDesc
locationUrl = serviceDesc.getEndpointURL();
}
if (locationUrl == null) {
// If nothing, use the actual transport URL
locationUrl = msgContext.getStrProp(MessageContext.TRANS_URL);
}
// Interface namespace is whatever is explicitly set
String interfaceNamespace = msgContext.getStrProp(MessageContext.WSDLGEN_INTFNAMESPACE);
if (interfaceNamespace == null) {
// If nothing, use the default namespace of the ServiceDesc
interfaceNamespace = serviceDesc.getDefaultNamespace();
}
if (interfaceNamespace == null) {
// If nothing still, use the location URL determined above
interfaceNamespace = locationUrl;
}
Emitter emitter = new Emitter();
String alias = (String) service.getOption("alias");
if (alias != null)
emitter.setServiceElementName(alias);
// Set style/use
emitter.setStyle(serviceDesc.getStyle());
emitter.setUse(serviceDesc.getUse());
if (serviceDesc instanceof JavaServiceDesc) {
emitter.setClsSmart(((JavaServiceDesc)serviceDesc).getImplClass(),
locationUrl);
}
// If a wsdl target namespace was provided, use the targetNamespace.
// Otherwise use the interfaceNamespace constructed above.
String targetNamespace = (String) service.getOption(OPTION_WSDL_TARGETNAMESPACE);
if (targetNamespace == null || targetNamespace.length() == 0) {
targetNamespace = interfaceNamespace;
}
emitter.setIntfNamespace(targetNamespace);
emitter.setLocationUrl(locationUrl);
emitter.setServiceDesc(serviceDesc);
emitter.setTypeMappingRegistry(msgContext.getTypeMappingRegistry());
String wsdlPortType = (String) service.getOption(OPTION_WSDL_PORTTYPE);
String wsdlServiceElement = (String) service.getOption(OPTION_WSDL_SERVICEELEMENT);
String wsdlServicePort = (String) service.getOption(OPTION_WSDL_SERVICEPORT);
String wsdlInputSchema = (String) service.getOption(OPTION_WSDL_INPUTSCHEMA);
String wsdlSoapActinMode = (String) service.getOption(OPTION_WSDL_SOAPACTION_MODE);
String extraClasses = (String) service.getOption(OPTION_EXTRACLASSES);
if (wsdlPortType != null && wsdlPortType.length() > 0) {
emitter.setPortTypeName(wsdlPortType);
}
if (wsdlServiceElement != null && wsdlServiceElement.length() > 0) {
emitter.setServiceElementName(wsdlServiceElement);
}
if (wsdlServicePort != null && wsdlServicePort.length() > 0) {
emitter.setServicePortName(wsdlServicePort);
}
if (wsdlInputSchema != null && wsdlInputSchema.length() > 0) {
emitter.setInputSchema(wsdlInputSchema);
}
if (wsdlSoapActinMode != null && wsdlSoapActinMode.length() > 0) {
emitter.setSoapAction(wsdlSoapActinMode);
}
if (extraClasses != null && extraClasses.length() > 0) {
emitter.setExtraClasses(extraClasses);
}
if (msgContext.isPropertyTrue(AxisEngine.PROP_EMIT_ALL_TYPES)) {
emitter.setEmitAllTypes(true);
}
Document doc = emitter.emit(Emitter.MODE_ALL);
msgContext.setProperty("WSDL", doc);
} catch (NoClassDefFoundError e) {
entLog.info(Messages.getMessage("toAxisFault00"), e);
throw new AxisFault(e.toString(), e);
} catch (Exception e) {
entLog.info(Messages.getMessage("toAxisFault00"), e);
throw AxisFault.makeFault(e);
}
if (log.isDebugEnabled())
log.debug("Exit: BasicProvider::generateWSDL (" + this +")");
}
由于RPCProvider添加至handler链中,故也需完成generateWSDL任务。该任务由父类
BasicProvider完成。实际生成WSDL的任务委托至Emitter类处理
至此,整个服务部署以及WSDL描述算是梳理完毕。