You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by sc...@apache.org on 2009/10/24 03:46:15 UTC

svn commit: r829296 [2/3] - in /webservices/axis2/trunk/java/modules: jaxws-integration/ jaxws-integration/test/org/apache/axis2/jaxws/sample/ jaxws-integration/test/org/apache/axis2/jaxws/sample/dlwminArrays/ jaxws/src/org/apache/axis2/datasource/jaxb...

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java Sat Oct 24 01:46:13 2009
@@ -20,34 +20,62 @@
 package org.apache.axis2.jaxws.marshaller.impl.alt;
 
 import org.apache.axis2.jaxws.ExceptionFactory;
+import org.apache.axis2.jaxws.description.AttachmentDescription;
+import org.apache.axis2.jaxws.description.AttachmentType;
 import org.apache.axis2.jaxws.description.EndpointDescription;
 import org.apache.axis2.jaxws.description.EndpointInterfaceDescription;
 import org.apache.axis2.jaxws.description.OperationDescription;
 import org.apache.axis2.jaxws.description.ParameterDescription;
 import org.apache.axis2.jaxws.i18n.Messages;
 import org.apache.axis2.jaxws.marshaller.MethodMarshaller;
+import org.apache.axis2.jaxws.message.Block;
 import org.apache.axis2.jaxws.message.Message;
+import org.apache.axis2.jaxws.message.OccurrenceArray;
 import org.apache.axis2.jaxws.message.Protocol;
+import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext;
+import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory;
 import org.apache.axis2.jaxws.message.factory.MessageFactory;
 import org.apache.axis2.jaxws.registry.FactoryRegistry;
 import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescription;
+import org.apache.axis2.util.JavaUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import javax.activation.DataHandler;
+import javax.jws.WebService;
+import javax.jws.WebParam.Mode;
 import javax.jws.soap.SOAPBinding.Style;
+import javax.xml.bind.JAXBElement;
 import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.ws.Holder;
 import javax.xml.ws.WebServiceException;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.TreeSet;
 
 /**
- * The Doc/Lit Wrapped Minimal Marshaller is used when 1) The web service is Doc/Lit Wrapped, and 2)
- * The wrapper and fault bean objects are missing (hence the term 'Minimal')
+ * The Doc/Lit Wrapped Minimal Marshaller is used when 
+ *   1) The web service is Doc/Lit Wrapped, and 
+ *   2) The wrapper and fault bean objects are missing (hence the term 'Minimal')
+ *   
+ */
+/**
+ * @author scheu
+ *
  */
 public class DocLitWrappedMinimalMethodMarshaller implements MethodMarshaller {
 
     private static Log log = LogFactory.getLog(DocLitWrappedMinimalMethodMarshaller.class);
 
+    private static JAXBBlockFactory factory =
+        (JAXBBlockFactory)FactoryRegistry.getFactory(JAXBBlockFactory.class);
+    
     public DocLitWrappedMinimalMethodMarshaller() {
         super();
     }
@@ -55,6 +83,9 @@
     public Message marshalRequest(Object[] signatureArguments, OperationDescription operationDesc)
             throws WebServiceException {
 
+        if (log.isDebugEnabled()) {
+            log.debug("enter marshalRequest operationDesc = " + operationDesc.getName());
+        }
         EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
         EndpointDescription endpointDesc = ed.getEndpointDescription();
         Protocol protocol = Protocol.getProtocolForBinding(endpointDesc.getClientBindingID());
@@ -107,12 +138,22 @@
 
             // We want to use "by Java Type" marshalling for 
             // all objects
-            for (PDElement pde : pdeList) {
+            for (int i=0; i<pdeList.size(); i++) {
+                
+                PDElement pde = pdeList.get(i);
+                
+                // If the actual value is an array or list
+                // this should be modeled as an 
+                // occurrence of elements
+                pde = processOccurrence(pde);
+                pdeList.set(i, pde);
+                
+                // Set by java type marshaling
                 ParameterDescription pd = pde.getParam();
                 Class type = pd.getParameterActualType();
                 pde.setByJavaTypeClass(type);
             }
-
+            
             // Put values onto the message
             MethodMarshallerUtils.toMessage(pdeList, m, packages);
             
@@ -121,39 +162,47 @@
                 m.setDoingSWA(true);
             }
 
+            if (log.isDebugEnabled()) {
+                log.debug("exit marshalRequest");
+            }
             return m;
         } catch (Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug("fail marshalRequest e=" + e);
+                log.debug(" " + JavaUtils.stackToString(e));
+            }
             throw ExceptionFactory.makeWebServiceException(e);
         }
+        
     }
 
     public Object[] demarshalRequest(Message message, OperationDescription operationDesc)
             throws WebServiceException {
 
+        if (log.isDebugEnabled()) {
+            log.debug("enter demarshalRequest operationDesc = " + operationDesc.getName());
+        }
         EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
         EndpointDescription endpointDesc = ed.getEndpointDescription();
 
         // Note all exceptions are caught and rethrown with a WebServiceException
         try {
-            // Sample RPC message
+         // Sample Document message
             // ..
             // <soapenv:body>
-            //    <m:op xmlns:m="urn://api">
-            //       <param xsi:type="data:foo" >...</param>
-            //    </m:op>
+            //    <m:operation>
+            //      <param>hello</param>
+            //    </m:operation>
             // </soapenv:body>
             //
             // Important points.
-            //   1) RPC has an operation element under the body.  This is the name of the
-            //      wsdl operation.
-            //   2) The data blocks are located underneath the operation element.  (In doc/lit
-            //      the data elements are underneath the body.
-            //   3) The name of the data blocks (param) are defined by the wsdl:part not the
-            //      schema.  Note that it is unqualified per WSI-BP
-            //   4) The type of the data block (data:foo) is defined by schema (thus there is 
-            //      JAXB type rendering.  
-            //   5) We always send an xsi:type, but other vendor's may not.
-            // Get the operation information
+            //   1) There is no operation element under the body.
+            //   2) The data blocks are located underneath the body.  
+            //   3) The name of the data block (m:operation) is defined by the schema and match the name of the operation.
+            //      This is called the wrapper element.  The wrapper element has a corresponding JAXB element pojo.
+            //   4) The parameters (m:param) are child elements of the wrapper element.
+            //   5) NOTE: For doc/literal wrapped "minimal", the wrapper JAXB element pojo is missing.
+            
             ParameterDescription[] pds = operationDesc.getParameterDescriptions();
             MarshalServiceRuntimeDescription marshalDesc =
                     MethodMarshallerUtils.getMarshalDesc(endpointDesc);
@@ -164,21 +213,42 @@
             message.setStyle(Style.DOCUMENT);
             message.setIndirection(1);
 
+            // Create an array of indices indicating where each parameter is located in the body
+            // A -1 indicates that the parameter is not in the body
+            int[] firstIndex = new int[pds.length];
+            int[] lastIndex = new int[pds.length];
+            for (int i=0; i<firstIndex.length; i++) {
+                firstIndex[i] = -1;  
+                lastIndex[i] = -1;  
+            }
+            calculateBodyIndex(firstIndex, lastIndex, pds, message.getBodyBlockQNames());
+            
             // We want to use "by Java Type" unmarshalling for 
             // all objects
             Class[] javaTypes = new Class[pds.length];
+            Class[] componentJavaTypes = new Class[pds.length];
             for (int i = 0; i < pds.length; i++) {
                 ParameterDescription pd = pds[i];
                 javaTypes[i] = pd.getParameterActualType();
+                if (javaTypes[i].isArray()) {
+                    componentJavaTypes[i] = javaTypes[i].getComponentType();
+                } else if (javaTypes[i].isAssignableFrom(List.class)) {
+                    componentJavaTypes[i] = getComponentType(pd, operationDesc, marshalDesc);
+                } else {
+                    componentJavaTypes[i]= null;
+                }   
             }
 
             // Unmarshal the ParamValues from the Message
-            List<PDElement> pvList = MethodMarshallerUtils.getPDElementsWithMissingElements(pds,
-                                                                         message,
-                                                                         packages,
-                                                                         true, // input
-                                                                         false,
-                                                                         javaTypes);  // sigh...unmarshal by type because there is no wrapper
+            List<PDElement> pvList = getPDElementsForDocLitWrappedMinimal(pds,
+                    message,
+                    packages,
+                    true, // input
+                    false,
+                    javaTypes,
+                    componentJavaTypes,
+                    firstIndex,
+                    lastIndex);
 
             // Build the signature arguments
             Object[] sigArguments = MethodMarshallerUtils.createRequestSignatureArgs(pds, pvList);
@@ -188,8 +258,15 @@
             // is for rpc/literal marshaling.  This code is for document/literal marshaling.
             // Nulls are allowed.
             
+            if (log.isDebugEnabled()) {
+                log.debug("exit demarshalRequest operationDesc");
+            }
             return sigArguments;
         } catch (Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug("fail demarshalRequest e= " + e);
+                log.debug(" " + JavaUtils.stackToString(e));
+            }
             throw ExceptionFactory.makeWebServiceException(e);
         }
     }
