svn commit: r1243026 - in /ofbiz/trunk/framework: entity/src/org/ofbiz/entity/serialize/XmlSerializer.java service/src/org/ofbiz/service/ModelService.java webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1243026 - in /ofbiz/trunk/framework: entity/src/org/ofbiz/entity/serialize/XmlSerializer.java service/src/org/ofbiz/service/ModelService.java webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java

jleroux@apache.org
Author: jleroux
Date: Sat Feb 11 10:50:56 2012
New Revision: 1243026

URL: http://svn.apache.org/viewvc?rev=1243026&view=rev
Log:
OFBiz SOAP implementation was not handling
* null values in Map
* BigDecimal
* correctly TimeStamp format (we use xsd:dateTime in ModelService.getTypes())
So CXF was not able to unmarshall a List of Maps with those types in them.

It does not introduce any regressions:
* A new specific SOAP null type is introduced using ("nillable","true") and ("xsi:nil","true) attributes. I had also to set the http://www.w3.org/2001/XMLSchema-instance schema on the null node. Because it was impossible to add it in the envelope header, not a big deal anyway.
* I introduced a 'T' in the TimeStamp format. It's is OK, the deserialisation handles it well (we use xsd:dateTime, see  http://www.w3.org/TR/xmlschema-2/#dateTime)/. We don't handle TimeZone...
* BigDecimal was missing and is now correctly handled. I used 10 decimals and half up rounding (ROUND_HALF_UP)

Also improves the SOAPEventHandler.sendError() method by passing the serviceName in the message

Modified:
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/serialize/XmlSerializer.java
    ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/serialize/XmlSerializer.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/serialize/XmlSerializer.java?rev=1243026&r1=1243025&r2=1243026&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/serialize/XmlSerializer.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/serialize/XmlSerializer.java Sat Feb 11 10:50:56 2012
@@ -22,6 +22,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.Serializable;
 import java.lang.ref.WeakReference;
+import java.math.BigDecimal;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -130,7 +131,7 @@ public class XmlSerializer {
     public static Element serializeSingle(Object object, Document document) throws SerializeException {
         if (document == null) return null;
 
-        if (object == null) return document.createElement("null");
+        if (object == null) return makeElement("null", object, document);
 
         // - Standard Objects -
         if (object instanceof String) {
@@ -147,9 +148,13 @@ public class XmlSerializer {
             return makeElement("std-Boolean", object, document);
         } else if (object instanceof Locale) {
             return makeElement("std-Locale", object, document);
+        } else if (object instanceof BigDecimal) {
+            String stringValue = ((BigDecimal) object).setScale(10, BigDecimal.ROUND_HALF_UP).toString();            
+            return makeElement("std-BigDecimal", stringValue, document);
             // - SQL Objects -
         } else if (object instanceof java.sql.Timestamp) {
-            return makeElement("sql-Timestamp", object, document);
+            String stringValue = object.toString().replace(' ', 'T');
+            return makeElement("sql-Timestamp", stringValue, document);
         } else if (object instanceof java.sql.Date) {
             return makeElement("sql-Date", object, document);
         } else if (object instanceof java.sql.Time) {
@@ -268,7 +273,15 @@ public class XmlSerializer {
     }
 
     public static Element makeElement(String elementName, Object value, Document document) {
-        if (value == null) return document.createElement("null");
+        if (value == null) {
+            Element element = document.createElement("null");
+            element.setAttribute("xsi:nil", "true");
+            // I tried to put the schema in the envelope header (in createAndSendSOAPResponse)
+            // resEnv.declareNamespace("http://www.w3.org/2001/XMLSchema-instance", null);
+            // But it gets prefixed and that does not work. So adding in each instance
+            element.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+            return element;
+        }
         Element element = document.createElement(elementName);
 
         element.setAttribute("value", value.toString());

Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java?rev=1243026&r1=1243025&r2=1243026&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java (original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java Sat Feb 11 10:50:56 2012
@@ -1365,6 +1365,18 @@ public class ModelService extends Abstra
         /*--------- Standard Objects --------*/
         /*-----------------------------------*/
 
+        /* null Element */
+        Element stdNullElement = document.createElement("xsd:element");
+        stdNullElement.setAttribute("name", "null");
+        Element stdNullElement0 = document.createElement("xsd:complexType");
+        stdNullElement.appendChild(stdNullElement0);
+        Element stdNullElement1 = document.createElement("xsd:attribute");
+        stdNullElement0.appendChild(stdNullElement1);
+        stdNullElement1.setAttribute("name", "value");
+        stdNullElement1.setAttribute("type", "xsd:string");
+        stdNullElement1.setAttribute("use", "required");
+        stdNullElement1.setAttribute("nillable", "true");
+        schema.appendChild(stdNullElement);
         /* std-String Element */
         Element stdStringElement = document.createElement("xsd:element");
         stdStringElement.setAttribute("name", "std-String");
@@ -1442,6 +1454,17 @@ public class ModelService extends Abstra
         stdLocaleElement1.setAttribute("type", "xsd:string");
         stdLocaleElement1.setAttribute("use", "required");
         schema.appendChild(stdLocaleElement);
+        /* std-BigDecimal Element */
+        Element stdBigDecimalElement = document.createElement("xsd:element");
+        stdBigDecimalElement.setAttribute("name", "std-BigDecimal");
+        Element stdBigDecimalElement0 = document.createElement("xsd:complexType");
+        stdBigDecimalElement.appendChild(stdBigDecimalElement0);
+        Element stdBigDecimalElement1 = document.createElement("xsd:attribute");
+        stdBigDecimalElement0.appendChild(stdBigDecimalElement1);
+        stdBigDecimalElement1.setAttribute("name", "value");
+        stdBigDecimalElement1.setAttribute("type", "xsd:decimal");
+        stdBigDecimalElement1.setAttribute("use", "required");
+        schema.appendChild(stdBigDecimalElement);
 
         /*-----------------------------------*/
         /*----------- SQL Objects -----------*/
@@ -1652,6 +1675,12 @@ public class ModelService extends Abstra
         mapValueComplexType.setAttribute("name", "map-Value");
         Element mapValueComplexType0 = document.createElement("xsd:choice");
         mapValueComplexType.appendChild(mapValueComplexType0);
+        Element mapValueComplexTypeNull = document.createElement("xsd:element");
+        mapValueComplexTypeNull.setAttribute("ref", "tns:null");
+        mapValueComplexTypeNull.setAttribute("minOccurs", "1");
+        mapValueComplexTypeNull.setAttribute("maxOccurs", "1");
+        mapValueComplexTypeNull.setAttribute("nillable", "true");
+        mapValueComplexType0.appendChild(mapValueComplexTypeNull);
         Element mapValueComplexType1 = document.createElement("xsd:element");
         mapValueComplexType1.setAttribute("ref", "tns:std-String");
         mapValueComplexType1.setAttribute("minOccurs", "1");
@@ -1778,12 +1807,24 @@ public class ModelService extends Abstra
         mapValueComplexType25.setAttribute("maxOccurs", "1");
         mapValueComplexType0.appendChild(mapValueComplexType25);
         schema.appendChild(mapValueComplexType);
+        Element mapValueComplexType26 = document.createElement("xsd:element");
+        mapValueComplexType26.setAttribute("ref", "tns:std-BigDecimal");
+        mapValueComplexType26.setAttribute("minOccurs", "1");
+        mapValueComplexType26.setAttribute("maxOccurs", "1");
+        mapValueComplexType0.appendChild(mapValueComplexType26);
+        schema.appendChild(mapValueComplexType);
 
         /* col-Collection Complex Type */
         Element colCollectionComplexType = document.createElement("xsd:complexType");
         colCollectionComplexType.setAttribute("name", "col-Collection");
         Element colCollectionComplexType0 = document.createElement("xsd:choice");
         colCollectionComplexType.appendChild(colCollectionComplexType0);
+        Element colCollectionComplexTypeNull = document.createElement("xsd:element");
+        colCollectionComplexTypeNull.setAttribute("ref", "tns:null");
+        colCollectionComplexTypeNull.setAttribute("minOccurs", "0");
+        colCollectionComplexTypeNull.setAttribute("maxOccurs", "unbounded");
+        colCollectionComplexTypeNull.setAttribute("nillable", "true");
+        colCollectionComplexType0.appendChild(colCollectionComplexTypeNull);
         Element colCollectionComplexType1 = document.createElement("xsd:element");
         colCollectionComplexType1.setAttribute("ref", "tns:std-String");
         colCollectionComplexType1.setAttribute("minOccurs", "0");
@@ -1910,6 +1951,12 @@ public class ModelService extends Abstra
         colCollectionComplexType25.setAttribute("maxOccurs", "unbounded");
         colCollectionComplexType0.appendChild(colCollectionComplexType25);
         schema.appendChild(colCollectionComplexType);
+        Element colCollectionComplexType26 = document.createElement("xsd:element");
+        colCollectionComplexType26.setAttribute("ref", "tns:std-BigDecimal");
+        colCollectionComplexType26.setAttribute("minOccurs", "0");
+        colCollectionComplexType26.setAttribute("maxOccurs", "unbounded");
+        colCollectionComplexType0.appendChild(colCollectionComplexType26);
+        schema.appendChild(colCollectionComplexType);
 
         types.setDocumentationElement(schema);
         return types;

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java?rev=1243026&r1=1243025&r2=1243026&view=diff
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java Sat Feb 11 10:50:56 2012
@@ -56,7 +56,6 @@ import org.ofbiz.service.ServiceUtil;
 import org.ofbiz.service.engine.SoapSerializer;
 import org.ofbiz.webapp.control.ConfigXMLReader.Event;
 import org.ofbiz.webapp.control.ConfigXMLReader.RequestMap;
-import org.ofbiz.webapp.control.ConfigXMLReader;
 import org.ofbiz.webapp.control.RequestHandler;
 import org.w3c.dom.Document;
 
@@ -97,7 +96,7 @@ public class SOAPEventHandler implements
                 } catch (GenericServiceException e) {
                     serviceName = null;
                 } catch (WSDLException e) {
-                    sendError(response, "Unable to obtain WSDL");
+                    sendError(response, "Unable to obtain WSDL", serviceName);
                     throw new EventHandlerException("Unable to obtain WSDL", e);
                 }
 
@@ -112,7 +111,7 @@ public class SOAPEventHandler implements
                     }
                     return null;
                 } else {
-                    sendError(response, "Unable to obtain WSDL");
+                    sendError(response, "Unable to obtain WSDL", serviceName);
                     throw new EventHandlerException("Unable to obtain WSDL");
                 }
             }
@@ -137,7 +136,7 @@ public class SOAPEventHandler implements
                     writer.flush();
                     return null;
                 } catch (Exception e) {
-                    sendError(response, "Unable to obtain WSDL");
+                    sendError(response, "Unable to obtain WSDL", null);
                     throw new EventHandlerException("Unable to obtain WSDL");
                 }
             }
@@ -163,30 +162,31 @@ public class SOAPEventHandler implements
                 }
             }
         } catch (Exception e) {
-            sendError(response, "Problem processing the service");
+            sendError(response, "Problem processing the service", null);
             throw new EventHandlerException("Cannot get the envelope", e);
         }
 
         Debug.logVerbose("[Processing]: SOAP Event", module);
 
