[jboss-svn-commits] JBL Code SVN: r34641 - in labs/jbossesb/branches/JBESB_4_7_CP/product: rosetta/src/org/jboss/soa/esb/dom and 5 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Aug 11 12:06:32 EDT 2010


Author: kevin.conner at jboss.com
Date: 2010-08-11 12:06:29 -0400 (Wed, 11 Aug 2010)
New Revision: 34641

Added:
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/soap-message-02.xml
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/JBESB_3327_SoapUIClientServiceMBeanUnitTest.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/collectionresponse.wsdl
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/expected_JBESB_3327_01.xml
Modified:
   labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/internal/soa/esb/soap/OGNLUtils.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/dom/YADOMUtil.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/MBeanSoapUIInvoker.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SOAPClient.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SoapUIInvoker.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/SOAPClient_Response_UnitTest.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/request/MockSOAPClient.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientService.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientServiceMBean.java
Log:
Pulled across fix for SOAPClient's OGNL util does not map collections properly from SOAP responses: JBESB-3452

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/internal/soa/esb/soap/OGNLUtils.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/internal/soa/esb/soap/OGNLUtils.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/internal/soa/esb/soap/OGNLUtils.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -23,6 +23,7 @@
     public static final String OGNL_ATTRIB = "ognl";
     public static final String IS_COLLECTION_ATTRIB = "is-collection";
     public static final String SOAPUI_CLONE_COMMENT = " repetitions:";
+    public static final String CLONED_POSTFIX = " - cloned";
     
     private enum SOAPNameSpaces 
     { 
@@ -117,6 +118,9 @@
         if (assertIsParentCollection(element)) {
             int count = YADOMUtil.countElementsBefore(element, element.getTagName());
             ognlToken = "[" + count + "]";
+        } else if (assertIsCollection(element)) {
+            int count = YADOMUtil.countElementsBefore(element, element.getTagName());
+            ognlToken = "." + localName + "[" + count + "]";
         } else {
             ognlToken = "." + localName;
         }
@@ -148,32 +152,54 @@
         return parentNS.equalsIgnoreCase( namespace );
     }
 
+    /**
+     * Assert if the given element is part of a collection.
+     * 
+     * @param element The element to be asserted
+     * @return <code>true</code>	if the element is part of a collection.
+     */
     private static boolean assertIsCollection(Element element) {
-        if(element.getAttributeNS(JBOSSESB_SOAP_NS, IS_COLLECTION_ATTRIB).equals("true")) {
-            // It's already been attributed... no need to check for the soapui comment...
-            return true;
-        }
+        Node parent = element.getParentNode();
+        if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { 
+            Element firstSibling = YADOMUtil.getFirstChildElementByName((Element) parent, element.getTagName());
+            Comment commentBefore = YADOMUtil.getCommentBefore(firstSibling);
 
-        Comment comment = (Comment)YADOMUtil.getFirstChildByType(element, Node.COMMENT_NODE);
-        if (comment != null
-            && comment.getTextContent().endsWith(SOAPUI_CLONE_COMMENT)) {
-            //possible array
-            Element first = YADOMUtil.getFirstChildElement(element);
-            Element last = YADOMUtil.getLastChildElement(element);
-            if (first != null && last != null && first.getTagName().equals(last.getTagName())) {
-                //The children are of same tag so the parent is a collection holder (array)
+            if(commentBefore != null 
+                && (commentBefore.getTextContent().endsWith(SOAPUI_CLONE_COMMENT)
+                    || commentBefore.getTextContent().endsWith(SOAPUI_CLONE_COMMENT + CLONED_POSTFIX))) {
                 return true;
             }
         }
 
-
         return false;
     }
 
+    /**
+     * Assert if the parent of the given element is the collection holder.
+     * 
+     * @param element The element to be asserted
+     * @return <code>true</code>	if the parent is the collection holder.
+     */
     private static boolean assertIsParentCollection(Element element) {
         Node parent = element.getParentNode();
-        if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE && assertIsCollection((Element)parent)) {
-            return true;
+        if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
+            Element pelement = (Element)parent;
+            if(pelement.getAttributeNS(JBOSSESB_SOAP_NS, IS_COLLECTION_ATTRIB).equals("true")) {
+                // It's already been attributed... no need to check for the soapui comment...
+                return true;
+            }
+
+            Comment comment = (Comment)YADOMUtil.getFirstChildByType(pelement, Node.COMMENT_NODE);
+            if (comment != null
+                && comment.getTextContent().endsWith(SOAPUI_CLONE_COMMENT)) {
+                //possible array
+                Element first = YADOMUtil.getFirstChildElement(pelement);
+                Element last = YADOMUtil.getLastChildElement(pelement);
+                if (first != null && last != null && first.getTagName().equals(last.getTagName())) {
+                    //The children are of same tag so it is an array
+                    return true;
+                }
+            }
         }
         return false;
     }

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/dom/YADOMUtil.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/dom/YADOMUtil.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/dom/YADOMUtil.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -508,4 +508,28 @@
 
         return null;
     }