@@ -200,6 +277,10 @@
             throws WebServiceException {
 
 
+        if (log.isDebugEnabled()) {
+            log.debug("enter marshalResponse operationDesc = " + operationDesc.getName());
+        }
+        
         EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
         EndpointDescription endpointDesc = ed.getEndpointDescription();
         // We want to respond with the same protocol as the request,
@@ -210,26 +291,23 @@
 
         // Note all exceptions are caught and rethrown with a WebServiceException
         try {
-            // Sample RPC message
+            // Sample Document message
             // ..
             // <soapenv:body>
-            //    <m:opResponse xmlns:m="urn://api">
-            //       <param xsi:type="data:foo" >...</param>
-            //    </m:op>
+            //    <m:operationResponse ... >
+            //       <param>hello</param>
+            //    </m:operationResponse>
             // </soapenv:body>
             //
             // Important points.
-            //   1) RPC has an operation element under the body.  This is the name of the
-            //      wsdl operation.
-            //   2) The data blocks are located underneath the operation element.  (In doc/lit
-            //      the data elements are underneath the body.
-            //   3) The name of the data blocks (param) are defined by the wsdl:part not the
-            //      schema.  Note that it is unqualified.
-            //   4) The type of the data block (data:foo) is defined by schema (thus there is 
-            //      JAXB type rendering.  Since we are using JAXB to marshal the data, 
-            //      we always generate an xsi:type attribute.  This is an implemenation detail
-            //      and is not defined by any spec.
-
+            //   1) There is no operation element in the message
+            //   2) The data blocks are located underneath the body element. 
+            //   3) The name of the data block (m:operationResponse) is defined by the schema.
+            //      It matches the operation name + "Response", and it has a corresponding JAXB element.
+            //      This element is called the wrapper element
+            //   4) The parameters are (param) are child elements of the wrapper element.
+            //   5) For "minimal" the pojo bean representing the OperationResponse is missing.
+            
             // Get the operation information
             ParameterDescription[] pds = operationDesc.getParameterDescriptions();
             MarshalServiceRuntimeDescription marshalDesc =
@@ -272,7 +350,14 @@
                 }
                 Element returnElement = null;
                 QName returnQName = new QName(returnNS, returnLocalPart);
-                if (marshalDesc.getAnnotationDesc(returnType).hasXmlRootElement()) {
+                if (isListOrArray(returnObject)) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Return element isListOrArray");
+                    }
+                    OccurrenceArray occurrenceArray = new OccurrenceArray(returnObject);
+                    JAXBElement jaxb = new JAXBElement(returnQName, returnType, occurrenceArray);
+                    returnElement = new Element(jaxb, returnQName);
+                } else if (marshalDesc.getAnnotationDesc(returnType).hasXmlRootElement()) {
                     returnElement = new Element(returnObject, returnQName);
                 } else {
                     returnElement = new Element(returnObject, returnQName, returnType);
@@ -297,7 +382,17 @@
 
             // We want to use "by Java Type" marshalling for 
             // all objects
-            for (PDElement pde : pdeList) {
+            for (int i=0; i<pdeList.size(); i++) {
+                
+                PDElement pde = pdeList.get(i);
+                
+                // If the actual value is an array or list
+                // this should be modeled as an 
+                // occurrence of elements
+                pde = processOccurrence(pde);
+                pdeList.set(i, pde);
+                
+                // Set by java type marshaling
                 ParameterDescription pd = pde.getParam();
                 Class type = pd.getParameterActualType();
                 pde.setByJavaTypeClass(type);
@@ -312,41 +407,94 @@
                 m.setDoingSWA(true);
             }
 
+            if (log.isDebugEnabled()) {
+                log.debug("exit marshalResponse");
+            }
             return m;
         } catch (Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug("fail marshalResponse e= " + e);
+                log.debug(" " + JavaUtils.stackToString(e));
+            }
             throw ExceptionFactory.makeWebServiceException(e);
         }
     }
 
