Announcement Announcement Module
Collapse
No announcement yet.
Multiple Services/Schemas/Endpoints Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multiple Services/Schemas/Endpoints

    I've been successful deploying the Spring web services samples and following along with the echo sample to create a meaningful web service of my own. I created the XSD with Request and Response, used the DefaultWsdl11Definition to generate the WSDL automatically, and exposed it using PayloadRootQNameEndpointMapping with the defaultEndpoint set. I'm able to use SOAP UI to automagically create a client SOAP request and render the response when it comes back. Wonderful stuff - thanks to Arjen and the Spring team for more great stuff.

    I have several other web services I'd like to deploy in a single WAR, so I've run into my first stumbling block. What is the best practice for configuring multiple services/schemas/endpoints in a single WAR? I'm having problems with the original service that was working now that I've removed the defaultEndpoint setting.

    %

  • #2
    I guess my ignorance revolves around the appropriate design and packaging of web services.

    Is the best practice one service per WAR file? Or should there be multiple services per WAR?

    Is an Endpoint a Service? Or is a Service a collection of related Endpoints?

    If I wrote an interface for a POJO service, I'd want it to be as cohesive as possible and include all the necessary related method signatures. How do I accomplish the same thing with web services?

    What about XSD and WSDL? Is it one XSD per Request/Response pair? Can an Endpoint reuse an XSD? If it does, must the namespace change?

    Sorry for the ignorant questions. The samples that I see (e.g., echo and the rest) appear to be one method/one XSD/one WAR per service. I don't know what the best practices are for web services that expose several methods. Thanks.

    %

    Comment


    • #3
      I create multiple services and also multiple versions of one service this way:

      - Create one xsd schema per service with an unique targetNamespace definition
      - create one endpoint per service
      - define the endpoint mappings in the servlet.xml file using an own marshaller per service (I use marshalling endpoints cause they are great to work with - you don't have to deal with xml docs, just pojos)

      Recommendation:
      - for the endpoint, I use PayloadRootAnnotationMethodEndpointMapping to autowire my endpoint methods to the ws methods.
      - if I need to create different versions of one service, I append a number to the namespace def. e.g. http://mycomp/schemas/myapp/ws1 (2..3..4)

      Robert

      Comment


      • #4
        Finally! An answer! I was up to 91 views without a word from anyone until now. Thank you for looking.

        Originally posted by robertoschwald View Post
        I create multiple services and also multiple versions of one service this way:

        - Create one xsd schema per service with an unique targetNamespace definition
        - create one endpoint per service
        - define the endpoint mappings in the servlet.xml file using an own marshaller per service (I use marshalling endpoints cause they are great to work with - you don't have to deal with xml docs, just pojos)
        This approach maps onto the samples. I've done this too, and I agree that it works.

        But one schema per service means one Request/Response per service. If I were writing a POJO service interface that exposed four CRUD operations and two business methods for a domain model object Foo I'd have six methods in the service interface. So far, so good.

        If I exposed that POJO service interface as web services, does that mean I'd have six XSDs, one for each method in the POJO service interface, and one endpoint per method?

        The namespaces and request roots have to be unique for the payload endpoint mapping lookup to succeed. If I put all six of those methods in the same namespace, would that mean the XSD request roots would look like <FooCreateRequest>, <FooReadRequest>, <FooUpdateRequest>, <FooDeleteRequest>, <FooMethod1Request>, and <FooMethod2Request>? Is it one XSD per XML request, or do all of them go in a single XSD?

        Sure is a good argument for REST, isn't it?

        Recommendation:
        - for the endpoint, I use PayloadRootAnnotationMethodEndpointMapping to autowire my endpoint methods to the ws methods.
        - if I need to create different versions of one service, I append a number to the namespace def. e.g. http://mycomp/schemas/myapp/ws1 (2..3..4)

        Robert
        Thank you for looking. I was beginning to think that I was a pariah on this board.

        %

        Comment


        • #5
          If I exposed that POJO service interface as web services, does that mean I'd have six XSDs, one for each method in the POJO service interface, and one endpoint per method?

          The namespaces and request roots have to be unique for the payload endpoint mapping lookup to succeed. If I put all six of those methods in the same namespace, would that mean the XSD request roots would look like <FooCreateRequest>, <FooReadRequest>, <FooUpdateRequest>, <FooDeleteRequest>, <FooMethod1Request>, and <FooMethod2Request>? Is it one XSD per XML request, or do all of them go in a single XSD?
          The latter of these is what I've done. I think of the "service" of the web service just as if it were a pojo/ejb/etc. service, with the XSD being the "interface" of the service and the actual service class is the "implementation" class of that "interface". If you would've written it as a pojo service as one class, FooService, with 6 methods (fooRead(), fooUpdate(), ... fooMethod2()), then I'd do the exact same thing with the web service class. This means, then, that in the one XSD, you have the 6 different pairs of XML elements as you mentioned (<FooCreateRequest>, <FooCreateResponse>, etc.). I then use PayloadRootAnnotationMethodEndpointMapping, as mentioned by Robert, to map the 6 messages onto the appropriate 6 methods in the service class (one endpoint).

          HTH,
          Greg

          Comment


          • #6
            Here is an overview how to implement this stuff

            - one schema for all methods you would like to handle in the endpoint.

            XSD Schema:

            Code:
            <schema xmlns="http://www.w3.org/2001/XMLSchema" 
              targetNamespace="http://your.domain/schemas/app/version1" 
              xmlns:xxx="http://your.domain/schemas/app/version1"
              elementFormDefault="qualified">
            
            <element name="FirstRequest">
            ...
            </element>
            <element name="FirstResponse">
            ...
            </element>
            
            <element name="SecondRequest">
            ...
            </element>
            <element name="SecondResponse">
            ...
            </element>
            
            ... other requests/responses, faults etc.
             
            </schema>

            Endpoint using PayloadRootAnnotationMethodEndpointMapping:

            Code:
            @Endpoint
            public class YourEndpoint {
              @PayloadRoot(localPart = "FirstRequest", namespace = "http://your.domain/schemas/app/version1")
            	public FirstResponse methodName(FirstRequest request) {...}
            
              @PayloadRoot(localPart = "SecondRequest", namespace = "http://your.domain/schemas/app/version1")
            	public SecondResponse secondMethodName(SecondRequest request) {...}
            
            }

            .. and of course the ws-servlet.xml file wires the stuff together.
            See the Airline JaxB example how to do that.


            If you want to generate the java classes of the schema using maven, you can use the maven-jaxb-plugin.

            And of course you need the MessageDispatcherServlet in the web.xml file.



            Hope this helps.

            Comment


            • #7
              Originally posted by robertoschwald View Post
              Here is an overview how to implement this stuff

              - one schema for all methods you would like to handle in the endpoint.

              XSD Schema:

              Code:
              <schema xmlns="http://www.w3.org/2001/XMLSchema" 
                targetNamespace="http://your.domain/schemas/app/version1" 
                xmlns:xxx="http://your.domain/schemas/app/version1"
                elementFormDefault="qualified">
              
              <element name="FirstRequest">
              ...
              </element>
              <element name="FirstResponse">
              ...
              </element>
              
              <element name="SecondRequest">
              ...
              </element>
              <element name="SecondResponse">
              ...
              </element>
              
              ... other requests/responses, faults etc.
               
              </schema>

              Endpoint using PayloadRootAnnotationMethodEndpointMapping:

              Code:
              @Endpoint
              public class YourEndpoint {
                @PayloadRoot(localPart = "FirstRequest", namespace = "http://your.domain/schemas/app/version1")
              	public FirstResponse methodName(FirstRequest request) {...}
              
                @PayloadRoot(localPart = "SecondRequest", namespace = "http://your.domain/schemas/app/version1")
              	public SecondResponse secondMethodName(SecondRequest request) {...}
              
              }

              .. and of course the ws-servlet.xml file wires the stuff together.
              See the Airline JaxB example how to do that.


              If you want to generate the java classes of the schema using maven, you can use the maven-jaxb-plugin.

              And of course you need the MessageDispatcherServlet in the web.xml file.



              Hope this helps.
              Very helpful Robert, thank you.

              I'm one of those dinosaurs who's still comfortable with XML config. Your example is telling me that it's time to take the plunge and make annotations my new habit. Thanks.

              %

              Comment


              • #8
                Hi robertoschwald,

                I am trying to handle multiple request and response using PayloadRootAnnotationMethodEndpointMapping but getting the following error:
                Code:
                INFO: Initializing Spring FrameworkServlet 'spring-ws'
                Oct 19, 2009 3:14:20 PM org.apache.catalina.core.StandardWrapperValve invoke
                SEVERE: Servlet.service() for servlet spring-ws threw exception
                java.lang.NoSuchMethodError: javax.xml.soap.SOAPFault.setFaultCode(Ljavax/xml/namespace/QName;)V
                	at com.sun.xml.messaging.saaj.soap.impl.BodyImpl.addFault(BodyImpl.java:108)
                	at com.sun.xml.messaging.saaj.soap.impl.BodyImpl.addFault(BodyImpl.java:120)
                	at org.springframework.ws.soap.saaj.Saaj12Implementation.addFault(Saaj12Implementation.java:97)
                	at org.springframework.ws.soap.saaj.SaajSoap11Body.addFault(SaajSoap11Body.java:55)
                	at org.springframework.ws.soap.saaj.SaajSoap11Body.addServerOrReceiverFault(SaajSoap11Body.java:73)
                	at org.springframework.ws.soap.server.endpoint.SimpleSoapExceptionResolver.resolveExceptionInternal(SimpleSoapExceptionResolver.java:66)
                	at org.springframework.ws.server.endpoint.AbstractEndpointExceptionResolver.resolveException(AbstractEndpointExceptionResolver.java:84)
                	at org.springframework.ws.server.MessageDispatcher.processEndpointException(MessageDispatcher.java:311)
                	at org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:235)
                	at org.springframework.ws.server.MessageDispatcher.receive(MessageDispatcher.java:168)
                	at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:88)
                	at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:57)
                	at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:230)
                	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
                	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
                	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
                	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
                	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
                	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
                	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
                	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
                	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
                	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
                	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
                	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
                	at java.lang.Thread.run(Unknown Source)
                It would be helpful if you explain/ show ws-servlet.xml for your example.
                Thanks

                Comment


                • #9
                  My advice is, to take a look to the Spring-WS Airline example.
                  There you find a complete configuration to look at.

                  See the spring-ws svn repository or
                  https://fisheye.springsource.org/bro...amples/airline

                  Comment


                  • #10
                    thanks robertoschwald,

                    Actually I am new to spring framework, I tried to understand the Airline sample code but not able to figure it out much. It include many other stuff as well.

                    My actual problem is :
                    I have created two different web services (project) for handling multiple request that is:
                    project1 having wsdl1, sprind-ws-1.xml, req-res1.xsd
                    and
                    project2 having wsdl2, sprind-ws-2.xml, req-res2.xsd

                    both are working fine but now i need to merge them in a single web project so that i can have only single war to deploy.
                    For that I tried to use PayloadRootAnnotationMethodEndpointMapping after goiing through chapter5, airline sampple and yours current post but getting the NoSuchMethodError.
                    Following is my current code:
                    Code:
                    <?xml version="1.0" encoding="UTF-8"?>
                    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
                    
                        <description>
                            This web application context contains Spring-WS beans. The beans defined in this context are automatically
                            detected by Spring-WS, similar to the way Controllers are picked up in Spring Web MVC.
                        </description>
                    
                    	<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>
                            
                        <bean id="orderEndpoint" class="com.mycompany.prod.ws.rfmscores.ws.AnnotationOrderEndpoint">
                             <constructor-arg ref="rfmScoreService"/>     
                        </bean>
                        
                    	<bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
                    
                    
                    	<bean id="validatingInterceptor"
                              class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
                            <description>
                                This interceptor validates both incoming and outgoing message contents according to the 'rfmscores.xsd' XML
                                Schema file.
                            </description>
                            <property name="xsdSchema" ref="schema"/>
                            <property name="validateRequest" value="true"/>
                            <property name="validateResponse" value="true"/>
                        </bean>
                    
                      <bean id="loggingInterceptor" class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor">
                            <description>
                                This interceptor logs the message payload.
                            </description>
                        </bean>
                    
                       
                    	<bean id="rfmscores" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
                            <description>
                                This bean definition represents a WSDL definition that is generated at runtime. It can be retrieved by
                                going to /prodservices/rfmscores.wsdl (i.e. the bean name corresponds to the filename).
                            </description>
                            <property name="schema" ref="schema"/>
                            <property name="portTypeName" value="RFMscore"/>
                            <property name="locationUri" value="http://localhost:8080/mycompany-prod-rfm-ws/rfmscores"/>
                            <property name="targetNamespace" value="http://prod.mycompany.com/rfm/rfmscores"/>
                        </bean>
                    
                        <bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
                            <description>
                                This bean definition contains the XSD schema.
                            </description>
                            <property name="xsd" value="/WEB-INF/rfmscores.xsd"/>
                        </bean>
                    
                        <bean id="rfmScoreService" class="com.mycompany.prod.ws.rfmscores.services.RFMScoreServiceImpl">
                            <description>
                                This bean is our "business" service.
                            </description>
                        </bean>
                    
                    </beans>
                    Code:
                    package com.mycompany.prod.ws.rfmscores.ws;
                    
                    import org.springframework.ws.server.endpoint.annotation.Endpoint;
                    import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
                    import com.mycompany.prod.ws.rfmscores.services.RFMScoreService;
                    
                    @Endpoint
                    public class AnnotationOrderEndpoint {
                    	
                    	/**
                    	 * Instance of RFMService
                    	 */
                    	private RFMScoreService rfmService;
                    	
                        public AnnotationOrderEndpoint(RFMScoreService rfmService) {
                            this.rfmService = rfmService;
                        }
                    
                        @PayloadRoot(localPart = "RFMScoresRequest", namespace = "http://prod.mycompany.com/rfm/rfmscores")
                        public void rfmScoresRequest(Object order) {
                        	System.out.println("Inside method2 222222222222");
                        }
                    }
                    Code:
                    <?xml version="1.0" encoding="UTF-8"?>
                    <xs:schema targetNamespace="http://prod.mycompany.com/rfm/rfmscores" xmlns:tns="http://prod.mycompany.com/rfm/rfmscores" xmlns="http://prod.mycompany.com/rfm/rfmscores" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified">
                      <xs:element name="RFMScoresRequest">
                        <xs:complexType>
                          <xs:sequence>
                            <xs:element name="userID" type="xs:string" minOccurs="1" />
                            <xs:element name="userType" type="xs:string" minOccurs="1" />
                            <xs:element name="channelID" minOccurs="1" >        
                    	    	<xs:simpleType>
                    				<xs:restriction base="xs:string">
                    					<xs:pattern value="1|2|3|ALL"/>
                    				</xs:restriction>
                    			</xs:simpleType>
                    		</xs:element>			
                            <xs:element name="scoreType" minOccurs="1" >                
                    	    	<xs:simpleType>
                    				<xs:restriction base="xs:string">
                    					<xs:pattern value="R|F|M|PR|PF|RFM|ALL"/>
                    			    </xs:restriction>
                    			</xs:simpleType>
                    		</xs:element>	        
                          </xs:sequence>
                        </xs:complexType>
                      </xs:element> 
                      <xs:element name="RFMScoresResponse">
                        <xs:complexType>
                          <xs:sequence>
                           <xs:element name="channelID" minOccurs="0" maxOccurs="unbounded">
                              <xs:complexType>
                                <xs:sequence>
                                  <xs:element name="ID" type="xs:string" minOccurs="0" />
                                  <xs:element name="scores" minOccurs="0" >
                    	              <xs:complexType>
                    	                <xs:simpleContent>
                    		                <xs:extension base="xs:string">
                    	     	         		<xs:attribute name="type" type="xs:string" use="required"/>
                    	     	         	</xs:extension>	
                         	         	</xs:simpleContent>
                    	              </xs:complexType>     	         	
                                  </xs:element>	              
                                </xs:sequence>
                              </xs:complexType>
                            </xs:element>
                          </xs:sequence>
                        </xs:complexType>
                      </xs:element>
                    </xs:schema>
                    I tried many things but still stuck with this multiple request and response. I would be very grateful if you helped me out

                    Thanks in advance

                    Comment

                    Working...
                    X