You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by sc...@apache.org on 2011/05/09 23:54:08 UTC

svn commit: r1101239 - in /tuscany/sca-java-2.x/trunk/modules: assembly/src/main/java/org/apache/tuscany/sca/interfacedef/util/ databinding-axiom/src/main/java/org/apache/tuscany/sca/databinding/axiom/ databinding-axiom/src/test/java/org/apache/tuscany...

Author: scottkurz
Date: Mon May  9 21:54:07 2011
New Revision: 1101239

URL: http://svn.apache.org/viewvc?rev=1101239&view=rev
Log:
Fix for TUSCANY-3857.  Also addressed a problem writing wrapper elements with child elements with minOccurs="0" which not get written into the wrapper payload.

Modified:
    tuscany/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/util/ElementInfo.java
    tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/main/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandler.java
    tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/test/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandlerTestCase.java
    tuscany/sca-java-2.x/trunk/modules/interface-wsdl/src/main/java/org/apache/tuscany/sca/interfacedef/wsdl/impl/WSDLOperationIntrospectorImpl.java

Modified: tuscany/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/util/ElementInfo.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/util/ElementInfo.java?rev=1101239&r1=1101238&r2=1101239&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/util/ElementInfo.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/util/ElementInfo.java Mon May  9 21:54:07 2011
@@ -32,6 +32,7 @@ public class ElementInfo {
     private final TypeInfo type;
     private boolean many = false;
     private boolean nillable = false;
+    private boolean omissible = false;
 
     /**
      * @param name
@@ -80,6 +81,14 @@ public class ElementInfo {
         this.nillable = nillable;
     }
 
+    public boolean isOmissible() {
+        return omissible;
+    }
+    
+    public void setOmissible(boolean omissible) {
+        this.omissible = omissible;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;

Modified: tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/main/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandler.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/main/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandler.java?rev=1101239&r1=1101238&r2=1101239&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/main/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandler.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/main/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandler.java Mon May  9 21:54:07 2011
@@ -22,6 +22,7 @@ package org.apache.tuscany.sca.databindi
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.logging.Logger;
 
 import javax.xml.XMLConstants;
 import javax.xml.namespace.QName;
@@ -32,6 +33,7 @@ import org.apache.axiom.om.OMElement;
 import org.apache.axiom.om.OMFactory;
 import org.apache.axiom.om.OMNamespace;
 import org.apache.tuscany.sca.databinding.WrapperHandler;
+import org.apache.tuscany.sca.databinding.javabeans.JavaBeansDataBinding;
 import org.apache.tuscany.sca.interfacedef.DataType;
 import org.apache.tuscany.sca.interfacedef.Operation;
 import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
@@ -46,7 +48,7 @@ import org.apache.tuscany.sca.interfaced
  * @version $Rev$ $Date$
  */
 public class OMElementWrapperHandler implements WrapperHandler<OMElement> {
-
+    private final static Logger logger = Logger.getLogger(OMElementWrapperHandler.class.getName());
     private OMFactory factory;
 
     public OMElementWrapperHandler() {
@@ -87,8 +89,12 @@ public class OMElementWrapperHandler imp
 
     private void addChild(OMElement wrapper, ElementInfo childElement, OMElement element) {
         if (element == null) {
-            OMElement e = wrapper.getOMFactory().createOMElement(childElement.getQName(), wrapper);
-            attachXSINil(e);
+            // Prefer xsi:nil="true" 
+            if (childElement.isNillable()) {
+                OMElement e = wrapper.getOMFactory().createOMElement(childElement.getQName(), wrapper);
+                attachXSINil(e);
+            } 
+            // else, we might have minOccurs="0", so don't add anything to the wrapper.
             return;
         }
         QName elementName = childElement.getQName();
@@ -105,15 +111,147 @@ public class OMElementWrapperHandler imp
         List<ElementInfo> childElements = input? operation.getWrapper().getInputChildElements():
             operation.getWrapper().getOutputChildElements();
 
+        // Used in both the schema-valid and schema-invalid paths
+        List<List<OMElement>> groupedElements = getElements(wrapper);    
+        
+        List<Object> children = null;
+        try {
+            children = getValidChildren(groupedElements, childElements);
+        } catch (InvalidChildException e) {
+            children = getInvalidChildren(groupedElements, childElements);
+        }
+        return children;
+    }
+    
+    private List<Object> getValidChildren(List<List<OMElement>> groupedElementList, List<ElementInfo> elementInfoList) throws InvalidChildException {
         List<Object> elements = new ArrayList<Object>();
-        int i = 0;
-        for (ElementInfo e : childElements) {
-            elements.add(getChild(wrapper, e, i));
-            i++;
+
+        Iterator<List<OMElement>> groupedElementListIter = groupedElementList.iterator();
+        List<OMElement> currentElemGroup = null;
+        QName currentPayloadElemQName = null;
+        int currentPayloadElemGroupSize = 0;
+        QName currentElementInfoQName = null;
+
+        boolean first = true;
+        boolean lookAtNextElementGroup = true;
+        boolean matchedLastElementGroup = false;
+        for (ElementInfo currentElementInfo : elementInfoList) {
+            currentElementInfoQName = currentElementInfo.getQName();
+            logger.fine("Iterating to next ElementInfo child with QName: " +  currentElementInfoQName + 
+                        ". Control variables lookAtNextElementGroup = " + lookAtNextElementGroup + 
+                        ", matchedLastElementGroup = " + matchedLastElementGroup);
+
+            if (first || lookAtNextElementGroup) { 
+                first = false;
+                currentElemGroup = groupedElementListIter.next();
+                matchedLastElementGroup = false;
+                currentPayloadElemGroupSize = currentElemGroup.size();
+                if (currentPayloadElemGroupSize < 1) {
+                    String logMsg = "Not sure how this would occur based on getElements() impl, " +
+                                    "but give the other routine a chance to happen to work.";
+                    logger.fine(logMsg);
+                    throw new InvalidChildException(logMsg);
+                }   
+                currentPayloadElemQName = currentElemGroup.get(0).getQName();  
+                logger.fine("Iterating to next payload element group with QName: " + currentPayloadElemQName);
+            }
+            
+            if (currentElementInfoQName.equals(currentPayloadElemQName)) {
+                //A Match!
+                logger.fine("Matched payload to child ElementInfo for QName: " + currentElementInfoQName);
+                matchedLastElementGroup = true;
+
+                if (currentElementInfo.isMany()) {
+                    // Includes case where this is only a single element of a "many"-typed ElementInfo,
+                    // which therefore gets wrapped in an array.
+                    
+                    logger.fine("ElementInfo 'isMany' = true, and group size = " + currentPayloadElemGroupSize);
+                    // These elements are all "alike" each other in having the same element QName 
+                    Iterator<OMElement> likeElemIterator = currentElemGroup.iterator();
+                    List<OMElement> likeTypedElements = new ArrayList<OMElement>();
+                    while (likeElemIterator.hasNext()) {
+                        OMElement child = likeElemIterator.next();
+                        attachXSIType(currentElementInfo, child);
+                        likeTypedElements.add(child);
+                    }
+                    elements.add(likeTypedElements.toArray());          
+                } else {
+                    if (currentPayloadElemGroupSize != 1) {
+                        String logMsg = "Detected invalid data.  Group size = " + currentPayloadElemGroupSize + " but 'isMany' = false";
+                        logger.fine(logMsg);
+                        throw new InvalidChildException(logMsg);
+                    }
+                    logger.fine("Single element.");
+                    OMElement child = currentElemGroup.get(0);
+                    attachXSIType(currentElementInfo, child);
+                    elements.add(child);
+                }
+                
+                // Advance to next group of payload elements
+                lookAtNextElementGroup = true;                
+            } else {
+                // No Match!
+                logger.fine("Did not match payload QName: " + currentPayloadElemQName +
+                            ", with child ElementInfo for QName: " + currentElementInfoQName);
+                
+                // For schema to be valid, we must have a minOccurs="0" child 
+                if (currentElementInfo.isOmissible()) {
+                    logger.fine("Child ElementInfo 'isOmissible' = true, so look at next ElementInfo.");
+                     // We need to account for this child in the wrapper child list.  Tempting to try
+                     // to use an empty array instead of a null in case isMany=true, however without a more
+                     // complete architecture for this sort of thing it's probably better NOT to introduce such
+                     // nuanced behavior, and instead to keep it simpler for now, so as not to create dependencies
+                     // on a specific null vs. empty mapping.
+                    elements.add(null); 
+                } else {
+                    String logMsg = "Detected invalid data. Child ElementInfo 'isOmissible' = false.";
+                    logger.fine(logMsg);
+                    throw new InvalidChildException(logMsg);
+                }
+                
+                // Advance to next ElementInfo, staying on the same group of payload elements.
+                lookAtNextElementGroup = false;
+            }
+        }
+        
+        // We should fail the match and throw an exception if either:
+        // 1) We haven't matched the last payload element group  
+        // 2) Though we may have matched the last one, there are more, but we are out of ElementInfo children.
+        if (!matchedLastElementGroup || groupedElementListIter.hasNext()) {
+            String logMsg = "Exhausted list of ElementInfo children without matching payload element group with QName: " + currentPayloadElemQName;
+            logger.fine(logMsg);
+            throw new InvalidChildException(logMsg);
         }
+
+        
         return elements;
     }
 
+    
+    private List<Object> getInvalidChildren(List<List<OMElement>> groupedElementList, List<ElementInfo> childElements) {
+        List<Object> retVal = new ArrayList<Object>();
+        
+        // Since not all the ElementInfo(s) will be represented, (if some elements don't appear as children
+        // of the wrapper payload, we need to loop through the schema 
+        for (int index=0; index < groupedElementList.size(); index++) {          
+            List<OMElement> elements = groupedElementList.get(index);
+            ElementInfo childElement = childElements.get(index);  
+            if (!childElement.isMany()) {
+                Object next = elements.isEmpty() ? null : attachXSIType(childElement, elements.get(0));
+                retVal.add(next);
+            } else {
+                Object[] array = elements.toArray();
+                for (Object item : array) {
+                    attachXSIType(childElement, (OMElement)item);
+                }
+                retVal.add(array);
+            }
+        }
+        
+        return retVal;
+    }
+    
+
     /**
      * @see org.apache.tuscany.sca.databinding.WrapperHandler#getWrapperType(Operation, boolean)
      */
@@ -174,42 +312,7 @@ public class OMElementWrapperHandler imp
         }
         return elements;
     }
-
-    public Object getChild(OMElement wrapper, ElementInfo childElement, int index) {
-        Iterator children = wrapper.getChildrenWithName(childElement.getQName());
-        if (!children.hasNext()) {
-            // No name match, try by index
-            List<List<OMElement>> list = getElements(wrapper);
-            List<OMElement> elements = list.get(index);
-            if (!childElement.isMany()) {
-                return elements.isEmpty() ? null : attachXSIType(childElement, elements.get(0));
-            } else {
-                Object[] array = elements.toArray();
-                for (Object item : array) {
-                    attachXSIType(childElement, (OMElement)item);
-                }
-                return array;
-            }
-        }
-        if (!childElement.isMany()) {
-            if (children.hasNext()) {
-                OMElement child = (OMElement)children.next();
-                attachXSIType(childElement, child);
-                return child;
-            } else {
-                return null;
-            }
-        } else {
-            List<OMElement> elements = new ArrayList<OMElement>();
-            for (; children.hasNext();) {
-                OMElement child = (OMElement)children.next();
-                attachXSIType(childElement, child);
-                elements.add(child);
-            }
-            return elements.toArray();
-        }
-    }
-
+    
     /**
      * Create xis:type if required 
      * @param childElement
@@ -248,4 +351,19 @@ public class OMElementWrapperHandler imp
         OMAttribute attr = element.getOMFactory().createOMAttribute("nil", xsiNS, "true");
         element.addAttribute(attr);
     }
+    
+    
+    private class InvalidChildException extends Exception {
+
+        private static final long serialVersionUID = 4858608999124013014L;
+        
+        public InvalidChildException() {
+            super();
+        }
+        
+        public InvalidChildException(String message) {
+            super(message);
+        }
+    }
+
 }

Modified: tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/test/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandlerTestCase.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/test/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandlerTestCase.java?rev=1101239&r1=1101238&r2=1101239&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/test/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandlerTestCase.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/databinding-axiom/src/test/java/org/apache/tuscany/sca/databinding/axiom/OMElementWrapperHandlerTestCase.java Mon May  9 21:54:07 2011
@@ -20,12 +20,15 @@
 package org.apache.tuscany.sca.databinding.axiom;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamException;
 
+import org.apache.axiom.om.OMAbstractFactory;
 import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMFactory;
 import org.apache.axiom.om.util.AXIOMUtil;
 import org.apache.tuscany.sca.interfacedef.Operation;
 import org.apache.tuscany.sca.interfacedef.impl.OperationImpl;
@@ -71,32 +74,34 @@ public class OMElementWrapperHandlerTest
         + " </wrapper>";
 
     private OMElementWrapperHandler handler;
+    private Operation op;
 
     @Before
     public void setUp() throws Exception {
         this.handler = new OMElementWrapperHandler();
+
+        List<ElementInfo> elements = new ArrayList<ElementInfo>();
+        for (QName inQName : new QName[] { INPUT1, INPUT2, INPUT3, INPUT4 }) {
+            ElementInfo e = new ElementInfo(inQName, null);
+            e.setNillable(true);
+            elements.add(e);
+        }
+        // INPUT1,4 are like maxOccurs="unbounded"
+        elements.get(0).setMany(true);
+        elements.get(3).setMany(true);
+        // INPUT2 is like minOccurs="0", nillable="false"
+        elements.get(1).setOmissible(true);
+        elements.get(1).setNillable(false);
+
+        WrapperInfo wrapperInfo = new WrapperInfo(AxiomDataBinding.NAME, null, null, elements, null);
+        this.op = new OperationImpl();
+        op.setWrapper(wrapperInfo);   
     }
-    
-    // Would be nice to do a "set" test too.
 
     @Test
-    @Ignore("TUSCANY-3857")
     public void testGetChildren() {
         try {
             OMElement wrapperElem = AXIOMUtil.stringToOM(WRAPPER_XML);
-            List<ElementInfo> elements = new ArrayList<ElementInfo>();
-            for (QName inQName : new QName[] { INPUT1, INPUT2, INPUT3, INPUT4 }) {
-                ElementInfo e = new ElementInfo(inQName, null);
-                e.setNillable(true);
-                elements.add(e);
-            }
-            // INPUT1,4 are "many" 
-            elements.get(0).setMany(true);
-            elements.get(3).setMany(true);
-            
-            WrapperInfo wrapperInfo = new WrapperInfo(AxiomDataBinding.NAME, null, null, elements, null);
-            Operation op = new OperationImpl();
-            op.setWrapper(wrapperInfo);
             List children = handler.getChildren(wrapperElem, op, true);
             Assert.assertEquals(4, children.size());
             Object[] firstChild = (Object[])children.get(0);
@@ -108,11 +113,38 @@ public class OMElementWrapperHandlerTest
             Assert.assertEquals("input3ContentsA", thirdChild.getText());
             Object[] fourthChild = (Object[])children.get(3);
             Assert.assertEquals(1, fourthChild.length);
-
         } catch (XMLStreamException e) {
             throw new RuntimeException(e); 
         }
     }
 
+    @Test
+    public void testSetChildren() {
+        OMFactory factory = OMAbstractFactory.getOMFactory();
+        OMElement wrapper = factory.createOMElement("wrapper", "myNamespace", "myns");
+        OMElement[] in1 = new OMElement[2];
+        in1[0] = factory.createOMElement(INPUT1);
+        in1[1] = factory.createOMElement(INPUT1);
+        OMElement in2 = null;
+        OMElement   in3 = factory.createOMElement(INPUT3);
+        OMElement[] in4 = new OMElement[1];
+        in4[0] = factory.createOMElement(INPUT4);
+        Object[] parms = new Object[] {in1, in2, in3, in4};
+
+        handler.setChildren(wrapper, parms, op, true);
+
+        Iterator<OMElement> iter = (Iterator<OMElement>)wrapper.getChildElements();
+        OMElement elem1 = iter.next();
+        OMElement elem2 = iter.next(); 
+        OMElement elem3 = iter.next();
+        OMElement elem4 = iter.next();
+        Assert.assertFalse(iter.hasNext());
+
+        Assert.assertEquals(INPUT1, elem1.getQName());
+        Assert.assertEquals(INPUT1, elem2.getQName());
+        Assert.assertEquals(INPUT3, elem3.getQName());
+        Assert.assertEquals(INPUT4, elem4.getQName());
+    }
+
 }
 

Modified: tuscany/sca-java-2.x/trunk/modules/interface-wsdl/src/main/java/org/apache/tuscany/sca/interfacedef/wsdl/impl/WSDLOperationIntrospectorImpl.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-wsdl/src/main/java/org/apache/tuscany/sca/interfacedef/wsdl/impl/WSDLOperationIntrospectorImpl.java?rev=1101239&r1=1101238&r2=1101239&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-wsdl/src/main/java/org/apache/tuscany/sca/interfacedef/wsdl/impl/WSDLOperationIntrospectorImpl.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/interface-wsdl/src/main/java/org/apache/tuscany/sca/interfacedef/wsdl/impl/WSDLOperationIntrospectorImpl.java Mon May  9 21:54:07 2011
@@ -582,6 +582,7 @@ public class WSDLOperationIntrospectorIm
         ElementInfo elementInfo = new ElementInfo(element.getQName(), getTypeInfo(element.getSchemaType()));
         elementInfo.setMany(element.getMaxOccurs() > 1);
         elementInfo.setNillable(element.isNillable());
+        elementInfo.setOmissible(element.getMinOccurs()==0);
         return elementInfo;
     }