added a simple XML-RPC client implementation, callable from within scripts

This commit is contained in:
Eric J. Bowersox 2003-07-16 22:57:27 +00:00
parent 2eb1f58dba
commit 354eeec28e
6 changed files with 378 additions and 1 deletions

View File

@ -341,6 +341,33 @@ public class XMLLoader
} // end getSubElementNS
/**
* Returns the sole sub-element of the specified element. Throws an error if the element has more than one
* sub-element.
*
* @param sect The <CODE>Element</CODE> to extract the sub-element from.
* @return The sub-element.
* @exception com.silverwrist.util.XMLLoadException If there is more than one sub-element.
*/
public final Element getSoleSubElement(Element sect) throws XMLLoadException
{
Element rc = null;
NodeList nl = sect.getChildNodes();
for (int i=0; i<nl.getLength(); i++)
{ // there can be only one!
Node n = nl.item(i);
if (n.getNodeType()!=Node.ELEMENT_NODE)
continue;
if (rc!=null)
throw new XMLLoadException("more than one subelement of <" + sect.getTagName() + "/> found");
rc = (Element)n;
} // end for
return rc;
} // end getSoleSubElement
/**
* Returns all sub-elements of an <CODE>Element</CODE> element that have a specific name.
*

View File

@ -1146,6 +1146,12 @@ public class ApplicationContainer
} // end removeSessionLink
public String getServerIdentity()
{
return m_identity;
} // end getServerIdentity
public void setServerHeader(HttpServletResponse resp)
{
resp.setHeader("Server",m_identity);

View File

@ -0,0 +1,32 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.dynamo.xmlrpc;
import java.io.IOException;
import java.net.URL;
import java.util.List;
public interface XmlRpcCaller
{
public URL getURL();
public Object call(String method, Object[] params) throws IOException, FaultCode;
public Object call(String method, List params) throws IOException, FaultCode;
} // end interface XmlRpcCaller

View File

@ -0,0 +1,31 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.dynamo.xmlrpc;
import java.net.MalformedURLException;
import java.net.URL;
public interface XmlRpcCallerFactory
{
public XmlRpcCaller newCaller(URL url);
public XmlRpcCaller newCaller(String url) throws MalformedURLException;
public XmlRpcCaller newCaller(String hostname, int port) throws MalformedURLException;
} // end interface XmlRpcCallerFactory

View File

@ -0,0 +1,247 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.dynamo.xmlrpc;
import java.io.*;
import java.net.*;
import java.util.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.util.xml.*;
class XmlRpcCallerImpl implements XmlRpcCaller
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private URL m_url;
private String m_identifier;
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
XmlRpcCallerImpl(URL url, String identifier)
{
m_url = url;
m_identifier = identifier;
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
private final byte[] buildCall(String method, List params) throws IOException
{
ByteArrayOutputStream stm = new ByteArrayOutputStream();
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(stm,"UTF-8"));
wr.write("<?xml version=\"1.0\"?>\r\n<methodCall>\r\n<methodName>");
wr.write(method);
wr.write("</methodName>\r\n");
if (params.size()>0)
{ // serialize the parameters
XmlRpcSerializer serializer = XmlRpcSerializer.get();
wr.write("<params>\r\n");
Iterator it = params.iterator();
while (it.hasNext())
{ // serialize the parameters
Object p = it.next();
wr.write("<param>");
serializer.serialize(wr,p);
wr.write("</param>\r\n");
} // end while
wr.write("</params>\r\n");
} // end if
wr.write("</methodCall>\r\n");
wr.flush();
return stm.toByteArray();
} // end buildCall
private final Object deserialize(Element val) throws IOException
{
XmlRpcSerializer serializer = XmlRpcSerializer.get();
try
{ // just call the serializer and translate its FaultCode if any
return serializer.deserialize(val);
} // end try
catch (FaultCode fc)
{ // Build the IOException and return it.
IOException ioe = new IOException("Value parsing error: " + fc.getMessage());
ioe.initCause(fc);
throw ioe;
} // end catch
} // end deserialize
private final Object parseResult(InputStream stm) throws IOException, FaultCode
{
XMLLoader loader = XMLLoader.get();
try
{ // parse the output from the server
Document result_doc = loader.load(stm,false);
// make sure it's a proper method response
Element method_response = loader.getRootElement(result_doc,"methodResponse");
// get the sub-element of the methodResponse (there can be only one!)
Element elt = loader.getSoleSubElement(method_response);
if (elt.getTagName().equals("params"))
{ // <params/> must contain <param/>, which must contain <value/>
Element param1 = loader.getSoleSubElement(elt);
loader.verifyNodeName(param1,"param",elt);
Element val1 = loader.getSoleSubElement(param1);
loader.verifyNodeName(val1,"value",param1);
// deserialize the value
return deserialize(val1);
} // end if
else if (elt.getTagName().equals("fault"))
{ // <fault/> must contain <value/>
Element val1 = loader.getSoleSubElement(elt);
loader.verifyNodeName(val1,"value",elt);
// get the fault value
Map fcdata = null;
try
{ // parse the value...
fcdata = (Map)deserialize(val1);
} // end try
catch (ClassCastException e)
{ // turn this into an IOException
throw new IOException("Fault parse failure: fault data must be struct");
} // end catch
// get the fault code
int fault_code = 0;
try
{ // retrieve struct member, convert to integer
Integer foo = (Integer)(fcdata.get("faultCode"));
if (foo==null)
throw new IOException("Fault parse failure: fault code member must be present");
fault_code = foo.intValue();
} // end try
catch (ClassCastException e)
{ // no go
throw new IOException("Fault parse failure: fault code member must be integer");
} // end catch
// get the fault string
String fault_string = null;
try
{ // retrieve struct member
fault_string = (String)(fcdata.get("faultString"));
if (fault_string==null)
throw new IOException("Fault parse failure: fault string member must be present");
} // end try
catch (ClassCastException e)
{ // no go
throw new IOException("Fault parse failure: fault string member must be string");
} // end catch
// throw the resulting FaultCode object
if (FaultCode.isSystemFaultCode(fault_code))
throw new SystemFaultCode(fault_code,fault_string);
else
throw new FaultCode(fault_code,fault_string);
} // end else if
else
throw new XMLLoadException("<methodResponse/> must contain either <params/> or <fault/>",method_response);
} // end try
catch (XMLLoadException e)
{ // translate all XML loading exceptions to I/O exceptions
IOException ioe = new IOException("XML parsing failure: " + e.getMessage());
ioe.initCause(e);
throw ioe;
} // end catch
} // end parseResult
/*--------------------------------------------------------------------------------
* Implementations from interface XmlRpcCaller
*--------------------------------------------------------------------------------
*/
public URL getURL()
{
return m_url;
} // end URL
public Object call(String method, Object[] params) throws IOException, FaultCode
{
if (params==null)
return this.call(method,Collections.EMPTY_LIST);
else
return this.call(method,Arrays.asList(params));
} // end call
public Object call(String method, List params) throws IOException, FaultCode
{
if (params==null)
params = Collections.EMPTY_LIST;
// Build the XML-RPC call body.
byte[] request_data = buildCall(method,params);
// Set up a URLConnection to post it.
URLConnection conn = m_url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setAllowUserInteraction(false);
conn.setUseCaches(false);
conn.setRequestProperty("User-Agent",m_identifier);
conn.setRequestProperty("Host",m_url.getHost());
conn.setRequestProperty("Content-Type","text/xml; charset=UTF-8");
conn.setRequestProperty("Content-Length",String.valueOf(request_data.length));
// Post the request data, and get the response data back.
OutputStream ostm = conn.getOutputStream();
ostm.write(request_data);
ostm.flush();
ostm.close();
InputStream istm = conn.getInputStream();
// Parse the XML-RPC response and return the return value, or throw the fault code.
return parseResult(istm);
} // end call
} // end class XmlRpcCallerImpl