+
+    /**
+     * Get the first child of the supplied element that matches a given tag name.
+     *
+     * @param element The element.
+     * @param name The name of the child element to search for.
+     * @return The first child element with the matching tag name.
+     */
+    public static Element getFirstChildElementByName(Element element, String name) {
+        NodeList children = element.getChildNodes();
+        int childCount = children.getLength();
+
+        for(int i = 0; i < childCount; i++) {
+            Node child = children.item(i);
+            if (child != null
+                && child.getNodeType() == Node.ELEMENT_NODE
+                && ((Element)child).getTagName() != null
+                && ((Element)child).getTagName().equals(name) ) {
+                return (Element) child;
+            }
+        }
+
+        return null;
+    }
 }

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/MBeanSoapUIInvoker.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/MBeanSoapUIInvoker.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/MBeanSoapUIInvoker.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -37,6 +37,7 @@
     private static final String[] buildRequestSig = new String[] {String.class.getName(), String.class.getName(), Map.class.getName(), Properties.class.getName(), String.class.getName(), String.class.getName()};
     private static final String[] buildFaultSig = new String[] {String.class.getName(), String.class.getName(), String.class.getName(), Map.class.getName(), Properties.class.getName(), String.class.getName(), String.class.getName()};
     private static final String[] getEndpointSig = new String[] {String.class.getName(), Properties.class.getName()};
+    private static final String[] mergeResponseSig = new String[] {String.class.getName(), String.class.getName(), String.class.getName(), Properties.class.getName(), String.class.getName(), String.class.getName()};
     private MBeanServer mbeanServer;
     private ObjectName serviceName;
 
@@ -155,6 +156,42 @@
         }
     }
 
+    /**
+     * Merge a SOAP response for the specified operation on the specified WSDL with its template.
+     *
+     * @param wsdl            WSDL URL.
+     * @param operation       Operation name.
+     * @param response        The actual response.
+     * @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
+     * @param smooksResource  {@link org.milyn.Smooks} transformation configuration resource file.
+     *                        Null if no transformations are to be performed on the SOAP message before serializing it
+     *                        for return.
+     *  @param soapNs         the SOAP namespace. If null one of the defaults will be used:
+     *                        http://schemas.xmlsoap.org/soap/envelope/
+     *                        http://www.w3.org/2003/05/soap-envelope 
+     * @return The SOAP Message.
+     * @throws java.io.IOException                   Failed to load WSDL.
+     * @throws UnsupportedOperationException Operation not supported on specified WSDL.
+     * @throws org.xml.sax.SAXException                  Failed to parse the SOAP UI generated request message.
+     */
+    public String mergeResponseTemplate(String wsdl, String operation, String response, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
+        try {
+            return (String) mbeanServer.invoke(serviceName, "mergeResponseTemplate", new Object[] {wsdl, operation, response, httpClientProps, smooksResource, soapNs}, mergeResponseSig);
+        } catch (InstanceNotFoundException e) {
+            throw new UnsupportedOperationException("SOAP UI Client Service not found under name '" + serviceName.getCanonicalName() + "'.  This service must be deployed before this action can be used.", e);
+        } catch (MBeanException e) {
+            if(e.getCause() instanceof IOException) {
+                throw (IOException)e.getCause();
+            }
+            throw new RuntimeException(e);
+        } catch (ReflectionException e) {
+            if(e.getCause() instanceof IOException) {
+                throw (IOException)e.getCause();
+            }
+            throw new RuntimeException(e);
+        }
+    }
+
     private void rethrowException(Throwable e) throws IOException, UnsupportedOperationException, SAXException {
         Throwable cause = e.getCause();
 

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SOAPClient.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SOAPClient.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SOAPClient.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -431,6 +431,17 @@
         }
         Response response = invokeEndpoint(request);
 
