Skip to content
This repository has been archived by the owner on May 9, 2020. It is now read-only.

Commit

Permalink
"Applied fix from trunk for revision: 1243026"
Browse files Browse the repository at this point in the history
------------------------------------------------------------------------
r1243026 | jleroux | 2012-02-11 11:50:56 +0100 (sam., 11 févr. 2012) | 12 lines

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
------------------------------------------------------------------------
�

git-svn-id: https://svn.apache.org/repos/asf/ofbiz/branches/release11.04@1384258 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
JacquesLeRoux committed Sep 13, 2012
1 parent 2d546bc commit fad892c
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 20 deletions.
19 changes: 16 additions & 3 deletions framework/entity/src/org/ofbiz/entity/serialize/XmlSerializer.java
Expand Up @@ -22,6 +22,7 @@
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;
Expand Down Expand Up @@ -130,7 +131,7 @@ public static Object deserialize(Document document, Delegator delegator) throws
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) {
Expand All @@ -147,9 +148,13 @@ public static Element serializeSingle(Object object, Document document) throws S
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) {
Expand Down Expand Up @@ -269,7 +274,15 @@ public static Element serializeCustom(Object object, Document document) throws S
}

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());
Expand Down
47 changes: 47 additions & 0 deletions framework/service/src/org/ofbiz/service/ModelService.java
Expand Up @@ -1358,6 +1358,18 @@ public Types getTypes(Document document, Definition def) {
/*--------- 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");
Expand Down Expand Up @@ -1435,6 +1447,17 @@ public Types getTypes(Document document, Definition def) {
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 -----------*/
Expand Down Expand Up @@ -1645,6 +1668,12 @@ public Types getTypes(Document document, Definition def) {
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");
Expand Down Expand Up @@ -1771,12 +1800,24 @@ public Types getTypes(Document document, Definition def) {
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");
Expand Down Expand Up @@ -1903,6 +1944,12 @@ public Types getTypes(Document document, Definition def) {
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;
Expand Down
43 changes: 26 additions & 17 deletions framework/webapp/src/org/ofbiz/webapp/event/SOAPEventHandler.java
Expand Up @@ -96,7 +96,7 @@ public String invoke(Event event, RequestMap requestMap, HttpServletRequest requ
} 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);
}

Expand All @@ -111,7 +111,7 @@ public String invoke(Event event, RequestMap requestMap, HttpServletRequest requ
}
return null;
} else {
sendError(response, "Unable to obtain WSDL");
sendError(response, "Unable to obtain WSDL", serviceName);
throw new EventHandlerException("Unable to obtain WSDL");
}
}
Expand All @@ -136,7 +136,7 @@ public String invoke(Event event, RequestMap requestMap, HttpServletRequest requ
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");
}
}
Expand All @@ -162,30 +162,31 @@ public String invoke(Event event, RequestMap requestMap, HttpServletRequest requ
}
}
} 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;
}
Expand All @@ -197,19 +198,19 @@ public String invoke(Event event, RequestMap requestMap, HttpServletRequest requ

} 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;
}
Expand All @@ -235,6 +236,7 @@ private void createAndSendSOAPResponse(Map<String, Object> serviceResults, Strin
// 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();
Expand Down Expand Up @@ -271,15 +273,15 @@ private void createAndSendSOAPResponse(Map<String, Object> serviceResults, Strin
}
}

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");
Expand All @@ -292,11 +294,18 @@ private void sendError(HttpServletResponse res, Object object) throws EventHandl
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 {
Expand Down

0 comments on commit fad892c

Please sign in to comment.