/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.spring.xmlrpc;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;
import org.apache.xmlrpc.WebServer;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcHandler;
import org.opennms.core.utils.ThreadCategory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
import org.springframework.remoting.support.RemoteExporter;
import org.springframework.util.MethodInvoker;
/**
* <p>XmlRpcServiceExporter class.</p>
*
* @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a>
* @version $Id: $
*/
public class XmlRpcServiceExporter extends RemoteExporter implements InitializingBean, DisposableBean, XmlRpcHandler {
private WebServer webServer;
private Object proxy;
private String serviceName;
/**
* <p>Getter for the field <code>webServer</code>.</p>
*
* @return a {@link org.apache.xmlrpc.WebServer} object.
*/
public WebServer getWebServer() {
return this.webServer;
}
/**
* <p>Setter for the field <code>webServer</code>.</p>
*
* @param webServer a {@link org.apache.xmlrpc.WebServer} object.
*/
public void setWebServer(WebServer webServer) {
this.webServer = webServer;
}
/**
* <p>Getter for the field <code>serviceName</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getServiceName() {
return this.serviceName;
}
/**
* <p>Setter for the field <code>serviceName</code>.</p>
*
* @param serviceName a {@link java.lang.String} object.
*/
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
/**
* <p>afterPropertiesSet</p>
*
* @throws java.lang.Exception if any.
*/
@Override
public void afterPropertiesSet() throws Exception {
if (this.webServer == null)
throw new IllegalArgumentException("webServer is required");
checkService();
checkServiceInterface();
this.proxy = getProxyForService();
if (serviceName == null || "".equals(serviceName)) {
this.webServer.addHandler("$default", this);
} else {
this.webServer.addHandler(serviceName, this);
}
}
/**
* <p>destroy</p>
*
* @throws java.lang.Exception if any.
*/
public void destroy() throws Exception {
if (serviceName == null || "".equals(serviceName)) {
this.webServer.removeHandler("$default");
} else {
this.webServer.removeHandler(serviceName);
}
}
public static class MsgPreservingXmlRpcException extends XmlRpcException {
/**
*
*/
private static final long serialVersionUID = -4693127622262382452L;
public MsgPreservingXmlRpcException(int code, String message) {
super(code, message);
}
public String toString() {
return getMessage();
}
}
/** {@inheritDoc} */
public Object execute(String method, @SuppressWarnings("unchecked") Vector params) throws Exception {
log().debug("calling: "+method+'('+toArgList(params)+')');
MethodInvoker invoker = new ArgumentConvertingMethodInvoker();
invoker.setTargetObject(this.proxy);
invoker.setTargetMethod(getMethodName(method));
invoker.setArguments(params.toArray());
invoker.prepare();
try {
Object returnValue = invoker.invoke();
if (returnValue == null && invoker.getPreparedMethod().getReturnType() == Void.TYPE) {
returnValue = "void";
}
else if (returnValue instanceof Map<?,?> && !(returnValue instanceof Hashtable<?,?>)) {
returnValue = new Hashtable<Object, Object>((Map<?, ?>)returnValue);
}
else if (returnValue instanceof Collection<?> && !(returnValue instanceof Vector<?>)) {
returnValue = new Vector<Object>((Collection<?>)returnValue);
}
log().debug("returning from: "+method+'('+toArgList(params)+") result = "+returnValue);
return returnValue;
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (targetException instanceof IllegalArgumentException) {
throw new MsgPreservingXmlRpcException(XmlRpcConstants.FAULT_INVALID_DATA, targetException.getMessage());
} else if (targetException instanceof MalformedURLException) {
throw new MsgPreservingXmlRpcException(XmlRpcConstants.FAULT_INVALID_URL, targetException.getMessage());
}
else if (targetException instanceof Exception && targetException.toString() != null) {
throw (Exception)targetException;
}
String msg = targetException.toString();
if (msg == null)
msg = targetException.getClass().getName();
Exception ex = new Exception(msg, targetException);
ex.setStackTrace(targetException.getStackTrace());
throw ex;
}
}
private String toArgList(@SuppressWarnings("unchecked") Vector params) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < params.size(); i++) {
if (i != 0) sb.append(", ");
sb.append(params.get(i));
}
return sb.toString();
}
private ThreadCategory log() {
return ThreadCategory.getInstance(getClass());
}
private String getMethodName(String method) {
if (this.serviceName == null || "".equals(serviceName))
return method;
else
return method.substring(serviceName.length());
}
}