/*
* Copyright 2014, The Sporting Exchange Limited
*
* Licensed 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 com.betfair.cougar.transport.impl.protocol.http.soap;
import com.betfair.cougar.core.api.client.EnumWrapper;
import com.betfair.cougar.core.api.transcription.Parameter;
import com.betfair.cougar.core.api.transcription.ParameterType;
import com.betfair.cougar.core.api.transcription.Transcribable;
import com.betfair.cougar.core.api.transcription.TranscribableParams;
import com.betfair.cougar.core.api.transcription.TranscriptionOutput;
import com.betfair.cougar.util.dates.DateTimeUtility;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.util.base64.Base64Utils;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Transcribes Transcribable java objects to XML.
*
*/
@SuppressWarnings("unchecked")
public class XMLTranscriptionOutput implements TranscriptionOutput {
private QName entryElementName;
private OMNamespace ns;
private OMFactory factory;
private OMElement currentNode;
private OMNamespace xsiNamespace;
/**
* Create an XMLTranscriptionOutput which will write transcibable objects to the specified
* element with the specified namespace.
* @param currentNode the XML element to transcribe the object to
* @param ns the namespace that should be used
* @param factory
*/
public XMLTranscriptionOutput(OMElement currentNode, OMNamespace ns, OMFactory factory) {
this.ns = ns;
this.factory = factory;
this.currentNode = currentNode;
entryElementName = new QName(ns.getNamespaceURI(), "entry", ns.getPrefix());
xsiNamespace = factory.createOMNamespace(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi");
}
@Override
public void writeObject(Object obj, Parameter param, boolean client) throws Exception {
if (obj != null || parameterIsNillable(param)) {
OMElement paramNode = factory.createOMElement(param.getName(), ns, currentNode);
writeObject(obj, param.getParameterType(), paramNode, client);
}
}
private boolean parameterIsNillable(Parameter param) {
return param.isMandatory()
|| param.getParameterType().getType() == ParameterType.Type.LIST
|| param.getParameterType().getType() == ParameterType.Type.SET
|| param.getParameterType().getType() == ParameterType.Type.MAP;
}
private void writeObject(Object obj, ParameterType paramType, OMElement node, boolean client) throws Exception {
if (obj == null) {
node.addAttribute("nil", "true", xsiNamespace);
} else {
switch(paramType.getType()) {
case OBJECT:
//decend
OMElement _copy = currentNode;
currentNode = node;
//transcribe
if (paramType.getImplementationClass().equals(EnumWrapper.class)) {
factory.createOMText(node, writeSimpleObjectString(obj, paramType.getComponentTypes()[0]));
}
else {
Transcribable t = (Transcribable)obj;
t.transcribe(this, TranscribableParams.getNone(), client);
//ascend
currentNode = _copy;
}
break;
case MAP:
Map map = (Map)obj;
for(Object obje:map.entrySet()){
Map.Entry e=(Map.Entry)obje;
OMElement entryElement = factory.createOMElement("entry", ns, node);
entryElement.addAttribute("key", writeSimpleObjectString(e.getKey(), paramType.getComponentTypes()[0]), null);
if (e.getValue() != null) {
writeObject(e.getValue(), paramType.getComponentTypes()[1], factory.createOMElement(paramType.getComponentTypes()[1].getImplementationClass().getSimpleName(), ns, entryElement), client);
}
}
break;
case LIST:
if (paramType.getComponentTypes()[0].getType() == ParameterType.Type.BYTE) {
factory.createOMText(node, Base64Utils.encode((byte[])obj));
} else {
List list = (List)obj;
for (Object element : list) {
//create element node
writeObject(element, paramType.getComponentTypes()[0], factory.createOMElement(paramType.getComponentTypes()[0].getImplementationClass().getSimpleName(), ns, node), client);
}
}
break;
case SET:
Set set = (Set)obj;
for (Object element : set) {
//create element node
writeObject(element, paramType.getComponentTypes()[0], factory.createOMElement(paramType.getComponentTypes()[0].getImplementationClass().getSimpleName(), ns, node), client);
}
break;
default :
factory.createOMText(node, writeSimpleObjectString(obj, paramType));
}
}
}
private String writeSimpleObjectString(Object obj, ParameterType paramType) {
switch(paramType.getType()) {
case BOOLEAN:
case DOUBLE:
case FLOAT:
case INT:
case LONG:
case STRING:
case ENUM:
case BYTE:
return obj.toString();
case DATE:
return DateTimeUtility.encode((Date)obj);
}
throw new UnsupportedOperationException("Parameter Type " + paramType + " is not a simple object");
}
}