added a simple XML-RPC client implementation, callable from within scripts
This commit is contained in:
parent
2eb1f58dba
commit
354eeec28e
|
@ -341,6 +341,33 @@ public class XMLLoader
|
||||||
|
|
||||||
} // end getSubElementNS
|
} // 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.
|
* Returns all sub-elements of an <CODE>Element</CODE> element that have a specific name.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1146,6 +1146,12 @@ public class ApplicationContainer
|
||||||
|
|
||||||
} // end removeSessionLink
|
} // end removeSessionLink
|
||||||
|
|
||||||
|
public String getServerIdentity()
|
||||||
|
{
|
||||||
|
return m_identity;
|
||||||
|
|
||||||
|
} // end getServerIdentity
|
||||||
|
|
||||||
public void setServerHeader(HttpServletResponse resp)
|
public void setServerHeader(HttpServletResponse resp)
|
||||||
{
|
{
|
||||||
resp.setHeader("Server",m_identity);
|
resp.setHeader("Server",m_identity);
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -17,6 +17,8 @@
|
||||||
*/
|
*/
|
||||||
package com.silverwrist.dynamo.xmlrpc;
|
package com.silverwrist.dynamo.xmlrpc;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.apache.commons.lang.CharSet;
|
import org.apache.commons.lang.CharSet;
|
||||||
import org.apache.commons.lang.CharSetUtils;
|
import org.apache.commons.lang.CharSetUtils;
|
||||||
|
@ -30,7 +32,8 @@ import com.silverwrist.dynamo.iface.*;
|
||||||
import com.silverwrist.dynamo.util.*;
|
import com.silverwrist.dynamo.util.*;
|
||||||
|
|
||||||
public class XmlRpcSubSystem
|
public class XmlRpcSubSystem
|
||||||
implements NamedObject, ComponentInitialize, ComponentShutdown, XmlRpcCreateSession, XmlRpcConfiguration
|
implements NamedObject, ComponentInitialize, ComponentShutdown, XmlRpcCreateSession, XmlRpcConfiguration,
|
||||||
|
XmlRpcCallerFactory
|
||||||
{
|
{
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Internal class implementing background sweep
|
* 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 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 ArrayList m_config_fmap = new ArrayList(); // fault mappers configured via the config data
|
||||||
private ComponentShutdown m_init_hook; // initialization services hook
|
private ComponentShutdown m_init_hook; // initialization services hook
|
||||||
|
private ComponentShutdown m_script; // script object registration hook
|
||||||
private ComponentShutdown m_sweep_task; // sweep task
|
private ComponentShutdown m_sweep_task; // sweep task
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
|
@ -571,6 +575,10 @@ public class XmlRpcSubSystem
|
||||||
(XmlRpcConfiguration)this);
|
(XmlRpcConfiguration)this);
|
||||||
m_init_hook = hooker.hookInitServiceProvider(ssp);
|
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.
|
// Set up the sweeper to run at a fixed rate.
|
||||||
BackgroundScheduler sched = (BackgroundScheduler)(services.queryService(BackgroundScheduler.class));
|
BackgroundScheduler sched = (BackgroundScheduler)(services.queryService(BackgroundScheduler.class));
|
||||||
m_sweep_task = sched.runTaskFixedRate(new SessionSweeper(),SWEEP_INTERVAL,SWEEP_INTERVAL);
|
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.shutdown(); // shut down the sweep task
|
||||||
m_sweep_task = null;
|
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.shutdown(); // shut down the initialization hook
|
||||||
m_init_hook = null;
|
m_init_hook = null;
|
||||||
|
|
||||||
|
@ -661,6 +672,29 @@ public class XmlRpcSubSystem
|
||||||
|
|
||||||
} // end addCapability
|
} // 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
|
* External operations
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue
Block a user