+        String serviceName = null;
         try {
             SOAPBody reqBody = reqEnv.getBody();
             validateSOAPBody(reqBody);
             OMElement serviceElement = reqBody.getFirstElement();
-            String serviceName = serviceElement.getLocalName();
+            serviceName = serviceElement.getLocalName();
             Map<String, Object> parameters = UtilGenerics.cast(SoapSerializer.deserialize(serviceElement.toString(), delegator));
             try {
                 // verify the service is exported for remote execution and invoke it
                 ModelService model = dispatcher.getDispatchContext().getModelService(serviceName);
 
                 if (model == null) {
-                    sendError(response, "Problem processing the service");
+                    sendError(response, "Problem processing the service", serviceName);
                     Debug.logError("Could not find Service [" + serviceName + "].", module);
                     return null;
                 }
 
                 if (!model.export) {
-                    sendError(response, "Problem processing the service");
+                    sendError(response, "Problem processing the service", serviceName);
                     Debug.logError("Trying to call Service [" + serviceName + "] that is not exported.", module);
                     return null;
                 }
@@ -198,19 +198,19 @@ public class SOAPEventHandler implements
 
             } catch (GenericServiceException e) {
                 if (UtilProperties.getPropertyAsBoolean("service", "secureSoapAnswer", true)) {
-                    sendError(response, "Problem processing the service, check your parameters.");
+                    sendError(response, "Problem processing the service, check your parameters.", serviceName);
                 } else {
                     if(e.getMessageList() == null) {
-                        sendError(response, e.getMessage());
+                        sendError(response, e.getMessage(), serviceName);
                     } else {
-                        sendError(response, e.getMessageList());
+                        sendError(response, e.getMessageList(), serviceName);
                     }
                     Debug.logError(e, module);
                     return null;
                 }
             }
         } catch (Exception e) {
-            sendError(response, e.getMessage());
+            sendError(response, e.getMessage(), serviceName);
             Debug.logError(e, module);
             return null;
         }