+    /**
+     * If the PDElement represents an array or List,
+     * a new PDElement is returned that models the 
+     * the array or List as a series of elements.
+     * @param pde
+     * @return new PDElement or same PDElement
+     */
+    private static PDElement processOccurrence(PDElement pde) {
+        // All arrays and lists should be marshaled as
+        // separate (occurrence) elements
+        Element element = pde.getElement();
+        if (element != null) {
+            Object elementValue = element.getElementValue();
+            if (elementValue instanceof JAXBElement) {
+                JAXBElement jaxb = (JAXBElement) elementValue;
+                Object value = jaxb.getValue();
+                if (isListOrArray(value)) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Build OccurrentArray");
+                    }
+                    OccurrenceArray occurrenceArray = new OccurrenceArray(value);
+                    JAXBElement newJAXBElement = 
+                        new JAXBElement(jaxb.getName(),
+                                jaxb.getDeclaredType(),
+                                occurrenceArray);
+                    element = new Element(newJAXBElement, jaxb.getName());
+                    pde = new PDElement(pde.getParam(), element, null);
+                }
+            }
+        }
+        return pde;
+    }
+    
+    /**
+     * @param value
+     * @return true if List or Array
+     */
+    private static boolean isListOrArray (Object value) {
+        boolean rc =(value instanceof List) || 
+                (value != null && value.getClass().isArray());
+        if (log.isDebugEnabled()) {
+            log.debug("isListOrArray for " + JavaUtils.getObjectIdentity(value) + " " + rc);
+        }
+        return rc;
+    }
 
     public Object demarshalResponse(Message message, Object[] signatureArgs,
                                     OperationDescription operationDesc)
             throws WebServiceException {
 
+        if (log.isDebugEnabled()) {
+            log.debug("enter demarshalResponse operationDesc = " + operationDesc.getName());
+        }
         EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
         EndpointDescription endpointDesc = ed.getEndpointDescription();
 
         // Note all exceptions are caught and rethrown with a WebServiceException
         try {
-            // Sample RPC message
+         // Sample Document message
             // ..
             // <soapenv:body>
-            //    <m:opResponse xmlns:m="urn://api">
-            //       <param xsi:type="data:foo" >...</param>
-            //    </m:op>
+            //    <m:operationResponse ... >
+            //       <param>hello</param>
+            //    </m:operationResponse>
             // </soapenv:body>
             //
             // Important points.
-            //   1) RPC has an operation element under the body.  This is the name of the
-            //      wsdl operation.
-            //   2) The data blocks are located underneath the operation element.  (In doc/lit
-            //      the data elements are underneath the body.
-            //   3) The name of the data blocks (param) are defined by the wsdl:part not the
-            //      schema.  Note that it is unqualified per WSI-BP
-            //   4) The type of the data block (data:foo) is defined by schema (thus there is 
-            //      JAXB type rendering.  
-            //   5) We always send an xsi:type, but other vendor's may not.
-            // Get the operation information
+            //   1) There is no operation element in the message
+            //   2) The data blocks are located underneath the body element. 
+            //   3) The name of the data block (m:operationResponse) is defined by the schema.
+            //      It matches the operation name + "Response", and it has a corresponding JAXB element.
+            //      This element is called the wrapper element
+            //   4) The parameters are (param) are child elements of the wrapper element.
+            //   5) For "minimal" the pojo bean representing the OperationResponse is missing
+            
             ParameterDescription[] pds = operationDesc.getParameterDescriptions();
             MarshalServiceRuntimeDescription marshalDesc =
                     MethodMarshallerUtils.getMarshalDesc(endpointDesc);
@@ -356,33 +504,66 @@
             message.setStyle(Style.DOCUMENT);
             message.setIndirection(1);
 
+            // Create an array of indices indicating where each parameter is located in the body
+            // A -1 indicates that the parameter is not in the body
+            int[] firstIndex = new int[pds.length];
+            int[] lastIndex = new int[pds.length];
+            for (int i=0; i<firstIndex.length; i++) {
+                firstIndex[i] = -1;  
+                lastIndex[i] = -1;  
+            }
+            calculateBodyIndex(firstIndex, lastIndex, pds, message.getBodyBlockQNames());
+            
+            int firstBodyParamIndex = -1;
+            
+            for (int i=0; i < pds.length; i++) {
+                if (pds[i].getMode() == Mode.OUT || pds[i].getMode() == Mode.INOUT) {
+                    if (firstIndex[i] >= 0 && firstBodyParamIndex == -1) {
+                        firstBodyParamIndex = firstIndex[i];
+                    }
+                }
+            }
+            
+            
             // Get the return value.
             Class returnType = operationDesc.getResultActualType();
+            Class returnComponentType = null;
+            if (returnType.isArray()) {
+                returnComponentType = returnType.getComponentType();
+            } else if (returnType.isAssignableFrom(List.class)) {
+                returnComponentType = getComponentType(null, operationDesc, marshalDesc);
+            } else {
+                returnComponentType= null;
+            }
             Object returnValue = null;
             boolean hasReturnInBody = false;
             if (returnType != void.class) {
                 // If the webresult is in the header, we need the name of the header so that we can find it.
                 Element returnElement = null;
                 if (operationDesc.isResultHeader()) {
-                    returnElement = MethodMarshallerUtils.getReturnElement(packages,
+                    returnElement = getReturnElementForDocLitWrappedMinimal(packages,
                                                                            message,
                                                                            returnType,
+                                                                           returnComponentType,
                                                                            operationDesc.isListType(),
                                                                            true,  // is a header
                                                                            operationDesc.getResultTargetNamespace(),
                                                                            // header ns
                                                                            operationDesc.getResultPartName(),     // header local part
-                                                                           MethodMarshallerUtils.numOutputBodyParams(pds) > 0);
+                                                                           MethodMarshallerUtils.numOutputBodyParams(pds) > 0,
+                                                                           firstBodyParamIndex);
 
                 } else {
-                    returnElement = MethodMarshallerUtils.getReturnElement(packages,
+                    returnElement = getReturnElementForDocLitWrappedMinimal(packages,
                                                                            message,
                                                                            returnType,
+                                                                           returnComponentType,
                                                                            operationDesc.isListType(),
                                                                            false,
                                                                            null,
                                                                            null,
-                                                                           MethodMarshallerUtils.numOutputBodyParams(pds) > 0);
+                                                                           MethodMarshallerUtils.numOutputBodyParams(pds) > 0,
+                                                                           firstBodyParamIndex);
                     hasReturnInBody = true;
 
                 }
@@ -400,26 +581,45 @@
             // We want to use "by Java Type" unmarshalling for 
             // all objects
             Class[] javaTypes = new Class[pds.length];
+            Class[] componentJavaTypes = new Class[pds.length];
             for (int i = 0; i < pds.length; i++) {
                 ParameterDescription pd = pds[i];
                 Class type = pd.getParameterActualType();
+                
+                if (type.isArray()) {
+                    componentJavaTypes[i] = type.getComponentType();
+                } else if (type.isAssignableFrom(List.class)) {
+                    componentJavaTypes[i] = getComponentType(pd, operationDesc, marshalDesc);
+                } else {
+                    componentJavaTypes[i]= null;
+                }
                 javaTypes[i] = type;
             }
 
             // Unmarshall the ParamValues from the Message
-            List<PDElement> pvList = MethodMarshallerUtils.getPDElements(pds,
-                                                                         message,
-                                                                         packages,
-                                                                         false, // output
-                                                                         hasReturnInBody,
-                                                                         javaTypes); // unmarshal by type
+            List<PDElement> pvList = getPDElementsForDocLitWrappedMinimal(pds,
+                    message,
+                    packages,
+                    false, // output
+                    hasReturnInBody,
+                    javaTypes,
+                    componentJavaTypes,
+                    firstIndex,
+                    lastIndex);
 
 
             // Populate the response Holders
             MethodMarshallerUtils.updateResponseSignatureArgs(pds, pvList, signatureArgs);
 
+            if (log.isDebugEnabled()) {
+                log.debug("exit demarshalResponse");
+            }
             return returnValue;
         } catch (Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug("fail demarshalResponse e=" + e);
+                log.debug(" " + JavaUtils.stackToString(e));
+            }
             throw ExceptionFactory.makeWebServiceException(e);
         }
     }
@@ -428,6 +628,9 @@
                                         OperationDescription operationDesc, Protocol protocol)
             throws WebServiceException {
 
+        if (log.isDebugEnabled()) {
+            log.debug("marshalFaultResponse operationDesc = " + operationDesc);
+        }
         EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
         EndpointDescription endpointDesc = ed.getEndpointDescription();
         MarshalServiceRuntimeDescription marshalDesc =
@@ -451,8 +654,15 @@
                                                        marshalDesc,
                                                        operationDesc,
                                                        m);
+            if (log.isDebugEnabled()) {
+                log.debug("exit marshalFaultResponse");
+            }
             return m;
         } catch (Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug("fail marshalFaultResponse e=" + e);
+                log.debug(" " + JavaUtils.stackToString(e));
+            }
             throw ExceptionFactory.makeWebServiceException(e);
         }
     }
@@ -460,6 +670,9 @@
     public Throwable demarshalFaultResponse(Message message, OperationDescription operationDesc)
             throws WebServiceException {
 
+        if (log.isDebugEnabled()) {
+            log.debug("demarshalFaultResponse operationDesc = " + operationDesc);
+        }
         EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
         EndpointDescription endpointDesc = ed.getEndpointDescription();
         MarshalServiceRuntimeDescription marshalDesc =
@@ -469,8 +682,15 @@
         try {
             Throwable t = MethodMarshallerUtils
                     .demarshalFaultResponse(operationDesc, marshalDesc, message);
+            if (log.isDebugEnabled()) {
+                log.debug("exit demarshalFaultResponse");
+            }
             return t;
         } catch (Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug("fail demarshalFaultResponse e=" +e);
+                log.debug(" " + JavaUtils.stackToString(e));
+            }
             throw ExceptionFactory.makeWebServiceException(e);
         }
     }
@@ -508,5 +728,556 @@
         qName = new QName(uri, localPart, prefix);
         return qName;
     }
