diff --git a/src/baseutil/com/silverwrist/util/xml/XMLLoader.java b/src/baseutil/com/silverwrist/util/xml/XMLLoader.java
index 9886ba6..8b1a81a 100644
--- a/src/baseutil/com/silverwrist/util/xml/XMLLoader.java
+++ b/src/baseutil/com/silverwrist/util/xml/XMLLoader.java
@@ -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 Element
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 found");
+ rc = (Element)n;
+
+ } // end for
+
+ return rc;
+
+ } // end getSoleSubElement
+
/**
* Returns all sub-elements of an Element
element that have a specific name.
*
diff --git a/src/dynamo-framework/com/silverwrist/dynamo/app/ApplicationContainer.java b/src/dynamo-framework/com/silverwrist/dynamo/app/ApplicationContainer.java
index a2c0f61..34ce94e 100644
--- a/src/dynamo-framework/com/silverwrist/dynamo/app/ApplicationContainer.java
+++ b/src/dynamo-framework/com/silverwrist/dynamo/app/ApplicationContainer.java
@@ -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);
diff --git a/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCaller.java b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCaller.java
new file mode 100644
index 0000000..aef88d5
--- /dev/null
+++ b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCaller.java
@@ -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 .
+ *
+ * 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 ,
+ * 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
diff --git a/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCallerFactory.java b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCallerFactory.java
new file mode 100644
index 0000000..293d165
--- /dev/null
+++ b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCallerFactory.java
@@ -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 .
+ *
+ * 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 ,
+ * 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
diff --git a/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCallerImpl.java b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCallerImpl.java
new file mode 100644
index 0000000..7ff5b62
--- /dev/null
+++ b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcCallerImpl.java
@@ -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 .
+ *
+ * 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 ,
+ * 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("\r\n\r\n");
+ wr.write(method);
+ wr.write("\r\n");
+ if (params.size()>0)
+ { // serialize the parameters
+ XmlRpcSerializer serializer = XmlRpcSerializer.get();
+ wr.write("\r\n");
+ Iterator it = params.iterator();
+ while (it.hasNext())
+ { // serialize the parameters
+ Object p = it.next();
+ wr.write("");
+ serializer.serialize(wr,p);
+ wr.write("\r\n");
+
+ } // end while
+
+ wr.write("\r\n");
+
+ } // end if
+
+ wr.write("\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"))
+ { // must contain , which must contain
+ 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"))
+ { // must contain
+ 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(" must contain either or ",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
diff --git a/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcSubSystem.java b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcSubSystem.java
index 31b2554..f30f549 100644
--- a/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcSubSystem.java
+++ b/src/dynamo-framework/com/silverwrist/dynamo/xmlrpc/XmlRpcSubSystem.java
@@ -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
*--------------------------------------------------------------------------------