package railo.runtime.net.rpc.server; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; 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.namespace.QName; 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.SimpleChain; import org.apache.axis.SimpleTargetedChain; import org.apache.axis.components.logger.LogFactory; import org.apache.axis.encoding.TypeMappingRegistry; import org.apache.axis.management.ServiceAdmin; import org.apache.axis.security.servlet.ServletSecurityProvider; import org.apache.axis.server.AxisServer; import org.apache.axis.transport.http.AxisHttpSession; import org.apache.axis.transport.http.FilterPrintWriter; import org.apache.axis.transport.http.HTTPConstants; import org.apache.axis.transport.http.ServletEndpointContextImpl; import org.apache.axis.utils.Messages; import org.apache.commons.logging.Log; import org.w3c.dom.Element; import railo.commons.io.IOUtil; import railo.commons.lang.ClassException; import railo.commons.lang.ClassUtil; import railo.runtime.Component; import railo.runtime.exp.PageException; import railo.runtime.exp.PageServletException; import railo.runtime.net.http.ReqRspUtil; import railo.runtime.net.rpc.TypeMappingUtil; import railo.runtime.op.Caster; /** * 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>. */ public final class RPCServer{ protected static Log log =LogFactory.getLog(RPCServer.class.getName()); private static Log tlog =LogFactory.getLog(Constants.TIME_LOG_CATEGORY); 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"; public static final String INIT_PROPERTY_DISABLE_SERVICES_LIST ="axis.disableServiceList"; public static final String INIT_PROPERTY_SERVICES_PATH ="axis.servicesPath"; private Handler transport; private ServletSecurityProvider securityProvider = null; private ServletContext context; private String webInfPath; private String homeDir; private AxisServer axisServer; private org.apache.axis.encoding.TypeMapping typeMapping; private static boolean isDevelopment=false; private static boolean isDebug = false; private static Map servers=new WeakHashMap(); /** * Initialization method. * @throws AxisFault */ private RPCServer(ServletContext context) throws AxisFault { this.context=context; initQueryStringHandlers(); ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo()); webInfPath = context.getRealPath("/WEB-INF"); homeDir = ReqRspUtil.getRootPath(context); } /** * Process GET requests. This includes handoff of pseudo-SOAP requests * * @param request request in * @param response request out * @throws ServletException */ public void doGet(HttpServletRequest request, HttpServletResponse response, Component component) throws ServletException { PrintWriter writer = new FilterPrintWriter(response); try { if (!doGet(request, response, writer,component)) { response.setContentType("text/html; charset=utf-8"); writer.println("<html><h1>Railo Webservice</h1>"); writer.println(Messages.getMessage("reachedServlet00")); writer.println("<p>" + Messages.getMessage("transportName00","<b>http</b>")); writer.println("</html>"); } } catch (Throwable e) { if(e instanceof InvocationTargetException) e= ((InvocationTargetException)e).getTargetException(); if(e instanceof PageException) throw new PageServletException((PageException)e); throw new ServletException(e); } } /** * 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. */ private 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 */ private void logException(Throwable e) { exceptionLog.info(Messages.getMessage("exception00"), e); } /* * * print a snippet of service info. * @param service service * @param writer output channel * @param serviceName where to put stuff * / private 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>"); }*/ /** * 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, Component component) throws ServletException, IOException { long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0; String soapAction = null; MessageContext msgContext = null; Message responseMsg = null; String contentType = null; InputStream is=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,component); // ? 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); } is=req.getInputStream(); Message requestMsg = new Message(is, 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)); 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."); } 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 (Throwable t) { if(t instanceof InvocationTargetException) t=((InvocationTargetException)t).getTargetException(); // Exception if(t instanceof Exception) { Exception e=(Exception) t; //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); } // throwable else { 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); } } finally { IOUtil.closeEL(is); } 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()"); } 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) { 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. */ private int getHttpServletResponseStatus(AxisFault af) { // 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!"); } } else { if (isDebug) { log.debug("Returned Content-Type:" + contentType); } try { res.setContentType(contentType); 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, Component component) { 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(homeDir)); log.debug("Constants.MC_RELATIVE_PATH:" + requestPath); log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" +String.valueOf(webInfPath)); 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(webInfPath)); } /* Set the Transport */ /*********************/ msgContext.setTransportName("http"); /* 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, homeDir); 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,webInfPath); msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO,req.getPathInfo()); msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION,req.getHeader(HTTPConstants.HEADER_AUTHORIZATION)); msgContext.setProperty(railo.runtime.net.rpc.server.Constants.COMPONENT, component); 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 = context.getRealPath(requestPath); if (realpath != null) { msgContext.setProperty(Constants.MC_REALPATH, realpath); } msgContext.setProperty(Constants.MC_CONFIGPATH, webInfPath); 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; } /** * Initialize a Handler for the transport defined in the Axis server config. * This includes optionally filling in query string handlers. */ public void initQueryStringHandlers() { 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"); } private boolean doGet(HttpServletRequest request,HttpServletResponse response,PrintWriter writer,Component component) throws AxisFault, ClassException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { String path = request.getServletPath(); String queryString = request.getQueryString(); AxisEngine engine = getEngine(); Iterator i = this.transport.getOptions().keySet().iterator(); if (queryString == null) { return false; } String servletURI = request.getContextPath() + path; String reqURI = request.getRequestURI(); // service name String serviceName; if (servletURI.length() + 1 < reqURI.length()) { serviceName = reqURI.substring(servletURI.length() + 1); } else { serviceName = ""; } while (i.hasNext()) { String queryHandler = (String) i.next(); //print.ln("queryhandler:"+queryHandler); if (queryHandler.startsWith("qs.")) { // Only attempt to match the query string with transport // parameters prefixed with "qs:". String handlerName = queryHandler.substring (queryHandler.indexOf(".") + 1). toLowerCase(); //print.ln("handlerName:"+handlerName); // 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; } // Attempt to dynamically load the query string handler // and its "invoke" method. MessageContext msgContext = createMessageContext(engine,request, response,component); Class plugin=ClassUtil.loadClass((String)this.transport.getOption(queryHandler)); Method pluginMethod = plugin.getDeclaredMethod("invoke", new Class[] {msgContext.getClass()}); msgContext.setProperty(MessageContext.TRANS_URL, HttpUtils.getRequestURL(request).toString()); //msgContext.setProperty(MessageContext.TRANS_URL, "http://DefaultNamespace"); msgContext.setProperty(HTTPConstants.PLUGIN_SERVICE_NAME, serviceName); msgContext.setProperty(HTTPConstants.PLUGIN_NAME,handlerName); msgContext.setProperty(HTTPConstants.PLUGIN_IS_DEVELOPMENT,Caster.toBoolean(isDevelopment)); msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,Boolean.FALSE); 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(ClassUtil.loadInstance(plugin),new Object[] {msgContext}); writer.close(); 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() : ""); } /** * get the engine for this Server from cache or context * @return * @throws AxisFault */ public AxisServer getEngine() throws AxisFault { if (axisServer == null) { synchronized (context) { Map environment = new HashMap(); environment.put(AxisEngine.ENV_SERVLET_CONTEXT, context); axisServer = AxisServer.getServer(environment); axisServer.setName("RailoCFC"); } // add Component Handler try { SimpleChain sc=(SimpleChain) axisServer.getGlobalRequest(); sc.addHandler(new ComponentHandler()); } catch (ConfigurationException e) { throw AxisFault.makeFault(e); } TypeMappingUtil.registerDefaults(axisServer.getTypeMappingRegistry()); } return axisServer; } public static RPCServer getInstance(int id, ServletContext servletContext) throws AxisFault { RPCServer server=(RPCServer) servers.get(Caster.toString(id)); if(server==null){ servers.put(Caster.toString(id), server=new RPCServer(servletContext)); } return server; } public void registerTypeMapping(Class clazz) { String fullname = clazz.getName();//,name,packages; QName qname = new QName("http://DefaultNamespace",fullname); registerTypeMapping(clazz, qname); } private void registerTypeMapping(Class clazz,QName qname) { TypeMappingRegistry reg = axisServer.getTypeMappingRegistry(); org.apache.axis.encoding.TypeMapping tm; tm=reg.getOrMakeTypeMapping("http://schemas.xmlsoap.org/soap/encoding/"); Class c = tm.getClassForQName(qname); if(c!=null && c!=clazz) { tm.removeDeserializer(c, qname); tm.removeSerializer(c, qname); } TypeMappingUtil.registerBeanTypeMapping(tm,clazz, qname); } }