*** empty log message ***
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
import com.silverwrist.dynamo.util.*;
|
||||
|
||||
class Capabilities implements XmlRpcDispatcher, XmlRpcTypeNames
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final String XMLRPC_NAME = "xmlrpc";
|
||||
private static final String XMLRPC_SPEC = "http://www.xmlrpc.com/spec";
|
||||
private static final int XMLRPC_VERSION = 1;
|
||||
|
||||
private static final String FAULTCODE_NAME = "faults_interop";
|
||||
private static final String FAULTCODE_SPEC = "http://xmlrpc-epi.sourceforge.net/cpecs/rfc.fault_codes.php";
|
||||
private static final int FAULTCODE_VERSION = 20010516;
|
||||
|
||||
private static final List SUPPORTED_METHODS;
|
||||
private static final List SIGNATURES;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private Hashtable m_capas = new Hashtable();
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Capabilities()
|
||||
{
|
||||
insertCapability(XMLRPC_NAME,XMLRPC_SPEC,XMLRPC_VERSION);
|
||||
insertCapability(FAULTCODE_NAME,FAULTCODE_SPEC,FAULTCODE_VERSION);
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcDispatcher
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getSessionIDParamValue(Request r, Application app)
|
||||
{
|
||||
return null; // dummy value
|
||||
|
||||
} // end getSessionIDParamValue
|
||||
|
||||
public Object dispatchXmlRpcCall(Request r, Application app) throws FaultCode
|
||||
{
|
||||
if (r.getParameters().size()!=0)
|
||||
throw new XmlRpcParameterError("system.getCapabilities: wrong parameter count");
|
||||
return new XmlRpcResult(m_capas);
|
||||
|
||||
} // end dispatchXmlRpcCall
|
||||
|
||||
public Collection getSupportedMethods(Request r)
|
||||
{
|
||||
return SUPPORTED_METHODS;
|
||||
|
||||
} // end getSupportedMethods
|
||||
|
||||
public List getMethodSignature(Request r, String method) throws FaultCode
|
||||
{
|
||||
return SIGNATURES;
|
||||
|
||||
} // end getMethodSignature
|
||||
|
||||
public String getMethodHelp(Request r, String method) throws FaultCode
|
||||
{
|
||||
ResourceBundle b = ResourceBundle.getBundle("com.silverwrist.dynamo.xmlrpc.XmlRpcMessages",
|
||||
Locale.getDefault());
|
||||
return b.getString("help.getCaps");
|
||||
|
||||
} // end getMethodHelp
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void insertCapability(String name, String url, int version)
|
||||
{
|
||||
HashMap tmp = new HashMap();
|
||||
tmp.put("specUrl",url);
|
||||
tmp.put("specVersion",new Integer(version));
|
||||
m_capas.put(name,Collections.unmodifiableMap(tmp));
|
||||
|
||||
} // end insertCapability
|
||||
|
||||
ComponentShutdown addCapability(String name, String url, int version)
|
||||
{
|
||||
insertCapability(name,url,version);
|
||||
return new ShutdownHashtableRemove(m_capas,name);
|
||||
|
||||
} // end addCapability
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Set up the supported methods list.
|
||||
SUPPORTED_METHODS = Collections.singletonList("system.getCapabilities");
|
||||
|
||||
// Set up the signature list.
|
||||
List l = Collections.singletonList(TYPE_STRUCT);
|
||||
SIGNATURES = Collections.singletonList(l);
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class Capabilities
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.dynamo.HttpStatusCode;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
public class FaultCode extends Throwable implements SelfRenderable
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static final int SYSTEM_FIRST = -32768;
|
||||
public static final int SYSTEM_LAST = -32000;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
protected int m_code;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructors
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public FaultCode()
|
||||
{
|
||||
super();
|
||||
m_code = 0;
|
||||
|
||||
} // end constructor
|
||||
|
||||
public FaultCode(int code)
|
||||
{
|
||||
super();
|
||||
m_code = (isSystemFaultCode(code) ? 0 : code);
|
||||
|
||||
} // end constructor
|
||||
|
||||
public FaultCode(String message)
|
||||
{
|
||||
super(message);
|
||||
m_code = 0;
|
||||
|
||||
} // end constructor
|
||||
|
||||
public FaultCode(int code, String message)
|
||||
{
|
||||
super(message);
|
||||
m_code = (isSystemFaultCode(code) ? 0 : code);
|
||||
|
||||
} // end constructor
|
||||
|
||||
public FaultCode(Throwable inner)
|
||||
{
|
||||
super(inner.getMessage(),inner);
|
||||
if (inner instanceof FaultCode)
|
||||
m_code = ((FaultCode)inner).getCode();
|
||||
else
|
||||
m_code = 0;
|
||||
|
||||
} // end constructor
|
||||
|
||||
public FaultCode(int code, Throwable inner)
|
||||
{
|
||||
super(inner.getMessage(),inner);
|
||||
m_code = (isSystemFaultCode(code) ? 0 : code);
|
||||
|
||||
} // end constructor
|
||||
|
||||
public FaultCode(String message, Throwable inner)
|
||||
{
|
||||
super(message,inner);
|
||||
if (inner instanceof FaultCode)
|
||||
m_code = ((FaultCode)inner).getCode();
|
||||
else
|
||||
m_code = 0;
|
||||
|
||||
} // end constructor
|
||||
|
||||
public FaultCode(int code, String message, Throwable inner)
|
||||
{
|
||||
super(message,inner);
|
||||
m_code = (isSystemFaultCode(code) ? 0 : code);
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface SelfRenderable
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public void render(SelfRenderControl control) throws IOException, RenderingException
|
||||
{
|
||||
// Create the rendered structure as raw text.
|
||||
StringBuffer b =
|
||||
new StringBuffer("<?xml version=\"1.0\"?>\r\n<methodResponse><fault><value><struct>\r\n<member>\r\n"
|
||||
+ "<name>faultCode</name>\r\n<value><int>");
|
||||
b.append(m_code);
|
||||
b.append("</int></value>\r\n</member>\r\n<member>\r\n<name>faultString</name>\r\n<value><string>");
|
||||
b.append(StringUtils.encodeHTML(getMessage()));
|
||||
b.append("</string></value>\r\n</member>\r\n</struct></value></fault></methodResponse>\r\n");
|
||||
|
||||
// Now render the binary equivalent of this structure.
|
||||
byte[] data = null;
|
||||
try
|
||||
{ // get a complete rendering of this data
|
||||
data = b.toString().getBytes("UTF-8");
|
||||
|
||||
} // end try
|
||||
catch (UnsupportedEncodingException e)
|
||||
{ // WTF? shouldn't happen
|
||||
data = b.toString().getBytes();
|
||||
|
||||
} // end catch
|
||||
|
||||
// send out the bytes as an XML message body
|
||||
control.status(HttpStatusCode.S_OK);
|
||||
BinaryRenderControl bctrl = control.getBinaryRender();
|
||||
bctrl.setContentType("text/xml; charset=UTF-8");
|
||||
bctrl.setContentLength(data.length);
|
||||
OutputStream stm = bctrl.getStream();
|
||||
stm.write(data);
|
||||
stm.flush();
|
||||
|
||||
} // end render
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External static operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static final boolean isSystemFaultCode(int code)
|
||||
{
|
||||
return ((code>=SYSTEM_FIRST) && (code<=SYSTEM_LAST));
|
||||
|
||||
} // end isSystemFaultCode
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public int getCode()
|
||||
{
|
||||
return m_code;
|
||||
|
||||
} // end getCode
|
||||
|
||||
} // end class FaultCode
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.lang.ref.*;
|
||||
import java.util.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
class IntrospectionDispatcher implements XmlRpcDispatcher, XmlRpcTypeNames
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final int DISP_LISTMETHODS = 0;
|
||||
private static final int DISP_METHODSIGNATURE = 1;
|
||||
private static final int DISP_METHODHELP = 2;
|
||||
|
||||
private static final Map DISPATCH_MAP;
|
||||
private static final List[] SIGNATURES;
|
||||
private static final String[] HELP_RESOURCES = {
|
||||
"help.listMeth", "help.methSig", "help.methHelp"
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private XmlRpcSubSystem m_subsys;
|
||||
private SoftReference m_methodlist = null;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
IntrospectionDispatcher(XmlRpcSubSystem subsys)
|
||||
{
|
||||
m_subsys = subsys;
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final void test0Param(Request r) throws XmlRpcParameterError
|
||||
{
|
||||
if (r.getParameters().size()!=0)
|
||||
throw new XmlRpcParameterError(r.getQueryString() + ": parameter count mismatch");
|
||||
|
||||
} // end test0Param
|
||||
|
||||
private static final String test1Param(Request r) throws XmlRpcParameterError
|
||||
{
|
||||
if (r.getParameters().size()!=1)
|
||||
throw new XmlRpcParameterError(r.getQueryString() + ": parameter count mismatch");
|
||||
Object rc = r.getParameters().get("0");
|
||||
if (rc instanceof String)
|
||||
return rc.toString();
|
||||
throw new XmlRpcParameterError(r.getQueryString() + ": parameter type mismatch");
|
||||
|
||||
} // end test1Param
|
||||
|
||||
private final List listMethods(Request r)
|
||||
{
|
||||
List rc = null;
|
||||
if (m_methodlist!=null)
|
||||
rc = (List)(m_methodlist.get());
|
||||
if (rc==null)
|
||||
{ // recompute the list of methods
|
||||
Set disps = m_subsys.getAllDispatchers();
|
||||
ArrayList output = new ArrayList();
|
||||
Iterator it = disps.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each dispatcher's available methods and add them to the list
|
||||
XmlRpcDispatcher xd = (XmlRpcDispatcher)(it.next());
|
||||
output.addAll(xd.getSupportedMethods(r));
|
||||
|
||||
} // end while
|
||||
|
||||
// sort the output, keep a reference to it
|
||||
Collections.sort(output);
|
||||
rc = Collections.unmodifiableList(output);
|
||||
m_methodlist = new SoftReference(rc);
|
||||
|
||||
} // end if
|
||||
|
||||
return rc;
|
||||
|
||||
} // end listMethods
|
||||
|
||||
private final Object methodSignature(Request r, String method) throws FaultCode
|
||||
{
|
||||
// Get the dispatcher for this method.
|
||||
XmlRpcDispatcher xd = m_subsys.getDispatcher(method);
|
||||
if (xd==null)
|
||||
throw new XmlRpcMethodNotFound(method);
|
||||
|
||||
// Ask it what the signatures are.
|
||||
List l = xd.getMethodSignature(r,method);
|
||||
if ((l==null) || l.isEmpty())
|
||||
return Boolean.FALSE;
|
||||
else
|
||||
return l;
|
||||
|
||||
} // end methodSignature
|
||||
|
||||
private final String methodHelp(Request r, String method) throws FaultCode
|
||||
{
|
||||
// Get the dispatcher for this method.
|
||||
XmlRpcDispatcher xd = m_subsys.getDispatcher(method);
|
||||
if (xd==null)
|
||||
throw new XmlRpcMethodNotFound(method);
|
||||
|
||||
// Return the doc string.
|
||||
return xd.getMethodHelp(r,method);
|
||||
|
||||
} // end methodHelp
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcDispatcher
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getSessionIDParamValue(Request r, Application app)
|
||||
{
|
||||
return null;
|
||||
|
||||
} // end getSessionIDParamValue
|
||||
|
||||
public Object dispatchXmlRpcCall(Request r, Application app) throws Exception, FaultCode
|
||||
{
|
||||
Integer index = (Integer)(DISPATCH_MAP.get(r.getQueryString()));
|
||||
if (index==null)
|
||||
throw new XmlRpcMethodNotFound(r.getQueryString());
|
||||
|
||||
switch (index.intValue())
|
||||
{
|
||||
case DISP_LISTMETHODS:
|
||||
test0Param(r);
|
||||
return listMethods(r);
|
||||
|
||||
case DISP_METHODSIGNATURE:
|
||||
return methodSignature(r,test1Param(r));
|
||||
|
||||
case DISP_METHODHELP:
|
||||
return methodHelp(r,test1Param(r));
|
||||
|
||||
default:
|
||||
throw new XmlRpcMethodNotFound(r.getQueryString());
|
||||
|
||||
} // end switch
|
||||
|
||||
} // end dispatchXmlRpcCall
|
||||
|
||||
public Collection getSupportedMethods(Request r)
|
||||
{
|
||||
return DISPATCH_MAP.keySet();
|
||||
|
||||
} // end getSupportedMethods
|
||||
|
||||
public List getMethodSignature(Request r, String method) throws FaultCode
|
||||
{
|
||||
Integer index = (Integer)(DISPATCH_MAP.get(r.getQueryString()));
|
||||
if (index==null)
|
||||
throw new XmlRpcMethodNotFound(r.getQueryString());
|
||||
return SIGNATURES[index.intValue()];
|
||||
|
||||
} // end getMethodSignature
|
||||
|
||||
public String getMethodHelp(Request r, String method) throws FaultCode
|
||||
{
|
||||
Integer index = (Integer)(DISPATCH_MAP.get(r.getQueryString()));
|
||||
if (index==null)
|
||||
throw new XmlRpcMethodNotFound(r.getQueryString());
|
||||
ResourceBundle b = ResourceBundle.getBundle("com.silverwrist.dynamo.xmlrpc.XmlRpcMessages",
|
||||
Locale.getDefault());
|
||||
return b.getString(HELP_RESOURCES[index.intValue()]);
|
||||
|
||||
} // end getMethodHelp
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Initialize the dispatch map.
|
||||
HashMap map = new HashMap();
|
||||
map.put("system.listMethods",new Integer(DISP_LISTMETHODS));
|
||||
map.put("system.methodSignature",new Integer(DISP_METHODSIGNATURE));
|
||||
map.put("system.methodHelp",new Integer(DISP_METHODHELP));
|
||||
DISPATCH_MAP = Collections.unmodifiableMap(map);
|
||||
|
||||
// Initialize the signatures list.
|
||||
List[] arr = new List[3];
|
||||
ArrayList tmp = new ArrayList(1);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
List l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_LISTMETHODS] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
tmp.add(TYPE_STRING);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_METHODSIGNATURE] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_STRING);
|
||||
tmp.add(TYPE_STRING);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_METHODHELP] = Collections.singletonList(l);
|
||||
SIGNATURES = arr;
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class IntrospectionDispatcher
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
class MultiCallDispatcher implements XmlRpcDispatcher, XmlRpcTypeNames
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final List SUPPORTED_METHODS;
|
||||
private static final List SIGNATURES;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private XmlRpcSubSystem m_subsystem;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MultiCallDispatcher(XmlRpcSubSystem subsystem)
|
||||
{
|
||||
m_subsystem = subsystem;
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final Map translateFaultCode(FaultCode fc)
|
||||
{
|
||||
HashMap rc = new HashMap();
|
||||
rc.put("faultCode",new Integer(fc.getCode()));
|
||||
rc.put("faultString",fc.getMessage());
|
||||
return Collections.unmodifiableMap(rc);
|
||||
|
||||
} // end translateFaultCode
|
||||
|
||||
private final Object callViaStructure(Request r, Application app, Object struc) throws FaultCode
|
||||
{
|
||||
// Validate that this is a structure of the right type, and get the method name and the
|
||||
// parameters.
|
||||
if (!(struc instanceof Map))
|
||||
throw new XmlRpcParameterError("system.multicall: expected struct");
|
||||
Map my_map = (Map)struc;
|
||||
Object foo = my_map.get("methodName");
|
||||
if (foo==null)
|
||||
throw new XmlRpcParameterError("system.multicall: missing methodName");
|
||||
if (!(foo instanceof String))
|
||||
throw new XmlRpcParameterError("system.multicall: methodName not string");
|
||||
String method_name = (String)foo;
|
||||
foo = my_map.get("params");
|
||||
if (foo==null)
|
||||
throw new XmlRpcParameterError("system.multicall: missing params");
|
||||
if (!(foo instanceof List))
|
||||
throw new XmlRpcParameterError("system.multicall: params not array");
|
||||
List params = (List)foo;
|
||||
|
||||
// Build our "nested" request and dispatch it.
|
||||
MultiCallRequest new_r = new MultiCallRequest(r,method_name,params);
|
||||
try
|
||||
{ // run this through the dispatcher!
|
||||
return m_subsystem.dispatch(new_r,app);
|
||||
|
||||
} // end try
|
||||
catch (Exception e)
|
||||
{ // translate exception to FaultCode before we return
|
||||
return m_subsystem.translateException(new_r,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end callViaStructure
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcDispatcher
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getSessionIDParamValue(Request r, Application app)
|
||||
{
|
||||
return null; // dummy value
|
||||
|
||||
} // end getSessionIDParamValue
|
||||
|
||||
public Object dispatchXmlRpcCall(Request r, Application app) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("system.multicall: wrong parameter count");
|
||||
Object parm = pm.get("0");
|
||||
if (!(parm instanceof List))
|
||||
throw new XmlRpcParameterError("system.multicall: parameter not array");
|
||||
|
||||
List call_strucs = (List)parm;
|
||||
List return_strucs = new ArrayList(call_strucs.size());
|
||||
Iterator it = call_strucs.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each call structure in turn and make sure it's OK
|
||||
Object call = it.next();
|
||||
Object rc = null;
|
||||
try
|
||||
{ // execute this call!
|
||||
rc = callViaStructure(r,app,call);
|
||||
if (rc instanceof FaultCode)
|
||||
rc = translateFaultCode((FaultCode)rc);
|
||||
else // encapsulate in a 1-element array
|
||||
rc = Collections.singletonList(rc);
|
||||
|
||||
} // end try
|
||||
catch (FaultCode fc)
|
||||
{ // translate a fault code if it gets thrown
|
||||
rc = translateFaultCode(fc);
|
||||
|
||||
} // end catch
|
||||
|
||||
return_strucs.add(rc); // add return value to list
|
||||
|
||||
} // end while
|
||||
|
||||
return new XmlRpcResult(return_strucs); // return list of return structures
|
||||
|
||||
} // end dispatchXmlRpcCall
|
||||
|
||||
public Collection getSupportedMethods(Request r)
|
||||
{
|
||||
return SUPPORTED_METHODS;
|
||||
|
||||
} // end getSupportedMethods
|
||||
|
||||
public List getMethodSignature(Request r, String method)
|
||||
{
|
||||
return SIGNATURES;
|
||||
|
||||
} // end getMethodSignatures
|
||||
|
||||
public String getMethodHelp(Request r, String method)
|
||||
{
|
||||
ResourceBundle b = ResourceBundle.getBundle("com.silverwrist.dynamo.xmlrpc.XmlRpcMessages",
|
||||
Locale.getDefault());
|
||||
return b.getString("help.multicall");
|
||||
|
||||
} // end getMethodHelp
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Initialize the supported methods list.
|
||||
SUPPORTED_METHODS = Collections.singletonList("system.multicall");
|
||||
|
||||
// Initialize the signatures list.
|
||||
ArrayList tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
List l = Collections.unmodifiableList(tmp);
|
||||
tmp = new ArrayList(1);
|
||||
tmp.add(l);
|
||||
SIGNATURES = Collections.unmodifiableList(tmp);
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class MultiCallDispatcher
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
import com.silverwrist.dynamo.util.*;
|
||||
|
||||
class MultiCallRequest extends FilterRequest
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private String m_method;
|
||||
private Map m_params;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MultiCallRequest(Request inner, String method, List params)
|
||||
{
|
||||
super(inner);
|
||||
m_method = method;
|
||||
HashMap tmp = new HashMap();
|
||||
Iterator it = params.iterator();
|
||||
int ndx = 0;
|
||||
while (it.hasNext())
|
||||
tmp.put(String.valueOf(ndx++),it.next());
|
||||
if (tmp.isEmpty())
|
||||
m_params = Collections.EMPTY_MAP;
|
||||
else
|
||||
m_params = Collections.unmodifiableMap(tmp);
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class FilterRequest
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getQueryString()
|
||||
{
|
||||
return m_method;
|
||||
|
||||
} // end getQueryString
|
||||
|
||||
public Map getParameters()
|
||||
{
|
||||
return m_params;
|
||||
|
||||
} // end getParameters
|
||||
|
||||
} // end class MultiCallRequest
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.regex.*;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
|
||||
class RegisteredDispatcher
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private Pattern m_pattern;
|
||||
private String m_expr;
|
||||
private XmlRpcDispatcher m_dispatcher;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
RegisteredDispatcher(String expr, XmlRpcDispatcher dispatcher) throws ConfigException
|
||||
{
|
||||
try
|
||||
{ // compile the pattern and save the dispatcher
|
||||
if (!(expr.startsWith("^")))
|
||||
expr = "^" + expr;
|
||||
m_pattern = Pattern.compile(expr);
|
||||
m_expr = expr;
|
||||
m_dispatcher = dispatcher;
|
||||
|
||||
} // end try
|
||||
catch (PatternSyntaxException e)
|
||||
{ // convert this to a ConfigException
|
||||
ConfigException ce = new ConfigException(RegisteredDispatcher.class,"XmlRpcMessages","pattern.error",e);
|
||||
ce.setParameter(0,expr);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class Object
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if ((o==null) || !(o instanceof RegisteredDispatcher))
|
||||
return false;
|
||||
RegisteredDispatcher other = (RegisteredDispatcher)o;
|
||||
return (m_expr.equals(other.m_expr) && (m_dispatcher==other.m_dispatcher));
|
||||
|
||||
} // end equals
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return m_expr.hashCode() ^ System.identityHashCode(m_dispatcher);
|
||||
|
||||
} // end hashCode
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
boolean match(String method_name)
|
||||
{
|
||||
return m_pattern.matcher(method_name).matches();
|
||||
|
||||
} // end match
|
||||
|
||||
XmlRpcDispatcher getDispatcher()
|
||||
{
|
||||
return m_dispatcher;
|
||||
|
||||
} // end getDispatcher
|
||||
|
||||
} // end class RegisteredDispatcher
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
class RegisteredFaultMapper
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private Class m_class;
|
||||
private XmlRpcFaultMapper m_fmap;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
RegisteredFaultMapper(Class klass, XmlRpcFaultMapper fmap)
|
||||
{
|
||||
m_class = klass;
|
||||
m_fmap = fmap;
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class Object
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if ((o==null) || !(o instanceof RegisteredFaultMapper))
|
||||
return false;
|
||||
RegisteredFaultMapper other = (RegisteredFaultMapper)o;
|
||||
return ((m_class==other.m_class) && (m_fmap==other.m_fmap));
|
||||
|
||||
} // end equals
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return m_class.hashCode() ^ System.identityHashCode(m_fmap);
|
||||
|
||||
} // end hashCode
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
boolean match(Class klass)
|
||||
{
|
||||
return (m_class==klass);
|
||||
|
||||
} // end match
|
||||
|
||||
XmlRpcFaultMapper getFaultMapper()
|
||||
{
|
||||
return m_fmap;
|
||||
|
||||
} // end getFaultMapper
|
||||
|
||||
} // end class RegisteredFaultMapper
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
import com.silverwrist.dynamo.util.*;
|
||||
|
||||
class ReplaceSessionRequest extends FilterRequest
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private DefaultSessionInfoProvider m_prov;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ReplaceSessionRequest(Request inner, SessionInfo session)
|
||||
{
|
||||
super(inner);
|
||||
m_prov = new DefaultSessionInfoProvider(session);
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class FilterRequest
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Queries this object for a specified service.
|
||||
*
|
||||
* @param klass The class of the object that should be returned as a service.
|
||||
* @return A service object. The service object is guaranteed to be of the class
|
||||
* specified by <CODE>klass</CODE>; that is, if <CODE>queryService(klass)</CODE>
|
||||
* yields some object <CODE>x</CODE>, then the expression <CODE>klass.isInstance(x)</CODE>
|
||||
* is true.
|
||||
* @exception com.silverwrist.dynamo.except.NoSuchServiceException If no service is available in
|
||||
* the specified class.
|
||||
*/
|
||||
public Object queryService(Class klass)
|
||||
{
|
||||
if (klass==SessionInfoProvider.class)
|
||||
return m_prov;
|
||||
return super.queryService(klass);
|
||||
|
||||
} // end queryService
|
||||
|
||||
} // end class ReplaceSessionRequest
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.w3c.dom.*;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.util.xml.*;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
public class ScriptDispatcher implements ComponentInitialize, XmlRpcDispatcher
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private String m_script_name;
|
||||
private String m_session_param = null;
|
||||
private Hashtable m_metadata = new Hashtable();
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ScriptDispatcher()
|
||||
{ // do nothing
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private final void loadMetadataList(List l) throws ConfigException
|
||||
{
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // create metadata elements
|
||||
Element elt = (Element)(it.next());
|
||||
XMLMetadata md = new XMLMetadata(elt);
|
||||
m_metadata.put(md.getMethodName(),md);
|
||||
|
||||
} // end while
|
||||
|
||||
} // end loadMetadataList
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ComponentInitialize
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public void initialize(Element config_root, ServiceProvider services) throws ConfigException
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
try
|
||||
{ // get the script name
|
||||
DOMElementHelper config_root_h = new DOMElementHelper(config_root);
|
||||
m_script_name = loader.getSubElementText(config_root_h,"script");
|
||||
|
||||
// get the session parameter
|
||||
Element elt = config_root_h.getSubElement("session");
|
||||
if (elt!=null)
|
||||
m_session_param = loader.getAttribute(elt,"param");
|
||||
|
||||
// load a metadata file if it's present
|
||||
String md_file = config_root_h.getSubElementText("metadata-file");
|
||||
if (md_file!=null)
|
||||
{ // try and load the metadata file
|
||||
InputStream stm = null;
|
||||
try
|
||||
{ // load the resource and parse it into XML
|
||||
ResourceProvider rprov = (ResourceProvider)(services.queryService(ResourceProvider.class));
|
||||
stm = rprov.getResource(md_file);
|
||||
Document doc = loader.load(stm,false);
|
||||
Element md_root = loader.getRootElement(doc,"metadata-file");
|
||||
loadMetadataList(loader.getMatchingSubElements(md_root,"metadata"));
|
||||
|
||||
} // end try
|
||||
catch (NoSuchResourceException e)
|
||||
{ // just ignore the file
|
||||
} // end catch
|
||||
catch (IOException e)
|
||||
{ // just ignore the file
|
||||
} // end catch
|
||||
finally
|
||||
{ // shut down stream
|
||||
IOUtils.shutdown(stm);
|
||||
|
||||
} // end finally
|
||||
|
||||
} // end if (metadata file specified)
|
||||
|
||||
// load direct metadata if it's present
|
||||
loadMetadataList(loader.getMatchingSubElements(config_root,"metadata"));
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate to ConfigException
|
||||
throw new ConfigException(e);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end initialize
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcDispatcher
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getSessionIDParamValue(Request r, Application app)
|
||||
{
|
||||
if (m_session_param==null)
|
||||
return null;
|
||||
Object o = r.getParameters().get(m_session_param);
|
||||
return ((o==null) ? null : o.toString());
|
||||
|
||||
} // end getSessionIDParamValue
|
||||
|
||||
public Object dispatchXmlRpcCall(Request r, Application app) throws Exception, FaultCode
|
||||
{
|
||||
ScriptExecute exec = (ScriptExecute)(r.queryService(ScriptExecute.class));
|
||||
return exec.executeScript(r,m_script_name);
|
||||
|
||||
} // end dispatchXmlRpcCall
|
||||
|
||||
public Collection getSupportedMethods(Request r)
|
||||
{
|
||||
return Collections.unmodifiableSet(m_metadata.keySet());
|
||||
|
||||
} // end getSupportedMethods
|
||||
|
||||
public List getMethodSignature(Request r, String method) throws FaultCode
|
||||
{
|
||||
XMLMetadata md = (XMLMetadata)(m_metadata.get(method));
|
||||
if (md!=null)
|
||||
return md.getSignatures();
|
||||
else
|
||||
return null;
|
||||
|
||||
} // end getMethodSignature
|
||||
|
||||
public String getMethodHelp(Request r, String method) throws FaultCode
|
||||
{
|
||||
XMLMetadata md = (XMLMetadata)(m_metadata.get(method));
|
||||
if (md!=null)
|
||||
return md.getDocumentation();
|
||||
else
|
||||
return "";
|
||||
|
||||
} // end getMethodHelp
|
||||
|
||||
} // end class ScriptDispatcher
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
class SystemFaultCode extends FaultCode
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static final int PARSE_ERROR = -32700;
|
||||
public static final int BAD_ENCODING = -32701;
|
||||
public static final int INVALID_CHARACTER = -32702;
|
||||
public static final int INVALID_REQUEST = -32600;
|
||||
public static final int METHOD_NOT_FOUND = -32601;
|
||||
public static final int INVALID_PARAMS = -32602;
|
||||
public static final int INTERNAL_ERROR = -32603;
|
||||
public static final int APPLICATION_ERROR = -32500;
|
||||
public static final int SERVER_ERROR = -32400;
|
||||
public static final int TRANSPORT_ERROR = -32300;
|
||||
|
||||
public static final int IMPL_ERROR_FIRST = -32099;
|
||||
public static final int IMPL_ERROR_LAST = -32000;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructors
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
SystemFaultCode()
|
||||
{
|
||||
super();
|
||||
|
||||
} // end constructor
|
||||
|
||||
SystemFaultCode(int code)
|
||||
{
|
||||
super();
|
||||
m_code = code;
|
||||
|
||||
} // end constructor
|
||||
|
||||
SystemFaultCode(String message)
|
||||
{
|
||||
super(message);
|
||||
|
||||
} // end constructor
|
||||
|
||||
SystemFaultCode(int code, String message)
|
||||
{
|
||||
super(message);
|
||||
m_code = code;
|
||||
|
||||
} // end constructor
|
||||
|
||||
SystemFaultCode(Throwable inner)
|
||||
{
|
||||
super(inner);
|
||||
|
||||
} // end constructor
|
||||
|
||||
SystemFaultCode(int code, Throwable inner)
|
||||
{
|
||||
super(inner);
|
||||
m_code = code;
|
||||
|
||||
} // end constructor
|
||||
|
||||
SystemFaultCode(String message, Throwable inner)
|
||||
{
|
||||
super(message,inner);
|
||||
|
||||
} // end constructor
|
||||
|
||||
SystemFaultCode(int code, String message, Throwable inner)
|
||||
{
|
||||
super(message,inner);
|
||||
m_code = code;
|
||||
|
||||
} // end constructor
|
||||
|
||||
} // end class SystemFaultCode
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.*;
|
||||
import org.apache.commons.lang.CharSetUtils;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
/**
|
||||
* Implements the functions called by the UserLand Software XML-RPC Validator, which act as a test
|
||||
* for the XML-RPC protocol stack.
|
||||
*
|
||||
* @author Eric J. Bowersox <erbo@silcom.com>
|
||||
* @version X
|
||||
*/
|
||||
public class Validator1Suite implements XmlRpcDispatcher, XmlRpcTypeNames
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final int DISP_ARRAYOFSTRUCTS = 0;
|
||||
private static final int DISP_COUNTTHEENTITIES = 1;
|
||||
private static final int DISP_EASYSTRUCT = 2;
|
||||
private static final int DISP_ECHOSTRUCT = 3;
|
||||
private static final int DISP_MANYTYPES = 4;
|
||||
private static final int DISP_MODERATESIZEARRAY = 5;
|
||||
private static final int DISP_NESTEDSTRUCT = 6;
|
||||
private static final int DISP_SIMPLESTRUCTRETURN = 7;
|
||||
|
||||
private static final Map DISPATCH_MAP;
|
||||
private static final List[] SIGNATURES;
|
||||
private static final String[] HELP_RESOURCES = {
|
||||
"help.v1.arrayOf", "help.v1.countEnt", "help.v1.ezStruct", "help.v1.echoStr",
|
||||
"help.v1.manyType", "help.v1.mSAC", "help.v1.nestStr", "help.v1.simple"
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public Validator1Suite()
|
||||
{ // do nothing
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* <CODE>validator1.arrayOfStructsTest(array) returns integer</CODE><P>
|
||||
* The parameter is an array of structs containing at least three elements, named
|
||||
* "moe", "larry", and "curly", all of which are integers. Function must add up all
|
||||
* the "curly" elements and return the sum.
|
||||
*
|
||||
* @param r The {@link com.silverwrist.dynamo.iface.Request} object containing the
|
||||
* parameters.
|
||||
* @return The return value from the method call.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If there is an error in the parameters.
|
||||
*/
|
||||
private Integer arrayOfStructsTest(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("validator1.arrayOfStructsTest: wrong parameter count");
|
||||
Object foo = pm.get("0");
|
||||
if (!(foo instanceof List))
|
||||
throw new XmlRpcParameterError("validator1.arrayOfStructsTest: array expected");
|
||||
|
||||
int accum = 0;
|
||||
Iterator it = ((List)foo).iterator();
|
||||
while (it.hasNext())
|
||||
{ // cycle through the list of structs
|
||||
foo = it.next();
|
||||
if (!(foo instanceof Map))
|
||||
throw new XmlRpcParameterError("validator1.arrayOfStructsTest: struct expected");
|
||||
Map struc = (Map)foo;
|
||||
foo = struc.get("curly");
|
||||
if ((foo!=null) && (foo instanceof Integer))
|
||||
accum += ((Integer)foo).intValue();
|
||||
|
||||
} // end while
|
||||
|
||||
return new Integer(accum);
|
||||
|
||||
} // end arrayOfStructsTest
|
||||
|
||||
/**
|
||||
* <CODE>validator1.countTheEntities(string) returns struct</CODE><P>
|
||||
*/
|
||||
private Map countTheEntities(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("validator1.countTheEntities: wrong parameter count");
|
||||
Object foo = pm.get("0");
|
||||
if (!(foo instanceof String))
|
||||
throw new XmlRpcParameterError("validator1.countTheEntities: string expected");
|
||||
String s = (String)foo;
|
||||
|
||||
// Create the output value.
|
||||
HashMap rc = new HashMap();
|
||||
rc.put("ctLeftAngleBrackets",new Integer(CharSetUtils.count(s,"<")));
|
||||
rc.put("ctRightAngleBrackets",new Integer(CharSetUtils.count(s,">")));
|
||||
rc.put("ctAmpersands",new Integer(CharSetUtils.count(s,"&")));
|
||||
rc.put("ctApostrophes",new Integer(CharSetUtils.count(s,"'")));
|
||||
rc.put("ctQuotes",new Integer(CharSetUtils.count(s,"\"")));
|
||||
return rc;
|
||||
|
||||
} // end countTheEntities
|
||||
|
||||
private Integer easyStructTest(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("validator1.easyStructTest: wrong parameter count");
|
||||
Object foo = pm.get("0");
|
||||
if (!(foo instanceof Map))
|
||||
throw new XmlRpcParameterError("validator1.easyStructTest: struct expected");
|
||||
|
||||
Map struc = (Map)foo;
|
||||
int sum = 0;
|
||||
foo = struc.get("moe");
|
||||
if ((foo!=null) && (foo instanceof Integer))
|
||||
sum += ((Integer)foo).intValue();
|
||||
foo = struc.get("larry");
|
||||
if ((foo!=null) && (foo instanceof Integer))
|
||||
sum += ((Integer)foo).intValue();
|
||||
foo = struc.get("curly");
|
||||
if ((foo!=null) && (foo instanceof Integer))
|
||||
sum += ((Integer)foo).intValue();
|
||||
return new Integer(sum);
|
||||
|
||||
} // end easyStructTest
|
||||
|
||||
private Map echoStructTest(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("validator1.echoStructTest: wrong parameter count");
|
||||
Object foo = pm.get("0");
|
||||
if (!(foo instanceof Map))
|
||||
throw new XmlRpcParameterError("validator1.echoStructTest: struct expected");
|
||||
return (Map)foo;
|
||||
|
||||
} // end echoStructTest
|
||||
|
||||
private List manyTypesTest(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=6)
|
||||
throw new XmlRpcParameterError("validator1.manyTypesTest: wrong parameter count");
|
||||
if (!(pm.get("0") instanceof Integer))
|
||||
throw new XmlRpcParameterError("validator1.manyTypesTest: integer expected");
|
||||
if (!(pm.get("1") instanceof Boolean))
|
||||
throw new XmlRpcParameterError("validator1.manyTypesTest: boolean expected");
|
||||
if (!(pm.get("2") instanceof String))
|
||||
throw new XmlRpcParameterError("validator1.manyTypesTest: string expected");
|
||||
if (!(pm.get("3") instanceof Double))
|
||||
throw new XmlRpcParameterError("validator1.manyTypesTest: double expected");
|
||||
if (!(pm.get("4") instanceof Date))
|
||||
throw new XmlRpcParameterError("validator1.manyTypesTest: date expected");
|
||||
if (!(pm.get("5") instanceof byte[]))
|
||||
throw new XmlRpcParameterError("validator1.manyTypesTest: base64 expected");
|
||||
|
||||
ArrayList rc = new ArrayList(6);
|
||||
for (int i=0; i<6; i++)
|
||||
rc.add(pm.get(String.valueOf(i)));
|
||||
return rc;
|
||||
|
||||
} // end manyTypesTest
|
||||
|
||||
private String moderateSizeArrayCheck(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("validator1.moderateSizeArrayCheck: wrong parameter count");
|
||||
Object foo = pm.get("0");
|
||||
if (!(foo instanceof List))
|
||||
throw new XmlRpcParameterError("validator1.moderateSizeArrayCheck: array expected");
|
||||
|
||||
List arr = (List)foo;
|
||||
StringBuffer rc = new StringBuffer(arr.get(0).toString());
|
||||
rc.append(arr.get(arr.size()-1));
|
||||
return rc.toString();
|
||||
|
||||
} // end moderateSizeArrayCheck
|
||||
|
||||
private Integer nestedStructTest(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("validator1.nestedStructTest: wrong parameter count");
|
||||
Object foo = pm.get("0");
|
||||
if (!(foo instanceof Map))
|
||||
throw new XmlRpcParameterError("validator1.nestedStructTest: struct expected");
|
||||
Map current = (Map)foo;
|
||||
|
||||
// Navigate down through the structure until we find the right map.
|
||||
foo = current.get("2000");
|
||||
if ((foo==null) || !(foo instanceof Map))
|
||||
throw new XmlRpcParameterError("validator1.nestedStructTest: struct expected");
|
||||
current = (Map)foo;
|
||||
foo = current.get("04");
|
||||
if ((foo==null) || !(foo instanceof Map))
|
||||
throw new XmlRpcParameterError("validator1.nestedStructTest: struct expected");
|
||||
current = (Map)foo;
|
||||
foo = current.get("01");
|
||||
if ((foo==null) || !(foo instanceof Map))
|
||||
throw new XmlRpcParameterError("validator1.nestedStructTest: struct expected");
|
||||
current = (Map)foo;
|
||||
|
||||
// Get the three integer fields, add them and return the result.
|
||||
int sum = 0;
|
||||
foo = current.get("moe");
|
||||
if ((foo!=null) && (foo instanceof Integer))
|
||||
sum += ((Integer)foo).intValue();
|
||||
foo = current.get("larry");
|
||||
if ((foo!=null) && (foo instanceof Integer))
|
||||
sum += ((Integer)foo).intValue();
|
||||
foo = current.get("curly");
|
||||
if ((foo!=null) && (foo instanceof Integer))
|
||||
sum += ((Integer)foo).intValue();
|
||||
return new Integer(sum);
|
||||
|
||||
} // end nestedStructTest
|
||||
|
||||
private Map simpleStructReturnTest(Request r) throws FaultCode
|
||||
{
|
||||
Map pm = r.getParameters();
|
||||
if (pm.size()!=1)
|
||||
throw new XmlRpcParameterError("validator1.simpleStructReturnTest: wrong parameter count");
|
||||
Object foo = pm.get("0");
|
||||
if (!(foo instanceof Integer))
|
||||
throw new XmlRpcParameterError("validator1.simpleStructReturnTest: integer expected");
|
||||
int base_val = ((Integer)foo).intValue();
|
||||
|
||||
// create the return structure
|
||||
HashMap rc = new HashMap();
|
||||
rc.put("times10",new Integer(base_val * 10));
|
||||
rc.put("times100",new Integer(base_val * 100));
|
||||
rc.put("times1000",new Integer(base_val * 1000));
|
||||
return rc;
|
||||
|
||||
} // end simpleStructReturnTest
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcDispatcher
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getSessionIDParamValue(Request r, Application app)
|
||||
{
|
||||
return null;
|
||||
|
||||
} // end getSessionIDParamValue
|
||||
|
||||
public Object dispatchXmlRpcCall(Request r, Application app) throws FaultCode
|
||||
{
|
||||
Integer disp = (Integer)(DISPATCH_MAP.get(r.getQueryString()));
|
||||
if (disp==null)
|
||||
throw new XmlRpcMethodNotFound(r.getQueryString());
|
||||
|
||||
switch (disp.intValue())
|
||||
{
|
||||
case DISP_ARRAYOFSTRUCTS:
|
||||
return arrayOfStructsTest(r);
|
||||
|
||||
case DISP_COUNTTHEENTITIES:
|
||||
return countTheEntities(r);
|
||||
|
||||
case DISP_EASYSTRUCT:
|
||||
return easyStructTest(r);
|
||||
|
||||
case DISP_ECHOSTRUCT:
|
||||
return echoStructTest(r);
|
||||
|
||||
case DISP_MANYTYPES:
|
||||
return manyTypesTest(r);
|
||||
|
||||
case DISP_MODERATESIZEARRAY:
|
||||
return moderateSizeArrayCheck(r);
|
||||
|
||||
case DISP_NESTEDSTRUCT:
|
||||
return nestedStructTest(r);
|
||||
|
||||
case DISP_SIMPLESTRUCTRETURN:
|
||||
return simpleStructReturnTest(r);
|
||||
|
||||
default:
|
||||
throw new XmlRpcMethodNotFound(r.getQueryString());
|
||||
|
||||
} // end switch
|
||||
|
||||
} // end dispatchXmlRpcCall
|
||||
|
||||
public Collection getSupportedMethods(Request r)
|
||||
{
|
||||
return DISPATCH_MAP.keySet();
|
||||
|
||||
} // end getSupportedMethods
|
||||
|
||||
public List getMethodSignature(Request r, String method) throws FaultCode
|
||||
{
|
||||
Integer disp = (Integer)(DISPATCH_MAP.get(method));
|
||||
if (disp==null)
|
||||
throw new XmlRpcMethodNotFound(method);
|
||||
return SIGNATURES[disp.intValue()];
|
||||
|
||||
} // end getMethodSignature
|
||||
|
||||
public String getMethodHelp(Request r, String method) throws FaultCode
|
||||
{
|
||||
Integer disp = (Integer)(DISPATCH_MAP.get(method));
|
||||
if (disp==null)
|
||||
throw new XmlRpcMethodNotFound(method);
|
||||
ResourceBundle b = ResourceBundle.getBundle("com.silverwrist.dynamo.xmlrpc.XmlRpcMessages",
|
||||
Locale.getDefault());
|
||||
return b.getString(HELP_RESOURCES[disp.intValue()]);
|
||||
|
||||
} // end getMethodHelp
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Create the dispatch map.
|
||||
HashMap mtmp = new HashMap();
|
||||
mtmp.put("validator1.arrayOfStructsTest",new Integer(DISP_ARRAYOFSTRUCTS));
|
||||
mtmp.put("validator1.countTheEntities",new Integer(DISP_COUNTTHEENTITIES));
|
||||
mtmp.put("validator1.easyStructTest",new Integer(DISP_EASYSTRUCT));
|
||||
mtmp.put("validator1.echoStructTest",new Integer(DISP_ECHOSTRUCT));
|
||||
mtmp.put("validator1.manyTypesTest",new Integer(DISP_MANYTYPES));
|
||||
mtmp.put("validator1.moderateSizeArrayCheck",new Integer(DISP_MODERATESIZEARRAY));
|
||||
mtmp.put("validator1.nestedStructTest",new Integer(DISP_NESTEDSTRUCT));
|
||||
mtmp.put("validator1.simpleStructReturnTest",new Integer(DISP_SIMPLESTRUCTRETURN));
|
||||
DISPATCH_MAP = Collections.unmodifiableMap(mtmp);
|
||||
|
||||
// Create the signatures.
|
||||
List[] arr = new List[8];
|
||||
ArrayList tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_INT);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
List l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_ARRAYOFSTRUCTS] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_STRUCT);
|
||||
tmp.add(TYPE_STRING);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_COUNTTHEENTITIES] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_INT);
|
||||
tmp.add(TYPE_STRUCT);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_EASYSTRUCT] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_STRUCT);
|
||||
tmp.add(TYPE_STRUCT);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_ECHOSTRUCT] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(7);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
tmp.add(TYPE_INT);
|
||||
tmp.add(TYPE_BOOLEAN);
|
||||
tmp.add(TYPE_STRING);
|
||||
tmp.add(TYPE_DOUBLE);
|
||||
tmp.add(TYPE_DATETIME);
|
||||
tmp.add(TYPE_BASE64);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_MANYTYPES] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_STRING);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_MODERATESIZEARRAY] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_INT);
|
||||
tmp.add(TYPE_STRUCT);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_NESTEDSTRUCT] = Collections.singletonList(l);
|
||||
tmp = new ArrayList(2);
|
||||
tmp.add(TYPE_STRUCT);
|
||||
tmp.add(TYPE_INT);
|
||||
l = Collections.unmodifiableList(tmp);
|
||||
arr[DISP_SIMPLESTRUCTRETURN] = Collections.singletonList(l);
|
||||
SIGNATURES = arr;
|
||||
|
||||
} // end static
|
||||
|
||||
} // end class Validator1Suite
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.*;
|
||||
import org.w3c.dom.*;
|
||||
import com.silverwrist.util.xml.*;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
|
||||
class XMLMetadata implements XmlRpcTypeNames
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final Set VALID_TYPES;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private String m_method_name;
|
||||
private List m_signatures;
|
||||
private String m_docs;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
XMLMetadata(Element md_root) throws ConfigException
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
try
|
||||
{ // get the method name
|
||||
m_method_name = loader.getAttribute(md_root,"method");
|
||||
|
||||
// look for method signatures
|
||||
ArrayList sigs = new ArrayList();
|
||||
List l_sigs = loader.getMatchingSubElements(md_root,"signature");
|
||||
Iterator it = l_sigs.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each signature
|
||||
Element sig_elt = (Element)(it.next());
|
||||
|
||||
// get the return type
|
||||
ArrayList sdata = new ArrayList();
|
||||
String s = loader.getSubElementText(sig_elt,"return").trim();
|
||||
verifyType(s);
|
||||
sdata.add(s);
|
||||
|
||||
// get all parameters
|
||||
List l_parms = loader.getMatchingSubElements(sig_elt,"param");
|
||||
Iterator it2 = l_parms.iterator();
|
||||
while (it2.hasNext())
|
||||
{ // get each parameter in turn
|
||||
Element elt = (Element)(it2.next());
|
||||
s = loader.getText(elt).trim();
|
||||
verifyType(s);
|
||||
sdata.add(s);
|
||||
|
||||
} // end while
|
||||
|
||||
// add signature to the list
|
||||
sdata.trimToSize();
|
||||
sigs.add(Collections.unmodifiableList(sdata));
|
||||
|
||||
} // end while
|
||||
|
||||
if (sigs.isEmpty())
|
||||
{ // no signatures - throw an exception
|
||||
ConfigException ce = new ConfigException(XMLMetadata.class,"XmlRpcMessages","md.noSigs");
|
||||
ce.setParameter(0,m_method_name);
|
||||
throw ce;
|
||||
|
||||
} // end if
|
||||
|
||||
// save the signatures
|
||||
sigs.trimToSize();
|
||||
m_signatures = Collections.unmodifiableList(sigs);
|
||||
|
||||
// load the documentation
|
||||
DOMElementHelper h = new DOMElementHelper(md_root);
|
||||
m_docs = h.getSubElementText("doc");
|
||||
if (m_docs==null)
|
||||
m_docs = "";
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate into ConfigException
|
||||
throw new ConfigException(e);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final void verifyType(String typename) throws ConfigException
|
||||
{
|
||||
if (!(VALID_TYPES.contains(typename)))
|
||||
{ // type value is not valid
|
||||
ConfigException ce = new ConfigException(XMLMetadata.class,"XmlRpcMessages","md.badType");
|
||||
ce.setParameter(0,typename);
|
||||
throw ce;
|
||||
|
||||
} // end if
|
||||
|
||||
} // end verifyType
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
String getMethodName()
|
||||
{
|
||||
return m_method_name;
|
||||
|
||||
} // end getMethodName
|
||||
|
||||
List getSignatures()
|
||||
{
|
||||
return m_signatures;
|
||||
|
||||
} // end getSignatures
|
||||
|
||||
String getDocumentation()
|
||||
{
|
||||
return m_docs;
|
||||
|
||||
} // end getDocumentation
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Initialize the valid type set.
|
||||
HashSet tmp = new HashSet();
|
||||
tmp.add(TYPE_INT);
|
||||
tmp.add(TYPE_BOOLEAN);
|
||||
tmp.add(TYPE_STRING);
|
||||
tmp.add(TYPE_DOUBLE);
|
||||
tmp.add(TYPE_DATETIME);
|
||||
tmp.add(TYPE_BASE64);
|
||||
tmp.add(TYPE_STRUCT);
|
||||
tmp.add(TYPE_ARRAY);
|
||||
VALID_TYPES = Collections.unmodifiableSet(tmp);
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class XMLMetadata
|
||||
@@ -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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import com.silverwrist.dynamo.except.ConfigException;
|
||||
import com.silverwrist.dynamo.iface.ComponentShutdown;
|
||||
|
||||
public interface XmlRpcConfiguration
|
||||
{
|
||||
public ComponentShutdown addDispatcher(String method, XmlRpcDispatcher disp) throws ConfigException;
|
||||
|
||||
public ComponentShutdown addFaultMapper(Class klass, XmlRpcFaultMapper fmap) throws ConfigException;
|
||||
|
||||
public ComponentShutdown addCapability(String name, String url, int version);
|
||||
|
||||
} // end interface XmlRpcConfiguration
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import com.silverwrist.dynamo.iface.Request;
|
||||
import com.silverwrist.dynamo.iface.SessionInfo;
|
||||
|
||||
public interface XmlRpcCreateSession
|
||||
{
|
||||
public SessionInfo createNewSession(Request r);
|
||||
|
||||
} // end interface XmlRpcCreateSession
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import com.silverwrist.dynamo.iface.Application;
|
||||
import com.silverwrist.dynamo.iface.Request;
|
||||
|
||||
public interface XmlRpcDispatcher
|
||||
{
|
||||
public String getSessionIDParamValue(Request r, Application app);
|
||||
|
||||
public Object dispatchXmlRpcCall(Request r, Application app) throws Exception, FaultCode;
|
||||
|
||||
public Collection getSupportedMethods(Request r);
|
||||
|
||||
public List getMethodSignature(Request r, String method) throws FaultCode;
|
||||
|
||||
public String getMethodHelp(Request r, String method) throws FaultCode;
|
||||
|
||||
} // end interface XmlRpcDispatcher
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import com.silverwrist.dynamo.iface.Request;
|
||||
|
||||
public interface XmlRpcFaultMapper
|
||||
{
|
||||
public int getXmlRpcFaultCodeForException(Request r, Throwable t);
|
||||
|
||||
} // end interface XmlRpcFaultMapper
|
||||
@@ -0,0 +1,81 @@
|
||||
# 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# ---------------------------------------------------------------------------------
|
||||
# This file has been localized for the en_US locale
|
||||
pattern.error=The regular expression pattern "{0}" is not valid.
|
||||
xdisp.notXD=The class {0} is not a valid XML-RPC dispatcher class.
|
||||
xdisp.classNotFound=The object class {0} was not found.
|
||||
xdisp.createError=Unable to create new object of class {0}.
|
||||
xfmap.noExceptClass=The exception class {0} was not found.
|
||||
xfmap.badExceptClass=The class {0} is not a valid exception class.
|
||||
xfmap.notXFM=The class {0} is not a valid XML-RPC fault mapper class.
|
||||
xfmap.classNotFound=The object class {0} was not found.
|
||||
xfmap.createError=Unable to create new object of class {0}.
|
||||
md.badType=Invalid data type specifier "{0}".
|
||||
md.noSigs=No type signatures specified in metadata for "{0}".
|
||||
help.multicall=Invokes multiple XML-RPC calls on this server and returns all the results. \r\n\
|
||||
Parameter: Array of structs, each containing a string 'methodName' and an array 'params', \
|
||||
each of which specifies an XML-RPC method to call. \r\n\
|
||||
Returns: An array of elements, either single-element arrays containing the return value, \
|
||||
or structs containing an int 'faultCode' and a string 'faultString'. \r\n\
|
||||
(See also Eric Kidd's RFC, <http://www.xmlrpc.com/discuss/msgReader$1208>.)
|
||||
help.v1.arrayOf=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameter: An array of structs, each of which contains at least three elements, 'moe', \
|
||||
'larry', and 'curly', all of type number. \r\n\
|
||||
Returns: The sum of all 'curly' structure elements.
|
||||
help.v1.countEnt=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameter: A string which may contain any number of left angle brackets, right angle \
|
||||
brackets, ampersands, apostrophes, and quotes. \r\n\
|
||||
Returns: A struct with 5 members, all numbers, 'ctLeftAngleBrackets', \
|
||||
'ctRightAngleBrackets', 'ctAmpersands', 'ctApostrophes', and 'ctQuotes', containing the \
|
||||
number of left angle brackets, right angle brackets, ampersands, apostrophes, and quotes \
|
||||
in the string, respectively.
|
||||
help.v1.ezStruct=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameter: A structure which contains three elements, 'moe', 'larry', and 'curly', all \
|
||||
of type number. \r\n\
|
||||
Returns: The sum of those three elements in the structure.
|
||||
help.v1.echoStr=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameter: An arbitrary struct. \r\nReturns: That same struct.
|
||||
help.v1.manyType=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameters: Six, all of different types.\r\nReturns: An array containing those six \
|
||||
parameters, in order.
|
||||
help.v1.mSAC=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameter: An array containing between 100 and 200 string values. \r\n\
|
||||
Returns: A string concatenating the first and last elements of the array.
|
||||
help.v1.nestStr=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameter: A struct modeling a daily calendar. It contains one struct for each year,
|
||||
with one struct for each month under that (identified by 2-digit numbers with leading
|
||||
zeroes, January is "01"), and one struct for each day under that (again, the days are
|
||||
2-digit numbers with leading zeroes). \r\n\
|
||||
Returns: From the entry in the nested structure for April 1, 2000 ("2000.04.01"), \
|
||||
the sum of the three number elements in that structure named 'moe', 'larry', and 'curly'.
|
||||
help.v1.simple=Part of the XML-RPC.COM Validation Suite. \r\n\
|
||||
Parameter: A single number.\r\nReturns: A struct containing three number elements, 'times10', \
|
||||
'times100', and 'times1000', which contain the parameter value multiplied by 10, 100, and \
|
||||
1000, respectively.
|
||||
help.getCaps=Returns the capabilities supported by this server. \r\n\
|
||||
Returns: A struct with each entry named according to the spec it refers to. Each entry's value \
|
||||
is a struct containing two entries, 'specUrl' (a string) and 'specVersion' (a number).
|
||||
help.listMeth=Lists all methods implemented by the XML-RPC server. \r\n\
|
||||
Returns: Array of strings, each of which is a method name implemented by the server.
|
||||
help.methSig=Returns method signatures associated with a method name. \r\n\
|
||||
Parameter: The method name to examine. \r\n\
|
||||
Returns: An array of method signatures, each of which is an array of type names. The first name \
|
||||
in each array is the return type, the others are the parameter types, in order.
|
||||
help.methHelp=Returns help string associated with a method name. \r\n\
|
||||
Parameter: The method name to examine. \r\n\
|
||||
Returns: A string containing the help for this method, which may contain HTML markup. If no \
|
||||
help is defined for this method, an empty string is returned.
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
public class XmlRpcMethodNotFound extends SystemFaultCode
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public XmlRpcMethodNotFound(String method_name)
|
||||
{
|
||||
super(METHOD_NOT_FOUND,"method not found: " + method_name);
|
||||
|
||||
} // end constructor
|
||||
|
||||
} // end class XmlRpcMethodNotFound
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
public class XmlRpcParameterError extends SystemFaultCode
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructors
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public XmlRpcParameterError(String message)
|
||||
{
|
||||
super(INVALID_PARAMS,message);
|
||||
|
||||
} // end constructor
|
||||
|
||||
public XmlRpcParameterError(String message, Throwable inner)
|
||||
{
|
||||
super(INVALID_PARAMS,message,inner);
|
||||
|
||||
} // end constructor
|
||||
|
||||
} // end class XmlRpcParameterError
|
||||
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* 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) 2002-03 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import org.w3c.dom.*;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.util.xml.*;
|
||||
import com.silverwrist.dynamo.RequestType;
|
||||
import com.silverwrist.dynamo.Verb;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
import com.silverwrist.dynamo.util.*;
|
||||
|
||||
/**
|
||||
* Implements the {@link com.silverwrist.dynamo.iface.Request Request} interface for all XML-RPC requests; parses
|
||||
* the request body.
|
||||
*
|
||||
* @author Eric J. Bowersox <erbo@silcom.com>
|
||||
* @version X
|
||||
*/
|
||||
class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
// Indicates the types of values associated with the request.
|
||||
private static final int ITYP_INTEGER = 0; // integer
|
||||
private static final int ITYP_BOOLEAN = 1; // Boolean
|
||||
private static final int ITYP_STRING = 2; // string
|
||||
private static final int ITYP_DOUBLE = 3; // double
|
||||
private static final int ITYP_DATETIME = 4; // date/time
|
||||
private static final int ITYP_BINARY = 5; // binary (byte array)
|
||||
private static final int ITYP_STRUCT = 6; // struct (Map)
|
||||
private static final int ITYP_ARRAY = 7; // array (List)
|
||||
|
||||
private static final Map MAP_TYPE; // maps element names to type values
|
||||
|
||||
private static final DateFormat s_iso8601; // used to format and parse date/time values
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private HttpServletRequest m_req; // associated HTTP request
|
||||
private String m_method; // XML-RPC method
|
||||
private HashMap m_params = new HashMap(); // parameters
|
||||
private Locale[] m_locales; // locale list
|
||||
private MemoryObjectStore m_attrs; // scratchpad for attributes
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new XML-RPC request, parsing the request body to get the actual request data.
|
||||
*
|
||||
* @param req The original <CODE>HttpServletRequest</CODE> passed to the servlet.
|
||||
* @param verb The verb associated with this request.
|
||||
* @param services A {@link com.silverwrist.dynamo.iface.ServiceProvider ServiceProvider} object controlling
|
||||
* access to request services.
|
||||
* @param prev The previous {@link com.silverwrist.dynamo.iface.Request Request} object. May be <CODE>null</CODE>.
|
||||
* @exception com.silverwrist.dynamo.except.RequestParseException If the request data is grossly wrong (these
|
||||
* errors are reported as HTTP error codes).
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the request (these errors
|
||||
* are reported as XML-RPC faults).
|
||||
*/
|
||||
XmlRpcRequest(HttpServletRequest req, Verb verb, ServiceProvider services, Request prev)
|
||||
throws RequestParseException, FaultCode
|
||||
{
|
||||
super("XmlRpcRequest",services);
|
||||
if (!(Verb.POST.equals(verb)))
|
||||
throw new RequestParseException("XML-RPC requests must be POST requests");
|
||||
String ctype = req.getContentType();
|
||||
if (!(ctype.startsWith("text/xml")))
|
||||
throw new RequestParseException("XML-RPC requests must have an XML content type");
|
||||
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
Document request_doc = null;
|
||||
try
|
||||
{ // parse the XML request
|
||||
request_doc = loader.load(req.getInputStream(),false);
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // parse error in XML body...
|
||||
throw new SystemFaultCode(SystemFaultCode.PARSE_ERROR,e);
|
||||
|
||||
} // end catch
|
||||
catch (IOException e)
|
||||
{ // I/O error in XML body...
|
||||
throw new SystemFaultCode(SystemFaultCode.PARSE_ERROR,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
try
|
||||
{ // load the XML body of the request, get the method name and parameters
|
||||
Element method_call = loader.getRootElement(request_doc,"methodCall");
|
||||
DOMElementHelper method_call_h = new DOMElementHelper(method_call);
|
||||
m_method = loader.getSubElementText(method_call_h,"methodName");
|
||||
Element params_elt = method_call_h.getSubElement("params");
|
||||
if (params_elt!=null)
|
||||
{ // get all <param/> elements from under <params/> and process them
|
||||
List l = loader.getMatchingSubElements(params_elt,"param");
|
||||
int ndx = 0;
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get the <value/> subelement from each <param/> and store it
|
||||
Element elt = (Element)(it.next());
|
||||
Element value_elt = loader.getSubElement(elt,"value");
|
||||
m_params.put(String.valueOf(ndx++),parseValue(value_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
} // end if (parameters present)
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate XML exceptions into RequestParseExceptions
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
m_req = req;
|
||||
m_locales = new Locale[1];
|
||||
m_locales[0] = Locale.getDefault();
|
||||
m_attrs = new MemoryObjectStore(XmlRpcRequest.class.getName(),prev);
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parses an XML-RPC <value/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <value/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private static final Object parseValue(Element elt) throws FaultCode
|
||||
{
|
||||
NodeList nl = elt.getChildNodes();
|
||||
Element type_spec = null;
|
||||
for (int i=0; i<nl.getLength(); i++)
|
||||
{ // look through the subelements to find the type-specific element
|
||||
Node n = nl.item(i);
|
||||
if (n.getNodeType()!=Node.ELEMENT_NODE)
|
||||
continue;
|
||||
if (type_spec!=null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,
|
||||
"more than one type-specifying element within a <value/> element");
|
||||
type_spec = (Element)n;
|
||||
|
||||
} // end for
|
||||
|
||||
Object rc = null;
|
||||
if (type_spec!=null)
|
||||
{ // figure out what type this element is
|
||||
Integer tval = (Integer)(MAP_TYPE.get(type_spec.getTagName()));
|
||||
if (tval==null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid type \"" + type_spec.getTagName()
|
||||
+ "\"");
|
||||
DOMElementHelper h = new DOMElementHelper(type_spec);
|
||||
switch (tval.intValue())
|
||||
{ // based on the type, act on the contents
|
||||
case ITYP_INTEGER:
|
||||
try
|
||||
{ // parse the integer value
|
||||
rc = new Integer(Integer.parseInt(h.getElementText(),10));
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException e)
|
||||
{ // value wasn't an integer
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid integer format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // value was null
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"integer value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_BOOLEAN:
|
||||
{ // test the Boolean value
|
||||
String s = h.getElementText();
|
||||
if (s==null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"boolean value not specified");
|
||||
if (s.equals("1"))
|
||||
rc = Boolean.TRUE;
|
||||
else if (s.equals("0"))
|
||||
rc = Boolean.FALSE;
|
||||
else
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid boolean format");
|
||||
|
||||
} // end case
|
||||
break;
|
||||
|
||||
case ITYP_STRING:
|
||||
{ // get the string value and return it
|
||||
rc = h.getElementText();
|
||||
if (rc==null)
|
||||
rc = EMPTY_STRING;
|
||||
|
||||
} // end case
|
||||
break;
|
||||
|
||||
case ITYP_DOUBLE:
|
||||
try
|
||||
{ // convert to a Double value
|
||||
rc = new Double(h.getElementText());
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException e)
|
||||
{ // value wasn't an integer
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid double format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // value was null
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"double value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_DATETIME:
|
||||
try
|
||||
{ // convert to a Date value
|
||||
rc = s_iso8601.parse(h.getElementText());
|
||||
|
||||
} // end try
|
||||
catch (java.text.ParseException e)
|
||||
{ // date couldn't be parsed
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid ISO 8601 date format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // no value in there...
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"date value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_BINARY:
|
||||
try
|
||||
{ // get the string equivalent of the formatted data
|
||||
String s = h.getElementText();
|
||||
if (s==null)
|
||||
{ // null string - return null array
|
||||
rc = new byte[0];
|
||||
break;
|
||||
|
||||
} // end if
|
||||
|
||||
// get a stream of encoded bytes
|
||||
ByteArrayInputStream encoded_stm = new ByteArrayInputStream(s.getBytes("US-ASCII"));
|
||||
|
||||
// use the JavaMail MIME decoder to turn it into decoded bytes
|
||||
InputStream decoded_stm = MimeUtility.decode(encoded_stm,"base64");
|
||||
|
||||
// copy the decoded bytes to a new array
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
IOUtils.copy(decoded_stm,output);
|
||||
IOUtils.shutdown(decoded_stm);
|
||||
IOUtils.shutdown(encoded_stm);
|
||||
|
||||
// retrieve the output array
|
||||
rc = output.toByteArray();
|
||||
IOUtils.shutdown(output);
|
||||
|
||||
} // end try
|
||||
catch (UnsupportedEncodingException e)
|
||||
{ // WTF? shouldn't happen
|
||||
throw new SystemFaultCode(SystemFaultCode.INTERNAL_ERROR,"internal error: unsupported encoding",e);
|
||||
|
||||
} // end catch
|
||||
catch (IOException e)
|
||||
{ // some sort of error copying binary values around
|
||||
throw new SystemFaultCode(SystemFaultCode.INTERNAL_ERROR,"unable to get binary data",e);
|
||||
|
||||
} // end catch
|
||||
catch (MessagingException e)
|
||||
{ // error in the MIME parsing - dump it out
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid binary data format",e);
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_STRUCT:
|
||||
rc = parseStruct(type_spec);
|
||||
break;
|
||||
|
||||
case ITYP_ARRAY:
|
||||
rc = parseArray(type_spec);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid type \""
|
||||
+ type_spec.getTagName() + "\"");
|
||||
|
||||
} // end switch
|
||||
|
||||
} // end if
|
||||
else
|
||||
{ // if there's no type-specifying element, treat it as a String
|
||||
DOMElementHelper h = new DOMElementHelper(elt);
|
||||
rc = h.getElementText();
|
||||
if (rc==null)
|
||||
rc = EMPTY_STRING;
|
||||
|
||||
} // end else
|
||||
|
||||
return rc;
|
||||
|
||||
} // end parseValue
|
||||
|
||||
/**
|
||||
* Parses an XML-RPC <struct/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <struct/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private static final Map parseStruct(Element elt) throws FaultCode
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
HashMap rc = new HashMap();
|
||||
try
|
||||
{ // get all <member/> sub-elements and process them
|
||||
List l = loader.getMatchingSubElements(elt,"member");
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each <member/> and add its <name/> and <value/> to the map
|
||||
Element x = (Element)(it.next());
|
||||
DOMElementHelper h = new DOMElementHelper(x);
|
||||
String name = loader.getSubElementText(h,"name");
|
||||
Element val_elt = loader.getSubElement(h,"value");
|
||||
rc.put(name,parseValue(val_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate load exception
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (rc.isEmpty())
|
||||
return Collections.EMPTY_MAP;
|
||||
else
|
||||
return Collections.unmodifiableMap(rc);
|
||||
|
||||
} // end parseStruct
|
||||
|
||||
/**
|
||||
* Parses an XML-RPC <array/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <array/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private static final List parseArray(Element elt) throws FaultCode
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
ArrayList rc = null;
|
||||
try
|
||||
{ // get the <data/> sub-element
|
||||
Element data_elt = loader.getSubElement(elt,"data");
|
||||
|
||||
// get the values it contains
|
||||
List l = loader.getMatchingSubElements(data_elt,"value");
|
||||
rc = new ArrayList(l.size());
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // parse the <value/> elements and add them to the list
|
||||
Element val_elt = (Element)(it.next());
|
||||
rc.add(parseValue(val_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate load exception
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
if ((rc==null) || rc.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
else
|
||||
return Collections.unmodifiableList(rc);
|
||||
|
||||
} // end parseArray
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ObjectProvider
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves an object from this <CODE>ObjectProvider</CODE>.
|
||||
*
|
||||
* @param namespace The namespace to interpret the name relative to.
|
||||
* @param name The name of the object to be retrieved.
|
||||
* @return The object reference specified.
|
||||
*/
|
||||
public Object getObject(String namespace, String name)
|
||||
{
|
||||
return m_attrs.getObject(namespace,name);
|
||||
|
||||
} // end getObject
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ObjectStore
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets an object into this <CODE>ObjectStore</CODE>.
|
||||
*
|
||||
* @param namespace The namespace to interpret the name relative to.
|
||||
* @param name The name of the object to be set.
|
||||
* @param value The object to set into the <CODE>ObjectStore</CODE>.
|
||||
* @return The previous object that was set into the <CODE>ObjectStore</CODE> under this namespace and name, or
|
||||
* <CODE>null</CODE> if there was no such object.
|
||||
*/
|
||||
public Object setObject(String namespace, String name, Object value)
|
||||
{
|
||||
return m_attrs.setObject(namespace,name,value);
|
||||
|
||||
} // end setObject
|
||||
|
||||
/**
|
||||
* Removes an object from this <CODE>ObjectStore</CODE>.
|
||||
*
|
||||
* @param namespace The namespace to interpret the name relative to.
|
||||
* @param name The name of the object to be removed.
|
||||
* @return The previous object that was set into the <CODE>ObjectStore</CODE> under this namespace and name, or
|
||||
* <CODE>null</CODE> if there was no such object.
|
||||
*/
|
||||
public Object removeObject(String namespace, String name)
|
||||
{
|
||||
return m_attrs.removeObject(namespace,name);
|
||||
|
||||
} // end removeObject
|
||||
|
||||
/**
|
||||
* Returns a collection of all object namespaces that have been set into this <CODE>ObjectStore</CODE>.
|
||||
*
|
||||
* @return A <CODE>java.util.Collection</CODE> containing <CODE>String</CODE> objects specifying all the
|
||||
* object namespaces.
|
||||
*/
|
||||
public Collection getNamespaces()
|
||||
{
|
||||
return m_attrs.getNamespaces();
|
||||
|
||||
} // end getNamespaces
|
||||
|
||||
/**
|
||||
* Returns a collection of all object names that have been set into this <CODE>ObjectStore</CODE> under a given
|
||||
* namespace.
|
||||
*
|
||||
* @param namespace The namespace to look for names under.
|
||||
* @return A <CODE>java.util.Collection</CODE> containing <CODE>String</CODE> objects specifying all the
|
||||
* object names for this namespace.
|
||||
*/
|
||||
public Collection getNamesForNamespace(String namespace)
|
||||
{
|
||||
return m_attrs.getNamesForNamespace(namespace);
|
||||
|
||||
} // end getNamesForNamespace
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface Request
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a value indicating the type of this request.
|
||||
*
|
||||
* @return The type of this request.
|
||||
* @see com.silverwrist.dynamo.RequestType#XMLRPC
|
||||
*/
|
||||
public RequestType getType()
|
||||
{
|
||||
return RequestType.XMLRPC;
|
||||
|
||||
} // end getType
|
||||
|
||||
/**
|
||||
* Returns the DNS name or IP address of the server to which the request was made.
|
||||
*
|
||||
* @return The server name to which the request was name.
|
||||
*/
|
||||
public String getServerName()
|
||||
{
|
||||
return m_req.getServerName();
|
||||
|
||||
} // end getServerName
|
||||
|
||||
/**
|
||||
* Returns the number of the port on which this request was made.
|
||||
*
|
||||
* @return The port number on which the request was made, or -1 if it could not be determined.
|
||||
*/
|
||||
public int getServerPort()
|
||||
{
|
||||
return m_req.getServerPort();
|
||||
|
||||
} // end getServerPort
|
||||
|
||||
/**
|
||||
* Returns the portion of the request URI that indicates the context of the request. The context path always comes
|
||||
* first in a request URI. The path starts with a "/" character but does not end with a "/" character. For servlets
|
||||
* in the default (root) context, this method returns "". The servlet container does not decode this string.
|
||||
*
|
||||
* @return The context path of the request.
|
||||
*/
|
||||
public String getContextPath()
|
||||
{
|
||||
return m_req.getContextPath();
|
||||
|
||||
} // end getContextPath
|
||||
|
||||
/**
|
||||
* Returns the part of this request's URL that calls the endpoint. This includes either the endpoint name or a path
|
||||
* to the endpoint, but does not include any extra path information or a query string. For XML-RPC requests,
|
||||
* this will usually be the value "/RPC2".
|
||||
*
|
||||
* @return The request path of this request.
|
||||
*/
|
||||
public String getRequestPath()
|
||||
{
|
||||
return m_req.getServletPath();
|
||||
|
||||
} // end getRequestPath
|
||||
|
||||
/**
|
||||
* Returns any extra path information associated with the URL the client sent when it made this request. The extra
|
||||
* path information follows the request path but precedes the query string. This method returns <CODE>null</CODE>
|
||||
* if there was no extra path information.
|
||||
*
|
||||
* @return The "extra path" of this request. If there is no "extra path," returns <CODE>null</CODE>.
|
||||
*/
|
||||
public String getExtraPath()
|
||||
{
|
||||
return null;
|
||||
|
||||
} // end getExtraPath
|
||||
|
||||
/**
|
||||
* Returns the query string that is contained in the request URL after the path. For XML-RPC requests, this is
|
||||
* the name of the method that was called.
|
||||
*
|
||||
* @return The method name associated with this request.
|
||||
*/
|
||||
public String getQueryString()
|
||||
{
|
||||
return m_method;
|
||||
|
||||
} // end getQueryString
|
||||
|
||||
/**
|
||||
* Returns a value indicating the action associated with this request. For XML-RPC requests, this verb is
|
||||
* always {@link com.silverwrist.dynamo.Verb#POST POST}.
|
||||
*
|
||||
* @return The action associated with this request.
|
||||
* @see com.silverwrist.dynamo.Verb
|
||||
*/
|
||||
public Verb getVerb()
|
||||
{
|
||||
return Verb.POST;
|
||||
|
||||
} // end getVerb
|
||||
|
||||
/**
|
||||
* Returns a string representation of the IP address of the client that made this request.
|
||||
*
|
||||
* @return The address of the client making the request.
|
||||
*/
|
||||
public String getSourceAddress()
|
||||
{
|
||||
return m_req.getRemoteAddr();
|
||||
|
||||
} // end getSourceAddress
|
||||
|
||||
/**
|
||||
* Returns a java.util.Map of the parameters of this request. For XML-RPC requests, these parameters are passed
|
||||
* as an array associated with the method call.
|
||||
* <P>The keys of the map are <CODE>String</CODE> objects; the values of the map are arrays of the type specified
|
||||
* by the return value of {@link #getParametersEntryClass() getParametersEntryClass()}. For XML-RPC, the keys
|
||||
* are printable-string equivalents of integers representing the parameters' position.
|
||||
*
|
||||
* @return The parameter map, as specified above. This map is read-only.
|
||||
*/
|
||||
public Map getParameters()
|
||||
{
|
||||
return Collections.unmodifiableMap(m_params);
|
||||
|
||||
} // end getParameters
|
||||
|
||||
/**
|
||||
* Returns a class specifying the fundamental type of objects contained in the arrays acting as the values of
|
||||
* the map returned by {@link #getParameters() getParameters()}. For XML-RPC, this class is <CODE>Object</CODE>,
|
||||
* indicating that the contained objects may be of any type, as the parser has already figured out their precise
|
||||
* type.
|
||||
*
|
||||
* @return The class of array elements within the parameter map.
|
||||
*/
|
||||
public Class getParametersEntryClass()
|
||||
{
|
||||
return Object.class;
|
||||
|
||||
} // end getParametersEntryClass
|
||||
|
||||
/**
|
||||
* Returns a java.util.Map of the data items of this request. Data items are lengthy streams of data associated
|
||||
* with a request. XML-RPC requests have no data items associated with them.
|
||||
*
|
||||
* @return The data item map, as specified above. This map is read-only.
|
||||
*/
|
||||
public Map getDataItems()
|
||||
{
|
||||
return Collections.EMPTY_MAP;
|
||||
|
||||
} // end getDataItems
|
||||
|
||||
/**
|
||||
* Returns an array of <CODE>Locale</CODE> objects indicating, in decreasing order starting with the preferred
|
||||
* locale, the locales that are acceptable to the client based on an <CODE>Accept-Language</CODE> header or similar.
|
||||
* method. If the client request doesn't provide an <CODE>Accept-Language</CODE> header or similar indication,
|
||||
* this method returns an array containing one <CODE>Locale</CODE>, the default locale for the server.
|
||||
*
|
||||
* @return An array of preferred <CODE>Locale</CODE> objects for the client.
|
||||
*/
|
||||
public Locale[] getLocales()
|
||||
{
|
||||
return m_locales;
|
||||
|
||||
} // end getLocales
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Initialize the type map.
|
||||
HashMap tmp = new HashMap();
|
||||
Integer foo = new Integer(ITYP_INTEGER);
|
||||
tmp.put("i4",foo);
|
||||
tmp.put("int",foo);
|
||||
tmp.put("boolean",new Integer(ITYP_BOOLEAN));
|
||||
tmp.put("string",new Integer(ITYP_STRING));
|
||||
tmp.put("double",new Integer(ITYP_DOUBLE));
|
||||
tmp.put("dateTime.iso8601",new Integer(ITYP_DATETIME));
|
||||
tmp.put("base64",new Integer(ITYP_BINARY));
|
||||
tmp.put("struct",new Integer(ITYP_STRUCT));
|
||||
tmp.put("array",new Integer(ITYP_ARRAY));
|
||||
MAP_TYPE = Collections.unmodifiableMap(tmp);
|
||||
|
||||
// Initialize the ISO 8601 date formatter.
|
||||
SimpleDateFormat iso = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
|
||||
iso.setCalendar(new GregorianCalendar(new SimpleTimeZone(0,"UTC")));
|
||||
s_iso8601 = iso;
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class XmlRpcRequest
|
||||
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.ref.Reference;
|
||||
import java.sql.Blob;
|
||||
import java.sql.SQLException;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.dynamo.HttpStatusCode;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
public class XmlRpcResult implements SelfRenderable, XmlRpcSelfSerializing
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final String SERIALIZED_NULL = "<string>null</string>";
|
||||
private static final String START_ARRAY = "<array><data>\r\n";
|
||||
private static final String END_ARRAY = "</data></array>";
|
||||
private static final String START_VALUE = "<value>";
|
||||
private static final String END_VALUE = "</value>\r\n";
|
||||
|
||||
private static final DateFormat s_iso8601;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private Object m_obj;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public XmlRpcResult(Object obj)
|
||||
{
|
||||
m_obj = obj;
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface SelfRenderable
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public void render(SelfRenderControl control) throws IOException, RenderingException
|
||||
{
|
||||
// Serialize the output value to a StringWriter.
|
||||
StringWriter wr = new StringWriter();
|
||||
wr.write("<methodResponse><params><param>\r\n<value>");
|
||||
serialize(wr,m_obj);
|
||||
wr.write("</value>\r\n</param></params></methodResponse>\r\n");
|
||||
|
||||
// Now render the binary equivalent of this structure.
|
||||
byte[] data = null;
|
||||
try
|
||||
{ // get a complete rendering of this data
|
||||
data = wr.toString().getBytes("UTF-8");
|
||||
|
||||
} // end try
|
||||
catch (UnsupportedEncodingException e)
|
||||
{ // WTF? shouldn't happen
|
||||
data = wr.toString().getBytes();
|
||||
|
||||
} // end catch
|
||||
|
||||
// send out the bytes as an XML message body
|
||||
control.status(HttpStatusCode.S_OK);
|
||||
BinaryRenderControl bctrl = control.getBinaryRender();
|
||||
bctrl.setContentType("text/xml; charset=UTF-8");
|
||||
bctrl.setContentLength(data.length);
|
||||
OutputStream stm = bctrl.getStream();
|
||||
stm.write(data);
|
||||
stm.flush();
|
||||
|
||||
} // end render
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcSelfSerializing
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public void serializeXmlRpc(Writer wr) throws IOException
|
||||
{
|
||||
serialize(wr,m_obj);
|
||||
|
||||
} // end serializeXmlRpc
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External static operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static void serializeBinary(Writer wr, InputStream stm) throws IOException
|
||||
{
|
||||
try
|
||||
{ // Encode the data as BASE-64.
|
||||
ByteArrayOutputStream internal_stm = new ByteArrayOutputStream();
|
||||
OutputStream encode_stm = MimeUtility.encode(internal_stm,"base64");
|
||||
IOUtils.copy(stm,encode_stm);
|
||||
encode_stm.flush();
|
||||
|
||||
// turn our encoded output into an InputStream
|
||||
ByteArrayInputStream internal2_stm = new ByteArrayInputStream(internal_stm.toByteArray());
|
||||
IOUtils.shutdown(encode_stm);
|
||||
IOUtils.shutdown(internal_stm);
|
||||
|
||||
// write out the data
|
||||
InputStreamReader rd = new InputStreamReader(internal2_stm,"US-ASCII");
|
||||
wr.write("<base64>");
|
||||
IOUtils.copy(rd,wr);
|
||||
wr.write("</base64>");
|
||||
IOUtils.shutdown(rd);
|
||||
IOUtils.shutdown(internal2_stm);
|
||||
|
||||
} // end try
|
||||
catch (MessagingException e)
|
||||
{ // encoder might have an error
|
||||
throw new IOException("error encoding binary data");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end serializeBinary
|
||||
|
||||
public static void serialize(Writer wr, boolean b) throws IOException
|
||||
{
|
||||
wr.write("<boolean>");
|
||||
wr.write(b ? "1" : "0");
|
||||
wr.write("</boolean>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, boolean[] b) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<b.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,b[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, byte b) throws IOException
|
||||
{
|
||||
serialize(wr,(int)b);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, byte[] b) throws IOException
|
||||
{
|
||||
serializeBinary(wr,new ByteArrayInputStream(b));
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, char c) throws IOException
|
||||
{
|
||||
wr.write("<string>");
|
||||
wr.write(c);
|
||||
wr.write("</string>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, char[] c) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<c.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,c[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, short s) throws IOException
|
||||
{
|
||||
serialize(wr,(int)s);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, short[] s) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<s.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,s[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, int i) throws IOException
|
||||
{
|
||||
wr.write("<int>");
|
||||
wr.write(String.valueOf(i));
|
||||
wr.write("</int>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, int[] ia) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<ia.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,ia[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, long l) throws IOException
|
||||
{
|
||||
serialize(wr,(double)l);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, long[] l) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<l.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,l[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, float f) throws IOException
|
||||
{
|
||||
serialize(wr,(double)f);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, float[] f) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<f.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,f[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, double d) throws IOException
|
||||
{
|
||||
wr.write("<double>");
|
||||
wr.write(String.valueOf(d));
|
||||
wr.write("</double>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, double[] d) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<d.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,d[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serializeCalendar(Writer wr, Calendar cal) throws IOException
|
||||
{
|
||||
wr.write("<dateTime.iso8601>");
|
||||
|
||||
// Encode the year first.
|
||||
StringBuffer conv = new StringBuffer("0000");
|
||||
conv.append(cal.get(Calendar.YEAR));
|
||||
String c = conv.toString();
|
||||
wr.write(c.substring(c.length()-4));
|
||||
|
||||
// Now the month...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.MONTH) - Calendar.JANUARY + 1);
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
|
||||
// And the day...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.DAY_OF_MONTH));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write("T");
|
||||
|
||||
// And the hour...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.HOUR_OF_DAY));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write(":");
|
||||
|
||||
// And the minute...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.MINUTE));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write(":");
|
||||
|
||||
// And the second...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.SECOND));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
|
||||
// And we're done!
|
||||
wr.write("</dateTime.iso8601>");
|
||||
|
||||
} // end serializeCalendar
|
||||
|
||||
public static void serializeCollection(Writer wr, Collection coll) throws IOException
|
||||
{
|
||||
serializeIterator(wr,coll.iterator());
|
||||
|
||||
} // end serializeCollection
|
||||
|
||||
public static void serializeDate(Writer wr, Date d) throws IOException
|
||||
{
|
||||
wr.write("<dateTime.iso8601>");
|
||||
wr.write(s_iso8601.format(d));
|
||||
wr.write("</dateTime.iso8601>");
|
||||
|
||||
} // end serializeDate
|
||||
|
||||
public static void serializeEnumeration(Writer wr, Enumeration enum) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
while (enum.hasMoreElements())
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,enum.nextElement());
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serializeIterator
|
||||
|
||||
public static void serializeIterator(Writer wr, Iterator it) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
while (it.hasNext())
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,it.next());
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serializeIterator
|
||||
|
||||
public static void serializeMap(Writer wr, Map map) throws IOException
|
||||
{
|
||||
wr.write("<struct>\r\n");
|
||||
Iterator it = map.entrySet().iterator();
|
||||
while (it.hasNext())
|
||||
{ // write each entry in turn
|
||||
Map.Entry ntry = (Map.Entry)(it.next());
|
||||
wr.write("<member>\r\n<name>");
|
||||
wr.write(StringUtils.encodeHTML(ntry.getKey().toString()));
|
||||
wr.write("</name>\r\n<value>");
|
||||
serialize(wr,ntry.getValue());
|
||||
wr.write("</value>\r\n</member>");
|
||||
|
||||
} // end while
|
||||
|
||||
wr.write("\r\n</struct>");
|
||||
|
||||
} // end serializeMap
|
||||
|
||||
public static void serializeString(Writer wr, String s) throws IOException
|
||||
{
|
||||
wr.write("<string>");
|
||||
wr.write(StringUtils.encodeHTML(s));
|
||||
wr.write("</string>");
|
||||
|
||||
} // end serializeString
|
||||
|
||||
public static void serialize(Writer wr, Object obj) throws IOException
|
||||
{
|
||||
if (obj==null)
|
||||
{ // null object - bye!
|
||||
wr.write(SERIALIZED_NULL);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj.getClass().isArray())
|
||||
{ // for arrays, serialize them specially
|
||||
Class component = obj.getClass().getComponentType();
|
||||
if (component==Boolean.TYPE)
|
||||
serialize(wr,(boolean[])obj);
|
||||
else if (component==Byte.TYPE)
|
||||
serialize(wr,(byte[])obj);
|
||||
else if (component==Character.TYPE)
|
||||
serialize(wr,(char[])obj);
|
||||
else if (component==Short.TYPE)
|
||||
serialize(wr,(short[])obj);
|
||||
else if (component==Integer.TYPE)
|
||||
serialize(wr,(int[])obj);
|
||||
else if (component==Long.TYPE)
|
||||
serialize(wr,(long[])obj);
|
||||
else if (component==Float.TYPE)
|
||||
serialize(wr,(float[])obj);
|
||||
else if (component==Double.TYPE)
|
||||
serialize(wr,(double[])obj);
|
||||
else
|
||||
serialize(wr,(Object[])obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof XmlRpcSelfSerializing)
|
||||
{ // some objects may be self-serializing
|
||||
((XmlRpcSelfSerializing)obj).serializeXmlRpc(wr);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof DynamicWrapper)
|
||||
{ // for dynamic wrappers, unwrap them
|
||||
serialize(wr,((DynamicWrapper)obj).unwrap());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof InputStream)
|
||||
{ // for InputStream, turn it into binary
|
||||
serializeBinary(wr,(InputStream)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Blob)
|
||||
{ // serialize the blob as a binary stream
|
||||
try
|
||||
{ // just get its input stream
|
||||
serializeBinary(wr,((Blob)obj).getBinaryStream());
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // fault on error here
|
||||
throw new IOException("error writing binary data");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Calendar)
|
||||
{ // serialize a Calendar
|
||||
serializeCalendar(wr,(Calendar)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Collection)
|
||||
{ // serialize a Collection
|
||||
serializeCollection(wr,(Collection)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Date)
|
||||
{ // serialize a Date
|
||||
serializeDate(wr,(Date)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Enumeration)
|
||||
{ // serialize a Enumeration
|
||||
serializeEnumeration(wr,(Enumeration)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Iterator)
|
||||
{ // serialize a Iterator
|
||||
serializeIterator(wr,(Iterator)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Map)
|
||||
{ // serialize a Map
|
||||
serializeMap(wr,(Map)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Reference)
|
||||
{ // for a Reference, serialize the referent
|
||||
serialize(wr,((Reference)obj).get());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Boolean)
|
||||
{ // serialize the boolean value
|
||||
serialize(wr,((Boolean)obj).booleanValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Character)
|
||||
{ // serialize the character value
|
||||
serialize(wr,((Character)obj).charValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if ((obj instanceof Byte) || (obj instanceof Short) || (obj instanceof Integer))
|
||||
{ // serialize the integer value
|
||||
serialize(wr,((Number)obj).intValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if ((obj instanceof Long) || (obj instanceof Float) || (obj instanceof Double))
|
||||
{ // serialize the double value
|
||||
serialize(wr,((Number)obj).doubleValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
// String and StringBuffer are handled properly by the fallback mechanism below
|
||||
|
||||
// last-ditch fallback method - use toString, get the string, and encode it
|
||||
serializeString(wr,obj.toString());
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, Object[] arr) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<arr.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,arr[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Initialize the ISO 8601 date formatter.
|
||||
SimpleDateFormat iso = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
|
||||
iso.setCalendar(new GregorianCalendar(new SimpleTimeZone(0,"UTC")));
|
||||
s_iso8601 = iso;
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class XmlRpcResult
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
public interface XmlRpcSelfSerializing
|
||||
{
|
||||
public void serializeXmlRpc(Writer wr) throws IOException;
|
||||
|
||||
} // end interface XmlRpcSelfSerializing
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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) 2002-03 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import com.silverwrist.dynamo.Namespaces;
|
||||
import com.silverwrist.dynamo.Verb;
|
||||
import com.silverwrist.dynamo.app.ApplicationContainer;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
import com.silverwrist.dynamo.servlet.HttpMethod;
|
||||
import com.silverwrist.dynamo.servlet.ServletBase;
|
||||
import com.silverwrist.dynamo.util.*;
|
||||
|
||||
public class XmlRpcServlet extends ServletBase implements ComponentShutdown
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private XmlRpcSubSystem m_subsystem; // pointer to the XML-RPC subsystem
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Abstract implementations from class ServletBase
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
protected Object process(Request r, Application app) throws Exception
|
||||
{
|
||||
try
|
||||
{ // dispatch the method call
|
||||
return m_subsystem.dispatch(r,app);
|
||||
|
||||
} // end try
|
||||
catch (FaultCode fc)
|
||||
{ // return the FaultCode to be output
|
||||
return fc;
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end process
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class ServletBase
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
protected void initServlet(ServiceProvider services) throws DynamoException
|
||||
{
|
||||
// Get the name of the XML-RPC subsystem object.
|
||||
ObjectProvider oprov = (ObjectProvider)(services.queryService(ObjectProvider.class));
|
||||
String subsys_name = (String)(oprov.getObject(Namespaces.SERVLET_INIT_NAMESPACE,"subsystem.object"));
|
||||
|
||||
// Get the subsystem object.
|
||||
m_subsystem = (XmlRpcSubSystem)(GetObjectUtils.getDynamoComponent(services,XmlRpcSubSystem.class,
|
||||
subsys_name));
|
||||
|
||||
} // end initServlet
|
||||
|
||||
protected boolean supportsMethod(HttpMethod method, Application app)
|
||||
{
|
||||
return HttpMethod.POST.equals(method);
|
||||
|
||||
} // end supportsMethod
|
||||
|
||||
protected ServiceProvider createRequestServices(HttpServletRequest req, HttpServletResponse resp)
|
||||
{
|
||||
// Create the service provider interface and return it.
|
||||
SimpleServiceProvider services = new SimpleServiceProvider("Request Services");
|
||||
services.addService(SessionInfoProvider.class,NullSessionInfo.getProvider());
|
||||
services.addService(BrowserDataProvider.class,createBrowserDataProvider(req));
|
||||
services.addService(HeaderInput.class,createHeaderInput(req));
|
||||
services.addService(XmlRpcCreateSession.class,m_subsystem);
|
||||
return services;
|
||||
|
||||
} // end createRequestServices
|
||||
|
||||
protected Request createRequest(HttpServletRequest req, Verb verb, ServiceProvider services, Request prev)
|
||||
throws RequestParseException
|
||||
{
|
||||
XmlRpcRequest xreq = null;
|
||||
try
|
||||
{ // create our special request type
|
||||
xreq = new XmlRpcRequest(req,verb,services,prev);
|
||||
|
||||
} // end try
|
||||
catch (FaultCode fc)
|
||||
{ // "wrap" the FaultCode - we'll get back to it
|
||||
throw new RequestParseException(fc.getMessage(),fc);
|
||||
|
||||
} // end catch
|
||||
|
||||
return xreq;
|
||||
|
||||
} // end createRequest
|
||||
|
||||
protected Object translateRequestParseException(RequestParseException e)
|
||||
{
|
||||
Throwable cause = e.getCause();
|
||||
if ((cause!=null) && (cause instanceof FaultCode))
|
||||
return cause;
|
||||
return super.translateRequestParseException(e);
|
||||
|
||||
} // end translateRequestParseException
|
||||
|
||||
protected Object translateException(Request r, Exception e)
|
||||
{
|
||||
return m_subsystem.translateException(r,e);
|
||||
|
||||
} // end translateException
|
||||
|
||||
protected ServiceProvider createOutputServices(HttpServletRequest req, HttpServletResponse resp)
|
||||
{
|
||||
return new SingletonServiceProvider("Rendering Services",BrowserDataProvider.class,
|
||||
createBrowserDataProvider(req));
|
||||
|
||||
} // end createOutputServices
|
||||
|
||||
protected void outputResult(HttpServletRequest req, HttpServletResponse resp,
|
||||
ServiceProvider services, Object result) throws IOException, RenderingException
|
||||
{
|
||||
if (result instanceof FaultCode)
|
||||
super.outputResult(req,resp,services,result);
|
||||
else if (result instanceof XmlRpcResult)
|
||||
super.outputResult(req,resp,services,result);
|
||||
else
|
||||
super.outputResult(req,resp,services,new XmlRpcResult(result));
|
||||
|
||||
} // end outputResult
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ComponentShutdown
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
m_subsystem = null;
|
||||
|
||||
} // end shutdown
|
||||
|
||||
} // end class XmlRpcServlet
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* 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) 2002-03 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.*;
|
||||
import org.apache.log4j.Logger;
|
||||
import com.silverwrist.dynamo.RequestType;
|
||||
import com.silverwrist.dynamo.app.ApplicationContainer;
|
||||
import com.silverwrist.dynamo.event.*;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
import com.silverwrist.dynamo.util.*;
|
||||
|
||||
/**
|
||||
* An implementation of {@link com.silverwrist.dynamo.iface.SessionInfo SessionInfo} that is managed
|
||||
* by the {@link com.silverwrist.dynamo.xmlrpc.XmlRpcSubSystem XmlRpcSubSystem}. Many XML-RPC
|
||||
* requests bear a "session ID" value, which is used to look up their session in a map maintained
|
||||
* by the subsystem.
|
||||
*
|
||||
* @author Eric J. Bowersox <erbo@silcom.com>
|
||||
* @version X
|
||||
*/
|
||||
class XmlRpcSessionInfo implements SessionInfo, ComponentShutdown
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static Logger logger = Logger.getLogger(XmlRpcSessionInfo.class);
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private XmlRpcSubSystem m_subsystem; // backreference to the XML-RPC subsystem
|
||||
private ApplicationContainer m_appcon; // backreference to the application container
|
||||
private String m_id; // ID of this session
|
||||
private MemoryObjectStore m_store; // where we put all our session attributes
|
||||
private long m_created; // time of creation
|
||||
private long m_last_access; // time of last access
|
||||
private int m_max_inactive; // maximum inactive interval in seconds
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a new <CODE>XmlRpcSessionInfo</CODE> instance.
|
||||
*
|
||||
* @param subsystem The XML-RPC subsystem object.
|
||||
* @param appcon The {@link com.silverwrist.dynamo.app.ApplicationContainer} for the application.
|
||||
* @param id The ID for the new session.
|
||||
*/
|
||||
XmlRpcSessionInfo(XmlRpcSubSystem subsystem, ApplicationContainer appcon, String id)
|
||||
{
|
||||
m_subsystem = subsystem;
|
||||
m_appcon = appcon;
|
||||
m_id = id;
|
||||
m_store = new MemoryObjectStore("Session Store " + m_id);
|
||||
m_max_inactive = subsystem.getDefaultMaxAge();
|
||||
m_created = m_last_access = System.currentTimeMillis();
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Shuts down the session. It sends out session-exiting notifications, unbinds all variables from the
|
||||
* session, and erases the contents.
|
||||
*/
|
||||
private final void destroy()
|
||||
{
|
||||
logger.info("Calling sessionExiting notifications on session " + m_id);
|
||||
|
||||
// Send the end-session notifications.
|
||||
SessionInfoListener[] listeners = m_appcon.getSessionListeners();
|
||||
if (listeners.length>0)
|
||||
{ // call each listener in turn
|
||||
SessionEventRequest req = new SessionEventRequest(m_appcon.wrapServices(null),this,false);
|
||||
SessionInfoEvent evt = new SessionInfoEvent(req,this);
|
||||
for (int i=0; i<listeners.length; i++)
|
||||
listeners[i].sessionExiting(evt);
|
||||
|
||||
} // end if
|
||||
|
||||
// Tell all the values in the object store they're being kicked out.
|
||||
m_store.visitAllContents(new ObjectVisitor()
|
||||
{
|
||||
public void visit(String namespace, String name, Object value)
|
||||
{
|
||||
if (value instanceof SessionValueBindListener)
|
||||
((SessionValueBindListener)value).valueRemoved(new SessionValueBindEvent(XmlRpcSessionInfo.this,
|
||||
namespace,name));
|
||||
|
||||
} // end visit
|
||||
|
||||
}); // end ObjectVisitor object
|
||||
|
||||
// Detach all data.
|
||||
m_store.clear();
|
||||
m_store = null;
|
||||
m_subsystem = null;
|
||||
|
||||
} // end destroy
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class Object
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one.
|
||||
*
|
||||
* @param o The reference object with which to compare.
|
||||
* @return <CODE>true</CODE> if this object is the same as the <CODE>o</CODE> argument; <CODE>false</CODE> otherwise.
|
||||
*/
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if ((o==null) || !(o instanceof XmlRpcSessionInfo))
|
||||
return false;
|
||||
SessionInfo other = (SessionInfo)o;
|
||||
return m_id.equals(other.getID());
|
||||
|
||||
} // end equals
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those
|
||||
* provided by <CODE>java.util.Hashtable</CODE>.
|
||||
*
|
||||
* @return A hash code value for this object.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return m_id.hashCode();
|
||||
|
||||
} // end hashCode
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object. In general, the <CODE>toString</CODE> method returns a string
|
||||
* that "textually represents" this object.
|
||||
*
|
||||
* @return A string representation of the object.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return "{XmlRpcSessionInfo id=" + m_id + "}";
|
||||
|
||||
} // end toString
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ObjectProvider
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves an object from this session's <CODE>ObjectProvider</CODE>.
|
||||
*
|
||||
* @param namespace The namespace to interpret the name relative to.
|
||||
* @param name The name of the object to be retrieved.
|
||||
* @return The object reference specified.
|
||||
*/
|
||||
public Object getObject(String namespace, String name)
|
||||
{
|
||||
if (namespace==null)
|
||||
throw new NullPointerException("XmlRpcSessionInfo.getObject(namespace)");
|
||||
if (name==null)
|
||||
throw new NullPointerException("XmlRpcSessionInfo.getObject(name)");
|
||||
|
||||
return m_store.getObject(namespace,name);
|
||||
|
||||
} // end getObject
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ObjectStore
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets an object into this session's <CODE>ObjectStore</CODE>. If the object implements
|
||||
* {@link com.silverwrist.dynamo.event.SessionValueBindListener SessionValueBindListener}, its
|
||||
* {@link com.silverwrist.dynamo.event.SessionValueBindListener#valueAdded(com.silverwrist.dynamo.event.SessionValueBindEvent) valueAdded()}
|
||||
* method will be called. If there was an object previously stored in this <CODE>ObjectStore</CODE> with the given
|
||||
* namespace and name, and it implements <CODE>SessionValueBindListener</CODE>, its
|
||||
* {@link com.silverwrist.dynamo.event.SessionValueBindListener#valueReplaced(com.silverwrist.dynamo.event.SessionValueBindEvent) valueReplaced()}
|
||||
* method will be called.
|
||||
*
|
||||
* @param namespace The namespace to interpret the name relative to.
|
||||
* @param name The name of the object to be set.
|
||||
* @param value The object to set into the <CODE>ObjectStore</CODE>.
|
||||
* @return The previous object that was set into the <CODE>ObjectStore</CODE> under this namespace and name, or
|
||||
* <CODE>null</CODE> if there was no such object.
|
||||
*/
|
||||
public Object setObject(String namespace, String name, Object value)
|
||||
{
|
||||
if (namespace==null)
|
||||
throw new NullPointerException("XmlRpcSessionInfo.setObject(namespace)");
|
||||
if (name==null)
|
||||
throw new NullPointerException("XmlRpcSessionInfo.setObject(name)");
|
||||
if (value==null)
|
||||
throw new NullPointerException("XmlRpcSessionInfo.setObject(value)");
|
||||
|
||||
Object old_val = m_store.setObject(namespace,name,value);
|
||||
if ( (value instanceof SessionValueBindListener)
|
||||
|| ((old_val!=null) && (old_val instanceof SessionValueBindListener)))
|
||||
{ // fire events indicating an object is being replaced and/or added
|
||||
SessionValueBindEvent evt = new SessionValueBindEvent(this,namespace,name,value);
|
||||
if ((old_val!=null) && (old_val instanceof SessionValueBindListener))
|
||||
((SessionValueBindListener)old_val).valueReplaced(evt);
|
||||
if (value instanceof SessionValueBindListener)
|
||||
((SessionValueBindListener)value).valueAdded(evt);
|
||||
|
||||
} // end if
|
||||
|
||||
return old_val;
|
||||
|
||||
} // end setObject
|
||||
|
||||
/**
|
||||
* Removes an object from this session's <CODE>ObjectStore</CODE>. If the object implements
|
||||
* {@link com.silverwrist.dynamo.event.SessionValueBindListener SessionValueBindListener}, its
|
||||
* {@link com.silverwrist.dynamo.event.SessionValueBindListener#valueRemoved(com.silverwrist.dynamo.event.SessionValueBindEvent) valueRemoved()}
|
||||
* method will be called.
|
||||
*
|
||||
* @param namespace The namespace to interpret the name relative to.
|
||||
* @param name The name of the object to be removed.
|
||||
* @return The previous object that was set into the <CODE>ObjectStore</CODE> under this namespace and name, or
|
||||
* <CODE>null</CODE> if there was no such object.
|
||||
*/
|
||||
public Object removeObject(String namespace, String name)
|
||||
{
|
||||
if (namespace==null)
|
||||
throw new NullPointerException("XmlRpcSessionInfo.removeObject(namespace)");
|
||||
if (name==null)
|
||||
throw new NullPointerException("XmlRpcSessionInfo.removeObject(name)");
|
||||
|
||||
Object old_val = m_store.removeObject(namespace,name);
|
||||
if ((old_val!=null) && (old_val instanceof SessionValueBindListener))
|
||||
((SessionValueBindListener)old_val).valueRemoved(new SessionValueBindEvent(this,namespace,name));
|
||||
return old_val;
|
||||
|
||||
} // end removeObject
|
||||
|
||||
/**
|
||||
* Returns a collection of all object namespaces that have been set into this session's <CODE>ObjectStore</CODE>.
|
||||
*
|
||||
* @return A <CODE>java.util.Collection</CODE> containing <CODE>String</CODE> objects specifying all the
|
||||
* object namespaces.
|
||||
*/
|
||||
public Collection getNamespaces()
|
||||
{
|
||||
return m_store.getNamespaces();
|
||||
|
||||
} // end getNamespaces
|
||||
|
||||
/**
|
||||
* Returns a collection of all object names that have been set into this session's <CODE>ObjectStore</CODE>
|
||||
* under a given namespace.
|
||||
*
|
||||
* @param namespace The namespace to look for names under.
|
||||
* @return A <CODE>java.util.Collection</CODE> containing <CODE>String</CODE> objects specifying all the
|
||||
* object names for this namespace.
|
||||
*/
|
||||
public Collection getNamesForNamespace(String namespace)
|
||||
{
|
||||
return m_store.getNamesForNamespace(namespace);
|
||||
|
||||
} // end getNamesForNamespace
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface SessionInfo
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a value indicating the type of this session. This will usually be the same as the type of the
|
||||
* {@link com.silverwrist.dynamo.iface.Request Request} objects that work with this session object.
|
||||
*
|
||||
* @return The type of this request.
|
||||
* @see com.silverwrist.dynamo.RequestType
|
||||
* @see com.silverwrist.dynamo.iface.Request#getType()
|
||||
*/
|
||||
public RequestType getSessionType()
|
||||
{
|
||||
return RequestType.XMLRPC;
|
||||
|
||||
} // end getSessionType
|
||||
|
||||
/**
|
||||
* Returns the unique identifier for this session.
|
||||
*
|
||||
* @return The unique identifier for this session.
|
||||
*/
|
||||
public String getID()
|
||||
{
|
||||
return m_id;
|
||||
|
||||
} // end getID
|
||||
|
||||
/**
|
||||
* Returns the time at which this session was created. This is expressed in the same units as
|
||||
* <CODE>System.currentTimeMillis()</CODE>.
|
||||
*
|
||||
* @return The time at which the session was created.
|
||||
*/
|
||||
public long getCreationTime()
|
||||
{
|
||||
return m_created;
|
||||
|
||||
} // end getCreationTime
|
||||
|
||||
/**
|
||||
* Returns the time at which this session was last accessed. This is expressed in the same units as
|
||||
* <CODE>System.currentTimeMillis()</CODE>.
|
||||
*
|
||||
* @return The time at which the session was last accessed.
|
||||
*/
|
||||
public long getLastAccessedTime()
|
||||
{
|
||||
return m_last_access;
|
||||
|
||||
} // end getLastAccessedTime
|
||||
|
||||
/**
|
||||
* Specifies the time, in seconds, between client requests before the framework will invalidate this
|
||||
* session. A negative value indicates the session should never timeout.
|
||||
*
|
||||
* @param interval An integer specifying the number of seconds.
|
||||
*/
|
||||
public void setMaxInactiveInterval(int interval)
|
||||
{
|
||||
m_max_inactive = interval;
|
||||
|
||||
} // end setMaxInactiveInterval
|
||||
|
||||
/**
|
||||
* Returns the maximum time interval, in seconds, that the framework will keep this session open between
|
||||
* client accesses. After this interval, the framework will invalidate the session. The maximum time
|
||||
* interval can be set with the {@link #setMaxInactiveInterval(int) setMaxInactiveInterval} method. A negative
|
||||
* value indicates the session should never timeout.
|
||||
*
|
||||
* @return An integer specifying the number of seconds this session remains open between client requests.
|
||||
*/
|
||||
public int getMaxInactiveInterval()
|
||||
{
|
||||
return m_max_inactive;
|
||||
|
||||
} // end getMaxInactiveInterval
|
||||
|
||||
/**
|
||||
* Causes the session to be invalidated, and any objects bound to it to be unbound. Also invalidates
|
||||
* any underlying session attributes in the enclosing environment (such as the servlet container), if
|
||||
* present.
|
||||
*/
|
||||
public void invalidate()
|
||||
{
|
||||
m_appcon.removeSessionLink(this);
|
||||
m_subsystem.zapSession(m_id);
|
||||
destroy();
|
||||
|
||||
} // end invalidate
|
||||
|
||||
/**
|
||||
* Causes the session to be invalidated, and any objects bound to it to be unbound. If there are any
|
||||
* underlying session attributes in the enclosing environment (such as the servlet container), they are
|
||||
* unaffected.
|
||||
*/
|
||||
public void detach()
|
||||
{
|
||||
this.invalidate();
|
||||
|
||||
} // end detach
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ComponentShutdown
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Shuts down the session. It sends out session-exiting notifications, unbinds all variables from the
|
||||
* session, and erases the contents.
|
||||
*/
|
||||
public void shutdown()
|
||||
{
|
||||
destroy();
|
||||
|
||||
} // end shutdown
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Updates the "last accessed" time for this session to the current time.
|
||||
*/
|
||||
synchronized void touch()
|
||||
{
|
||||
m_last_access = System.currentTimeMillis();
|
||||
|
||||
} // end touch
|
||||
|
||||
/**
|
||||
* Returns whether or not this session has expired and should be removed.
|
||||
*
|
||||
* @param time_tick A current time stamp value.
|
||||
* @return <CODE>true</CODE> if the session has expired, <CODE>false</CODE> if not.
|
||||
*/
|
||||
synchronized boolean isExpired(long time_tick)
|
||||
{
|
||||
if (m_max_inactive<0)
|
||||
return false; // never expire
|
||||
else
|
||||
return (time_tick - m_last_access) > (m_max_inactive * 1000L);
|
||||
|
||||
} // end isExpired
|
||||
|
||||
/**
|
||||
* Sends out all session-initialized notifications. This is done as a separate operation because of the need
|
||||
* to provide a {@link com.silverwrist.dynamo.iface.Request Request} context to send the event out in.
|
||||
*
|
||||
* @param r The <CODE>Request</CODE> to provide context for the events.
|
||||
*/
|
||||
void newSession(Request r)
|
||||
{
|
||||
logger.info("Calling sessionInitialized notifications on session " + m_id);
|
||||
|
||||
// Send the start-session notifications.
|
||||
SessionInfoListener[] listeners = m_appcon.getSessionListeners();
|
||||
if (listeners.length>0)
|
||||
{ // call each listener in turn
|
||||
SessionEventRequest req = new SessionEventRequest(this,true,r);
|
||||
SessionInfoEvent evt = new SessionInfoEvent(req,this);
|
||||
for (int i=0; i<listeners.length; i++)
|
||||
listeners[i].sessionInitialized(evt);
|
||||
|
||||
} // end if
|
||||
|
||||
m_appcon.addSessionLink(this); // set it up to be zapped with the other sessions
|
||||
|
||||
} // end newSession
|
||||
|
||||
} // end class XmlRpcSessionInfo
|
||||
@@ -0,0 +1,790 @@
|
||||
/*
|
||||
* 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) 2002-03 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.util.*;
|
||||
import org.apache.commons.lang.CharSet;
|
||||
import org.apache.commons.lang.CharSetUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.w3c.dom.*;
|
||||
import com.silverwrist.util.xml.*;
|
||||
import com.silverwrist.dynamo.Namespaces;
|
||||
import com.silverwrist.dynamo.app.ApplicationContainer;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
import com.silverwrist.dynamo.util.*;
|
||||
|
||||
public class XmlRpcSubSystem
|
||||
implements NamedObject, ComponentInitialize, ComponentShutdown, XmlRpcCreateSession, XmlRpcConfiguration
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal class implementing background sweep
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private class SessionSweeper implements BackgroundTask
|
||||
{
|
||||
/*====================================================================
|
||||
* Constructor
|
||||
*====================================================================
|
||||
*/
|
||||
|
||||
SessionSweeper()
|
||||
{ // do nothing
|
||||
} // end constructor
|
||||
|
||||
/*====================================================================
|
||||
* Implementations from interface BackgroundTask
|
||||
*====================================================================
|
||||
*/
|
||||
|
||||
public void run(ServiceProvider services)
|
||||
{
|
||||
LinkedList dead_sessions = new LinkedList();
|
||||
long timer_tick = System.currentTimeMillis();
|
||||
synchronized (m_sessions)
|
||||
{ // loop over the session list and add things to it
|
||||
Iterator it = m_sessions.values().iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each session and test its expiration status
|
||||
XmlRpcSessionInfo session = (XmlRpcSessionInfo)(it.next());
|
||||
if (session.isExpired(timer_tick))
|
||||
dead_sessions.addLast(session);
|
||||
|
||||
} // end while
|
||||
|
||||
} // end synchronizedBlock
|
||||
|
||||
while (!(dead_sessions.isEmpty()))
|
||||
{ // invalidate all the dead sessions
|
||||
XmlRpcSessionInfo session = (XmlRpcSessionInfo)(dead_sessions.removeFirst());
|
||||
session.invalidate();
|
||||
|
||||
} // end while
|
||||
|
||||
} // end run
|
||||
|
||||
} // end class SessionSweeper
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static Logger logger = Logger.getLogger(XmlRpcSubSystem.class);
|
||||
|
||||
private static final long SWEEP_INTERVAL = 60000L; // every minute
|
||||
private static final int DEFAULT_MAX_AGE = 3600; // last for one hour
|
||||
|
||||
private static final String[] METHOD_CHARS = { "A-Z", "a-z", "0-9", "_.:/" };
|
||||
|
||||
private static final CharSet s_method_chars;
|
||||
|
||||
private static final String PREFIX = "xmlrpcsess:";
|
||||
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
|
||||
private static final int ID_LENGTH = 40;
|
||||
|
||||
private static Random rng = new Random(); // random number generator
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private ApplicationContainer m_appcon = null; // application container
|
||||
private LinkedList m_shutdown_list = new LinkedList(); // objects to be shut down
|
||||
private String m_name; // name of this object
|
||||
private Capabilities m_capas = new Capabilities(); // capabilities manager
|
||||
private int m_default_maxage = DEFAULT_MAX_AGE; // default maximum age of sessions
|
||||
private Hashtable m_sessions = new Hashtable(); // sessions we manage
|
||||
private ArrayList m_internal_disp = new ArrayList(); // internal dispatchers
|
||||
private Vector m_installed_disp = new Vector(); // dispatchers installed via the API
|
||||
private ArrayList m_config_disp = new ArrayList(); // dispatchers configured via the config data
|
||||
private ArrayList m_internal_fmap = new ArrayList(); // internal fault mappers
|
||||
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_sweep_task; // sweep task
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public XmlRpcSubSystem()
|
||||
{
|
||||
try
|
||||
{ // Add internal dispatchers to the first list
|
||||
m_internal_disp.add(new RegisteredDispatcher("system\\.getCapabilities",m_capas));
|
||||
m_internal_disp.add(new RegisteredDispatcher("system\\.multicall",new MultiCallDispatcher(this)));
|
||||
IntrospectionDispatcher id = new IntrospectionDispatcher(this);
|
||||
m_internal_disp.add(new RegisteredDispatcher("system\\.listMethods",id));
|
||||
m_internal_disp.add(new RegisteredDispatcher("system\\.methodSignature",id));
|
||||
m_internal_disp.add(new RegisteredDispatcher("system\\.methodHelp",id));
|
||||
|
||||
} // end try
|
||||
catch (ConfigException e)
|
||||
{ // this shouldn't happen....
|
||||
logger.fatal("ACK! internal dispatcher add failed!",e);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final ComponentInitialize getComponentInitialize(Object obj)
|
||||
{
|
||||
if (obj instanceof ComponentInitialize)
|
||||
return (ComponentInitialize)obj;
|
||||
if (obj instanceof ServiceProvider)
|
||||
{ // it may be a service provider interface
|
||||
try
|
||||
{ // look for ComponentInitialize as a service
|
||||
ServiceProvider sp = (ServiceProvider)obj;
|
||||
ComponentInitialize rc = (ComponentInitialize)(sp.queryService(ComponentInitialize.class));
|
||||
return rc;
|
||||
|
||||
} // end try
|
||||
catch (NoSuchServiceException e)
|
||||
{ // do nothing here
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
return null; // no dice!
|
||||
|
||||
} // end getComponentInitialize
|
||||
|
||||
private static final ComponentShutdown getComponentShutdown(Object obj)
|
||||
{
|
||||
if (obj instanceof ComponentShutdown)
|
||||
return (ComponentShutdown)obj;
|
||||
if (obj instanceof ServiceProvider)
|
||||
{ // it may be a service provider interface
|
||||
try
|
||||
{ // look for ComponentShutdown as a service
|
||||
ServiceProvider sp = (ServiceProvider)obj;
|
||||
ComponentShutdown rc = (ComponentShutdown)(sp.queryService(ComponentShutdown.class));
|
||||
return rc;
|
||||
|
||||
} // end try
|
||||
catch (NoSuchServiceException e)
|
||||
{ // do nothing here
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
return null; // no dice!
|
||||
|
||||
} // end getComponentShutdown
|
||||
|
||||
private static final boolean isValidMethodName(String name)
|
||||
{
|
||||
if ((name==null) || (name.length()==0))
|
||||
return false;
|
||||
for (int i=0; i<name.length(); i++)
|
||||
{ // test each character in turn
|
||||
if (!(s_method_chars.contains(name.charAt(i))))
|
||||
return false; // found a bogus character
|
||||
|
||||
} // end for
|
||||
|
||||
return true; // all tests passed - ship it!
|
||||
|
||||
} // end isValidMethodName
|
||||
|
||||
private static final XmlRpcDispatcher scanDispatcherList(List l, String method_name)
|
||||
{
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // locate a dispatcher by matching the method name
|
||||
RegisteredDispatcher disp = (RegisteredDispatcher)(it.next());
|
||||
if (disp.match(method_name))
|
||||
return disp.getDispatcher();
|
||||
|
||||
} // end while
|
||||
|
||||
return null;
|
||||
|
||||
} // end scanDispatcherList
|
||||
|
||||
private static final void copyDispatchers(Set dest, List source)
|
||||
{
|
||||
Iterator it = source.iterator();
|
||||
while (it.hasNext())
|
||||
{ // strip out all dispatchers and return them
|
||||
RegisteredDispatcher disp = (RegisteredDispatcher)(it.next());
|
||||
dest.add(disp.getDispatcher());
|
||||
|
||||
} // end while
|
||||
|
||||
} // end copyDispatchers
|
||||
|
||||
private static final XmlRpcFaultMapper scanFaultMapperList(List l, Class klass)
|
||||
{
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // locate a fault mapper by matching the class
|
||||
RegisteredFaultMapper fmap = (RegisteredFaultMapper)(it.next());
|
||||
if (fmap.match(klass))
|
||||
return fmap.getFaultMapper();
|
||||
|
||||
} // end while
|
||||
|
||||
return null;
|
||||
|
||||
} // end scanFaultMapperList
|
||||
|
||||
private static final String generateID()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer(PREFIX);
|
||||
for (int i=0; i<ID_LENGTH; i++)
|
||||
buf.append(ALPHABET.charAt(rng.nextInt(ALPHABET.length())));
|
||||
return buf.toString();
|
||||
|
||||
} // end generateID
|
||||
|
||||
private final XmlRpcDispatcher createDispatcherObject(Element config_root, ServiceProvider services)
|
||||
throws ConfigException
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
String klassname = null;
|
||||
try
|
||||
{ // get the classname and load it, and create an object
|
||||
klassname = loader.getAttribute(config_root,"classname");
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("createDispatcherObject: Creating new XmlRpcDispatcher of class " + klassname);
|
||||
|
||||
Class klass = Class.forName(klassname);
|
||||
if (!(XmlRpcDispatcher.class.isAssignableFrom(klass)))
|
||||
{ // this object is not a valid XmlRpcDispatcher
|
||||
logger.error("object " + klassname + " does not implement XmlRpcDispatcher");
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xdisp.notXD");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end if
|
||||
|
||||
// instantiate the object, and initialize it as needed
|
||||
Object rc = klass.newInstance();
|
||||
ComponentInitialize init = getComponentInitialize(rc);
|
||||
if (init!=null)
|
||||
init.initialize(config_root,services);
|
||||
|
||||
synchronized (this)
|
||||
{ // save its shutdown hook for later
|
||||
ComponentShutdown sd = getComponentShutdown(rc);
|
||||
if (sd!=null)
|
||||
m_shutdown_list.addFirst(sd);
|
||||
|
||||
} // end synchronized block
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("XML-RPC dispatcher (of class " + klassname + ") created");
|
||||
|
||||
return (XmlRpcDispatcher)rc;
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // error getting class name - throw the ConfigException
|
||||
logger.error("XML loader failure",e);
|
||||
throw new ConfigException(e);
|
||||
|
||||
} // end catch
|
||||
catch (ClassNotFoundException e)
|
||||
{ // the class was not found
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xdisp.classNotFound");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
catch (IllegalAccessException e)
|
||||
{ // unable to create this object
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xdisp.createError");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
catch (InstantiationException e)
|
||||
{ // unable to create this object
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xdisp.createError");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end createDispatcherObject
|
||||
|
||||
private final XmlRpcFaultMapper createFaultMapperObject(Element config_root, ServiceProvider services)
|
||||
throws ConfigException
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
String klassname = null;
|
||||
try
|
||||
{ // get the classname and load it, and create an object
|
||||
klassname = loader.getAttribute(config_root,"classname");
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("createFaultMapperObject: Creating new XmlRpcFaultMapper of class " + klassname);
|
||||
|
||||
Class klass = Class.forName(klassname);
|
||||
if (!(XmlRpcFaultMapper.class.isAssignableFrom(klass)))
|
||||
{ // this object is not a valid XmlRpcFaultMapper
|
||||
logger.error("object " + klassname + " does not implement XmlRpcFaultMapper");
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xfmap.notXFM");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end if
|
||||
|
||||
// instantiate the object, and initialize it as needed
|
||||
Object rc = klass.newInstance();
|
||||
ComponentInitialize init = getComponentInitialize(rc);
|
||||
if (init!=null)
|
||||
init.initialize(config_root,services);
|
||||
|
||||
synchronized (this)
|
||||
{ // save its shutdown hook for later
|
||||
ComponentShutdown sd = getComponentShutdown(rc);
|
||||
if (sd!=null)
|
||||
m_shutdown_list.addFirst(sd);
|
||||
|
||||
} // end synchronized block
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("XML-RPC fault mapper (of class " + klassname + ") created");
|
||||
|
||||
return (XmlRpcFaultMapper)rc;
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // error getting class name - throw the ConfigException
|
||||
logger.error("XML loader failure",e);
|
||||
throw new ConfigException(e);
|
||||
|
||||
} // end catch
|
||||
catch (ClassNotFoundException e)
|
||||
{ // the class was not found
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xfmap.classNotFound");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
catch (IllegalAccessException e)
|
||||
{ // unable to create this object
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xfmap.createError");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
catch (InstantiationException e)
|
||||
{ // unable to create this object
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages","xfmap.createError");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end createFaultMapperObject
|
||||
|
||||
private final SessionInfo lookupSession(String id, Request r)
|
||||
{
|
||||
XmlRpcSessionInfo rc = null;
|
||||
boolean is_new = false;
|
||||
synchronized (m_sessions)
|
||||
{ // look up a session...
|
||||
rc = (XmlRpcSessionInfo)(m_sessions.get(id));
|
||||
if (rc==null)
|
||||
{ // not present - add it with this ID, which must have been valid at one point
|
||||
rc = new XmlRpcSessionInfo(this,m_appcon,id);
|
||||
m_sessions.put(id,rc);
|
||||
is_new = true;
|
||||
|
||||
} // end if
|
||||
|
||||
} // end synchronized block
|
||||
|
||||
if (is_new)
|
||||
rc.newSession(r); // yay! new session!
|
||||
else
|
||||
rc.touch(); // update last access time
|
||||
|
||||
return rc;
|
||||
|
||||
} // end lookupSession
|
||||
|
||||
private final Object execDispatcher(XmlRpcDispatcher disp, Request r, Application app)
|
||||
throws Exception, FaultCode
|
||||
{
|
||||
Request my_req = r;
|
||||
String session_id = disp.getSessionIDParamValue(r,app);
|
||||
if (session_id!=null)
|
||||
{ // get the session and "tack it" onto the request
|
||||
SessionInfo session = lookupSession(session_id,r);
|
||||
if (session!=null)
|
||||
my_req = new ReplaceSessionRequest(r,session);
|
||||
|
||||
} // end if
|
||||
|
||||
return disp.dispatchXmlRpcCall(my_req,app);
|
||||
|
||||
} // end execDispatcher
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface NamedObject
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the name of this object.
|
||||
*
|
||||
* @return The name of this object.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return m_name;
|
||||
|
||||
} // end getName
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ComponentInitialize
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize the XML-RPC subsystem.
|
||||
*
|
||||
* @param config_root Pointer to the section of the Dynamo XML configuration file that configures this
|
||||
* particular component. This is to be considered "read-only" by the component.
|
||||
* @param services An implementation of {@link com.silverwrist.dynamo.iface.ServiceProvider ServiceProvider}
|
||||
* which provides initialization services to the component. This will include an implementation
|
||||
* of {@link com.silverwrist.dynamo.iface.ObjectProvider ObjectProvider} which may be used to
|
||||
* get information about other objects previously initialized by the application.
|
||||
* @exception com.silverwrist.dynamo.except.ConfigException If an error is encountered in the component
|
||||
* configuration.
|
||||
*/
|
||||
public void initialize(Element config_root, ServiceProvider services) throws ConfigException
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
try
|
||||
{ // verify the right node name
|
||||
loader.verifyNodeName(config_root,"object");
|
||||
|
||||
// get the object's name
|
||||
m_name = loader.getAttribute(config_root,"name");
|
||||
|
||||
// get the default maximum age
|
||||
m_default_maxage = loader.getAttributeInt(config_root,"maxAge",DEFAULT_MAX_AGE);
|
||||
|
||||
// load up a list of all dispatch objects to be initialized
|
||||
List l = loader.getMatchingSubElements(config_root,"dispatch");
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // load each dispatch object in turn
|
||||
Element d_elt = (Element)(it.next());
|
||||
String method_name = loader.getAttribute(d_elt,"method");
|
||||
XmlRpcDispatcher disp_obj = createDispatcherObject(d_elt,services);
|
||||
m_config_disp.add(new RegisteredDispatcher(method_name,disp_obj));
|
||||
|
||||
} // end while
|
||||
|
||||
// load up the list of all fault mapper objects to be initialized
|
||||
l = loader.getMatchingSubElements(config_root,"fault-mapper");
|
||||
it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // load each fault mapper object in turn
|
||||
Element fm_elt = (Element)(it.next());
|
||||
String klassname = loader.getAttribute(fm_elt,"for");
|
||||
Class klass = null;
|
||||
try
|
||||
{ // get the class for which this will translate
|
||||
klass = Class.forName(klassname);
|
||||
if (!(Exception.class.isAssignableFrom(klass)))
|
||||
{ // it's not an Exception - we can't have that
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages",
|
||||
"xfmap.badExceptClass");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end if
|
||||
|
||||
} // end try
|
||||
catch (ClassNotFoundException e)
|
||||
{ // class was not found
|
||||
ConfigException ce = new ConfigException(XmlRpcSubSystem.class,"XmlRpcMessages",
|
||||
"xfmap.noExceptClass");
|
||||
ce.setParameter(0,klassname);
|
||||
throw ce;
|
||||
|
||||
} // end catch
|
||||
|
||||
XmlRpcFaultMapper fm_obj = createFaultMapperObject(fm_elt,services);
|
||||
m_config_fmap.add(new RegisteredFaultMapper(klass,fm_obj));
|
||||
|
||||
} // end while
|
||||
|
||||
// load up the list of all capabilities to be added
|
||||
l = loader.getMatchingSubElements(config_root,"capability");
|
||||
it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each capability in turn and push it in
|
||||
Element capa_elt = (Element)(it.next());
|
||||
String name = loader.getAttribute(capa_elt,"name");
|
||||
String url = loader.getAttribute(capa_elt,"url");
|
||||
int version = loader.getAttributeInt(capa_elt,"version");
|
||||
m_capas.insertCapability(name,url,version);
|
||||
|
||||
} // end while
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // error loading XML config data
|
||||
throw new ConfigException(e);
|
||||
|
||||
} // end catch
|
||||
|
||||
// Get the application container.
|
||||
ObjectProvider op = (ObjectProvider)(services.queryService(ObjectProvider.class));
|
||||
m_appcon = (ApplicationContainer)(op.getObject(Namespaces.DYNAMO_APPLICATION_NAMESPACE,"__container__"));
|
||||
|
||||
// Add the XmlRpcConfiguration service to Dynamo's init services.
|
||||
HookServiceProviders hooker = (HookServiceProviders)(services.queryService(HookServiceProviders.class));
|
||||
SingletonServiceProvider ssp = new SingletonServiceProvider("XmlRpcSubSystem",XmlRpcConfiguration.class,
|
||||
(XmlRpcConfiguration)this);
|
||||
m_init_hook = hooker.hookInitServiceProvider(ssp);
|
||||
|
||||
// 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);
|
||||
|
||||
} // end initialize
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ComponentShutdown
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Shuts down the XML-RPC subsystem.
|
||||
*/
|
||||
public void shutdown()
|
||||
{
|
||||
m_sweep_task.shutdown(); // shut down the sweep task
|
||||
m_sweep_task = null;
|
||||
|
||||
m_init_hook.shutdown(); // shut down the initialization hook
|
||||
m_init_hook = null;
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("XmlRpcSubSystem.shutdown(): " + m_shutdown_list.size() + " objects to blow away");
|
||||
|
||||
while (m_shutdown_list.size()>0)
|
||||
{ // shut down all components in reverse order of creation
|
||||
ComponentShutdown sd = (ComponentShutdown)(m_shutdown_list.removeFirst());
|
||||
sd.shutdown();
|
||||
|
||||
} // end while
|
||||
|
||||
m_sessions.clear(); // sessions already shut down by application container
|
||||
m_internal_disp.clear();
|
||||
m_installed_disp.clear();
|
||||
m_config_disp.clear();
|
||||
m_appcon = null;
|
||||
|
||||
} // end shutdown
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcCreateSession
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public SessionInfo createNewSession(Request r)
|
||||
{
|
||||
XmlRpcSessionInfo rc = null;
|
||||
synchronized (m_sessions)
|
||||
{ // generate a new session ID and add it to the table
|
||||
String new_id = generateID();
|
||||
while (m_sessions.containsKey(new_id))
|
||||
new_id = generateID();
|
||||
rc = new XmlRpcSessionInfo(this,m_appcon,new_id);
|
||||
m_sessions.put(new_id,rc);
|
||||
|
||||
} // end synchronized block
|
||||
|
||||
rc.newSession(r); // initiate me!
|
||||
return rc;
|
||||
|
||||
} // end createNewSession
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface XmlRpcConfiguration
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public ComponentShutdown addDispatcher(String method, XmlRpcDispatcher disp) throws ConfigException
|
||||
{
|
||||
RegisteredDispatcher rd = new RegisteredDispatcher(method,disp);
|
||||
m_installed_disp.add(rd);
|
||||
return new ShutdownVectorRemove(m_installed_disp,rd);
|
||||
|
||||
} // end addDispatcher
|
||||
|
||||
public ComponentShutdown addFaultMapper(Class klass, XmlRpcFaultMapper fmap) throws ConfigException
|
||||
{
|
||||
RegisteredFaultMapper rfm = new RegisteredFaultMapper(klass,fmap);
|
||||
m_installed_fmap.add(rfm);
|
||||
return new ShutdownVectorRemove(m_installed_fmap,rfm);
|
||||
|
||||
} // end addFaultMapper
|
||||
|
||||
public ComponentShutdown addCapability(String name, String url, int version)
|
||||
{
|
||||
return m_capas.addCapability(name,url,version);
|
||||
|
||||
} // end addCapability
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the default maximum inactive interval for XML-RPC sessions, in seconds.
|
||||
*
|
||||
* @return The default maximum inactive interval for XML-RPC sessions, in seconds.
|
||||
*/
|
||||
int getDefaultMaxAge()
|
||||
{
|
||||
return m_default_maxage;
|
||||
|
||||
} // end getDefaultMaxAge
|
||||
|
||||
/**
|
||||
* Removes a session from the list of sessions we manage.
|
||||
*
|
||||
* @param id ID of the session to be removed.
|
||||
*/
|
||||
void zapSession(String id)
|
||||
{
|
||||
m_sessions.remove(id);
|
||||
|
||||
} // end zapSession
|
||||
|
||||
XmlRpcDispatcher getDispatcher(String method_name)
|
||||
{
|
||||
XmlRpcDispatcher disp = scanDispatcherList(m_internal_disp,method_name);
|
||||
if (disp==null)
|
||||
disp = scanDispatcherList(m_installed_disp,method_name);
|
||||
if (disp==null)
|
||||
disp = scanDispatcherList(m_config_disp,method_name);
|
||||
return disp;
|
||||
|
||||
} // end getDispatcher
|
||||
|
||||
Set getAllDispatchers()
|
||||
{
|
||||
HashSet rc = new HashSet();
|
||||
copyDispatchers(rc,m_internal_disp);
|
||||
copyDispatchers(rc,m_installed_disp);
|
||||
copyDispatchers(rc,m_config_disp);
|
||||
return rc;
|
||||
|
||||
} // end getAllDispatchers
|
||||
|
||||
Object dispatch(Request r, Application app) throws Exception, FaultCode
|
||||
{
|
||||
// Get method name and make sure it's valid.
|
||||
String method_name = r.getQueryString();
|
||||
if (!isValidMethodName(method_name))
|
||||
throw new SystemFaultCode(SystemFaultCode.METHOD_NOT_FOUND,"Invalid method name: " + method_name);
|
||||
|
||||
// Look for the appropriate dispatcher object.
|
||||
XmlRpcDispatcher disp = getDispatcher(method_name);
|
||||
if (disp==null) // dispatcher not found!
|
||||
throw new XmlRpcMethodNotFound(method_name);
|
||||
|
||||
// Execute the dispatcher!
|
||||
return execDispatcher(disp,r,app);
|
||||
|
||||
} // end dispatch
|
||||
|
||||
FaultCode translateException(Request r, Exception e)
|
||||
{
|
||||
Class klass = e.getClass();
|
||||
int code = 0;
|
||||
do
|
||||
{ // scan upwards through the list of fault mappers and through class hierarchy
|
||||
XmlRpcFaultMapper fmap = scanFaultMapperList(m_internal_fmap,klass);
|
||||
if (fmap!=null)
|
||||
{ // try the fault mapper
|
||||
code = fmap.getXmlRpcFaultCodeForException(r,e);
|
||||
if (code!=0)
|
||||
break;
|
||||
else
|
||||
fmap = null;
|
||||
|
||||
} // end if
|
||||
|
||||
if (fmap==null)
|
||||
fmap = scanFaultMapperList(m_installed_fmap,klass);
|
||||
if (fmap!=null)
|
||||
{ // try the fault mapper
|
||||
code = fmap.getXmlRpcFaultCodeForException(r,e);
|
||||
if (code!=0)
|
||||
break;
|
||||
else
|
||||
fmap = null;
|
||||
|
||||
} // end if
|
||||
|
||||
if (fmap==null)
|
||||
fmap = scanFaultMapperList(m_config_fmap,klass);
|
||||
if (fmap!=null)
|
||||
{ // try the fault mapper
|
||||
code = fmap.getXmlRpcFaultCodeForException(r,e);
|
||||
if (code!=0)
|
||||
break;
|
||||
else
|
||||
fmap = null;
|
||||
|
||||
} // end if
|
||||
|
||||
if (fmap==null)
|
||||
klass = klass.getSuperclass(); // try the superclass and see if that gets us anywhere
|
||||
|
||||
} while (klass!=Throwable.class); // end do
|
||||
|
||||
return new FaultCode(code,e);
|
||||
|
||||
} // end translateException
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // evaluate the character set
|
||||
s_method_chars = CharSetUtils.evaluateSet(METHOD_CHARS);
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class XmlRpcSubSystem
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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) 2002-03 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
public interface XmlRpcTypeNames
|
||||
{
|
||||
public static final String TYPE_INT = "number";
|
||||
|
||||
public static final String TYPE_BOOLEAN = "boolean";
|
||||
|
||||
public static final String TYPE_STRING = "string";
|
||||
|
||||
public static final String TYPE_DOUBLE = "double";
|
||||
|
||||
public static final String TYPE_DATETIME = "dateTime";
|
||||
|
||||
public static final String TYPE_BASE64 = "base64";
|
||||
|
||||
public static final String TYPE_STRUCT = "struct";
|
||||
|
||||
public static final String TYPE_ARRAY = "array";
|
||||
|
||||
} // end interface XmlRpcTypeNames
|
||||
Reference in New Issue
Block a user