+    
+    /**
+     * Return the list of PDElements that is unmarshalled from the wire.
+     * NOTE: This method is slower as the normal getPDElements method because it 
+     * must cache the message in order to do QName matches.
+     * This method is only necessary to support the cases where the incoming message
+     * may have missing data items.  
+     * Currently this is limited to the document/literal minimal case.
+     * 
+     * @param params ParameterDescription for this operation
+     * @param message Message
+     * @param packages set of packages needed to unmarshal objects for this operation
+     * @param isInput indicates if input or output  params (input on server, output on client)
+     * @param hasReturnInBody if isInput=false, then this parameter indicates whether a 
+     * return value is expected in the body.
+     * @param javaType 
+     * @param javaComponentType
+     * @param firstIndex (array indicating the first block corresponding to the parameter)
+     * @param lastIndex  (array indicating the last block corresponding to the parameter)
+     * @see getPDElements
+     * @return ParamValues
+     */
+    static List<PDElement> getPDElementsForDocLitWrappedMinimal(ParameterDescription[] params,
+                                         Message message,
+                                         TreeSet<String> packages,
+                                         boolean isInput,
+                                         boolean hasReturnInBody, 
+                                         Class[] javaType,
+                                         Class[] javaComponentType,
+                                         int[] firstIndex,
+                                         int[] lastIndex
+                                         ) throws XMLStreamException {
+
+        if (log.isDebugEnabled()) {
+            log.debug("start getPDElementsForDocLitWrappedMinimal");
+        }
+        List<PDElement> pdeList = new ArrayList<PDElement>();
+        
+        int totalBodyBlocks = message.getNumBodyBlocks();  
+        
+        
+        
+        // TODO What if return is an swa attachment, then this should start
+        // at 1 not 0.
+        int swaIndex = 0;
+        
+        for (int i = 0; i < params.length; i++) {
+            ParameterDescription pd = params[i];
+            
+            if (log.isDebugEnabled()) {
+                log.debug("  processing Parameter " + pd);
+            }
+            
+
+            if (pd.getMode() == Mode.IN && isInput ||
+                    pd.getMode() == Mode.INOUT ||
+                    pd.getMode() == Mode.OUT && !isInput) {
+
+                // Don't consider async handlers, they are are not represented on the wire,
+                // thus they don't have a PDElement
+                // TODO
+                //if (isAsyncHandler(param)) {
+                //    continue;
+                //}
+
+                Block block = null;
+                JAXBBlockContext context = new JAXBBlockContext(packages);
+
+                AttachmentDescription attachmentDesc = pd.getAttachmentDescription();
+                if (attachmentDesc == null) {
+                    
+                    // In most cases the entire java object is unmarshalled.
+                    // But in some cases, the java object is a series of
+                    // elements.
+                    boolean unmarshalComponents = false;
+                    if (pd.isListType() || javaComponentType[i] == null) {
+                        context.setProcessType(javaType[i]);
+                        context.setIsxmlList(pd.isListType());
+                    } else {
+                        context.setProcessType(javaComponentType[i]);
+                        unmarshalComponents = true;
+                    }
+                    
+                    
+                    // Unmarshal the object into a JAXB object or JAXBElement
+                    Element element = null;
+                    if (pd.isHeader()) {
+                        
+                        if (log.isDebugEnabled()) {
+                            log.debug("  get block from the headers");
+                        }
+                        // Get the Block from the header
+                        // NOTE The parameter name is always used to get the header 
+                        // element
+                        String localName = pd.getParameterName();
+                        block = message.getHeaderBlock(pd.getTargetNamespace(),
+                                                       localName,
+                                                       context,
+                                                       factory);
+                        element = new Element(block.getBusinessObject(true), 
+                                block.getQName());
+                    } else if (firstIndex[i] >= 0) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("  get block from the " + firstIndex[i] +
+                                    " to the " + lastIndex[i]);
+                        }
+                        // You must use this method if there are more than one body block
+                        // This method may cause OM expansion
+                        if (unmarshalComponents) {
+                            Object container = makeContainer(javaType[i],
+                                    javaComponentType[i],
+                                    (lastIndex[i] - firstIndex[i]) + 1);
+
+                            for (int blockI=firstIndex[i]; blockI<=lastIndex[i]; blockI++) {
+                                block = message.getBodyBlock(blockI, context, factory);
+                                Object value = block.getBusinessObject(true);
+                                if (value instanceof JAXBElement) {
+                                    value = ((JAXBElement) value).getValue();
+                                }
+                                if (log.isDebugEnabled()) {
+                                    log.debug(" get Business Object " + JavaUtils.getObjectIdentity(value) + " from block " + blockI);
+
+                                }
+
+                                addComponent(container, value, blockI - firstIndex[i]);
+                                
+                            }
+                            element = new Element(container,     
+                                    block.getQName());
+
+                        } else {
+                            block = message.getBodyBlock(firstIndex[i], context, factory);
+                            element = new Element(block.getBusinessObject(true), 
+                                    block.getQName());
+                        }
+                    }  else {
+                        // Missing parameter
+                        if (log.isDebugEnabled()) {
+                            log.debug("  there is no block for this parameter.");
+                        }
+                        QName qName = new QName(pd.getTargetNamespace(), pd.getPartName());
+                        if (!unmarshalComponents) {
+                            element = new Element(null, qName);
+                        } else {
+                            Object container = makeContainer(javaType[i],
+                                    javaComponentType[i], 0);
+                            element = new Element(container, qName);
+                        }
+                    }
+                    
+                    
+                    PDElement pde =
+                        new PDElement(pd, element, javaComponentType[i] == null ? null
+                                : javaComponentType[i]);
+                    pdeList.add(pde);
+                } else {
+                    // Attachment Processing
+                    if (attachmentDesc.getAttachmentType() == AttachmentType.SWA) {
+                        String partName = pd.getPartName();
+                        String cid = null;
+                        if (log.isDebugEnabled()) {
+                            log.debug("Getting the attachment dataHandler for partName=" + partName);
+                        }
+                        if (partName != null && partName.length() > 0) {
+                            // Compliant WS-I behavior
+                            cid = message.getAttachmentID(partName);
+                        }
+                        if (cid == null) {
+                            if (log.isDebugEnabled()) {
+                                log.debug("Attachment dataHandler was not found.  Fallback to use attachment " + swaIndex);
+                            }
+                            // Toleration mode for non-compliant attachment names
+                            cid = message.getAttachmentID(swaIndex);
+                        }
+                        DataHandler dh = message.getDataHandler(cid);
+                        Attachment attachment = new Attachment(dh, cid);
+                        PDElement pde = new PDElement(pd, null, null, attachment);
+                        pdeList.add(pde);
+                        swaIndex++;
+                    } else {
+                        throw ExceptionFactory.makeWebServiceException(Messages.getMessage("pdElementErr"));
+                    }
+                }
+            }
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("end getPDElementsWithMissingElements");
+        }
+        return pdeList;
+    }
+    
+    /**
+     * Calculate the index of the first block for the parameter and
+     * the last block (inclusive) for the parameter
+     * @param firstIndex
+     * @param lastIndex
+     * @param params
+     * @param qNames
+     */
+    private static void calculateBodyIndex(int[] firstIndex, int[] lastIndex, 
+            ParameterDescription[] params, 
+            List<QName> qNames) {
+        if (log.isDebugEnabled()) {
+            log.debug("Start calculateBodyIndex");
+            for (int i=0; i<qNames.size(); i++) {
+                log.debug("   QName " + i + " = " + qNames.get(i));
+            }
+        }
+        for (int pi=0; pi<params.length; pi++) {
+            if (pi >= 0) {
+                ParameterDescription pd = params[pi];
+                if (log.isDebugEnabled()) {
+                    log.debug("  ParameterDescription =" + pd.toString());
+                    log.debug("  original firstIndex = " + firstIndex[pi]);
+                    log.debug("  original lastIndex = " + lastIndex[pi]);
+                }
+                firstIndex[pi] = -1;  // Reset index
+                lastIndex[pi] = -1;  // Reset index
+                // Found a parameter that is expected in the body
+                // Calculate its index by looking for an exact qname match
+                for (int qi=0; qi<qNames.size(); qi++) {
+                    QName qName = qNames.get(qi);
+                    if (qName.getLocalPart().equals(pd.getPartName())) {
+                        if (qName.getNamespaceURI().equals(pd.getTargetNamespace())) {
+                            if (firstIndex[pi] < 0) {
+                                if(log.isDebugEnabled()) {
+                                    log.debug("    set first index to " + qi);
+                                }
+                                firstIndex[pi] = qi;
+                            }
+                            lastIndex[pi] = qi;
+                        }
+                    }
+                }
+                // Fallback to searching for just the part name
+                if (firstIndex[pi] < 0) {
+                    for (int qi=0; qi<qNames.size(); qi++) {
+                        QName qName = qNames.get(qi);
+                        if (qName.getLocalPart().equals(pd.getPartName())) {
+                            if (firstIndex[pi] < 0) {
+                                if(log.isDebugEnabled()) {
+                                    log.debug("    fallback: set first index to " + qi);
+                                }
+                                firstIndex[pi] = qi;
+                            }
+                            lastIndex[pi] = qi;
+                        }
+                    }
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug("  last index = " + lastIndex[pi]);
+                }
+            }
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("End calculateBodyIndex");
+        }
+    }
 
