1 2 Previous Next 27 Replies Latest reply on Apr 13, 2011 12:15 AM by rakeshmehta

    Providing your own wsdl instead of the generated one.

      Alright, it took me a long time to put all the pieces together after searching the forums and jira. If you want to serve up your own wsdl instead of the generated one you do the following:

      In the interface you specify the wsdlLocation:

      @WebService(name = "Echo", targetNamespace = "http://echo/", wsdlLocation="META-INF/wsdl/EchoService.wsdl")
      


      Then when you package your war file, you put the wsdl in the META-INF/wsdl directory of your war.

      I apologize if this is obvious, but it took me a while to figure out.

      Here is the full working example using top-down design:

      First I started with EchoService.wsdl
      <?xml version="1.0" encoding="UTF-8"?>
      <definitions name='EchoService' targetNamespace='http://echo/' xmlns='http://schemas.xmlsoap.org/wsdl/' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:tns='http://echo/' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
       <types>
       <xs:schema targetNamespace='http://echo/' version='1.0' xmlns:tns='http://echo/' xmlns:xs='http://www.w3.org/2001/XMLSchema'>
       <xs:element name='echo' type='tns:echo'/>
       <xs:element name='echoResponse' type='tns:echoResponse'/>
       <xs:complexType name='echo'>
       <xs:sequence>
       <xs:element minOccurs='0' name='arg0' type='xs:string'/>
       </xs:sequence>
       </xs:complexType>
       <xs:complexType name='echoResponse'>
       <xs:sequence>
       <xs:element minOccurs='0' name='return' type='xs:string'/>
       </xs:sequence>
       </xs:complexType>
       </xs:schema>
       </types>
       <message name='Echo_echo'>
       <part element='tns:echo' name='echo'/>
       </message>
       <message name='Echo_echoResponse'>
       <part element='tns:echoResponse' name='echoResponse'/>
       </message>
       <portType name='Echo'>
       <operation name='echo' parameterOrder='echo'>
       <input message='tns:Echo_echo'/>
       <output message='tns:Echo_echoResponse'/>
       </operation>
       </portType>
       <binding name='EchoBinding' type='tns:Echo'>
       <soap:binding style='document' transport='http://schemas.xmlsoap.org/soap/http'/>
       <operation name='echo'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body use='literal'/>
       </input>
       <output>
       <soap:body use='literal'/>
       </output>
       </operation>
       </binding>
       <service name='EchoService'>
       <documentation>Congrats! You have published your own WSDL!</documentation>
       <port binding='tns:EchoBinding' name='EchoPort'>
       <soap:address location='REPLACE_WITH_ACTUAL_URL'/>
       </port>
       </service>
      </definitions>


      Then I generated the java files using wsconsume:
      $ wsconsume -k EchoService.wsdl
      echo/Echo.java
      echo/EchoResponse.java
      echo/EchoService.java
      echo/Echo_Type.java
      echo/ObjectFactory.java
      echo/package-info.java
      echo/Echo.java
      echo/EchoResponse.java
      echo/EchoService.java
      echo/Echo_Type.java
      echo/ObjectFactory.java
      echo/package-info.java


      I promptly threw away EchoService.java because it's really for the client, not the server.

      Next I implemented EchoImpl.java
      package echo;
      
      @javax.jws.WebService(endpointInterface="echo.Echo")
      public class EchoImpl implements Echo
      {
       public String echo(String arg0)
       {
       return arg0;
       }
      }


      Then I edited Echo.java and added wsdlLocation (bolded below)
      package echo;
      
      import javax.jws.WebMethod;
      import javax.jws.WebParam;
      import javax.jws.WebResult;
      import javax.jws.WebService;
      import javax.xml.ws.RequestWrapper;
      import javax.xml.ws.ResponseWrapper;
      
      
      /**
       * JBossWS Generated Source
       * ....
       * JAX-WS Version: 2.0
       *
       */
      @WebService(name = "Echo", targetNamespace = "http://echo/", wsdlLocation="META-INF/wsdl/EchoService.wsdl")
      public interface Echo {
      
      
       /**
       *
       * @param arg0
       * @return
       * returns java.lang.String
       */
       @WebMethod
       @WebResult(targetNamespace = "")
       @RequestWrapper(localName = "echo", targetNamespace = "http://echo/", className = "echo.Echo_Type")
       @ResponseWrapper(localName = "echoResponse", targetNamespace = "http://echo/", className = "echo.EchoResponse")
       public String echo(
       @WebParam(name = "arg0", targetNamespace = "")
       String arg0);
      
      }
      


      Next I created a web.xml:
      <?xml version="1.0" encoding="UTF-8"?>
      
      <web-app 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://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
       version="2.4">
      
       <servlet>
       <servlet-name>echo</servlet-name>
       <servlet-class>echo.Echo</servlet-class>
       </servlet>
      
       <servlet-mapping>
       <servlet-name>echo</servlet-name>
       <url-pattern>/*</url-pattern>
       </servlet-mapping>
      
      </web-app>
      


      Then I packed them up into a echo.war:
      META-INF/
      META-INF/MANIFEST.MF
      META-INF/wsdl/
      META-INF/wsdl/EchoService.wsdl
      WEB-INF/
      WEB-INF/classes/
      WEB-INF/classes/echo/
      WEB-INF/classes/echo/Echo.class
      WEB-INF/classes/echo/EchoImpl.class
      WEB-INF/classes/echo/EchoResponse.class
      WEB-INF/classes/echo/Echo_Type.class
      WEB-INF/classes/echo/ObjectFactory.class
      WEB-INF/classes/echo/package-info.class
      WEB-INF/web.xml


      Then I dropped it into the deploy directory.

      When I looked at the log file, I saw it deployed my wsdl:
      07:39:03,777 INFO [TomcatDeployer] deploy, ctxPath=/echo, warUrl=.../tmp/deploy/tmp45417echo-exp.war/
      07:39:04,839 INFO [WSDLFilePublisher] WSDL published to: file:/D:/jboss/jboss-4.2.0.CR1/server/default/data/wsdl/echo.war/EchoService.wsdl
      07:39:04,886 INFO [ServiceEndpointManager] WebService started: http://127.0.0.1:8080/echo


      Instead of what it did when I didn't properly specify the wsdlLocation:
      07:10:04,777 INFO [TomcatDeployer] undeploy, ctxPath=/echo, warUrl=.../tmp/deploy/tmp45397echo-exp.war/
      07:10:06,449 INFO [TomcatDeployer] deploy, ctxPath=/echo, warUrl=.../tmp/deploy/tmp45400echo-exp.war/
      07:10:06,730 INFO [WSDLFilePublisher] WSDL published to: file:/D:/jboss/jboss-4.2.0.CR1/server/default/data/wsdl/echo.war/EchoService45401.wsdl


      Sure enough, going to http://127.0.0.1:8080/echo?wsdl displayed my wsdl, not the generated one.

      Hope this helps some of you out there.

        • 1. Re: Providing your own wsdl instead of the generated one.
          peterj

          I did the same (see my post at http://www.jboss.com/index.html?module=bb&op=viewtopic&t=104664). All of this works fine. Have you tried to access the web service from a client yet? When I attempt to do this, the web services container attempts to instantiate the interface instead of the class, which of course fails miserably. My current hunch is that the web services container is ignoring the WebService annotation on the class (hence the reason why placing wsdlLocation there is ignored). Of course, no-one from the JBossWS team has replied to my post...

          • 2. Re: Providing your own wsdl instead of the generated one.

            Yeppers, just started doing the clinet, and go the same thing:

            07:39:04,886 INFO [ServiceEndpointManager] WebService started: http://127.0.0.1:8080/echo
            08:31:07,730 ERROR [SOAPFaultHelperJAXWS] SOAP request exception
            java.lang.InstantiationException: echo.Echo
             at java.lang.Class.newInstance0(Class.java:335)


            But I get my wsdl... now I have to figure out what I messed up now.

            • 3. Re: Providing your own wsdl instead of the generated one.
              peterj

              I have tried a wide variety of combinations of elements on the WebService annotation on both the class and the interface to no success. The only thing that works is deleting the interface, renaming the class to Echo.

              That (and the fact that the wsdlLocation has no effect when added the WebService on the class) is what lead me to think the container is ignoring the WebService annotation on the class - it is as if the endpointInterface element is being totally ignored.

              • 4. Re: Providing your own wsdl instead of the generated one.

                I'll try doing some of what you suggest and see what I can get to happen.

                Over here http://www.jboss.com/index.html?module=bb&op=viewtopic&t=99158
                dwin seems to have been able to make it happen. I wonder if s/he ran a client.

                dwin mentions

                you just have to ensure that the wsdl in wsdl location does not contradict the web service implementation.


                I'm not sure what exaclty s/he is referring to, but perhaps there is something in the hand coded wsdl which contradicts the annotation, thus cases this problem. Maybe by investigating the difference in the generated and hand coded, I can find the answer.

                Let me know if you get it working, and I will do the same.

                • 5. Re: Providing your own wsdl instead of the generated one.

                   

                  "ngtdave" wrote:

                  07:39:04,886 INFO [ServiceEndpointManager] WebService started: http://127.0.0.1:8080/echo
                  08:31:07,730 ERROR [SOAPFaultHelperJAXWS] SOAP request exception
                  java.lang.InstantiationException: echo.Echo
                   at java.lang.Class.newInstance0(Class.java:335)



                  Alright, I get this error without the wsdlLocation change I made, so it's not that.

                  BTW I'm using JBoss 4.2.0.CR1 with jbossws-1.2.0.GA (build=200703010320)
                  and java 1.5.0_11-b03

                  • 6. Re: Providing your own wsdl instead of the generated one.

                    Alright, I got it working.

                    First I changed my web.xml to use the impl bean:

                    <servlet-class>echo.EchoImpl</servlet-class>

                    per this discussion:
                    http://www.jboss.com/index.html?module=bb&op=viewtopic&t=70837
                    where Diesler says:
                    So this is trying to instanciate an interface. Your web.xml should contain the endpoint impl bean not the SEI. Is that the case?


                    but then I got this error:
                    9:55:24,824 ERROR [ServiceEndpointDeployer] Cannot create service endpoint
                    rg.jboss.ws.WSException: Cannot find port in wsdl: {http://echo/}EchoImplPort


                    So then I remembered:
                    https://jax-ws.dev.java.net/jax-ws-ea3/docs/annotations.html#2.1%20javax.jws.WebService%7Coutline
                    specifies:
                    javax.jws.WebService.portName - The wsdl:portName


                    So I tried to change Echo.java to declare the port, but I got an error:
                    09:56:05,683 ERROR [MainDeployer] Could not create deployment: file:/D:/jboss/jboss-4.2.0.CR1/server/default/deploy/echo.war
                    org.jboss.deployment.DeploymentException: Cannot create service endpoint; - nested throwable: (org.jboss.ws.WSException: @WebService[portName,serviceName,endpoi
                    ntInterface] MUST NOT be defined on: echo.Echo)


                    So I changed EchoImple.java:
                    @javax.jws.WebService(endpointInterface="echo.Echo",portName="EchoPort")
                    public class EchoImpl implements Echo
                    ....
                    



                    Now it works and it still serves out my wsdl.

                    I'm not sure if this is a bug or not because the docs here https://jax-ws.dev.java.net/jax-ws-ea3/docs/annotations.html#2.1%20javax.jws.WebService%7Coutline
                    say:
                    endpointInterface - The qualified name of the service endpoint interface. This annotation allows the separation of interface contract from implementation. If this property is specified, all other WebService properties are ignored as are all other 181 annotations. Only the annotations on the service endpoint interface will be taken into consideration. The endpoint implementation class is not required to implement the endpointInterface.

                    Which I take to mean the other parameters (portName) should be ignored if endpointInterface is specified.


                    • 7. Re: Providing your own wsdl instead of the generated one.

                      Just to be clear which versions I'm using:
                      Boss 4.2.0.CR1
                      jbossws-1.2.0.GA (build=200703010320)
                      java 1.5.0_11-b03

                      Here are the final files.

                      EchoService.wsdl (note the \<documentation\> tag near the bottom)

                      <?xml version="1.0" encoding="UTF-8"?>
                      <definitions name='EchoService' targetNamespace='http://echo/' xmlns='http://schemas.xmlsoap.org/wsdl/' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:tns='http://echo/' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
                       <types>
                       <xs:schema targetNamespace='http://echo/' version='1.0' xmlns:tns='http://echo/' xmlns:xs='http://www.w3.org/2001/XMLSchema'>
                       <xs:element name='echo' type='tns:echo'/>
                       <xs:element name='echoResponse' type='tns:echoResponse'/>
                       <xs:complexType name='echo'>
                       <xs:sequence>
                       <xs:element minOccurs='0' name='arg0' type='xs:string'/>
                       </xs:sequence>
                       </xs:complexType>
                       <xs:complexType name='echoResponse'>
                       <xs:sequence>
                       <xs:element minOccurs='0' name='return' type='xs:string'/>
                       </xs:sequence>
                       </xs:complexType>
                       </xs:schema>
                       </types>
                       <message name='Echo_echo'>
                       <part element='tns:echo' name='echo'/>
                       </message>
                       <message name='Echo_echoResponse'>
                       <part element='tns:echoResponse' name='echoResponse'/>
                       </message>
                       <portType name='Echo'>
                       <operation name='echo' parameterOrder='echo'>
                       <input message='tns:Echo_echo'/>
                       <output message='tns:Echo_echoResponse'/>
                       </operation>
                       </portType>
                       <binding name='EchoBinding' type='tns:Echo'>
                       <soap:binding style='document' transport='http://schemas.xmlsoap.org/soap/http'/>
                       <operation name='echo'>
                       <soap:operation soapAction=''/>
                       <input>
                       <soap:body use='literal'/>
                       </input>
                       <output>
                       <soap:body use='literal'/>
                       </output>
                       </operation>
                       </binding>
                       <service name='EchoService'>
                       <documentation>Congrats! You have published your own WSDL!</documentation>
                       <port binding='tns:EchoBinding' name='EchoPort'>
                       <soap:address location='REPLACE_WITH_ACTUAL_URL'/>
                       </port>
                       </service>
                      </definitions>



                      web.xml (note <servlet-class> specifies the imple):
                      <?xml version="1.0" encoding="UTF-8"?>
                      
                      <web-app 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://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
                       version="2.4">
                      
                       <servlet>
                       <servlet-name>echo</servlet-name>
                       <servlet-class>echo.EchoImpl</servlet-class>
                       </servlet>
                      
                       <servlet-mapping>
                       <servlet-name>echo</servlet-name>
                       <url-pattern>/*</url-pattern>
                       </servlet-mapping>
                      
                      </web-app>


                      Echo.java (note wsdlLocation added by hand to @WebService)
                      package echo;
                      
                      import javax.jws.WebMethod;
                      import javax.jws.WebParam;
                      import javax.jws.WebResult;
                      import javax.jws.WebService;
                      import javax.xml.ws.RequestWrapper;
                      import javax.xml.ws.ResponseWrapper;
                      
                      
                      /**
                       * JBossWS Generated Source
                       *
                       * ...
                       * JAX-WS Version: 2.0
                       *
                       */
                      @WebService(name = "Echo", targetNamespace = "http://echo/", wsdlLocation="META-INF/wsdl/EchoService.wsdl")
                      public interface Echo {
                      
                      
                       /**
                       *
                       * @param arg0
                       * @return
                       * returns java.lang.String
                       */
                       @WebMethod
                       @WebResult(targetNamespace = "")
                       @RequestWrapper(localName = "echo", targetNamespace = "http://echo/", className = "echo.Echo_Type")
                       @ResponseWrapper(localName = "echoResponse", targetNamespace = "http://echo/", className = "echo.EchoResponse")
                       public String echo(
                       @WebParam(name = "arg0", targetNamespace = "")
                       String arg0);
                      
                      }
                      


                      and finally EchoImpl.java (not the portName)
                      package echo;
                      
                      @javax.jws.WebService(endpointInterface="echo.Echo", portName="EchoPort")
                      public class EchoImpl implements Echo
                      {
                       public String echo(String arg0)
                       {
                       return arg0;
                       }
                      }


                      And for completeness, the war structure
                      META-INF/
                      META-INF/MANIFEST.MF
                      META-INF/wsdl/
                      META-INF/wsdl/EchoService.wsdl
                      WEB-INF/
                      WEB-INF/classes/
                      WEB-INF/classes/echo/
                      WEB-INF/classes/echo/Echo.class
                      WEB-INF/classes/echo/EchoImpl.class
                      WEB-INF/classes/echo/EchoResponse.class
                      WEB-INF/classes/echo/Echo_Type.class
                      WEB-INF/classes/echo/ObjectFactory.class
                      WEB-INF/classes/echo/package-info.class
                      WEB-INF/web.xml






                      • 8. Re: Providing your own wsdl instead of the generated one.
                        peterj

                        One more thing. You can now move the wsdlLocation from the interface to the class. This way, you do not have to modify the generated files (not a big deal in this example, but a real big deal if you have many endpoints and are generating the stubs quite often).

                        • 9. Re: Providing your own wsdl instead of the generated one.
                          jason.greene

                          Yes it makes more sense on the implementation bean than the interface. Although the spec unfortunately requires that we support it on the interface:

                          From JAXWSWebServiceMetaDataBuilder:

                          // The spec states that WSDL location should be allowed on an SEI, although it
                          // makes far more sense on the implementation bean, so we ALWAYS override the SEI
                          // when wsdlLocation is defined on the bean
                          if (wsdlLocation.length() == 0)
                           wsdlLocation = seiAnnotation.wsdlLocation();
                          


                          -Jason

                          • 10. Re: Providing your own wsdl instead of the generated one.
                            sgof

                            I followed this steps, but wsconsume generate only 2 class: the interface and the class which implement it.

                            I create the web.xml, generate the war file, and when I put it in jboss I obtain this:

                            09:39:15,267 ERROR [MainDeployer] Could not create deployment: file:/C:/jboss-4.
                            0.5.GA/server/default/deploy/WPM3.war
                            org.jboss.deployment.DeploymentException: Cannot create service endpoint; - nest
                            ed throwable: (org.jboss.ws.WSException: Cannot find required security resource:
                            WEB-INF/wsse.keystore)

                            So, I create an empty file called wsse.keystore, and I obtain this:


                            09:40:26,803 ERROR [MainDeployer] Could not create deployment: file:/C:/jboss-4.
                            0.5.GA/server/default/deploy/WPM3.war
                            org.jboss.deployment.DeploymentException: Cannot create service endpoint; - nest
                            ed throwable: (org.jboss.ws.WSException: Cannot find required security resource:
                            WEB-INF/wsse.truststore)


                            So, I create an empty file called wsse.truststore, and I obtain this:



                            09:45:19,415 ERROR [MainDeployer] Could not create deployment: file:/C:/jboss-4.
                            0.5.GA/server/default/deploy/WPM3.war
                            org.jboss.deployment.DeploymentException: Cannot create service endpoint; - nest
                            ed throwable: (org.jboss.ws.WSException: Cannot find port in wsdl: {http://local
                            host:8080/WPM3}wpmPort)



                            Can you help me?

                            • 11. Re: Providing your own wsdl instead of the generated one.

                              sgof,

                              I am not using any sort of security, so I'm not sure what those errors are about. The last error sounds like your wsdl is not syntactically correct. I would suggest starting with a simple example wsdl like the one I provided and a plain JBoss 4.0.5.GA install and get that working first. Once that works, try modifying the project bit by bit to fit what you are trying to do.

                              Hope this helps.

                              • 12. Re: Providing your own wsdl instead of the generated one.
                                jacobsm

                                ngtdave and PeterJ:

                                Thank you for this topic. It was quite helpful.

                                • 13. Re: Providing your own wsdl instead of the generated one.

                                  Glad to have helped. :)

                                  "jacobsm" wrote:
                                  ngtdave and PeterJ:

                                  Thank you for this topic. It was quite helpful.


                                  • 14. Re: Providing your own wsdl instead of the generated one.
                                    jbossws_newbee

                                    ngtdave and PeterJ:

                                    Thank you very much for the post. It was quite helpful. I was able to publish the EchoService.wsdl.
                                    However, the EchoClient as per the JBossWSUserGuide(http://www.jboss.org/jbossws/docs/jaxws_userguide-2.0/index.html#d0e741)
                                    gives me the following Exception:

                                    Command:
                                    wsrunclient.bat EchoClient 'HelloWorld'
                                    Exception in thread "main" javax.xml.ws.WebServiceException: java.lang.IllegalStateException: Could not setup remoting client
                                    at org.jboss.ws.core.jaxws.client.ClientImpl.handleRemoteException(Clien
                                    tImpl.java:304)
                                    at org.jboss.ws.core.jaxws.client.ClientImpl.invoke(ClientImpl.java:242)
                                    at org.jboss.ws.core.jaxws.client.ClientProxy.invoke(ClientProxy.java:16
                                    4)
                                    at org.jboss.ws.core.jaxws.client.ClientProxy.invoke(ClientProxy.java:15
                                    0)
                                    at $Proxy15.echo(Unknown Source)
                                    at echo.EchoClient.main(EchoClient.java:15)
                                    Caused by: java.lang.IllegalStateException: Could not setup remoting client
                                    at org.jboss.ws.core.client.RemotingConnectionImpl.createRemotingClient(
                                    RemotingConnectionImpl.java:240)

                                    Any pointers?

                                    1 2 Previous Next