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
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
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
|
||||
*--------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue
Block a user