+    /**
+     * Unmarshal the return object from the message
+     *
+     * @param packages
+     * @param message
+     * @param javaTypeClass
+     * @param javaComponentTypeClass
+     * @param isHeader
+     * @param headerNS                 (only needed if isHeader)
+     * @param headerLocalPart          (only needed if isHeader)
+     * @param hasOutputBodyParams (true if the method has out or inout params other 
+     * than the return value)
+     * @param ioutputBodyArgIndes (first index of output body argument or -1)
+     * 
+     * @return Element
+     * @throws WebService
+     * @throws XMLStreamException
+     */
+    static Element getReturnElementForDocLitWrappedMinimal(TreeSet<String> packages,
+                                    Message message,
+                                    Class javaTypeClass,  
+                                    Class javaComponentTypeClass,  
+                                    boolean isList,
+                                    boolean isHeader,
+                                    String headerNS,
+                                    String headerLocalPart,
+                                    boolean hasOutputBodyParams,
+                                    int outputBodyArgIndex) 
+
+            throws WebServiceException, XMLStreamException {
+
+        // The return object is the first block in the body
+        JAXBBlockContext context = new JAXBBlockContext(packages);
+        
+        // In most cases the entire java object is unmarshalled.
+        // But in some cases, the java object is a series of
+        // elements.
+        boolean unmarshalComponents = false;
+        if (isList || javaComponentTypeClass == null) {
+            context.setProcessType(javaTypeClass);
+            context.setIsxmlList(isList);
+        } else {
+            context.setProcessType(javaComponentTypeClass);
+            unmarshalComponents = true;
+        }
+        
+        Element returnElement = null;
+        if (isHeader) {
+            
+            // In header
+            Block block = message.getHeaderBlock(headerNS, headerLocalPart, context, factory);
+            // Get the business object.  We want to return the object that represents the type.
+            returnElement = new Element(block.getBusinessObject(true), block.getQName());
+        } 
+        else {
+            // In Body
+            
+            // Determine how many return elements are present
+            int numBodyBlocks = message.getNumBodyBlocks();
+            if (outputBodyArgIndex >= 0) {
+                numBodyBlocks = outputBodyArgIndex;
+            }
+            if (!unmarshalComponents) {
+                if (numBodyBlocks == 1) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Case A: Not unmarshalling components, and only 1 block");
+                    }
+                    // Normal case: Only one body block
+                    // We can use the get body block method
+                    // that streams the whole block content.
+                    Block block = message.getBodyBlock(context, factory);
+                    //We look for body block only when the return type associated with operation is not void.
+                    //If a null body block is returned in response on a operation that is not void, its a user error.               
+                    returnElement = new Element(block.getBusinessObject(true), block.getQName());
+                } else if (numBodyBlocks > 1) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Case B: Not unmarshalling components, and multiple blocks");
+                    }
+                    // There is only one return element
+                    Block block = message.getBodyBlock(0, context, factory);
+                    returnElement = new Element(block.getBusinessObject(true), block.getQName());
+
+                }       
+            } else {        
+                if (numBodyBlocks > 0) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Case C: unmarshalling components.  Number of blocks=" + numBodyBlocks);
+                    }
+                    // Assume that all the qnames matching the first QName are for the return
+                    List<QName> qNames = message.getBodyBlockQNames();
+                    int firstIndex = 0;
+                    int lastIndex = 0;
+                    QName returnQName = qNames.get(0);
+                    if (log.isDebugEnabled()) {
+                        log.debug(" returnQName =" + returnQName);
+                    }
+                    do {
+                        lastIndex++;
+                    } while (lastIndex < qNames.size() &&
+                            returnQName.equals(qNames.get(lastIndex)));
+
+                    // Multiple Elements for QName
+                    int numElements = lastIndex - firstIndex;
+                    if (log.isDebugEnabled()) {
+                        log.debug(" number of return blocks=" + numElements);
+                    }
+                    Object container = makeContainer(javaTypeClass, 
+                            javaComponentTypeClass, 
+                            numElements);
+                    
+                    for (int blockI=firstIndex; blockI<lastIndex; blockI++) {
+                        Block block = message.getBodyBlock(blockI, context, factory);
+                        Object value = block.getBusinessObject(true);
+                        if (value instanceof JAXBElement) {
+                            value = ((JAXBElement) value).getValue();
+                        }
+                        if (log.isDebugEnabled()) {
+                            log.debug(" get return Business object (" + JavaUtils.getObjectIdentity(value) +
+                                    ") for block " + blockI);
+
+                        }
+                        
+                        addComponent(container, value, blockI);
+                        
+                        
+                    }
+                    returnElement = new Element(container, returnQName);
+
+                } else {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Case D: unmarshalling components, but there are no blocks");
+                    }
+                    Object container = makeContainer(javaTypeClass, 
+                            javaComponentTypeClass, 
+                            0);
+                    QName qName = new QName("", "return");
+                    returnElement = new Element(container, qName);
+                }
+            }
+        
+            //We look for body block only when the return type associated with operation is not void.
+            //If a null body block is returned in response on a operation that has non void return type, its a user error.
+            if (returnElement == null){
+                if(log.isDebugEnabled()){
+                    log.debug("Empty Body Block Found in response Message for wsdl Operation defintion that expects an Output");
+                    log.debug("Return type associated with SEI operation is not void, Body Block cannot be null");
+                }
+                throw ExceptionFactory.makeWebServiceException(Messages.getMessage("MethodMarshallerUtilErr1"));    
+            }
+        }
+        
+        if (log.isDebugEnabled()) {
+            log.debug("getReturnElementForDocLitWrappedMinimal " + JavaUtils.getObjectIdentity(returnElement));
+            
+        }
+        
+        return returnElement;
+    }
+    
+    /**
+     * Make a container array or List
+     * @param type
+     * @param componentType
+     * @param numComponents
+     * @return container array or list
+     */
+    private static Object makeContainer(Class type, 
+            Class componentType, 
+            int numComponents) {
+        Object container = null;
+        if (type.isArray()) {
+            container = Array.newInstance(componentType, 
+                    numComponents);
+        } else {
+            try {
+                container = type.newInstance();
+            } catch (Exception e) {
+                container = new ArrayList();
+            }
+        }
+        return container;
+    }
+    
+    /**
+     * Add component to the container object
+     * @param container array or List
+     * @param component
+     * @param index
+     * @param container
+     */
+    private static void addComponent(Object container, Object component, int index) {
+        if (container.getClass().isArray()) {
+            if (component != null) {
+                Array.set(container, index, component);
+            }
+        } else {
+            ((List) container).add(component);
+        }
+    }
+    
+    /**
+     * Return ComponentType, might need to look at the GenericType
+     * @param pd ParameterDesc or null if return
+     * @param operationDesc OperationDescription
+     * @param msrd MarshalServiceRuntimeDescription
+     * @return
+     */
+    private static Class getComponentType(ParameterDescription pd, 
+            OperationDescription operationDesc,    
+            MarshalServiceRuntimeDescription msrd) {
+        Class componentType = null;
+        if (log.isDebugEnabled()) {
+            log.debug("start getComponentType");
+            log.debug(" ParameterDescription=" + pd);
+        }
+        
+        // Determine if array, list, or other
+        Class cls = null;
+        if (pd == null) {
+            cls = operationDesc.getResultActualType();
+        } else {
+            cls = pd.getParameterActualType();
+        }
+        
+        if (cls != null) {
+            if (cls.isArray()) {
+                componentType = cls.getComponentType();
+            } else if (List.class.isAssignableFrom(cls)) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Parameter is a List: " + cls);
+                }
+                Method method = msrd.getMethod(operationDesc);
+                if (log.isDebugEnabled()) {
+                    log.debug("Method is: " + method);
+                }
+                Type genericType = null;
+                if (pd == null) {
+                   genericType =method.getGenericReturnType();
+                } else {
+                    ParameterDescription[] pds = operationDesc.getParameterDescriptions();
+                    for (int i=0; i< pds.length; i++) {
+                        if (pds[i] == pd) {
+                            genericType = method.getGenericParameterTypes()[i];
+                        }
+                    }
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug("genericType is: " + genericType.getClass() + " "+ genericType);
+                }
+                if (genericType instanceof Class) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(" genericType instanceof Class");
+                    }
+                    componentType =  String.class;
+                } else if (genericType instanceof ParameterizedType) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(" genericType instanceof ParameterizedType");
+                    }
+                    ParameterizedType pt = (ParameterizedType) genericType;
+                    if (pt.getRawType() == Holder.class) {
+                        if (log.isDebugEnabled()) {
+                            log.debug(" strip off holder");
+                        }
+                        genericType = pt.getActualTypeArguments()[0];
+                        if (genericType instanceof Class) {
+                            componentType =  String.class;
+                        } else if (genericType instanceof ParameterizedType) {
+                            pt = (ParameterizedType) genericType;
+                        }
+                    }
+                    if (componentType == null) {
+                        Type comp = pt.getActualTypeArguments()[0];
+                        if (log.isDebugEnabled()) {
+                            log.debug(" comp =" + comp.getClass() + " " + comp);
+                        }
+                        if (comp instanceof Class) {
+                            componentType = (Class) comp;
+                        } else if (comp instanceof ParameterizedType) {
+                            componentType = (Class) ((ParameterizedType) comp).getRawType();
+                        }
+                    }
+                }
+                    
+            }
+        }
+        
+        
+        if (log.isDebugEnabled()) {
+            log.debug("end getComponentType=" + componentType);
+        }
+        return componentType;
+    }
 }

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java Sat Oct 24 01:46:13 2009
@@ -372,245 +372,9 @@
         return pdeList;
     }
 
