-
1. Re: How to recieve RPC/encoded SOAP messages in JBoss5?
pa12399 Dec 8, 2009 9:14 AM (in response to shadowcreeper)Hi
I am having the exact same issue as well. One of my clients is using RPC encoded in their WSDL, which I am having to call. So, I am unable to port the client into the latest version of JBoss. Any pointers would be greatly appreciated. -
2. Re: How to recieve RPC/encoded SOAP messages in JBoss5?
shadowcreeper Dec 9, 2009 2:47 PM (in response to shadowcreeper)OK, here's what seems to be working for me... It's a horrible hack, but it works...
First, take your WSDL file and turn it into RPC/literal (for me it was as easy as replacing the word "encoded" with "literal").
Next, setup your JBossWS stuff as though you will be receiving RPC/literal documents (from its standpoint, you will).
Now for the tricky part... You will have already setup a servlet (@WebService), which you now need to add an XSLT filter to...
All I had to do to make my SOAP messages understandable to JBossWS was flatten the "multiRef" nodes.
Original SOAP message:<myWebServiceMethod> <myArgumentObject href="#id0"/> </myWebServiceMethod> <multiRef id="id0" ...> <actualGutsOfArgument/> <referencedGutNum2 href="#id2"/> </multiRef> <multiRef id="id2" ...> <moreActualGuts/> </multiRef>
Flattened SOAP message:<myWebServiceMethod> <myArgumentObject id="id0" ...> <actualGutsOfArgument/> <referencedGutNum2 id="id2" ...> <moreActualGuts/> </referencedGutNum2> </myArgumentObject> </myWebServiceMethod>
Note: The only attribute I removed was "href", all of the attributes to the multiRef node became attributes to the node that referenced it (this includes xsi:type info which I believe gets ignored anyway since it is already specified in the XSD file that my WSDL references).
The filter will look something like this:public class MultiRefFlattener implements Filter { private Transformer m_transformer = null; public void init ( FilterConfig filterConfig ) throws ServletException { final String stylePath = filterConfig.getServletContext().getRealPath( "WEB-INF/multi-ref-flattener.xslt" ); final Source styleSource = new StreamSource( stylePath ); final TransformerFactory transformerFactory = TransformerFactory.newInstance(); try { m_transformer = transformerFactory.newTransformer( styleSource ); } catch( TransformerConfigurationException e ) { throw new ServletException( "Error creating XSLT transformer: ", e ); } } public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain chain ) throws IOException, ServletException { final String requestText; try { final CharArrayWriter caw = new CharArrayWriter(); final StreamResult result = new StreamResult(caw); m_transformer.transform(new StreamSource(request.getInputStream()), result); requestText = caw.toString(); } catch( TransformerException e ) { throw new ServletException( "Error filtering data" ); } final ServletInputStream requestStream = new ServletInputStream() { private int m_column = 0; public int read () throws IOException { if( m_column >= requestText.length() ) return -1; final int character = requestText.charAt( m_column ); ++m_column; return character; } }; final HttpServletRequest httpServletRequest = (HttpServletRequest)request; final HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper( httpServletRequest ) { @Override public int getContentLength () { return requestText.length(); } @Override public ServletInputStream getInputStream () throws IOException { return requestStream; } }; chain.doFilter( wrapper, response ); } public void destroy () { m_transformer = null; } }
If anybody has a better way of faking an HttpServletRequest, please let me know.
And here is my flattening XSLT file:<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <xsl:template match="/"> <xsl:call-template name="CopyNode"/> </xsl:template> <xsl:template name="CopyNodeRef"> <xsl:param name="elementName"/> <xsl:param name="hrefId"/> <xsl:copy> <xsl:element name="$elementName"> <xsl:for-each select="//multiRef[@id = $hrefId]/@*"> <xsl:copy> <xsl:apply-templates mode="keeping"/> </xsl:copy> </xsl:for-each> <xsl:for-each select="//multiRef[@id = $hrefId]/node()[not(@href)]"> <xsl:call-template name="CopyNode"/> </xsl:for-each> <xsl:for-each select="//multiRef[@id = $hrefId]/node()[@href]"> <xsl:call-template name="CopyNodeRef"> <xsl:with-param name="elementName" select="name()"/> <xsl:with-param name="hrefId" select="substring(@href, 2)"/> </xsl:call-template> </xsl:for-each> </xsl:element> </xsl:copy> </xsl:template> <xsl:template name="CopyNode"> <xsl:copy> <xsl:call-template name="CopyAttributes"/> <xsl:for-each select="node()[not(@href|@id)]"> <xsl:call-template name="CopyNode"/> </xsl:for-each> <xsl:for-each select="node()[@href]"> <xsl:call-template name="CopyNodeRef"> <xsl:with-param name="elementName" select="name()"/> <xsl:with-param name="hrefId" select="substring(@href, 2)"/> </xsl:call-template> </xsl:for-each> </xsl:copy> </xsl:template> <xsl:template name="CopyAttributes"> <xsl:for-each select="@*"> <xsl:copy> <xsl:apply-templates mode="keeping"/> </xsl:copy> </xsl:for-each> </xsl:template> </xsl:stylesheet>
If anybody has a better idea for a flattener, please let me know.
I hope this helps.
-Shadow