6 Replies Latest reply on Nov 23, 2005 5:46 AM by thomas.diesler

    custom exception received by ws client as AxisFault with bla

    jpowerwa

      I am trying to get custom exceptions working from a web service on JBoss 4.0.2. The custom exception is being written into the SOAP response properly, at least to my eyes, but it is not being deserialized properly by the client. It comes across as an AxisFault with no cause or detail. The detailMessage is filled in properly, but that's it. There is no indication of the exception class, so I can't do anything with it. It looks like this:

      RemoteException re=AxisFault
      * cause=null
      * detail=null
      * detail Message="The given login or password is invalid."

      The custom exception is a subclass of Java.lang.Exception. It has one data member: a String named message. The bean serializer and deserializer are registered. The exception shows up in the wsdl and mapping files properly, as far as I can tell. The wsdl is generated by java2wsdl and the mapping file is generated by wscompile.

      I have tried making the exception a subclass of AxisFault, based on a recommendation I found on the web, but that didn't help. In fact, then the SOAP response did not contain the right exception class information anymore.

      I've tried experimenting with the --typeMappingVersion option in java2wsdl, to no avail.

      I've tried experimenting with the methods in my exception class. First, with a constructor that takes the message and only a getter, as specified for JAX-RPC. I've also tried adding a default constructor and setter, but that didn't help.

      I know that I can wrap the exception in a RemoteException on the server and then pull the exception classname out on the client side, but then the SOAP isn't nice and interoperable, so I'd rather not do that.

      I have been banging my head against this for too long, now, and I would really appreciate any help.

      ----------------------------------------------------------------------
      Here are the artifacts:

      From SOAP response:

      <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <soapenv:Body>
      <soapenv:Fault>
      soapenv:Client
      The given login or password is invalid.

      <fault xsi:type="ns1:AuthenticationCredentialsException" xmlns:ns1="http://security.enterprise.foo.com">
      <message xsi:type="xsd:string">The given login or password is invalid.


      </soapenv:Fault>
      </soapenv:Body>
      </soapenv:Envelope>

      ----------------------------------------------------------------------
      From jax-rpc mapping file:

      <java-xml-type-mapping>
      <java-type>com.foo.enterprise.security.AuthenticationCredentialsException</java-type>
      <root-type-qname xmlns:typeNS="http://security.enterprise.foo.com">typeNS:AuthenticationCredentialsException</root-type-qname>
      <qname-scope>complexType</qname-scope>
      <variable-mapping>
      <java-variable-name>message</java-variable-name>
      <xml-element-name>message</xml-element-name>

      <exception-mapping>
      <exception-type>com.foo.enterprise.security.AuthenticationCredentialsException</exception-type>
      <wsdl-message xmlns:exMsgNS="http://security.enterprise.foo.com">exMsgNS:AuthenticationCredentialsException</wsdl-message>
      <constructor-parameter-order>
      <element-name>message</element-name>
      </constructor-parameter-order>
      </exception-mapping>

      ----------------------------------------------------------------------
      From wsdl:

      < schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://security.enterprise.foo.com">
      ...
      < complexType name="AuthenticationCredentialsException">
      < sequence>
      < element name="message" nillable="true" type="soapenc:string"/>
      < /sequence>
      < /complexType>
      < / schema>
      ...
      <wsdl:message name="AuthenticationCredentialsException">
      <wsdl:part name="fault" type="tns2:AuthenticationCredentialsException"/>
      </wsdl:message>
      ...
      <wsdl:portType name="AuthenticationJse">
      <wsdl:operation name="authenticate" parameterOrder="in0 in1 in2">
      <wsdl:input name="authenticateRequest" message="impl:authenticateRequest"/>
      <wsdl:output name="authenticateResponse" message="impl:authenticateResponse"/>
      <wsdl:fault name="AuthenticationCredentialsException" message="impl:AuthenticationCredentialsException"/>
      </wsdl:operation>
      </wsdl:portType>
      ...
      <wsdl:binding name="AuthenticationJsePortSoapBinding" type="impl:AuthenticationJse">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="authenticate">
      <wsdlsoap:operation soapAction=""/>
      <wsdl:input name="authenticateRequest">
      <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://tws.foo.com"/>
      </wsdl:input>
      <wsdl:output name="authenticateResponse">
      <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://tws.foo.com"/>
      </wsdl:output>
      <wsdl:fault name="AuthenticationCredentialsException">
      <wsdlsoap:fault name="AuthenticationCredentialsException" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://tws.foo.com"/>
      </wsdl:fault>
      </wsdl:operation>
      </wsdl:binding>

        • 1. Re: custom exception received by ws client as AxisFault with
          bogsolomon

          From the looks of your WSDL you are using rpc/encoded which I know JBoss 4.0.2 does not support because of BP-1.0. Also not sure if your fault message is BP-1.0 compliant which might be the problem.

          Look at
          http://www-128.ibm.com/developerworks/library/ws-basicprofile11.html

          espcially the


          When a MESSAGE contains a soap:Fault element, that element MUST NOT have element children other than faultcode, faultstring, faultactor and detail.


          part.[/url]

          • 2. Re: custom exception received by ws client as AxisFault
            jpowerwa

            Thanks for that tip. I've changed my setup so that both the wsdl and the jax-rpc mapping file are being generated with wscompile, and I changed the encoding style to RPC/LITERAL. My client is still not properly generating the custom exception thrown by the web service endpoint, but it looks different now.

            If anyone has more help for me, I am very much in need of assistance!

            Here are the insides of the AxisFault that I am seeing on my client instead of my custom exception. Now the name of the exception class is in the detailMessage and the faultString:

            this= TmsServicesImpl (id=50)
            principalName= "foo"
            password= "bar"
            repositoryName= "baz"
            authTokenBean= null
            re= AxisFault (id=59)
             cause= null
             detail= null
             detailMessage= "com.mycompany.enterprise.security.AuthenticationCredentialsException"
             faultActor= null
             faultCode= QName (id=71)
             faultDetails= Vector (id=73)
             faultHeaders= null
             faultNode= null
             faultString= "com.mycompany.enterprise.security.AuthenticationCredentialsException"
             faultSubCode= null
             stackTrace= null


            Here is the SOAP message that is coming back from the server:
            <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
             <soapenv:Body>
             <soapenv:Fault>
             <faultcode>soapenv:Client</faultcode>
             <faultstring>com.mycompany.enterprise.security.AuthenticationCredentialsException</faultstring>
             <detail>
             <ns1:AuthenticationCredentialsException xmlns:ns1="http://security.enterprise.mycompany.com">
             <msg>Bad login</msg>
             <message xsi:nil="1"/>
             </ns1:AuthenticationCredentialsException>
             </detail>
             </soapenv:Fault>
             </soapenv:Body>
            </soapenv:Envelope>
            



            Here is the JAX-RPC mapping file:
            <?xml version="1.0" encoding="UTF-8"?>
            <java-wsdl-mapping version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd">
            <package-mapping>
            <package-type>com.mycompany.tws</package-type>
            <namespaceURI>http://tws.mycompany.com/types</namespaceURI>
            </package-mapping>
            <package-mapping>
            <package-type>com.mycompany.tws</package-type>
            <namespaceURI>http://tws.mycompany.com</namespaceURI>
            </package-mapping>
            <package-mapping>
            <package-type>com.mycompany.tws.security</package-type>
            <namespaceURI>http://security.tws.mycompany.com</namespaceURI>
            </package-mapping>
            <package-mapping>
            <package-type>com.mycompany.enterprise.security</package-type>
            <namespaceURI>http://security.enterprise.mycompany.com</namespaceURI>
            </package-mapping>
            <package-mapping>
            <package-type>com.mycompany.enterprise.security</package-type>
            <namespaceURI>http://security.enterprise.mycompany.com</namespaceURI>
            </package-mapping>
            <package-mapping>
            <package-type>com.mycompany.tws.security</package-type>
            <namespaceURI>http://security.tws.mycompany.com</namespaceURI>
            </package-mapping>
            <java-xml-type-mapping>
            <java-type>com.mycompany.enterprise.security.AuthenticationCredentialsException</java-type>
            <root-type-qname xmlns:typeNS="http://security.enterprise.mycompany.com">typeNS:AuthenticationCredentialsException</root-type-qname>
            <qname-scope>complexType</qname-scope>
            <variable-mapping>
            <java-variable-name>msg</java-variable-name>
            <xml-element-name>msg</xml-element-name>
            </variable-mapping>
            </java-xml-type-mapping>
            <java-xml-type-mapping>
            <java-type>com.mycompany.tws.security.AuthenticationTokenBean</java-type>
            <root-type-qname xmlns:typeNS="http://security.tws.mycompany.com">typeNS:AuthenticationTokenBean</root-type-qname>
            <qname-scope>complexType</qname-scope>
            <variable-mapping>
            <java-variable-name>value</java-variable-name>
            <xml-element-name>value</xml-element-name>
            </variable-mapping>
            </java-xml-type-mapping>
            <exception-mapping>
            <exception-type>com.mycompany.enterprise.security.AuthenticationCredentialsException</exception-type>
            <wsdl-message xmlns:exMsgNS="http://security.enterprise.mycompany.com">exMsgNS:AuthenticationCredentialsException</wsdl-message>
            <constructor-parameter-order>
            <element-name>msg</element-name>
            </constructor-parameter-order>
            </exception-mapping>
            <service-interface-mapping>
            <service-interface>com.mycompany.tws.Tws</service-interface>
            <wsdl-service-name xmlns:serviceNS="http://tws.mycompany.com">serviceNS:Tws</wsdl-service-name>
            <port-mapping>
            <port-name>AuthenticationJsePort</port-name>
            <java-port-name>AuthenticationJsePort</java-port-name>
            </port-mapping>
            </service-interface-mapping>
            <service-endpoint-interface-mapping>
            <service-endpoint-interface>com.mycompany.tws.AuthenticationJse</service-endpoint-interface>
            <wsdl-port-type xmlns:portTypeNS="http://tws.mycompany.com">portTypeNS:AuthenticationJse</wsdl-port-type>
            <wsdl-binding xmlns:bindingNS="http://tws.mycompany.com">bindingNS:AuthenticationJseBinding</wsdl-binding>
            <service-endpoint-method-mapping>
            <java-method-name>authenticate</java-method-name>
            <wsdl-operation>authenticate</wsdl-operation>
            <method-param-parts-mapping>
            <param-position>0</param-position>
            <param-type>java.lang.String</param-type>
            <wsdl-message-mapping>
            <wsdl-message xmlns:wsdlMsgNS="http://tws.mycompany.com">wsdlMsgNS:AuthenticationJse_authenticate</wsdl-message>
            <wsdl-message-part-name>String_1</wsdl-message-part-name>
            <parameter-mode>IN</parameter-mode>
            </wsdl-message-mapping>
            </method-param-parts-mapping>
            <method-param-parts-mapping>
            <param-position>1</param-position>
            <param-type>java.lang.String</param-type>
            <wsdl-message-mapping>
            <wsdl-message xmlns:wsdlMsgNS="http://tws.mycompany.com">wsdlMsgNS:AuthenticationJse_authenticate</wsdl-message>
            <wsdl-message-part-name>String_2</wsdl-message-part-name>
            <parameter-mode>IN</parameter-mode>
            </wsdl-message-mapping>
            </method-param-parts-mapping>
            <method-param-parts-mapping>
            <param-position>2</param-position>
            <param-type>java.lang.String</param-type>
            <wsdl-message-mapping>
            <wsdl-message xmlns:wsdlMsgNS="http://tws.mycompany.com">wsdlMsgNS:AuthenticationJse_authenticate</wsdl-message>
            <wsdl-message-part-name>String_3</wsdl-message-part-name>
            <parameter-mode>IN</parameter-mode>
            </wsdl-message-mapping>
            </method-param-parts-mapping>
            <wsdl-return-value-mapping>
            <method-return-value>com.mycompany.tws.security.AuthenticationTokenBean</method-return-value>
            <wsdl-message xmlns:wsdlMsgNS="http://tws.mycompany.com">wsdlMsgNS:AuthenticationJse_authenticateResponse</wsdl-message>
            <wsdl-message-part-name>result</wsdl-message-part-name>
            </wsdl-return-value-mapping>
            </service-endpoint-method-mapping>
            </service-endpoint-interface-mapping>
            </java-wsdl-mapping>



            And here is the WSDL:
            <?xml version="1.0" encoding="UTF-8"?>
            
            <definitions name="tws" targetNamespace="http://tws.mycompany.com" xmlns:tns="http://tws.mycompany.com" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns2="http://security.enterprise.mycompany.com" xmlns:ns3="http://security.tws.mycompany.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
             <types>
             <schema targetNamespace="http://security.enterprise.mycompany.com" xmlns:tns="http://security.enterprise.mycompany.com" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://tws.mycompany.com/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema">
             <import namespace="http://security.tws.mycompany.com"/>
             <import namespace="http://tws.mycompany.com/types"/>
             <complexType name="AuthenticationCredentialsException">
             <sequence>
             <element name="msg" type="string" nillable="true"/></sequence></complexType>
             <element name="AuthenticationCredentialsException" type="tns:AuthenticationCredentialsException"/>
             <schema targetNamespace="http://security.tws.mycompany.com" xmlns:tns="http://security.tws.mycompany.com" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema">
             <import namespace="http://security.enterprise.mycompany.com"/>
             <import namespace="http://tws.mycompany.com/types"/>
             <complexType name="AuthenticationTokenBean">
             <sequence>
             <element name="value" type="long" nillable="true"/></sequence></complexType></schema></types>
             <message name="AuthenticationJse_authenticate">
             <part name="String_1" type="xsd:string"/>
             <part name="String_2" type="xsd:string"/>
             <part name="String_3" type="xsd:string"/></message>
             <message name="AuthenticationJse_authenticateResponse">
             <part name="result" type="ns3:AuthenticationTokenBean"/></message>
             <message name="AuthenticationCredentialsException">
             <part name="AuthenticationCredentialsException" element="ns2:AuthenticationCredentialsException"/></message>
             <portType name="AuthenticationJse">
             <operation name="authenticate" parameterOrder="String_1 String_2 String_3">
             <input message="tns:AuthenticationJse_authenticate"/>
             <output message="tns:AuthenticationJse_authenticateResponse"/>
             <fault name="AuthenticationCredentialsException" message="tns:AuthenticationCredentialsException"/></operation></portType>
            
             <binding name="AuthenticationJseBinding" type="tns:AuthenticationJse">
             <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
             <operation name="authenticate">
             <soap:operation soapAction=""/>
             <input>
             <soap:body use="literal" namespace="http://tws.mycompany.com"/></input>
             <output>
             <soap:body use="literal" namespace="http://tws.mycompany.com"/></output>
             <fault name="AuthenticationCredentialsException">
             <soap:fault name="AuthenticationCredentialsException" use="literal"/></fault></operation></binding>
             <service name="Tws">
             <port name="AuthenticationJsePort" binding="tns:AuthenticationJseBinding">
             <soap:address location="REPLACE_WITH_ACTUAL_URL"/></port></service></definitions>
            


            • 3. Re: custom exception received by ws client as AxisFault with
              jpowerwa

              A little more info. Part of my original problem went away when I changed the name of the single member data field in my custom exception. It was named "message," which was causing problems because of a JBoss exception serialization bug detailed here: http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3890609

              When I changed the name of the data member and accessor to "msg" rather than "message," I started getting the classname of my custom exception in the detail message of the axis fault on the client side, rather than just the contents of the message.

              But I'm still not getting my real exception on the client side. Argh.

              • 4. Re: custom exception received by ws client as AxisFault with
                bogsolomon

                The fault message being sent looks valid. Did you regenerate the artifacts for the client side for use with rpc/literal? Other then that not sure what the problem could be.

                On an unrelated note. Why do you have the same package/namespace mapping in your haxrpc-mapping twice?

                • 5. Re: custom exception received by ws client as AxisFault with
                  jpowerwa

                  Thanks for the reply.

                  Regarding the multiple declarations of the package/namespace mapping in the jaxrpc mapping file, I don't know why that is happening. My only guess is that it comes from the fact that the service endpoint has three methods. I'm only dealing with one right now, but there is code for three. I'm generating the mapping file using wscompile from this config:

                  <?xml version="1.0" encoding="UTF-8"?>
                  <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
                   <service name="tws"
                   targetNamespace="http://tws.mycompany.com"
                   typeNamespace="http://tws.mycompany.com/types"
                   packageName="com.mycompany.tws"
                   >
                   <interface name="com.mycompany.tws.AuthenticationJse"/>
                   <namespaceMappingRegistry>
                   <namespaceMapping
                   namespace="http://security.enterprise.mycompany.com"
                   packageName="com.mycompany.enterprise.security"
                   />
                   <namespaceMapping
                   namespace="http://security.tws.mycompany.com"
                   packageName="com.mycompany.tws.security"
                   />
                   </namespaceMappingRegistry>
                   </service>
                  </configuration>
                  


                  Regarding client-side artifacts, I am using dynamic proxy, so besides recompiling my client and redeploying the service, I didn't do anything.

                  Here's how I'm calling the service:

                  private static final String AUTH_WSDL_URL = "http://localhost:8080/tms/security/authentication?WSDL";
                  private static final String TWS_NS = "http://tws.mycompany.com";
                  private static final String TWS_SECURITY_NS = "http://security.tws.mycompany.com";
                  private static final QName TWS_SERVICE_QNAME = new QName(TWS_NS, "Tws");
                  private static final QName AUTH_JSE_PORT_QNAME = new QName(TWS_NS, "AuthenticationJsePort");
                  
                  public TmsServicesImpl() throws ServiceUnavailableException {
                   Service authService = getService(AUTH_WSDL_URL, TWS_SERVICE_QNAME);
                   if (authService != null) {
                   TypeMappingRegistry reg = authService.getTypeMappingRegistry();
                   TypeMapping mapping = reg.getDefaultTypeMapping();
                   registerType(mapping, TWS_SECURITY_NS, "AuthenticationTokenBean",
                   AuthenticationTokenBean.class);
                   m_authenticationService = (AuthenticationJse)
                   getServicePort(authService, AUTH_JSE_PORT_QNAME,
                   AuthenticationJse.class);
                   }
                  }
                  
                  /**
                   * Handles the common mechanics and exception handling involved with fetching
                   * a TWS service endpoint.
                   * @param wsdlUrl the URL of the WSDL for the service endpoint.
                   * @param srvcName the qualifed name of the service endpoint.
                   * @return a remote reference to the service.
                   */
                  private Service getService(String wsdlUrl, QName srvcName)
                  throws ServiceUnavailableException {
                   Service srvc = null;
                   try {
                   srvc = javax.xml.rpc.ServiceFactory.newInstance().createService(
                   new URL(wsdlUrl), srvcName);
                   } catch (MalformedURLException mue) {
                   mue.printStackTrace();
                   return null;
                   } catch (ServiceException se) {
                   throw new ServiceUnavailableException(
                   "Service " + srvcName.toString() + " is unavailable.", se);
                   }
                   return srvc;
                  }
                  
                  /**
                   * Handles the common mechanics and exception handling involved with fetching
                   * a TWS service port.
                   * @param service the service
                   * @param qn the qualified name of the service port
                   * @param jse the class of the JSE interface to be fetched
                   * @return a remote reference to the service port.
                   */
                  private Remote getServicePort(Service service, QName qn, Class jse) {
                   try {
                   return service.getPort(qn, jse);
                   } catch (ServiceException se) {
                   se.printStackTrace();
                   return null;
                   }
                  }
                  
                  private void registerType(TypeMapping mapping, String nameSpace,
                   String localName, Class type) {
                   QName qn = new QName(nameSpace, localName);
                   mapping.register (
                   type,
                   qn,
                   new BeanSerializerFactory(type, qn),
                   new BeanDeserializerFactory(type, qn)
                   );
                  }


                  Should I be doing something different? I don't like that I have to register the serializers for the return type manually. I know there is a JBoss-specific ServiceFactory implementation that takes the jaxrpc mapping as an argument to avoid this problem, but I don't want to use the JBoss-specific service factory because since this client will need to work for a service deployed on BEA, also.



                  • 6. Re: custom exception received by ws client as AxisFault with
                    thomas.diesler

                    Did you follow the wiki?
                    http://wiki.jboss.org/wiki/Wiki.jsp?page=WSExceptions

                    The samples attached to the wiki and the testsuite also contain custom exceptions.