View File

@ -17,6 +17,8 @@
*/
package com.silverwrist.dynamo.xmlrpc;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import org.apache.commons.lang.CharSet;
import org.apache.commons.lang.CharSetUtils;
@ -30,7 +32,8 @@ import com.silverwrist.dynamo.iface.*;
import com.silverwrist.dynamo.util.*;
public class XmlRpcSubSystem
implements NamedObject, ComponentInitialize, ComponentShutdown, XmlRpcCreateSession, XmlRpcConfiguration
implements NamedObject, ComponentInitialize, ComponentShutdown, XmlRpcCreateSession, XmlRpcConfiguration,
XmlRpcCallerFactory
{
/*--------------------------------------------------------------------------------
* Internal class implementing background sweep
@ -119,6 +122,7 @@ public class XmlRpcSubSystem
private Vector m_installed_fmap = new Vector(); // fault mappers installed via the API
private ArrayList m_config_fmap = new ArrayList(); // fault mappers configured via the config data
private ComponentShutdown m_init_hook; // initialization services hook
private ComponentShutdown m_script; // script object registration hook
private ComponentShutdown m_sweep_task; // sweep task
/*--------------------------------------------------------------------------------
@ -571,6 +575,10 @@ public class XmlRpcSubSystem
(XmlRpcConfiguration)this);
m_init_hook = hooker.hookInitServiceProvider(ssp);
// Add the XML-RPC caller factory to the script engine under the name "xmlrpc."
ScriptEngineConfig seconf = (ScriptEngineConfig)(services.queryService(ScriptEngineConfig.class));
m_script = seconf.addDeclaredObject("xmlrpc",this,XmlRpcCallerFactory.class);
// Set up the sweeper to run at a fixed rate.
BackgroundScheduler sched = (BackgroundScheduler)(services.queryService(BackgroundScheduler.class));
m_sweep_task = sched.runTaskFixedRate(new SessionSweeper(),SWEEP_INTERVAL,SWEEP_INTERVAL);
@ -590,6 +598,9 @@ public class XmlRpcSubSystem
m_sweep_task.shutdown(); // shut down the sweep task
m_sweep_task = null;
m_script.shutdown(); // shut down the script object
m_script = null;
m_init_hook.shutdown(); // shut down the initialization hook
m_init_hook = null;
@ -661,6 +672,29 @@ public class XmlRpcSubSystem
} // end addCapability
/*--------------------------------------------------------------------------------
* Implementations from interface XmlRpcCallerFactory
*--------------------------------------------------------------------------------
*/
public XmlRpcCaller newCaller(URL url)
{
return new XmlRpcCallerImpl(url,m_appcon.getServerIdentity());
} // end newCaller
public XmlRpcCaller newCaller(String url) throws MalformedURLException
{
return this.newCaller(new URL(url));
} // end newCaller
public XmlRpcCaller newCaller(String hostname, int port) throws MalformedURLException
{
return this.newCaller(new URL("http://" + hostname + ":" + port + "/RPC2"));
} // end newCaller
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------