/*
* Created on Jun 22, 2005
*
* 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.
*
* Copyright @2005 the original author or authors.
*/
package org.springmodules.remoting.xmlrpc.dom;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.xml.SimpleSaxErrorHandler;
import org.springmodules.remoting.xmlrpc.XmlRpcWriterException;
import org.springmodules.remoting.xmlrpc.support.XmlRpcArray;
import org.springmodules.remoting.xmlrpc.support.XmlRpcBase64;
import org.springmodules.remoting.xmlrpc.support.XmlRpcBoolean;
import org.springmodules.remoting.xmlrpc.support.XmlRpcDateTime;
import org.springmodules.remoting.xmlrpc.support.XmlRpcDouble;
import org.springmodules.remoting.xmlrpc.support.XmlRpcElement;
import org.springmodules.remoting.xmlrpc.support.XmlRpcElementNames;
import org.springmodules.remoting.xmlrpc.support.XmlRpcInteger;
import org.springmodules.remoting.xmlrpc.support.XmlRpcScalar;
import org.springmodules.remoting.xmlrpc.support.XmlRpcString;
import org.springmodules.remoting.xmlrpc.support.XmlRpcStruct;
import org.springmodules.remoting.xmlrpc.support.XmlRpcStruct.XmlRpcMember;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.xml.sax.ErrorHandler;
/**
* <p>
* Template for XML-RPC request/response writes that use DOM to create XML.
* </p>
*
* @author Alex Ruiz
*
* @version $Revision$ $Date$
*/
public abstract class AbstractDomXmlRpcWriter {
/**
* <p>
* Implementation of <code>org.xml.sax.ErrorHandler</code> for custom
* handling of XML parsing errors and warnings.
* </p>
* <p>
* If not set, a default <code>{@link SimpleSaxErrorHandler}</code> is used
* that simply logs warnings using the logger instance of the view class, and
* rethrows errors to discontinue the XML transformation.
* </p>
*
* @see org.springframework.util.xml.SimpleSaxErrorHandler
*/
private ErrorHandler errorHandler;
protected final Log logger = LogFactory.getLog(getClass());
public AbstractDomXmlRpcWriter() {
super();
setErrorHandler(new SimpleSaxErrorHandler(logger));
}
/**
* Creates the XML representation of the given XML-RPC array.
*
* @param array
* the XML-RPC array.
* @param document
* the XML document used to create new XML elements.
* @return the created XML element.
*/
protected final Element createArrayElement(XmlRpcArray array,
Document document) {
Element dataElement = document.createElement(XmlRpcElementNames.DATA);
XmlRpcElement[] elements = array.getElements();
int elementCount = elements.length;
for (int i = 0; i < elementCount; i++) {
Element valueElement = createValueElement(elements[i], document);
dataElement.appendChild(valueElement);
}
Element arrayElement = document.createElement(XmlRpcElementNames.ARRAY);
arrayElement.appendChild(dataElement);
return arrayElement;
}
/**
* Creates an empty XML document.
*
* @return the created XML document.
*/
protected final Document createEmptyXmlDocument() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP implementation [" + factory + "]");
}
DocumentBuilder docBuilder = factory.newDocumentBuilder();
docBuilder.setErrorHandler(errorHandler);
return docBuilder.newDocument();
} catch (ParserConfigurationException exception) {
throw new XmlRpcWriterException("Parser configuration exception",
exception);
}
}
/**
* Creates a XML representation of the given member of a XML-RPC struct.
*
* @param member
* the member of a XML-RPC struct.
* @param document
* the XML document used to create new XML elements.
* @return the created XML element.
*/
protected final Element createMemberElement(XmlRpcMember member,
Document document) {
Element nameElement = document.createElement(XmlRpcElementNames.NAME);
Text text = document.createTextNode(member.name);
nameElement.appendChild(text);
Element valueElement = createValueElement(member.value, document);
Element memberElement = document.createElement(XmlRpcElementNames.MEMBER);
memberElement.appendChild(nameElement);
memberElement.appendChild(valueElement);
return memberElement;
}
/**
* Creates the XML representation of the given XML-RPC parameter.
*
* @param parameter
* the XML-RPC parameter.
* @param document
* the XML document used to create new XML elements.
* @return the created XML element.
*/
protected final Element createParameterElement(XmlRpcElement parameter,
Document document) {
Element valueElement = createValueElement(parameter, document);
Element parameterElement = document.createElement(XmlRpcElementNames.PARAM);
parameterElement.appendChild(valueElement);
return parameterElement;
}
/**
* Creates the XML representation of the given XML-RPC parameters.
*
* @param parameters
* the XML-RPC parameters.
* @param document
* the XML document used to create new XML elements.
* @return the created XML element.
*/
protected final Element createParametersElement(XmlRpcElement[] parameters,
Document document) {
Element parametersElement = document
.createElement(XmlRpcElementNames.PARAMS);
int parameterCount = parameters.length;
for (int i = 0; i < parameterCount; i++) {
Element parameterElement = createParameterElement(parameters[i], document);
parametersElement.appendChild(parameterElement);
}
return parametersElement;
}
/**
* Creates the XML representation of the given XML-RPC scalar value.
*
* @param elementName
* the name of the XML element to create.
* @param value
* the XML-RPC scalar value.
* @param document
* the DOM document to add the created XML element to.
* @return the created XML element.
*/
protected final Element createScalarElement(String elementName,
XmlRpcElement value, Document document) {
Element scalarElement = document.createElement(elementName);
XmlRpcScalar scalarValue = (XmlRpcScalar) value;
Text text = document.createTextNode(scalarValue.getValueAsString());
scalarElement.appendChild(text);
return scalarElement;
}
/**
* Creates the XML representation of the given XML-RPC struct.
*
* @param struct
* the XML-RPC struct.
* @param document
* the XML document used to create new XML elements.
* @return the created XML element.
*/
protected final Element createStructElement(XmlRpcStruct struct,
Document document) {
Element structElement = document.createElement(XmlRpcElementNames.STRUCT);
XmlRpcMember[] members = struct.getMembers();
int memberCount = members.length;
for (int i = 0; i < memberCount; i++) {
Element memberElement = createMemberElement(members[i], document);
structElement.appendChild(memberElement);
}
return structElement;
}
/**
* Creates the XML representation of the given XML-RPC value.
*
* @param value
* the XML-RPC value.
* @param document
* the XML document used to create new XML elements.
* @return the created XML element.
*/
protected final Element createValueElement(XmlRpcElement value,
Document document) {
Element child = null;
if (value instanceof XmlRpcArray) {
child = createArrayElement((XmlRpcArray) value, document);
} else if (value instanceof XmlRpcBase64) {
child = createScalarElement(XmlRpcElementNames.BASE_64, value, document);
} else if (value instanceof XmlRpcBoolean) {
child = createScalarElement(XmlRpcElementNames.BOOLEAN, value, document);
} else if (value instanceof XmlRpcDateTime) {
child = createScalarElement(XmlRpcElementNames.DATE_TIME, value, document);
} else if (value instanceof XmlRpcDouble) {
child = createScalarElement(XmlRpcElementNames.DOUBLE, value, document);
} else if (value instanceof XmlRpcInteger) {
child = createScalarElement(XmlRpcElementNames.I4, value, document);
} else if (value instanceof XmlRpcString) {
child = createScalarElement(XmlRpcElementNames.STRING, value, document);
} else if (value instanceof XmlRpcStruct) {
child = createStructElement((XmlRpcStruct) value, document);
}
Element valueElement = document.createElement(XmlRpcElementNames.VALUE);
valueElement.appendChild(child);
return valueElement;
}
public final void setErrorHandler(ErrorHandler newErrorHandler) {
errorHandler = newErrorHandler;
}
}