+        if(responseAsOgnlMap) {
+            try {
+                String mergedResponse = soapUIInvoker.mergeResponseTemplate(wsdl, getEndpointOperation(), response.getBody(), httpClientProps, null, soapNs);
+                response.setBody(mergedResponse);
+            } catch (IOException e) {
+                throw new ActionProcessingException("soapUI Client Service invocation failed.", e);
+            } catch (SAXException e) {
+                throw new ActionProcessingException("soapUI Client Service invocation failed.", e);
+            }
+        }
+
         // And process the response into the message...
         processResponse(message, response);
 
@@ -473,6 +484,9 @@
     	protected String getBody() {
     		return body;
     	}
+    	protected void setBody(String body) {
+    		this.body = body;
+    	}
     	protected int getStatusCode() {
     		return statusCode;
     	}

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SoapUIInvoker.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SoapUIInvoker.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/main/java/org/jboss/soa/esb/actions/soap/SoapUIInvoker.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -17,4 +17,6 @@
     String buildFault(String wsdl, String operation, String faultName, Map params, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException;
 
     String getEndpoint(String wsdl, Properties httpClientProps) throws IOException;
+
+    String mergeResponseTemplate(String wsdl, String operation, String response, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException;
 }

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/SOAPClient_Response_UnitTest.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/SOAPClient_Response_UnitTest.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/SOAPClient_Response_UnitTest.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -79,6 +79,34 @@
         assertEquals("{customerOrder.orderheader.customerName=Tom Fennelly, customerOrder.items[0].partNumber=1, customerOrder.items[0].description=desc-1, customerOrder.items[0].quantity=1, customerOrder.items[0].price=1.1, customerOrder.items[0].extensionAmount=1, customerOrder.items[1].partNumber=2, customerOrder.items[1].description=desc-2, customerOrder.items[1].quantity=2, customerOrder.items[1].price=2.2, customerOrder.items[1].extensionAmount=2}", responseMap.toString());
     }
 
+    public void test_OgnlMap_ResponseProcessing_4() throws ConfigurationException, ActionProcessingException {
+        ConfigTree actionConfig = configUtil.getActionConfig("OrderNotificationService", "soapui-client-action-02");
+        SOAPClient soapClient = new SOAPClient(actionConfig);
+        String responseString = new String(StreamUtils.readStream(getClass().getResourceAsStream("soap-message-02.xml")));
+        String expected = "{processOrderResponse.OrderStatus.id=1," +
+                          " processOrderResponse.OrderStatus.comment=order processed," +
+                          " processOrderResponse.OrderStatus.returnCode=1," +
+                          " processOrderResponse.OrderStatus.lineItems[0].id=1," +
+                          " processOrderResponse.OrderStatus.lineItems[0].name=Item1," +
+                          " processOrderResponse.OrderStatus.lineItems[0].price=10," +
+                          " processOrderResponse.OrderStatus.lineItems[0].comments[0]=Item1 Comments1," +
+                          " processOrderResponse.OrderStatus.lineItems[0].comments[1]=Item1 Comments2," +
+                          " processOrderResponse.OrderStatus.lineItems[1].id=2," +
+                          " processOrderResponse.OrderStatus.lineItems[1].name=Item2," +
+                          " processOrderResponse.OrderStatus.lineItems[1].price=15," +
+                          " processOrderResponse.OrderStatus.lineItems[1].comments[0]=Item2 Comments1," +
+                          " processOrderResponse.OrderStatus.lineItems[1].comments[1]=Item2 Comments2," +
+                          " processOrderResponse.OrderStatus.lineItems[1].comments[2]=Item2 Comments3," +
+                          " processOrderResponse.OrderStatus.lineItems[1].comments[3]=Item2 Comments4}";
+
+        Message message = MessageFactory.getInstance().getMessage();
+
+        soapClient.processResponse(message, new Response(responseString));
+        Map<String, String> responseMap = (Map<String, String>) message.getBody().get();
+
+        assertEquals(expected, responseMap.toString());
+    }
+
     public void test_No_ResponseProcessing() throws ConfigurationException, ActionProcessingException {
         ConfigTree actionConfig = configUtil.getActionConfig("OrderNotificationService", "soapui-client-action-03");
         SOAPClient soapClient = new SOAPClient(actionConfig);

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/request/MockSOAPClient.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/request/MockSOAPClient.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/request/MockSOAPClient.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -62,6 +62,10 @@
                 public String getEndpoint(String wsdl, Properties httpClientProps) throws IOException {
                     return service.getEndpoint(wsdl, httpClientProps);
                 }
+
+                public String mergeResponseTemplate(String wsdl, String operation, String response, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
+                    return service.mergeResponseTemplate(wsdl, operation, response, httpClientProps, smooksResource, soapNs);
+                }
             };
             
             setSoapUIInvoker(soapUIInvoker);

