Announcement Announcement Module
Collapse
No announcement yet.
Plain Old XML (POX) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Plain Old XML (POX)

    -- I swear I posted this message yesterday but I can't see it anywhere, I must be going mad!

    Anyway, I wanted to ask a couple of questions about Spring-WS but thought I would first try and give a brief overview of why I'm looking at it.

    My team are pretty much sold on the concept of adopting an SOA architecture in our products. We're looking at exposing some application data from a business system as a service, and consuming that data in a web GUI app. We also need to pass descriptions of stuff to a service so it can work out some additional info for us and pass back the results. Hardly groundbreaking

    We started out by working out what XML will be flowing between the service and the client, and created XSDs for them. We then used JAXB 2.0 to create some Java obects we could work with to populate and create the XML messages.

    We then implemented a basic prototype of this stuff, and we did it with Spring MVC. So the web service is implemented as a controller sitting on a URL that receives an HTTP POST with the input XML in the body. It then crunches some numbers and populates up a result object. The object is then tossed into a custom view where it is then turned into XML using JAXB and written to the HttpResponse output stream.

    From what I understand, this approach could be described as 'POX'. I noticed that the M2 release of Spring-WS announced POX support, but there doesn't appear to be any samples/documentation on HOW to build something with it.

    Am I missing something obvious somewhere? I've got the airline sample up and running, and I've read through the reference docs.

    What steps would I need to go through to replace my Spring MVC service and deploy it as a service via Spring-WS?

    I'm not convinced that I need to go down the SOAP route, but I'd also be glad of any comments around that area as well.

  • #2
    Well, if you have a working solution, then I suggest you keep it Migrating from Spring-MVC to Spring-WS will take some work (not a lot though).

    But you are right, there is no sample for the POX support yet. But since most classes are not dependent on SOAP, but rather on WebServiceMessage, of which the PoxMessage is just a subinterface. Basically, it involves using a DomPoxMessageFactory rather than a SaajSoapMessageFactory. You can then use a AbstractMarshallingEndpoint and inject it with the JaxbMarshaller.

    You could also decide to use the O/X Mapping support without using the rest of SWS. This way, you can create your own MVC View that uses a Marshaller, and use Spring DI to wire everything up.

    Comment


    • #3
      The current 'working' solution I have is a few hours quick hack, so it's not something I have to hold onto.

      I'll need to re-read your statement on the message factories and marshalling endpoints in conjunction with the code, then I'll no doubt be back with more questions

      I guess my real decision is whether to stay in MVC or go down the Spring WS route. My gut feel is that I should explore more with the WS route and at least demo my existing prototype in that environment.

      Our orginization is only just starting to consider rolling our web services on top of our components and my team just happens to be one of the first to get there.

      I currently have an assumption that if I go down the Spring WS route now, then it may be easier for me to convert to using SOAP at a later date if that's the direction our organization goes in. I don't think I'll care too much about that since I'm designing my services from a data first view point, it's all about the XML messages to me - I don't think I'll care if they get wrapped up in SOAP...is that naive?

      Comment


      • #4
        Originally posted by GavinL View Post
        I currently have an assumption that if I go down the Spring WS route now, then it may be easier for me to convert to using SOAP at a later date if that's the direction our organization goes in. I don't think I'll care too much about that since I'm designing my services from a data first view point, it's all about the XML messages to me - I don't think I'll care if they get wrapped up in SOAP...is that naive?
        That's not naive at all, it's the right way to look at things! Web services are about handling XML messages, it doesn't matter whether the payload is contained in a SOAP envelope or not. And SWS actually makes it really easy to up/down-grade from POX to SOAP.

        Comment


        • #5
          Wow, what an epiphany I've had this afternoon

          I've got a crude example of my stuff running in Spring WS using a POX approach. I now see the huge value of using Spring WS to implement our apps. Bottom line is that my apps DON'T care if we're using SOAP or POX, which means I can leave that decision until later which is exactly what I want to do. As you confirmed in your previous post, all my apps really care about is the fact that they've received a service request described in XML, whether it came in via soap or not. I have to say that your presentation from Spring One also helped firm up some of the ideas (http://www.javapolis.com/S106/talks/...es/index.html).

          Anyway, I'll summarise what I've blindly hacked together to get a simple XML exchange going, in case anyone else wants to do something similar.

          My starting point is that I have my XML messages and corresponding java classes hooked up using Jaxb2 already done. So my job was to see if I could create a quick service in Spring WS that would take one of messages and return a result message.

          So, here's my beans:
          Code:
              <bean id="handlerAdapter" class="org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter">        
                  <property name="messageFactory" ref="messageFactory"/>
              </bean>
             
              <bean id="messageFactory" class="org.springframework.ws.pox.dom.DomPoxMessageFactory">
              </bean>
          
              <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
                  <property name="defaultHandler" ref="messageDispatcher"/>
              </bean>
          
              <bean id="messageDispatcher" class="org.springframework.ws.server.MessageDispatcher">
                  <property name="endpointMappings">
                      <list>
                          <ref local="poxMapping"/>
                      </list>
                  </property>
              </bean>
          
           <bean id="poxMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
                  <property name="mappings">
                      <props>
                          <prop key="event">
                              eventEndpoint
                          </prop>
                      </props>
                  </property>
                  <property name="interceptors">
                      <ref local="loggingInterceptor"/>
                  </property>
              </bean>
          
              <bean id="loggingInterceptor" class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor">
              </bean>
              
              <bean id="eventEndpoint" class="ws.endpoint.EventEndpoint">
                  <property name="marshaller" ref="jaxbMarshaller"/>
                  <property name="unmarshaller" ref="jaxbMarshaller"/>
              </bean>
          
              <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                  <property name="contextPath" value="com.agilent.railbird.shared"/>
              </bean>
          Dodgye points are that I'm using a rather simplistic mapping in my PayloadRootQNameEndpointMapping mappings, I'm not doing any validation and have no security. But I can layer all this in later right?

          And my endpoint class, all this endpoint is doing is printing out a property of the received object (to prove I really got a populated object), and returning a canned result object which I first create from some hard coded XML instead of doing my real business logic stuff:
          Code:
          public class EventEndpoint extends AbstractMarshallingPayloadEndpoint {
          
          	@Override
          	protected Object invokeInternal(Object requestObject) throws Exception {
          		
          		Event event = (Event) requestObject;
          		
          		logger.debug("got Event with id: " + event.getIdentifier());
          		
          		String treeXml = "<tree>" + 
          ...SNIP...  
          "</tree>";
          		 
          		Tree tree = (Tree) this.getUnmarshaller().unmarshal(new StringSource(treeXml));
          		
          		
          		return tree;
          	}
          
          }
          I'll post up my shockingly hacked together test client in just a sec...
          Last edited by GavinL; Mar 2nd, 2007, 09:51 AM.

          Comment


          • #6
            Here's a horribly hacked together bit of code that send some XML to my service and does something with the result. This code was put together purely to check that the stuff in the post above deployed with Spring WS was doing its thing...

            My next job is to go look at jaxws stuff and try to move away from hacky client code like this

            Code:
            public class TestClient extends TestCase {
            
            	protected final Log logger = LogFactory.getLog(getClass());
            	
            		public void testClient()
            		{
            			logger.info("Starting test");
            			
            			String hardXML = "<event> .. SNIP .. </event>";
            
            			Event event = null;
            			Tree tree = null;
            			try {
            				// Using HttpURLConnection to talk to web service.
            				// We pass the event xml and expect to get back an xml representation
            				// of a Tree object (containing drilldown data).
            				
            				URL url = new URL("http","localhost",8080,"/WS/test");
            				
            				HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
            				httpConnection.setDoOutput (true);
            				httpConnection.setDoInput(true);
            				httpConnection.setRequestMethod ("POST"); 
            				httpConnection.setRequestProperty("Content-Type", "text/xml");
            				httpConnection.setUseCaches(false);
            				OutputStream os = httpConnection.getOutputStream();
            				OutputStreamWriter ow = new OutputStreamWriter(os);
            
            				ow.write(hardXML);
            				ow.flush();
            				ow.close();
            				
            				
            				// Read the response...
            				// In this case it will be an xml representation of a Tree
            				BufferedReader in = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
            				String input;
            				StringBuffer response = new StringBuffer(256);
            	        	while((input = in.readLine()) != null) {
            					response.append(input + "\r");
            				}
            	        	
            	        	httpConnection.disconnect();
            
            	        	
            	        	// Throws the XML at Jaxb...
            	        	ObjectFactory of = new ObjectFactory();	
            	        	tree = of.getTree(response.toString());
            
            	        	assertNotNull("Got Tree object from XML",tree);
            	        	
            	        	// log something from the object to prove it is populated.....
            	        	List<DrilldownTree> dds = tree.getDrilldownTree();
            	        	DrilldownTree dd = dds.get(0);
            	        	logger.debug("got tree: " + dd.getDdTypeName());
            	        	
            				
            			} catch (Exception ex) {
            				System.out.println(ex.getMessage());
            				ex.printStackTrace();	       
            			  }
            		}
            }

            Comment


            • #7
              Gavin,

              I would also recommend looking into using XFire-Spring with JSR181. What you describe (XSD + JAXB/XJC?) is exactly what I have been doing but using XFire-Spring to expose the services. I've found it MUCH easier than using Spring MVC to do REST-like services (which is not that difficult in the first place).

              Start with XSD and generate JAXB artifacts for request response objects. Create service beans in spring with jsr181 annotations, and use XFire to expose them (xfire also generates the WSDL, or if you have WSDL you can tell xfire where to get it with an annotation).

              I've found this approach very easy and lightweight. I'm sure Spring WS is more elegant, but if you are looking for something that is quick and easy and not a hack, this is a great way to do it.

              There are a number of articles/blog posts about it, but I found this one the clearest:

              http://www.memestorm.com/blog/basic-...e-and-jsr-181/

              Good luck,

              --Joachim

              Comment

              Working...
              X