4 Replies Latest reply on Oct 24, 2004 7:01 AM by wejaeger

    Throwing application exception

    gpnewton


      I've got a very simple test application that I'm using to learn how to do web service endpoints for EJBs in JBoss 4.0. The method I'm calling throws an application defined exception (extends Exception) under certain circumstances.

      For a client application, I used the Axis WSDL2Java tool to generate client stubs. It does generate the exception class, and the method in the stub it generates does throw the exception.

      Everything works great if no exception is thrown, but when the method does throw an exception, what the client code actually catches is not the defined application exception. I'm trying to figure out what I'm doing wrong and how to make it so that I can get the application exceptions on the client side. The stack trace from the client side is included below. Where is the MBeanException coming from??

      ____________________________________________________________

      AxisFault
      faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Client
      faultSubcode:
      faultString: MBeanException: null Cause: com.sipstorm.test.webservice.TestException: Divide by 0!
      faultActor:
      faultNode:
      faultDetail:
      {http://xml.apache.org/axis/}stackTrace: AxisFault
      faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Client
      faultSubcode:
      faultString: MBeanException: null Cause: com.sipstorm.test.webservice.TestException: Divide by 0!
      faultActor:
      faultNode:
      faultDetail:

      MBeanException: null Cause: com.sipstorm.test.webservice.TestException: Divide by 0!
      at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:260)
      at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:169)
      at org.apache.axis.encoding.DeserializationContextImpl.endElement(DeserializationContextImpl.java:1015)
      at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1712)
      at org.apache.crimson.parser.Parser2.content(Parser2.java:1963)
      at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1691)
      at org.apache.crimson.parser.Parser2.content(Parser2.java:1963)
      at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1691)
      at org.apache.crimson.parser.Parser2.parseInternal(Parser2.java:667)
      at org.apache.crimson.parser.Parser2.parse(Parser2.java:337)
      at org.apache.crimson.parser.XMLReaderImpl.parse(XMLReaderImpl.java:448)
      at javax.xml.parsers.SAXParser.parse(SAXParser.java:345)
      at org.apache.axis.encoding.DeserializationContextImpl.parse(DeserializationContextImpl.java:242)
      at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:538)
      at org.apache.axis.Message.getSOAPEnvelope(Message.java:376)
      at org.apache.axis.client.Call.invokeEngine(Call.java:2583)
      at org.apache.axis.client.Call.invoke(Call.java:2553)
      at org.apache.axis.client.Call.invoke(Call.java:2248)
      at org.apache.axis.client.Call.invoke(Call.java:2171)
      at org.apache.axis.client.Call.invoke(Call.java:1691)
      at com.sipstorm.test.webservice.TestEndpointBindingStub.divide(TestEndpointBindingStub.java:143)
      at com.sipstorm.test.client.Client.main(Client.java:28)


      MBeanException: null Cause: com.sipstorm.test.webservice.TestException: Divide by 0!
      at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:260)
      at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:169)
      at org.apache.axis.encoding.DeserializationContextImpl.endElement(DeserializationContextImpl.java:1015)
      at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1712)
      at org.apache.crimson.parser.Parser2.content(Parser2.java:1963)
      at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1691)
      at org.apache.crimson.parser.Parser2.content(Parser2.java:1963)
      at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1691)
      at org.apache.crimson.parser.Parser2.parseInternal(Parser2.java:667)
      at org.apache.crimson.parser.Parser2.parse(Parser2.java:337)
      at org.apache.crimson.parser.XMLReaderImpl.parse(XMLReaderImpl.java:448)
      at javax.xml.parsers.SAXParser.parse(SAXParser.java:345)
      at org.apache.axis.encoding.DeserializationContextImpl.parse(DeserializationContextImpl.java:242)
      at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:538)
      at org.apache.axis.Message.getSOAPEnvelope(Message.java:376)
      at org.apache.axis.client.Call.invokeEngine(Call.java:2583)
      at org.apache.axis.client.Call.invoke(Call.java:2553)
      at org.apache.axis.client.Call.invoke(Call.java:2248)
      at org.apache.axis.client.Call.invoke(Call.java:2171)
      at org.apache.axis.client.Call.invoke(Call.java:1691)
      at com.sipstorm.test.webservice.TestEndpointBindingStub.divide(TestEndpointBindingStub.java:143)
      at com.sipstorm.test.client.Client.main(Client.java:28)

        • 1. Re: Throwing application exception
          wejaeger

          Hi,

          your client can never recieve a custom exceptions, because jboss wraps all custom exception with a MBeanException.

          To get it (temporarily) work, I changed line 393 of 'jaxrpc/src/main/org/apache/axis/providers/java/JavaProvider.java'

          from

          AxisFault fault = AxisFault.makeFault(exp);

          to

          AxisFault fault = AxisFault.makeFault(exp.getCause() != null && exp.getCause() instanceof Exception ? (Exception)exp.getCause() : null);


          but this is a real hack. A much better solition is needed.

          Regards

          Werner


          • 2. Re: Throwing application exception
            thomas.diesler

            In general server side java exceptions do get propagated to the client. This is logical, because the client stack may not even have the notion of exceptions in their language.

            To debug this properly, you should examine the fault message that is generated on the server side. It should contain the QName of the custom fault.

            On the client side that fault QName should be mapped to a java exeption. Note, it may have a different name and reside in a differnt package then the exception being thrown at the server side.

            The client code should be able to catch that user exception. See the wiki for an example.

            Werner, you are right. That change is a terrible hack :)

            • 3. Re: Throwing application exception
              gpnewton

              Hi guys,

              Thanks for the input. I'm still confused about a few things though. I'm fairly new to this (SOAP on JBoss), so I apologize in advance if I ask stupid questions. :) We're in the process of migrating off of Weblogic to JBoss (yippee!) and we've relied on Weblogic for the generation of web services from SS EJBs, and for the generation of client code. That client code does somehow map back to the service specific exceptions thrown by the EJB methods, so I'm struggling to find something comparable to reduce the amount of code rework necessary.

              I've been reading the JAXRPC spec to see what to expect, and I'm using the TCPMonitor to actually see the messages going back and forth.

              Here's the exceprt from the WSDL:

              <binding name="TestEndpointBinding" type="tns:TestEndpoint">
               <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
               <operation name="divide">
               <soap:operation soapAction=""/>
               <input>
               <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="webservice.test.sipstorm.com"/>
               </input>
               <output>
               <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="webservice.test.sipstorm.com"/>
               </output>
               <fault name="TestException">
               <soap:fault name="TestException" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="webservice.test.sipstorm.com"/>
               </fault>
               </operation>
              </binding>
              


              From what I've read, that seems like a reasonable mapping from the exception (TestException) to a SOAP fault.

              Here's the response back to the client when the exception is thrown:

              HTTP/1.1 500 Internal Server Error
              X-Powered-By: Servlet 2.4; Tomcat-5.0.28/JBoss-4.0.0 (build: CVSTag=JBoss_4_0_0 date=200409200418)
              Content-Type: text/xml;charset=utf-8
              Date: Sun, 24 Oct 2004 01:49:29 GMT
              Server: Apache-Coyote/1.1
              
              Connection: close
              
              <?xml version="1.0" encoding="UTF-8"?>
              <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>MBeanException: null Cause: com.sipstorm.test.webservice.TestException</faultstring>
               <detail/>
               </soapenv:Fault>
               </soapenv:Body>
              </soapenv:Envelope>
              


              Without parsing the text out after the MBeanException part, there's really nothing meaningful in the AxisFault that the client catches. Is there something I'm missing? Any pointers / best practices would be greatfully accepted.

              Greg


              • 4. Re: Throwing application exception
                wejaeger

                I totally argree with Thomas, that a custom server exception should be mapped to a java exception on the client side using the QName.
                To do so, requires that the fault message contains the QName.

                What I wanted to point out is, that any server side custom exception, thrown by a SEI implementation (I only tried it out with SSB)
                is lost, because on the way back it is wrapped with a MBeanExeption.

                Thus, the returned fault message did no longer contain any useful information about the originating exception.

                Because RC1 and RC2 handled custom exception correctly, I still consider this to be a bug in the 4.0.0 release.

                The admitting terrible and even incorrect hack, I did just not to break existing client code, that worked perfectly with the web service deployed on JBoss RC1 and RC2.

                I really like JBoss AS and would appreciate to see this problem to be fixed.

                Werner