-    /**
-     * Return the list of PDElements that is unmarshalled from the wire.
-     * NOTE: This method is slower as the normal getPDElements method because it 
-     * must cache the message in order to do QName matches.
-     * This method is only necessary to support the cases where the incoming message
-     * may have missing data items.  
-     * Currently this is limited to the document/literal minimal case.
-     * 
-     * @param params ParameterDescription for this operation
-     * @param message Message
-     * @param packages set of packages needed to unmarshal objects for this operation
-     * @param isInput indicates if input or output  params (input on server, output on client)
-     * @param hasReturnInBody if isInput=false, then this parameter indicates whether a 
-     * return value is expected in the body.
-     * @param unmarshalByJavaType in most scenarios this is null.  
-     * Only use this in the scenarios that require unmarshalling by java type
-     * @see getPDElements
-     * @return ParamValues
-     */
-    static List<PDElement> getPDElementsWithMissingElements(ParameterDescription[] params,
-                                         Message message,
-                                         TreeSet<String> packages,
-                                         boolean isInput,
-                                         boolean hasReturnInBody, 
-                                         Class[] unmarshalByJavaType) throws XMLStreamException {
-
-        if (log.isDebugEnabled()) {
-            log.debug("start getPDElementsWithMissingElements");
-        }
-        List<PDElement> pdeList = new ArrayList<PDElement>();
-        
-        // Create an array of indices indicating where each parameter is located in the body
-        // A -1 indicates that the parameter is not in the body
-        int[] bodyIndex = new int[params.length];
-        for (int i=0; i<bodyIndex.length; i++) {
-            bodyIndex[i] = -1;  
-        }
-
-        // Calculate the array indices based on the parameter location 
-        int bi = (!isInput && hasReturnInBody) ? 1 : 0;  // If there is a return in the body, the output parameters start at index 1
-        for (int i = 0; i < params.length; i++) {
-            ParameterDescription pd = params[i];
-
-            if (pd.getMode() == Mode.IN && isInput ||
-                    pd.getMode() == Mode.INOUT ||
-                    pd.getMode() == Mode.OUT && !isInput) {
-                if (!pd.isHeader() && !isSWAAttachment(pd)) {
-                    bodyIndex[i] = bi;
-                    bi++;
-                }
-            }
-        }
-        int totalBodyBlocks = bi;        
-        
-        // Now recalculate the bodyIndex array if the number of expected body parameters 
-        // does not match the incoming message.
-        if (message.getNumBodyBlocks() != totalBodyBlocks) {
-            calculateBodyIndex(bodyIndex, params, message.getBodyBlockQNames());
-        }
-        
-        // TODO What if return is an swa attachment, then this should start
-        // at 1 not 0.
-        int swaIndex = 0;
-        
-        for (int i = 0; i < params.length; i++) {
-            ParameterDescription pd = params[i];
-            
-            if (log.isDebugEnabled()) {
-                log.debug("  processing Parameter " + pd);
-            }
-            
-
-            if (pd.getMode() == Mode.IN && isInput ||
-                    pd.getMode() == Mode.INOUT ||
-                    pd.getMode() == Mode.OUT && !isInput) {
-
-                // Don't consider async handlers, they are are not represented on the wire,
-                // thus they don't have a PDElement
-                // TODO
-                //if (isAsyncHandler(param)) {
-                //    continue;
-                //}
-
-                Block block = null;
-                JAXBBlockContext context = new JAXBBlockContext(packages);
-
-                AttachmentDescription attachmentDesc = pd.getAttachmentDescription();
-                if (attachmentDesc == null) {
-                    
-                    // Normal Processing: Not an Attachment
-                    // Trigger unmarshal by java type if necessary
-                    if (unmarshalByJavaType != null && unmarshalByJavaType[i] != null) {
-                        context.setProcessType(unmarshalByJavaType[i]);
-                        context.setIsxmlList(pd.isListType());
-                    }
-                    
-                    // Unmarshal the object into a JAXB object or JAXBElement
-                    Element element = null;
-                    if (pd.isHeader()) {
-                        
-                        if (log.isDebugEnabled()) {
-                            log.debug("  get block from the headers");
-                        }
-                        // Get the Block from the header
-                        // NOTE The parameter name is always used to get the header 
-                        // element
-                        String localName = pd.getParameterName();
-                        block = message.getHeaderBlock(pd.getTargetNamespace(),
-                                                       localName,
-                                                       context,
-                                                       factory);
-                        element = new Element(block.getBusinessObject(true), 
-                                block.getQName());
-                    } else if (bodyIndex[i] >= 0) {
-                        if (totalBodyBlocks > 1) {
-                            if (log.isDebugEnabled()) {
-                                log.debug("  get block from the " + bodyIndex[i] +
-                                        " element in the body block");
-                            }
-                            // You must use this method if there are more than one body block
-                            // This method may cause OM expansion
-                            block = message.getBodyBlock(bodyIndex[i], context, factory);
-                        } else {
-                            if (log.isDebugEnabled()) {
-                                log.debug("  this is the only block in the body block");
-                            }
-                            // Use this method if you know there is only one body block.
-                            // This method prevents OM expansion.
-                            block = message.getBodyBlock(context, factory);
-                        }
-                        element = new Element(block.getBusinessObject(true), 
-                                block.getQName());
-                    } else {
-                        // Missing parameter
-                        if (log.isDebugEnabled()) {
-                            log.debug("  there is no block for this parameter.");
-                        }
-                        QName qName = new QName(pd.getTargetNamespace(), pd.getPartName());
-                        element = new Element(null, qName);
-                    }
-                    
-                    
-                    PDElement pde =
-                        new PDElement(pd, element, unmarshalByJavaType == null ? null
-                                : unmarshalByJavaType[i]);
-                    pdeList.add(pde);
-                } else {
-                    // Attachment Processing
-                    if (attachmentDesc.getAttachmentType() == AttachmentType.SWA) {
-                        String partName = pd.getPartName();
-                        String cid = null;
-                        if (log.isDebugEnabled()) {
-                            log.debug("Getting the attachment dataHandler for partName=" + partName);
-                        }
-                        if (partName != null && partName.length() > 0) {
-                            // Compliant WS-I behavior
-                            cid = message.getAttachmentID(partName);
-                        }
-                        if (cid == null) {
-                            if (log.isDebugEnabled()) {
-                                log.debug("Attachment dataHandler was not found.  Fallback to use attachment " + swaIndex);
-                            }
-                            // Toleration mode for non-compliant attachment names
-                            cid = message.getAttachmentID(swaIndex);
-                        }
-                        DataHandler dh = message.getDataHandler(cid);
-                        Attachment attachment = new Attachment(dh, cid);
-                        PDElement pde = new PDElement(pd, null, null, attachment);
-                        pdeList.add(pde);
-                        swaIndex++;
-                    } else {
-                        throw ExceptionFactory.makeWebServiceException(Messages.getMessage("pdElementErr"));
-                    }
-                }
-            }
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("end getPDElementsWithMissingElements");
-        }
-        return pdeList;
-    }
     
