I have been trying for a few days to get a JBoss web service using reliable messaging and ws addressing to talk to an M$ client. There are lots of useful tuts on the topic, but nothing that showed all the bits which I needed to set up. I have it working, so I figured I would post the important bits for other folks to see.
I am using the following stacks:
JBoss 5.0.1 running on Fedora 10
Jbossws-CXF 3.1.0
Visual Studio 2008 running on Server 2003
The combination which seems to work is
Soap 1.1 or 1.2
Reliable Messaging 1.0 (February 2005 version)
Addressing 1.0 (August 2004 version)
My Service is a standard EJB using annotaitons to link to the handcrafted wsdl. It seems that you need to use handcrafted wsdl to do anything interesting. Here is the web service definition:
package com.redhat.vdc.backend;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.wsf.spi.annotation.WebContext;
import com.redhat.vdc.action.VdcActionParameters;
import com.redhat.vdc.action.VdcActionType;
import com.redhat.vdc.action.VdcReturnValue;
import com.redhat.vdc.common.utils.SessionContainer;
import com.redhat.vdc.common.utils.VdcException;
@WebService(serviceName = "WCFBackendBean", wsdlLocation = "META-INF/wsdl/com.redhat.vdc.backend.WCFBackendBean.wsdl")
@WebContext(contextRoot = "/backends", urlPattern = "wcf")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
@Stateless(name = "WCFBackend")
public class WCFBackendBean extends VdcAdapter {
@EJB(beanName = "Backend")
Backend backend;
Log log = LogFactory.getLog(WCFBackendBean.class);
@WebMethod
@WebResult(name = "vdcReturnValue")
public VdcReturnValue runAction(
@WebParam(name = "actionType") VdcActionType type,
@WebParam(name = "parameters") VdcActionParameters params) {
try {
this.initializeSession() ;
this.incrementRequestCounter() ;
log.debug("Request Number: " + SessionContainer.getInstance().getData("requestCount")) ;
return backend.runAction(type, params);
} catch (VdcException e) {
throw e;
} catch (Exception e) {
throw new VdcException(e);
} finally {
resetSession() ;
}
}
}
The WSDl is located in the META-INF directory of the EJB jar. It defines the standards listed above:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://backend.vdc.redhat.com/"
name="BareBackendBean" xmlns:tns="http://backend.vdc.redhat.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap11="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/"
xmlns:soap12CXF="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy"
xmlns:wsrmp="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"
xmlns:wsrmp11="http://docs.oasis-open.org/ws-rx/wsrmp/200702"
xmlns:wsrmp10ForJavaNative="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:wsrmp10="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema>
<xsd:import namespace="http://backend.vdc.redhat.com/"
schemaLocation="WCFBackendBean_schema1.xsd" />
</xsd:schema>
</types>
<message name="runAction">
<part name="parameters" element="tns:runAction" />
</message>
<message name="runActionResponse">
<part name="parameters" element="tns:runActionResponse" />
</message>
<portType name="BareBackendBean">
<operation name="runAction">
<input
wsaw:Action="http://backend.vdc.redhat.com/BareBackendBean/runActionRequest"
message="tns:runAction">
</input>
<output message="tns:runActionResponse">
</output>
</operation>
</portType>
<binding name="BareBackendBeanPortBinding" type="tns:BareBackendBean">
<wsaw:UsingAddressing />
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="runAction">
<soap:operation soapAction="" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="BareBackendBean">
<port name="BareBackendBeanPort" binding="tns:BareBackendBeanPortBinding">
<soap:address location="http://127.0.0.1:8080/backends/bare" />
</port>
</service>
</definitions>
Also in the META-INF directory is a jboss-cxf.xml file which has the following contents. Again, this references the versions of the WS standards listed above:
<beans xmlns='http://www.springframework.org/schema/beans'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:beans='http://www.springframework.org/schema/beans'
xmlns:jaxws='http://cxf.apache.org/jaxws'
xmlns:wsp='http://www.w3.org/2006/07/ws-policy'
xmlns:p='http://cxf.apache.org/policy'
xsi:schemaLocation='http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/policy
http://cxf.apache.org/schemas/policy.xsd
http://www.w3.org/2006/07/ws-policy
http://www.w3.org/2006/11/ws-policy.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd'>
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<wsp:Policy wsu:Id="wsrm10policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wswa:UsingAddressing xmlns:wswa="http://www.w3.org/2006/05/addressing/wsdl" />
<wsrmp:RMAssertion xmlns:wsrmp="http://schemas.xmlsoap.org/ws/2005/02/rm/policy" >
<wsrmp:AcknowledgementInterval Milliseconds="1000"/>
</wsrmp:RMAssertion>
</wsp:Policy>
<jaxws:endpoint id='WCFBackend'
implementor='com.redhat.vdc.backend.WCFBackendBean'>
<jaxws:invoker>
<bean class='org.jboss.wsf.stack.cxf.InvokerJSE' />
</jaxws:invoker>
<jaxws:features>
<p:policies namespace="http://www.w3.org/2006/07/ws-policy">
<wsp:PolicyReference URI="#wsrm10policy"
xmlns:wsp="http://www.w3.org/2006/07/ws-policy" />
</p:policies>
</jaxws:features>
<jaxws:outInterceptors>
<ref bean="logOutbound"/>
</jaxws:outInterceptors>
<jaxws:inInterceptors>
<ref bean="logInbound"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
On the client side, I used the visual studio tool to create a reference to th web service. By default, I got a basicHttpBindings in the app.config file. The voodoo was to replace the basic binding with a custom binding that references the same WS standards. Here is the file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="WCFBackendBeanPortBinding1">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap11WSAddressingAugust2004" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<reliableSession ordered="true" reliableMessagingVersion="WSReliableMessagingFebruary2005" flowControlEnabled="true" inactivityTimeout="00:15:00" />
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="true" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://hattrick.usersys.redhat.com:8080/backends/wcf"
binding="customBinding" bindingConfiguration="WCFBackendBeanPortBinding1"
contract="ServiceReferenceWCF.WCFBackendBean" name="WCFBackendBeanPort1" />
</client>
</system.serviceModel>
</configuration>
Deploy the ejb, compile the front end, and it works. The same endpoint can be use by a CXF client, so there is good interoperability between java and C#.
Apr 22, 2009 @ 15:56:15
Have you ever had problems with webmethod returning a string array (string[]) or int array (int[])?
I have just implemented a WCF client to a JBossWS and only the webmethods returning the string[] and int[] don’t work. The exception in C# is an “ArgumentException”.
Very strange because another webmethod return my bean array and all works fine!
Apr 22, 2009 @ 17:00:56
I did with an array of objects. I ended up having to create a concrete subclass to hold the array of objects. I would dig into the JAXB stuff to see if there are any annotations which improve the marshalling.
Apr 23, 2009 @ 21:19:00
Here is the post in the MSDN Forum where I explain the problem with all the details. The exception is very strange and it seems depending only from the client side (I think).
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/0a48d50d-64d1-43b1-be05-d1b15643223f/
I think to do an example with a sample WS client and WS in JBoss where the problem is replicated and sharing it with everbody.
The problem I have is too strange! And I’m beginning to think it is a my mistake.
I have to admit that I am a newbie in WCF and JBOSSWS too
Apr 25, 2009 @ 08:07:35
The problem is not related to the arrays but a mistake in the deserialization of the SOAP message for the missing attribute in the ‘System.Xml.Serialization.XmlArrayAttribute’.
I have to say that WCF mapping of a WSDL exported from JBossWS is not very good and probably we are pioneers in this field. What do you think about the error? Have you had the time to see the post I updateed?