Copied: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/soap-message-02.xml (from rev 33435, labs/jbossesb/trunk/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/soap-message-02.xml)
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/soap-message-02.xml	                        (rev 0)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soap/src/test/java/org/jboss/soa/esb/actions/soap/soap-message-02.xml	2010-08-11 16:06:29 UTC (rev 34641)
@@ -0,0 +1,32 @@
+<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ord='http://webservice_consumer_list/orderProcessor'>
+   <env:Header>
+   </env:Header>
+   <env:Body>
+      <ord:processOrderResponse>
+         <OrderStatus>
+            <id>1</id>
+            <comment>order processed</comment>
+            <returnCode>1</returnCode>
+            <!--Zero or more repetitions:-->
+            <lineItems>
+               <id>1</id>
+               <name>Item1</name>
+               <price>10</price>
+               <!--Zero or more repetitions:-->
+               <comments>Item1 Comments1</comments>
+               <comments>Item1 Comments2</comments>
+            </lineItems>
+            <lineItems>
+               <id>2</id>
+               <name>Item2</name>
+               <price>15</price>
+               <!--Zero or more repetitions:-->
+               <comments>Item2 Comments1</comments>
+               <comments>Item2 Comments2</comments>
+               <comments>Item2 Comments3</comments>
+               <comments>Item2 Comments4</comments>
+            </lineItems>
+         </OrderStatus>
+      </ord:processOrderResponse>
+   </env:Body>
+</env:Envelope>
\ No newline at end of file

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientService.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientService.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientService.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -101,7 +101,6 @@
     private DocumentBuilderFactory docBuilderFactory ;
     private SmooksCache smooksCache;
     private ESBProperties properties;
-    private static final String CLONED_POSTFIX = " - cloned";
     private static final String SOAPUI_OPTIONAL_COMMENT = "Optional:";
     private static final String REMOVE_POSTFIX = " to be removed";
     private static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
@@ -416,6 +415,28 @@
         return wsdlInterfaces[0].getEndpoints()[0];
     }
 
+    /**
+     * Use soapUI to Merge a SOAP response for the specified operation on the specified WSDL with its template.
+     *
+     * @param wsdl            WSDL URL.
+     * @param operation       Operation name.
+     * @param response        The actual response.
+     * @param smooksResource  {@link org.milyn.Smooks} transformation configuration resource file.
+     *                        Null if no transformations are to be performed on the SOAP message before serializing it
+     *                        for return.
+     * @param soapNs 		  optional SOAP namespace
+     * @return The SOAP Message.
+     * @throws IOException                   Failed to load WSDL.
+     * @throws UnsupportedOperationException Operation not supported on specified WSDL.
+     * @throws SAXException                  Failed to parse the SOAP UI generated request message.
+     */
+    public String mergeResponseTemplate(String wsdl, String operation, String response, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
+    	Operation operationInst = getOperation(wsdl, operation, httpClientProps);
+        WsdlOperation wsdlOperation = (WsdlOperation)operationInst;
+        String responseTemplate = wsdlOperation.createResponse(true);
+        return mergeSOAPMessage(responseTemplate, response, smooksResource, soapNs);
+    }
+
     private WsdlInterface[] getWsdlInterfaces(String wsdl, Properties httpClientProps) throws IOException {
         try {
             WsdlInterface[] wsdlInterfaces = wsdls.get(wsdl);
@@ -541,6 +562,96 @@
         }
     }
 