-    /**
-     * @param bodyIndex
-     * @param params
-     * @param qNames
-     */
-    private static void calculateBodyIndex(int[] bodyIndex, 
-            ParameterDescription[] params, 
-            List<QName> qNames) {
-        if (log.isDebugEnabled()) {
-            log.debug("Start calculateBodyIndex");
-            for (int i=0; i<qNames.size(); i++) {
-                log.debug("   QName " + i + " = " + qNames.get(i));
-            }
-        }
-        for (int pi=0; pi<params.length; pi++) {
-            if (pi >= 0) {
-                ParameterDescription pd = params[pi];
-                if (log.isDebugEnabled()) {
-                    log.debug("  ParameterDescription =" + pd.toString());
-                    log.debug("  original bodyIndex = " + bodyIndex[pi]);
-                }
-                bodyIndex[pi] = -1;  // Reset index
-                // Found a parameter that is expected in the body
-                // Calculate its index by looking for an exact qname match
-                for (int qi=0; qi<qNames.size(); qi++) {
-                    QName qName = qNames.get(qi);
-                    if (qName.getLocalPart().equals(pd.getPartName())) {
-                        if (qName.getNamespaceURI().equals(pd.getTargetNamespace())) {
-                            if(log.isDebugEnabled()) {
-                                log.debug("    found exact match with " + qName);
-                            }
-                            bodyIndex[pi] = qi;
-                        }
-                    }
-                }
-                // Fallback to searching for just the part name
-                if (bodyIndex[pi] < 0) {
-                    for (int qi=0; qi<qNames.size(); qi++) {
-                        QName qName = qNames.get(qi);
-                        if (qName.getLocalPart().equals(pd.getPartName())) {
-                            if(log.isDebugEnabled()) {
-                                log.debug("    found fallback match with " + qName);
-                            }
-                            bodyIndex[pi] = qi;
-                        }
-                    }
-                }
-                if (log.isDebugEnabled()) {
-                    log.debug("  final bodyIndex = " + bodyIndex[pi]);
-                }
-            }
-        }
-        if (log.isDebugEnabled()) {
-            log.debug("End calculateBodyIndex");
-        }
-    }
+    
+    
     
     /**
      * Creates the request signature arguments (server) from a list

Added: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java?rev=829296&view=auto
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java (added)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java Sat Oct 24 01:46:13 2009
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.axis2.jaxws.message;
+
+import java.lang.reflect.Array;
+import java.util.List;
+
+import org.apache.axis2.util.JavaUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Used by the marshaling engine to wrap an array or List
+ * to indicate that the components should be marshaled
+ * as a series of elements (occurrence elements).
+ * 
+ * The DocLitMinimalMethodMarshaller will create
+ * a JAXBElement whose name is the name of the elements
+ * and whose value is a OccurrenceArray that 
+ * holds a List or array
+ * 
+ * @See DocLitWrappedMinimalMethodMarshaler
+ * @See JAXBDSContext
+ */
+public class OccurrenceArray {
+    
+    private static Log log = LogFactory.getLog(OccurrenceArray.class);
+    
+    // The held value will be a List or Array
+    Object value = null;
+    public OccurrenceArray(Object value) {
+        if (log.isDebugEnabled()) {
+            log.debug("Creating OccurrenceArray for " + JavaUtils.getObjectIdentity(value));
+        }
+        this.value = value;
+    }
+    
+    /**
+     * Get the List or array as a Object[]
+     * @return Object[] 
+     */
+    public Object[] getAsArray() {
+        Object[] objects = null;
+        if (value instanceof List) {
+            List l = (List) value;
+            objects = new Object[l.size()];
+            for (int i=0; i<l.size(); i++) {
+                objects[i] = l.get(i);
+            }
+        } else {
+            
+            objects = new Object[Array.getLength(value)];
+            for (int i=0; i<objects.length; i++) {
+                objects[i] = Array.get(value, i);
+            }
+        }
+        return objects;
+    }
+}

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java Sat Oct 24 01:46:13 2009
@@ -44,6 +44,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.ref.SoftReference;
 import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
 import java.net.URL;
 import java.net.URLDecoder;
 import java.security.PrivilegedActionException;
@@ -97,7 +98,10 @@
 
     // Construction Type
     public enum CONSTRUCTION_TYPE {
-        BY_CLASS_ARRAY, BY_CONTEXT_PATH, UNKNOWN}
+        BY_CLASS_ARRAY,   // New Instance with Class[] 
+        BY_CONTEXT_PATH,  // New Instance with context path string (preferred)
+        BY_CLASS_ARRAY_PLUS_ARRAYS, // New Instance with Class[] plus arrays of each class are added
+        UNKNOWN}
 
     ;
     