@@ -236,6 +236,7 @@ public class SOAPEventHandler implements
         // setup the response
             Debug.logVerbose("[EventHandler] : Setting up response message", module);
             String xmlResults = SoapSerializer.serialize(serviceResults);
+            //Debug.log("xmlResults ==================" + xmlResults, module);
             XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(xmlResults));
             StAXOMBuilder resultsBuilder = new StAXOMBuilder(reader);
             OMElement resultSer = resultsBuilder.getDocumentElement();
@@ -272,15 +273,15 @@ public class SOAPEventHandler implements
         }
     }
 
-    private void sendError(HttpServletResponse res, String errorMessage) throws EventHandlerException {
+    private void sendError(HttpServletResponse res, String errorMessage, String serviceName) throws EventHandlerException {
         // setup the response
-        sendError(res, ServiceUtil.returnError(errorMessage));
+        sendError(res, ServiceUtil.returnError(errorMessage), serviceName);
     }
 
-    private void sendError(HttpServletResponse res, List<String> errorMessages) throws EventHandlerException {
-        sendError(res, ServiceUtil.returnError(errorMessages));
+    private void sendError(HttpServletResponse res, List<String> errorMessages, String serviceName) throws EventHandlerException {
+        sendError(res, ServiceUtil.returnError(errorMessages.toString()), serviceName);
     }
-    private void sendError(HttpServletResponse res, Object object) throws EventHandlerException {
+    private void sendError(HttpServletResponse res, Object object, String serviceName) throws EventHandlerException {
         try {
             // setup the response
             res.setContentType("text/xml");
@@ -293,11 +294,18 @@ public class SOAPEventHandler implements
             SOAPFactory factory = OMAbstractFactory.getSOAP11Factory();
             SOAPEnvelope resEnv = factory.createSOAPEnvelope();
             SOAPBody resBody = factory.createSOAPBody();
-            OMElement errMsg = factory.createOMElement(new QName("Response"));
+            OMElement errMsg = factory.createOMElement(new QName((serviceName != null ? serviceName : "") + "Response"));
             errMsg.addChild(resultSer.getFirstElement());
             resBody.addChild(errMsg);
             resEnv.addChild(resBody);
 
+            // The declareDefaultNamespace method doesn't work see (https://issues.apache.org/jira/browse/AXIS2-3156)
+            // so the following doesn't work:
+            // resService.declareDefaultNamespace(ModelService.TNS);
+            // instead, create the xmlns attribute directly:
+            OMAttribute defaultNS = factory.createOMAttribute("xmlns", null, ModelService.TNS);
+            errMsg.addAttribute(defaultNS);
+
             // log the response message
             if (Debug.verboseOn()) {
                 try {