/**
* 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.camel.dataformat.xmlrpc;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.apache.camel.Exchange;
import org.apache.camel.component.xmlrpc.XmlRpcConstants;
import org.apache.camel.component.xmlrpc.XmlRpcRequestImpl;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.DataFormatName;
import org.apache.camel.support.ServiceSupport;
import org.apache.camel.util.IOHelper;
import org.apache.ws.commons.serialize.CharSetXMLWriter;
import org.apache.ws.commons.serialize.XMLWriter;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcRequest;
import org.apache.xmlrpc.client.XmlRpcClientException;
import org.apache.xmlrpc.common.TypeFactory;
import org.apache.xmlrpc.common.TypeFactoryImpl;
import org.apache.xmlrpc.common.XmlRpcHttpRequestConfigImpl;
import org.apache.xmlrpc.common.XmlRpcStreamRequestConfig;
import org.apache.xmlrpc.parser.XmlRpcRequestParser;
import org.apache.xmlrpc.parser.XmlRpcResponseParser;
import org.apache.xmlrpc.util.SAXParsers;
public class XmlRpcDataFormat extends ServiceSupport implements DataFormat, DataFormatName {
private XmlRpcStreamRequestConfig xmlRpcStreamRequestConfig = new XmlRpcHttpRequestConfigImpl();
private TypeFactory typeFactory = new TypeFactoryImpl(null);
private boolean isRequest;
protected XMLWriter getXMLWriter(Exchange exchange, OutputStream outputStream) throws XmlRpcException {
XMLWriter writer = new CharSetXMLWriter();
String encoding = IOHelper.getCharsetName(exchange);
writer.setEncoding(encoding);
writer.setIndenting(false);
writer.setFlushing(true);
try {
writer.setWriter(new BufferedWriter(new OutputStreamWriter(outputStream, encoding)));
} catch (UnsupportedEncodingException e) {
throw new XmlRpcException("Unsupported encoding: " + encoding, e);
}
return writer;
}
@Override
public String getDataFormatName() {
return "xmlrpc";
}
@Override
public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception {
// need to check the object type
XMLWriter control = getXMLWriter(exchange, stream);
XmlRpcWriter writer = new XmlRpcWriter(xmlRpcStreamRequestConfig, control, typeFactory);
XmlRpcRequest request = null;
if (isRequest || graph instanceof XmlRpcRequest) {
request = exchange.getContext().getTypeConverter().mandatoryConvertTo(XmlRpcRequest.class, exchange, graph);
}
if (request != null) {
writer.writeRequest(xmlRpcStreamRequestConfig, request);
} else {
// write the result here directly
// TODO write the fault message here
writer.write(xmlRpcStreamRequestConfig, graph);
}
}
protected int getErrorCode(Exchange exchange) {
return exchange.getIn().getHeader(XmlRpcConstants.ERROR_CODE, int.class);
}
@Override
public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
if (isRequest) {
return unmarshalRequest(exchange, stream);
} else {
return unmarshalResponse(exchange, stream);
}
}
protected Object unmarshalResponse(Exchange exchange, InputStream stream) throws Exception {
InputSource isource = new InputSource(stream);
XMLReader xr = newXMLReader();
XmlRpcResponseParser xp;
try {
xp = new XmlRpcResponseParser(xmlRpcStreamRequestConfig, typeFactory);
xr.setContentHandler(xp);
xr.parse(isource);
} catch (SAXException e) {
throw new XmlRpcClientException("Failed to parse server's response: " + e.getMessage(), e);
} catch (IOException e) {
throw new XmlRpcClientException("Failed to read server's response: " + e.getMessage(), e);
}
if (xp.isSuccess()) {
return xp.getResult();
}
Throwable t = xp.getErrorCause();
if (t == null) {
throw new XmlRpcException(xp.getErrorCode(), xp.getErrorMessage());
}
if (t instanceof XmlRpcException) {
throw (XmlRpcException)t;
}
if (t instanceof RuntimeException) {
throw (RuntimeException)t;
}
throw new XmlRpcException(xp.getErrorCode(), xp.getErrorMessage(), t);
}
protected Object unmarshalRequest(Exchange exchange, InputStream stream) throws Exception {
InputSource isource = new InputSource(stream);
XMLReader xr = newXMLReader();
XmlRpcRequestParser xp;
try {
xp = new XmlRpcRequestParser(xmlRpcStreamRequestConfig, typeFactory);
xr.setContentHandler(xp);
xr.parse(isource);
} catch (SAXException e) {
throw new XmlRpcClientException("Failed to parse server's response: " + e.getMessage(), e);
} catch (IOException e) {
throw new XmlRpcClientException("Failed to read server's response: " + e.getMessage(), e);
}
return new XmlRpcRequestImpl(xp.getMethodName(), xp.getParams());
}
protected XMLReader newXMLReader() throws XmlRpcException {
return SAXParsers.newXMLReader();
}
public boolean isRequest() {
return isRequest;
}
public void setRequest(boolean isRequest) {
this.isRequest = isRequest;
}
public void setXmlRpcStreamRequestConfig(XmlRpcStreamRequestConfig config) {
this.xmlRpcStreamRequestConfig = config;
}
public XmlRpcStreamRequestConfig getXmlRpcStreamRequestConfig() {
return xmlRpcStreamRequestConfig;
}
public void setTypeFactory(TypeFactory typeFactory) {
this.typeFactory = typeFactory;
}
public TypeFactory getTypeFactory() {
return typeFactory;
}
@Override
protected void doStart() throws Exception {
// noop
}
@Override
protected void doStop() throws Exception {
// noop
}
}