@@ -164,11 +168,38 @@
      * @throws JAXBException
      */
     public static JAXBContext getJAXBContext(TreeSet<String> contextPackages,
-                                             Holder<CONSTRUCTION_TYPE> constructionType, 
+                                             Holder<CONSTRUCTION_TYPE> constructionType,
                                              String key,
                                              ClassLoader cacheKey,
                                              Map<String, ?> properties)
             throws JAXBException {
+        return getJAXBContext(contextPackages, 
+                        constructionType, 
+                        false, 
+                        key, 
+                        cacheKey, 
+                        properties);
+    }
+    /**
+     * Get a JAXBContext for the class
+     *
+     * Note: The contextPackage object is used by multiple threads.  It should be considered immutable
+     * and not altered by this method.
+     * 
+     * @param contextPackage  Set<Package> 
+     * @param contructionType (output value that indicates how the context was constructed)
+     * @param forceArrays (forces the returned JAXBContext to include the array types)
+     * @param cacheKey ClassLoader
+     * @return JAXBContext
+     * @throws JAXBException
+     */
+    public static JAXBContext getJAXBContext(TreeSet<String> contextPackages,
+                                             Holder<CONSTRUCTION_TYPE> constructionType, 
+                                             boolean forceArrays,
+                                             String key,
+                                             ClassLoader cacheKey,
+                                             Map<String, ?> properties) 
+        throws JAXBException {
         // JAXBContexts for the same class can be reused and are supposed to be thread-safe
         if (log.isDebugEnabled()) {
             log.debug("Following packages are in this batch of getJAXBContext() :");
@@ -220,7 +251,18 @@
             contextValue = innerMap.get(cl);
         }
       
-        
+        // If the context value is found, but the caller requested that the JAXBContext
+        // contain arrays, then rebuild the JAXBContext value
+        if (forceArrays &&
+            contextValue != null && 
+            contextValue.constructionType != JAXBUtils.CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS) {
+            if(log.isDebugEnabled()) {
+                log.debug("Found a JAXBContextValue with constructionType=" + 
+                            contextValue.constructionType + "  but the caller requested a JAXBContext " +
+                          " that includes arrays.  A new JAXBContext will be built");
+            }
+            contextValue = null;
+        }
 
         if (contextPackages == null) {
             contextPackages = new TreeSet<String>();
@@ -231,6 +273,11 @@
                 ClassLoader clKey = (cacheKey != null) ? cacheKey:cl;
                 contextValue = innerMap.get(clKey);
                 adjustPoolSize(innerMap);
+                if (forceArrays &&
+                        contextValue != null && 
+                        contextValue.constructionType != JAXBUtils.CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS) {
+                    contextValue = null;
+                }
                 if (contextValue==null) {
                     // Create a copy of the contextPackages.  This new TreeSet will
                     // contain only the valid contextPackages.
@@ -240,13 +287,14 @@
                     TreeSet<String> validContextPackages = new TreeSet<String>(contextPackages); 
                     
                     ClassLoader tryCl = cl;
-                    contextValue = createJAXBContextValue(validContextPackages, cl, properties);
+                    contextValue = createJAXBContextValue(validContextPackages, cl, forceArrays, properties);
 
                     // If we don't get all the classes, try the cached classloader 
                     if (cacheKey != null && validContextPackages.size() != contextPackages.size()) {
                         tryCl = cacheKey;
                         validContextPackages = new TreeSet<String>(contextPackages);
-                        contextValue = createJAXBContextValue(validContextPackages, cacheKey, properties);
+                        contextValue = createJAXBContextValue(validContextPackages, cacheKey, 
+                                                              forceArrays, properties);
                     }
                     synchronized (jaxbMap) {
                         // Add the context value with the original package set
@@ -254,7 +302,7 @@
                         SoftReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>> 
                         softRef1 = jaxbMap.get(key);
                         if (softRef1 != null) {
-                            map1 = softRef.get();
+                            map1 = softRef1.get();
                         }
                         if (map1 == null) {
                             map1 = new ConcurrentHashMap<ClassLoader, JAXBContextValue>();
@@ -271,13 +319,13 @@
                         SoftReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>> 
                         softRef2 = jaxbMap.get(validPackagesKey);
                         if (softRef2 != null) {
-                            map2 = softRef.get();
+                            map2 = softRef2.get();
                         }
                         if (map2 == null) {
                             map2 = new ConcurrentHashMap<ClassLoader, JAXBContextValue>();
                             softRef2 = 
                                 new SoftReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>(map2);
-                            jaxbMap.put(key, softRef2);
+                            jaxbMap.put(validPackagesKey, softRef2);
                         }
                         map2.put(clKey, contextValue);
                         
@@ -293,6 +341,11 @@
                 log.debug("JAXBContext [from pool] for " + key);
             }
         }
+        if (log.isDebugEnabled()) {
+            log.debug("JAXBContext constructionType= " + contextValue.constructionType);
+            log.debug("JAXBContextValue = " + JavaUtils.getObjectIdentity(contextValue));
+            log.debug("JAXBContext = " + JavaUtils.getObjectIdentity(contextValue.jaxbContext));
+        }
         constructionType.value = contextValue.constructionType;
         return contextValue.jaxbContext;
     }
@@ -302,11 +355,14 @@
      *
      * @param contextPackages Set<String>
      * @param cl              ClassLoader
+     * @param forceArrays     boolean (true if JAXBContext must include all arrays)
+     * @param properties      Map of properties for the JAXBContext.newInstance creation method
      * @return JAXBContextValue (JAXBContext + constructionType)
      * @throws JAXBException
      */
     private static JAXBContextValue createJAXBContextValue(TreeSet<String> contextPackages,
                                                            ClassLoader cl,
+                                                           boolean forceArrays,
                                                            Map<String, ?> properties) throws JAXBException {
 
         JAXBContextValue contextValue = null;
@@ -374,7 +430,7 @@
         // The packages are examined to see if they have ObjectFactory/package-info classes.
         // Invalid packages are removed from the list
         it = contextPackages.iterator();
-        boolean contextConstruction = true;
+        boolean contextConstruction = (!forceArrays);
         boolean isJAXBFound = false;
         while (it.hasNext()) {
             String p = it.next();
@@ -413,7 +469,7 @@
 
         if (!isJAXBFound) {
             if (log.isDebugEnabled()) {
-                log.debug("Both ObjectFactory & package-info not found in package hierachy");
+                log.debug("ObjectFactory & package-info are not found in package hierachy");
             }
         }
 
@@ -428,6 +484,17 @@
         
         if (innerMap != null) {
             contextValue = innerMap.get(cl);
+            if (forceArrays &&
+                    contextValue != null && 
+                    contextValue.constructionType != JAXBUtils.CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS) {
+                if(log.isDebugEnabled()) {
+                    log.debug("Found a JAXBContextValue with constructionType=" + 
+                            contextValue.constructionType + "  but the caller requested a JAXBContext " +
+                    " that includes arrays.  A new JAXBContext will be built");
+                }
+                contextValue = null;
+            } 
+            
             if (contextValue != null) {
                 if (log.isDebugEnabled()) {
                     log.debug("Successfully found JAXBContext with updated context list:" +
@@ -458,7 +525,11 @@
             Class[] classArray = fullList.toArray(new Class[0]);
             JAXBContext context = JAXBContext_newInstance(classArray, cl, properties);
             if (context != null) {
-                contextValue = new JAXBContextValue(context, CONSTRUCTION_TYPE.BY_CLASS_ARRAY);
+                if (forceArrays) {
+                    contextValue = new JAXBContextValue(context, CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS);
+                } else {
+                    contextValue = new JAXBContextValue(context, CONSTRUCTION_TYPE.BY_CLASS_ARRAY);
+                }
             }
         }
         if (log.isDebugEnabled()) {
@@ -553,6 +624,7 @@
      */
     public static Marshaller getJAXBMarshaller(JAXBContext context) throws JAXBException {
         Marshaller m = null;
+        
         if (!ENABLE_MARSHALL_POOLING) {
             if (log.isDebugEnabled()) {
                 log.debug("Marshaller created [no pooling]");
@@ -585,6 +657,8 @@
     public static void releaseJAXBMarshaller(JAXBContext context, Marshaller marshaller) {
         if (log.isDebugEnabled()) {
             log.debug("Marshaller placed back into pool");
+            log.debug("  Marshaller = " + JavaUtils.getObjectIdentity(marshaller));
+            log.debug("  JAXBContext = " + JavaUtils.getObjectIdentity(context));
         }
         if (ENABLE_MARSHALL_POOLING) {
             marshaller.setAttachmentMarshaller(null);
@@ -933,6 +1007,7 @@
             "javax.xml.namespace.QName[]" };
 
     private static void addCommonArrayClasses(List<Class> list) {
+        
         // Add common primitives arrays (necessary for RPC list type support)
         ClassLoader cl = getContextClassLoader();
 
@@ -954,7 +1029,10 @@
                 }
             }
         }
+        
     }
+    
+    
 
     /** @return ClassLoader */
     private static ClassLoader getContextClassLoader() {

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java Sat Oct 24 01:46:13 2009
@@ -571,6 +571,9 @@
                                                            operationQName.getPrefix());
             opElement.setLocalName(operationQName.getLocalPart());
             opElement.setNamespace(ns);
+            
+            // Necessary to avoid duplicate namespaces later.
+            opElement.declareNamespace("http://www.w3.org/2001/XMLSchema-instance", "xsi");
         }
     }
 

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java Sat Oct 24 01:46:13 2009
@@ -25,6 +25,7 @@
 import org.apache.axis2.jaxws.message.factory.MessageFactory;
 import org.apache.axis2.jaxws.utility.PropertyDescriptorPlus;
 
+import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.TreeSet;
 
@@ -76,6 +77,13 @@
      * @return FaultBeanDescriptor that describes the fault bean
      */
     public FaultBeanDesc getFaultBeanDesc(FaultDescription faultDesc);
+    
+    /**
+     * @param opDesc
+     * @return Method
+     */
+    public Method getMethod(OperationDescription opDesc);
+    
 
     /** @return MessageFactory for this Marshaller */
     public MessageFactory getMessageFactory();