+    private String mergeSOAPMessage(String soapMessageTemplate, String response, String smooksResource, String soapNs) throws IOException, SAXException {
+        Document templateDoc = getDocument(soapMessageTemplate);
+        Element templateRoot = templateDoc.getDocumentElement();
+
+        Document messageDoc = getDocument(response);
+        Element messageRoot = messageDoc.getDocumentElement();
+
+        debugDoc(messageRoot);
+        debugDoc(templateRoot);
+
+        mergeTemplate(templateRoot, messageRoot, 0);
+
+        if(smooksResource != null) {
+            applySmooksTransform(smooksResource, messageDoc);
+        }
+
+        debugDoc(messageRoot);
+
+        try
+        {
+            final StringWriter sw = new StringWriter() ;
+            final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
+            XMLHelper.readDomNode(messageRoot, writer, true) ;
+	        return sw.toString();
+        }
+        catch (final XMLStreamException xmlse)
+        {
+            final IOException ioe = new IOException("Failed to serialize the output SOAP message") ;
+            ioe.initCause(xmlse) ;
+            throw ioe ;
+        }
+    }
+
+    private void debugDoc(Element doc)
+    {
+        if(logger.isDebugEnabled()) {
+            logger.debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
+            try {
+                final StringWriter sw = new StringWriter() ;
+                final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
+                XMLHelper.readDomNode(doc, writer, true) ;
+                logger.debug(sw.toString());
+            } catch (final XMLStreamException xmlse) {
+                logger.debug("Failed to print the SOAP message") ;
+            }
+            logger.debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
+        }
+    }
+
+    /**
+     * Merge the template to accommodate data collections.
+     * <p/>
+     * It merges the soapUI cllection comment nodes to the message where appropriate.
+     *
+     * @param template The template element to be merged.
+     * @param instance The element to be processed.
+     * @param index    The template's element instance index.
+     */
+    private void mergeTemplate(Element template, Element instance, int index) {
+        if (template != null && instance != null) {
+            if (index == 0) {
+                //Process only if this is the first element of its kind
+                Comment comment = YADOMUtil.getCommentBefore(template);
+                if (comment != null
+                    && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)) {
+                    Node parent = instance.getParentNode();
+                    if (parent != null) {
+                        Comment newComment = parent.getOwnerDocument().createComment(comment.getTextContent());
+                        parent.insertBefore(newComment, instance);
+                    }
+                }
+            }
+
+            NodeList children = template.getChildNodes();
+            int nodesCount = children.getLength();
+            for (int i = 0; i < nodesCount; i++) {
+                Node templateNode = children.item(i);
+                if (templateNode.getNodeType() == Node.ELEMENT_NODE) {
+                    //We may have many instances of this template 
+                    //and each could have a nested collection so run through them
+                    NodeList instances = instance.getElementsByTagNameNS(templateNode.getNamespaceURI(), templateNode.getLocalName());
+                    int instancesSize = instances.getLength();
+                    for (int j = 0; j < instancesSize; j++) {
+                        mergeTemplate((Element) templateNode, (Element) instances.item(j), j);
+                    }
+                }
+            }
+        }
+    }
+
     private Document getDocument(String soapMessageTemplate) throws IOException {
         try {
             final XMLEventReader reader = XMLHelper.getXMLEventReader(new StringReader(soapMessageTemplate)) ;
@@ -588,14 +699,18 @@
      *                decide whether or not cloning is required.
      */
     private void expandMessage(Element element, Map params) {
-
+        boolean elementRemoved = false;
         // If this element is not a cloned element, check does it need to be cloned...
         if (!element.hasAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, IS_CLONE_ATTRIB)) {
-            String ognl = OGNLUtils.getOGNLExpression(element);
             Element clonePoint = getClonePoint(element);
 
             if(clonePoint != null) {
                 int collectionSize;
+                String ognl = OGNLUtils.getOGNLExpression(element);
+                //We don't need the index value when expanding the message
+                if (ognl.endsWith("]")) {
+                    ognl = ognl.substring(0, ognl.lastIndexOf("["));
+                }
 
                 collectionSize = calculateCollectionSize(ognl, params);
 
@@ -604,6 +719,7 @@
                     if(clonePoint == element) {
                         // If the clonePoint is the element itself, we remove it... we're done with it...
                         clonePoint.getParentNode().removeChild(clonePoint);
+                        elementRemoved = true;
                     } else {
                         // If the clonePoint is not the element itself (it's a child element), leave it
                         // and check it again when we get to it...
@@ -612,6 +728,7 @@
                 } else if(collectionSize == 0) {
                     // It's a collection, but has no entries, remove it...
                     clonePoint.getParentNode().removeChild(clonePoint);
+                    elementRemoved = true;
                 } else if(collectionSize == 1) {
                     // It's a collection, but no need to clone coz we
                     // already have an entry for it...
@@ -620,7 +737,7 @@
                     // It's a collection and we need to do some cloning
                     if(clonePoint != null) {
                         // We already have one, so decrement by one...
-                        cloneCollectionTemplateElement(clonePoint, (collectionSize - 1), ognl);
+                        cloneCollectionTemplateElement(clonePoint, (collectionSize - 1), ognl, params);
                     } else {
                         logger.warn("Collection/array template element <" + element.getLocalName() + "> would appear to be invalid.  It doesn't contain any child elements.");
                     }
@@ -628,7 +745,13 @@
             }
         }
 
-        // Now do the same for the child elements...
+        if (!elementRemoved){
+            // Now do the same for the child elements...
+            expandChildren(element, params);
+        }
+    }
+
+    private void expandChildren(Element element, Map params) {
         List<Node> children = YADOMUtil.copyNodeList(element.getChildNodes());
         for (Node node : children) {
             if (node.getNodeType() == Node.ELEMENT_NODE) {
@@ -682,16 +805,18 @@
         // Is it this element...
         comment = YADOMUtil.getCommentBefore(element);
         if(comment != null && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)) {
-            comment.setTextContent(comment.getTextContent() + CLONED_POSTFIX);
+            comment.setTextContent(comment.getTextContent() + OGNLUtils.CLONED_POSTFIX);
             return element;
         }
 
         // Is it the first child element of this element...
         Element firstChildElement = YADOMUtil.getFirstChildElement(element);
         if(firstChildElement != null) {
+            Element lastChildElement = YADOMUtil.getLastChildElement(element);
             comment = YADOMUtil.getCommentBefore(firstChildElement);
-            if(comment != null && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)) {
-                comment.setTextContent(comment.getTextContent() + CLONED_POSTFIX);
+            if(comment != null && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)
+                && lastChildElement != null && firstChildElement.getTagName().equals(lastChildElement.getTagName())) {
+                comment.setTextContent(comment.getTextContent() + OGNLUtils.CLONED_POSTFIX);
                 return firstChildElement;
             }
         }
@@ -707,11 +832,11 @@
         }
 
         String commentText = comment.getTextContent();
-        if(!commentText.endsWith(CLONED_POSTFIX)) {
+        if(!commentText.endsWith(OGNLUtils.CLONED_POSTFIX)) {
             throw new IllegalStateException("Call to reset a 'clonePoint' that doesn't have a proper clone comment before it.");
         }
 
-        comment.setTextContent(commentText.substring(0, commentText.length() - CLONED_POSTFIX.length()));
+        comment.setTextContent(commentText.substring(0, commentText.length() - OGNLUtils.CLONED_POSTFIX.length()));
     }
 
     /**
@@ -726,8 +851,9 @@
      * @param cloneCount The number of times it needs to be cloned.
      * @param ognl       The OGNL expression for the collection/array. Not including the
      *                   indexing part.
+     * @param params     The message params.
      */
-    private void cloneCollectionTemplateElement(Element element, int cloneCount, String ognl) {
+    private void cloneCollectionTemplateElement(Element element, int cloneCount, String ognl, Map params) {
         if (element == null) {
             return;
         }
@@ -746,6 +872,8 @@
             } else {
                 parent.insertBefore(clone, insertPoint);
             }
+            //The clones can have collections too, so we need to expand them here
+            expandChildren(clone, params);
         }
     }
 

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientServiceMBean.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientServiceMBean.java	2010-08-11 15:42:19 UTC (rev 34640)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/main/java/org/jboss/soa/esb/services/soapui/SoapUIClientServiceMBean.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -85,6 +85,23 @@
     public abstract String getEndpoint(String wsdl, Properties httpClientProps) throws IOException;
     
     /**
+     * Use soapUI mockService to Merge a SOAP response for the specified operation on the specified WSDL with its template.
+     *
+     * @param wsdl            WSDL URL.
+     * @param operation       Operation name.
+     * @param response        The actual response.
+     * @param smooksResource  {@link org.milyn.Smooks} transformation configuration resource file.
+     *                        Null if no transformations are to be performed on the SOAP message before serializing it
+     *                        for return.
+     * @param soapNs 		  optional SOAP namespace
+     * @return The SOAP Message.
+     * @throws IOException                   Failed to load WSDL.
+     * @throws UnsupportedOperationException Operation not supported on specified WSDL.
+     * @throws SAXException                  Failed to parse the SOAP UI generated request message.
+     */
+    public abstract String mergeResponseTemplate(String wsdl, String operation, String response, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException;
+
+    /**
      * Get the property file.
      * @return The name of the property file being used.
      */

Copied: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/JBESB_3327_SoapUIClientServiceMBeanUnitTest.java (from rev 33435, labs/jbossesb/trunk/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/JBESB_3327_SoapUIClientServiceMBeanUnitTest.java)
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/JBESB_3327_SoapUIClientServiceMBeanUnitTest.java	                        (rev 0)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/JBESB_3327_SoapUIClientServiceMBeanUnitTest.java	2010-08-11 16:06:29 UTC (rev 34641)
@@ -0,0 +1,92 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and others contributors as indicated
+ * by the @authors tag. All rights reserved.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ * (C) 2005-2006, JBoss Inc.
+ */
+package org.jboss.soa.esb.services.soapui;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import junit.framework.TestCase;
+
+import org.jboss.internal.soa.esb.util.XMLHelper;
+import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.http.HttpClientFactory;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ * @author <a href="mailto:mageshbk at jboss.com">Magesh Kumar B</a>
+ */
+public class JBESB_3327_SoapUIClientServiceMBeanUnitTest extends TestCase {
+
+    private static final String WSDL_LOCATAION = "src/test/java/org/jboss/soa/esb/services/soapui";
+    private Properties properties;
+
+    protected void setUp() throws Exception {
+        properties = new Properties();
+    }
+
+    public void test_collection_in_response() throws IOException, SAXException, ParserConfigurationException, ConfigurationException {
+        File wsdlFile = new File(WSDL_LOCATAION + "/collectionresponse.wsdl");
+        SoapUIClientService mbean = new SoapUIClientService();
+        String response = 
+                        "<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>\n" +
+                        "   <env:Header>\n" +
+                        "   </env:Header>\n" +
+                        "   <env:Body>\n" +
+                        "      <ord:processOrderResponse xmlns:ord='http://webservice_consumer_list/orderProcessor'>\n" +
+                        "         <OrderStatus>\n" +
+                        "            <id>1</id>\n" +
+                        "            <comment>order processed</comment>\n" +
+                        "            <returnCode>1</returnCode>\n" +
+                        "            <lineItems>\n" +
+                        "               <id>1</id>\n" +
+                        "               <name>Item1</name>\n" +
+                        "               <price>10</price>\n" +
+                        "               <comments>Item1 Comments1</comments>\n" +
+                        "               <comments>Item1 Comments2</comments>\n" +
+                        "            </lineItems>\n" +
+                        "            <lineItems>\n" +
+                        "               <id>2</id>\n" +
+                        "               <name>Item2</name>\n" +
+                        "               <price>15</price>\n" +
+                        "               <comments>Item2 Comments1</comments>\n" +
+                        "               <comments>Item2 Comments2</comments>\n" +
+                        "               <comments>Item2 Comments3</comments>\n" +
+                        "               <comments>Item2 Comments4</comments>\n" +
+                        "            </lineItems>\n" +
+                        "         </OrderStatus>\n" +
+                        "      </ord:processOrderResponse>\n" +
+                        "   </env:Body>\n" +
+                        "</env:Envelope>\n";
+
+        String expected = "expected_JBESB_3327_01.xml";
+
+        properties.setProperty(HttpClientFactory.TARGET_HOST_URL, wsdlFile.toURI().toString());
+
+        String message = mbean.mergeResponseTemplate(wsdlFile.toURI().toString(), "processOrder", response, properties, null, null);
+
+        assertTrue("Generated SOAP message not as expected. See " + expected + ".  Generated message: \n" + 
+                    message, XMLHelper.compareXMLContent(getClass().getResourceAsStream(expected), new ByteArrayInputStream(message.getBytes())));
+    }
+}
\ No newline at end of file

Copied: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/collectionresponse.wsdl (from rev 33435, labs/jbossesb/trunk/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/collectionresponse.wsdl)
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/collectionresponse.wsdl	                        (rev 0)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/collectionresponse.wsdl	2010-08-11 16:06:29 UTC (rev 34641)
@@ -0,0 +1,58 @@
+<definitions name="OrderProcessorWSService" targetNamespace="http://webservice_consumer_list/orderProcessor" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webservice_consumer_list/orderProcessor" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <types>
+  <xs:schema targetNamespace="http://webservice_consumer_list/orderProcessor" version="1.0" xmlns:tns="http://webservice_consumer_list/orderProcessor" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+   <xs:complexType name="order">
+    <xs:sequence>
+     <xs:element minOccurs="0" name="id" type="xs:long"/>
+     <xs:element maxOccurs="unbounded" minOccurs="0" name="lineItems" nillable="true" type="tns:lineItem"/>
+     <xs:element minOccurs="0" name="shipTo" type="xs:string"/>
+    </xs:sequence>
+   </xs:complexType>
+   <xs:complexType name="lineItem">
+    <xs:sequence>
+     <xs:element maxOccurs="unbounded" minOccurs="0" name="comments" nillable="true" type="xs:string"/>
+     <xs:element minOccurs="0" name="id" type="xs:long"/>
+     <xs:element minOccurs="0" name="name" type="xs:string"/>
+     <xs:element minOccurs="0" name="price" type="xs:float"/>
+    </xs:sequence>
+   </xs:complexType>
+   <xs:complexType name="orderStatus">
+    <xs:sequence>
+     <xs:element minOccurs="0" name="id" type="xs:long"/>
+     <xs:element minOccurs="0" name="comment" type="xs:string"/>
+     <xs:element name="returnCode" type="xs:int"/>
+     <xs:element maxOccurs="unbounded" minOccurs="0" name="lineItems" nillable="true" type="tns:lineItem"/>
+    </xs:sequence>
+   </xs:complexType>
+  </xs:schema>
+ </types>
+ <message name="OrderProcessor_processOrder">
+  <part name="order" type="tns:order"/>
+ </message>
+ <message name="OrderProcessor_processOrderResponse">
+  <part name="OrderStatus" type="tns:orderStatus"/>
+ </message>
+ <portType name="OrderProcessor">
+  <operation name="processOrder" parameterOrder="order">
+   <input message="tns:OrderProcessor_processOrder"/>
+   <output message="tns:OrderProcessor_processOrderResponse"/>
+  </operation>
+ </portType>
+ <binding name="OrderProcessorBinding" type="tns:OrderProcessor">
+  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
+  <operation name="processOrder">
+   <soap:operation soapAction=""/>
+   <input>
+    <soap:body namespace="http://webservice_consumer_list/orderProcessor" use="literal"/>
+   </input>
+   <output>
+    <soap:body namespace="http://webservice_consumer_list/orderProcessor" use="literal"/>
+   </output>
+  </operation>
+ </binding>
+ <service name="OrderProcessorWSService">
+  <port binding="tns:OrderProcessorBinding" name="OrderProcessorPort">
+   <soap:address location="http://127.0.0.1:8080/Quickstart_webservice_consumer_list/OrderProcessorWS"/>
+  </port>
+ </service>
+</definitions>
\ No newline at end of file

Copied: labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/expected_JBESB_3327_01.xml (from rev 33435, labs/jbossesb/trunk/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/expected_JBESB_3327_01.xml)
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/expected_JBESB_3327_01.xml	                        (rev 0)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/soapui-client/src/test/java/org/jboss/soa/esb/services/soapui/expected_JBESB_3327_01.xml	2010-08-11 16:06:29 UTC (rev 34641)
@@ -0,0 +1,32 @@
+<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
+   <env:Header>
+   </env:Header>
+   <env:Body>
+      <ord:processOrderResponse xmlns:ord='http://webservice_consumer_list/orderProcessor'>
+         <OrderStatus>
+            <id>1</id>
+            <comment>order processed</comment>
+            <returnCode>1</returnCode>
+            <!--Zero or more repetitions:-->
+            <lineItems>
+               <id>1</id>
+               <name>Item1</name>
+               <price>10</price>
+               <!--Zero or more repetitions:-->
+               <comments>Item1 Comments1</comments>
+               <comments>Item1 Comments2</comments>
+            </lineItems>
+            <lineItems>
+               <id>2</id>
+               <name>Item2</name>
+               <price>15</price>
+               <!--Zero or more repetitions:-->
+               <comments>Item2 Comments1</comments>
+               <comments>Item2 Comments2</comments>
+               <comments>Item2 Comments3</comments>
+               <comments>Item2 Comments4</comments>
+            </lineItems>
+         </OrderStatus>
+      </ord:processOrderResponse>
+   </env:Body>
+</env:Envelope>
\ No newline at end of file



More information about the jboss-svn-commits mailing list