From 6ea41dc6199fb016212e716492c26341eb266989 Mon Sep 17 00:00:00 2001 From: "Eric J. Bowersox" Date: Sun, 13 Jan 2002 09:12:51 +0000 Subject: [PATCH] the first implementation of an XML-RPC server endpoint within Venice... also tweaked the session code to allow session types other than standard HTTP cookie-based sessions. The XML-RPC code doesn't do anything interesting yet. --- etc/ui-config.xml | 11 + etc/web.xml | 11 + lib/.gitignore | 3 +- lib/README.lib | 1 + scripts/logout.js | 3 +- .../silverwrist/venice/ui/NullSession.java | 164 ++++++ .../silverwrist/venice/ui/RequestInput.java | 9 +- .../venice/ui/VeniceUISession.java | 51 ++ .../venice/ui/VeniceUISessionFactory.java | 31 ++ .../venice/ui/config/RootConfig.java | 41 +- .../venice/ui/rpc/XmlRpcDispatch.java | 28 ++ .../venice/ui/rpc/XmlRpcFault.java | 123 +++++ .../venice/ui/rpc/XmlRpcMethod.java | 172 +++++++ .../venice/ui/rpc/XmlRpcRequest.java | 392 +++++++++++++++ .../venice/ui/rpc/XmlRpcSelfSerializer.java | 24 + .../venice/ui/rpc/XmlRpcSerializer.java | 471 ++++++++++++++++++ .../venice/ui/rpc/XmlRpcServlet.java | 198 ++++++++ .../venice/ui/rpc/XmlRpcTestHandler.java | 70 +++ .../venice/ui/servlet/BaseServlet.java | 88 +++- .../ui/servlet/HttpVeniceUISession.java | 206 ++++++++ .../venice/ui/servlet/RequestImpl.java | 225 ++++----- .../silverwrist/venice/util/XMLLoader.java | 47 +- 22 files changed, 2238 insertions(+), 131 deletions(-) create mode 100644 src/com/silverwrist/venice/ui/NullSession.java create mode 100644 src/com/silverwrist/venice/ui/VeniceUISession.java create mode 100644 src/com/silverwrist/venice/ui/VeniceUISessionFactory.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcDispatch.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcFault.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcMethod.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcRequest.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcSelfSerializer.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcSerializer.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcServlet.java create mode 100644 src/com/silverwrist/venice/ui/rpc/XmlRpcTestHandler.java create mode 100644 src/com/silverwrist/venice/ui/servlet/HttpVeniceUISession.java diff --git a/etc/ui-config.xml b/etc/ui-config.xml index a2cb493..d192f1e 100644 --- a/etc/ui-config.xml +++ b/etc/ui-config.xml @@ -271,6 +271,17 @@ + + + + + + + + + + + diff --git a/etc/web.xml b/etc/web.xml index 87396f9..8f6afb8 100644 --- a/etc/web.xml +++ b/etc/web.xml @@ -119,6 +119,12 @@ com.silverwrist.venice.ui.servlet.RemapperServlet + + XmlRpc + Handles XML-RPC calls for the application. + com.silverwrist.venice.ui.rpc.XmlRpcServlet + + @@ -182,6 +188,11 @@ /verifyemail + + XmlRpc + /RPC2 + + 60 diff --git a/lib/.gitignore b/lib/.gitignore index 8bc3108..a93d63b 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,7 +1,8 @@ bsf.jar jacl.jar +jakarta-regexp*.jar js.jar log4j.jar mysql.jar mm.mysql*.jar -tcljava.jar \ No newline at end of file +tcljava.jar diff --git a/lib/README.lib b/lib/README.lib index 4b392a9..1382f87 100644 --- a/lib/README.lib +++ b/lib/README.lib @@ -6,6 +6,7 @@ compatible with the versions specified here. Library Version File Name(s) Install To ------------------------------------------------------------------------------------------------- +Apache Jakarta Regexp 1.2 jakarta-regexp-1.2.jar Venice "lib" subdirectory Apache LOG4J 1.1.3 log4j.jar Venice "lib" subdirectory Bean Scripting Framework 2.2 bsf.jar Venice "lib" subdirectory Jacl (Tcl interpreter) 1.3(CVS) jacl.jar, tcljava.jar Venice "lib" subdirectory diff --git a/scripts/logout.js b/scripts/logout.js index 391828d..536496b 100644 --- a/scripts/logout.js +++ b/scripts/logout.js @@ -31,8 +31,7 @@ if (user.isLoggedIn()) { // user is logged in - we want to log out // TODO: only remove the login cookie if it was actually set! rinput.deleteCookie(RequestInput.LOGIN_COOKIE); // remove the login cookie - rinput.replaceUser(null); // no more user context - rinput.setSessionAttribute(RequestInput.LEFT_MENU_SESSION_ATTR,null); // and clear menus too + rinput.endSession(); target = "top.js.vs"; // take 'em back to the top diff --git a/src/com/silverwrist/venice/ui/NullSession.java b/src/com/silverwrist/venice/ui/NullSession.java new file mode 100644 index 0000000..a1e8ec3 --- /dev/null +++ b/src/com/silverwrist/venice/ui/NullSession.java @@ -0,0 +1,164 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui; + +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import com.silverwrist.venice.core.*; +import com.silverwrist.venice.ui.config.RootConfig; + +public class NullSession implements VeniceUISession, VeniceUISessionFactory +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static NullSession self = null; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + private NullSession() + { // do nothing + } // end constructor + + /*-------------------------------------------------------------------------------- + * Internal operations + *-------------------------------------------------------------------------------- + */ + + private final void bogus() + { + throw new IllegalStateException("null session is not valid"); + + } // end bogus + + /*-------------------------------------------------------------------------------- + * Implementations from interface VeniceUISession + *-------------------------------------------------------------------------------- + */ + + public long getCreationTime() + { + bogus(); + return 0; + + } // end getCreationTime + + public String getID() + { + return null; + + } // end getID + + public long getLastAccessedTime() + { + return 0; + + } // end getLastAccessedTime + + public void setMaxInactiveInterval(int interval) + { // do nothing + } // end setMaxInactiveInterval + + public int getMaxInactiveInterval() + { + return -1; + + } // end getMaxInactiveInterval + + public Object getAttribute(String name) + { + bogus(); + return null; + + } // end getAttribute + + public Enumeration getAttributeNames() + { + bogus(); + return null; + + } // end getAttributeNames + + public void setAttribute(String name, Object o) + { + bogus(); + + } // end setAttribute + + public void removeAttribute(String name) + { + bogus(); + + } // end removeAttribute + + public void invalidate() + { + bogus(); + + } // end invalidate + + public UserContext getUser() + { + bogus(); + return null; + + } // end getUser + + public void setUser(UserContext user) + { + bogus(); + + } // end setUser + + public void preprocess(RequestInput ri) + { // do nothing + } // end preprocess + + /*-------------------------------------------------------------------------------- + * Implementations from interface VeniceUISessionFactory + *-------------------------------------------------------------------------------- + */ + + public VeniceUISession createSession(ServletContext ctxt, HttpServletRequest request, + HttpServletResponse response, VeniceEngine engine, + RootConfig config) + { + return this; + + } // end createSession + + /*-------------------------------------------------------------------------------- + * External static operations + *-------------------------------------------------------------------------------- + */ + + public static final synchronized NullSession get() + { + if (self==null) + self = new NullSession(); + return self; + + } // end get + +} // end class NullSession diff --git a/src/com/silverwrist/venice/ui/RequestInput.java b/src/com/silverwrist/venice/ui/RequestInput.java index 3c8ec2f..81df735 100644 --- a/src/com/silverwrist/venice/ui/RequestInput.java +++ b/src/com/silverwrist/venice/ui/RequestInput.java @@ -11,7 +11,7 @@ * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are - * Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ @@ -23,6 +23,7 @@ import java.io.IOException; import java.util.Date; import java.util.Enumeration; import java.util.Map; +import org.w3c.dom.Document; import com.silverwrist.util.ServletMultipartException; import com.silverwrist.venice.core.CommunityContext; import com.silverwrist.venice.core.UserContext; @@ -53,6 +54,8 @@ public interface RequestInput extends LinkTypes public abstract String getSourceAddress(); + public abstract void endSession(); + public abstract boolean hasParameter(String name); public abstract String getParameter(String name); @@ -75,6 +78,10 @@ public interface RequestInput extends LinkTypes public abstract InputStream getParameterDataStream(String name) throws ServletMultipartException; + public abstract Document getRequestDocument(); + + public abstract boolean sessionBound(); + public abstract boolean isImageButtonClicked(String name); public abstract Object getAppAttribute(String name); diff --git a/src/com/silverwrist/venice/ui/VeniceUISession.java b/src/com/silverwrist/venice/ui/VeniceUISession.java new file mode 100644 index 0000000..d06908f --- /dev/null +++ b/src/com/silverwrist/venice/ui/VeniceUISession.java @@ -0,0 +1,51 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui; + +import java.util.*; +import com.silverwrist.venice.core.*; + +public interface VeniceUISession +{ + public abstract long getCreationTime(); + + public abstract String getID(); + + public abstract long getLastAccessedTime(); + + public abstract void setMaxInactiveInterval(int interval); + + public abstract int getMaxInactiveInterval(); + + public abstract Object getAttribute(String name); + + public abstract Enumeration getAttributeNames(); + + public abstract void setAttribute(String name, Object o); + + public abstract void removeAttribute(String name); + + public abstract void invalidate(); + + public abstract UserContext getUser(); + + public abstract void setUser(UserContext user); + + public abstract void preprocess(RequestInput ri); + +} // end class VeniceUISession diff --git a/src/com/silverwrist/venice/ui/VeniceUISessionFactory.java b/src/com/silverwrist/venice/ui/VeniceUISessionFactory.java new file mode 100644 index 0000000..fdf998d --- /dev/null +++ b/src/com/silverwrist/venice/ui/VeniceUISessionFactory.java @@ -0,0 +1,31 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui; + +import javax.servlet.*; +import javax.servlet.http.*; +import com.silverwrist.venice.core.VeniceEngine; +import com.silverwrist.venice.ui.config.RootConfig; + +public interface VeniceUISessionFactory +{ + public abstract VeniceUISession createSession(ServletContext ctxt, HttpServletRequest request, + HttpServletResponse response, VeniceEngine engine, + RootConfig config) throws ServletException; + +} // end interface VeniceUISessionFactory diff --git a/src/com/silverwrist/venice/ui/config/RootConfig.java b/src/com/silverwrist/venice/ui/config/RootConfig.java index e5452ba..972898f 100644 --- a/src/com/silverwrist/venice/ui/config/RootConfig.java +++ b/src/com/silverwrist/venice/ui/config/RootConfig.java @@ -11,7 +11,7 @@ * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are - * Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ @@ -30,6 +30,7 @@ import com.silverwrist.venice.ui.menus.CommunityMenu; import com.silverwrist.venice.ui.menus.CommunityMenuFactory; import com.silverwrist.venice.ui.menus.Menu; import com.silverwrist.venice.ui.menus.MenuComponent; +import com.silverwrist.venice.ui.rpc.XmlRpcMethod; import com.silverwrist.venice.util.*; public class RootConfig implements LinkTypes, ColorSelectors @@ -79,6 +80,7 @@ public class RootConfig implements LinkTypes, ColorSelectors private ButtonHolder buttons; // the button definitions private String[] content_hdr; // the content header parts private Remapper remapper; // the URL remapper + private List xmlrpc_methods; // the list of XML-RPC methods private StockMessages stock_messages; // the stock messages private Map menus; // the menus private DialogManager dialogs; // the dialog manager @@ -324,7 +326,7 @@ public class RootConfig implements LinkTypes, ColorSelectors for (i=0; i section. + sect = loader.configGetSubSection(root_h,"rpc"); + sect_h = new DOMElementHelper(sect); + + // Get the section. + sect1 = loader.configGetSubSection(sect_h,"xmlrpc-methods"); + nl = sect1.getChildNodes(); + ArrayList tmp_alist = new ArrayList(); + for (i=0; i element and use it to initialize a method + if (n.getNodeName().equals("method")) + tmp_alist.add(new XmlRpcMethod((Element)n)); + + } // end if + + } // end for + + if (tmp_alist.isEmpty()) + xmlrpc_methods = Collections.EMPTY_LIST; + else + { // save off the methods list + tmp_alist.trimToSize(); + xmlrpc_methods = Collections.unmodifiableList(tmp_alist); + + } // end else + // Get the section. sect = loader.configGetSubSection(root_h,"messages"); @@ -718,6 +749,12 @@ public class RootConfig implements LinkTypes, ColorSelectors } // end getDefaultServletAddress + public final List getXmlRpcMethods() + { + return xmlrpc_methods; + + } // end getXmlRpcMethods + /*-------------------------------------------------------------------------------- * Static initializer *-------------------------------------------------------------------------------- diff --git a/src/com/silverwrist/venice/ui/rpc/XmlRpcDispatch.java b/src/com/silverwrist/venice/ui/rpc/XmlRpcDispatch.java new file mode 100644 index 0000000..4935d19 --- /dev/null +++ b/src/com/silverwrist/venice/ui/rpc/XmlRpcDispatch.java @@ -0,0 +1,28 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +import java.util.Map; +import com.silverwrist.venice.ui.RequestInput; + +public interface XmlRpcDispatch +{ + public abstract Object dispatch(RequestInput req, XmlRpcRequest xreq, Map environment) + throws Exception, XmlRpcFault; + +} // end interface XmlRpcDispatch diff --git a/src/com/silverwrist/venice/ui/rpc/XmlRpcFault.java b/src/com/silverwrist/venice/ui/rpc/XmlRpcFault.java new file mode 100644 index 0000000..2da3e61 --- /dev/null +++ b/src/com/silverwrist/venice/ui/rpc/XmlRpcFault.java @@ -0,0 +1,123 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +import java.io.IOException; +import com.silverwrist.util.StringUtil; +import com.silverwrist.venice.ui.*; +import com.silverwrist.venice.ui.helpers.ThrowableContent; + +public class XmlRpcFault extends ThrowableContent implements ContentExecute +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + // Some "standard" XML-RPC error codes. + 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 DEFAULT_ERROR = 0; + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private int fault_code = DEFAULT_ERROR; + + /*-------------------------------------------------------------------------------- + * Constructors + *-------------------------------------------------------------------------------- + */ + + public XmlRpcFault(String msg) + { + super(msg); + + } // end constructor + + public XmlRpcFault(int code, String msg) + { + super(msg); + fault_code = code; + + } // end constructor + + public XmlRpcFault(Throwable t) + { + super(t); + + } // end constructor + + public XmlRpcFault(int code, Throwable t) + { + super(t); + fault_code = code; + + } // end constructor + + public XmlRpcFault(String msg, Throwable t) + { + super(msg,t); + + } // end constructor + + public XmlRpcFault(int code, String msg, Throwable t) + { + super(msg,t); + fault_code = code; + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Implementations from interface ContentExecute + *-------------------------------------------------------------------------------- + */ + + public void execute(RequestExec req) throws IOException + { + StringBuffer b = + new StringBuffer("\r\n\r\n\r\n" + + "faultCode\r\n"); + b.append(fault_code); + b.append("\r\n\r\n\r\nfaultString\r\n"); + b.append(StringUtil.encodeHTML(getMessage())); + b.append("\r\n\r\n\r\n"); + byte[] raw = b.toString().getBytes("UTF-8"); + req.sendBinary("text/xml",raw); + + } // end execute + + /*-------------------------------------------------------------------------------- + * External operations + *-------------------------------------------------------------------------------- + */ + + public final int getFaultCode() + { + return fault_code; + + } // end getFaultCode + +} // end class XmlRpcFault diff --git a/src/com/silverwrist/venice/ui/rpc/XmlRpcMethod.java b/src/com/silverwrist/venice/ui/rpc/XmlRpcMethod.java new file mode 100644 index 0000000..1855063 --- /dev/null +++ b/src/com/silverwrist/venice/ui/rpc/XmlRpcMethod.java @@ -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 . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +import java.util.*; +import org.apache.log4j.*; +import org.apache.regexp.*; +import org.w3c.dom.*; +import com.silverwrist.util.*; +import com.silverwrist.venice.except.*; +import com.silverwrist.venice.ui.*; +import com.silverwrist.venice.util.XMLLoader; + +public class XmlRpcMethod +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static Category logger = Category.getInstance(XmlRpcMethod.class); + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private REProgram method_pgm; // regular expression program to match method name + private String remap_value = null; // remap value + private Class obj_class = null; // "class" handler for object + private Map raw_env; // "raw" environment + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + public XmlRpcMethod(Element cfg) throws ConfigException + { + XMLLoader loader = XMLLoader.get(); + String method_name = loader.configGetAttribute(cfg,"name"); + try + { // compile the method name into a regular expression program + RECompiler comp = new RECompiler(); + method_pgm = comp.compile("^" + method_name + "$"); + + } // end try + catch (RESyntaxException rese) + { // not a valid regular expression program + logger.error("not a valid RE expression: " + method_name,rese); + throw new ConfigException("method name \"" + method_name + "\" not valid regular expression",cfg); + + } // end catch + + DOMElementHelper cfg_h = new DOMElementHelper(cfg); + Element sub; + + if ((sub = cfg_h.getSubElement("object"))!=null) + { // object handler element is present + DOMElementHelper sub_h = new DOMElementHelper(sub); + if (sub_h.hasAttribute("class")) + { // the class is valid - try and load it + try + { // load the class referenced by the handler + obj_class = Class.forName(sub.getAttribute("class")); + if (!(XmlRpcDispatch.class.isAssignableFrom(obj_class))) + throw new ConfigException("object handler class \"" + sub.getAttribute("class") + + "\" is not an XmlRpcDispatch class",sub); + + } // end try + catch (ClassNotFoundException cnfe) + { // class not found - bail out + throw new ConfigException("object handler class \"" + sub.getAttribute("class") + + "\" not found",sub); + + } // end catch + + } // end if + else // no referent for object handler - bail out now + throw new ConfigException("object handler for method \"" + "\" not valid",sub); + + } // end if + else // no handler - this is an error + throw new ConfigException("method \"" + method_name + "\" does not have a valid handler",cfg); + + NodeList nl = sub.getChildNodes(); + HashMap tmp_env = new HashMap(); + for (int i=0; i. + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +import java.io.*; +import java.util.*; +import javax.mail.*; +import javax.mail.internet.*; +import org.w3c.dom.*; +import com.silverwrist.util.*; +import com.silverwrist.venice.except.*; +import com.silverwrist.venice.util.XMLLoader; + +public class XmlRpcRequest +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static SimpleTimeZone utc = new SimpleTimeZone(0,"UTC"); + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + String method_name; // the method name + List method_params; // the method parameters + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + XmlRpcRequest(Document req_doc) throws XmlRpcFault + { + if (req_doc==null) + throw new XmlRpcFault(XmlRpcFault.INVALID_REQUEST,"no XML call structure found"); + + try + { + // load the initial structure and method name + XMLLoader loader = XMLLoader.get(); + Element root = loader.postGetRootElement(req_doc,"methodCall"); + DOMElementHelper root_h = new DOMElementHelper(root); + method_name = loader.postGetSubElementText(root_h,"methodName"); + + // parse the parameters + Element params = root_h.getSubElement("params"); + ArrayList tmp_method_params = new ArrayList(); + if (params!=null) + { // look for children of the node + NodeList nl = params.getChildNodes(); + for (int i=0; i node + if (!(n.getNodeName().equals("param"))) + throw new XmlRpcFault(XmlRpcFault.INVALID_REQUEST, + "non-param element found inside \"params\" element"); + tmp_method_params.add(parseValue(loader.postGetSubSection((Element)n,"value"))); + + } // end if + // else ignore this node + + } // end for + + } // end if + + // save the method parameters + if (tmp_method_params.isEmpty()) + method_params = Collections.EMPTY_LIST; + else + { // make it read-only before + tmp_method_params.trimToSize(); + method_params = Collections.unmodifiableList(tmp_method_params); + + } // end else + + } // end try + catch (ValidationException ve) + { // validation exceptions get translated to XML-RPC faults + throw new XmlRpcFault(XmlRpcFault.INVALID_REQUEST,ve); + + } // end catch + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Internal static operations + *-------------------------------------------------------------------------------- + */ + + private static final Object parseValue(Element val) throws ValidationException, XmlRpcFault + { + XMLLoader loader = XMLLoader.get(); + + // see if the value has an embedded type... + NodeList nl = val.getChildNodes(); + Element type = null; + for (int i=0; i elements within the element + Node n = nl.item(i); + if (n.getNodeType()==Node.ELEMENT_NODE) + { // make sure we've got a value element here! + if (!(n.getNodeName().equals("value"))) + throw new XmlRpcFault(XmlRpcFault.INVALID_REQUEST, + "non-value element found inside array \"data\" element"); + rc.add(parseValue((Element)n)); + + } // end if + + } // end for + + if (rc.isEmpty()) + return Collections.EMPTY_LIST; + else + { // trim the result array and return the list + rc.trimToSize(); + return Collections.unmodifiableList(rc); + + } // end else + + } // end parseArray + + private static final Map parseStruct(Element val) throws XmlRpcFault, ValidationException + { + XMLLoader loader = XMLLoader.get(); + NodeList nl = val.getChildNodes(); + HashMap rc = new HashMap(); + for (int i=0; i elements within a element + Node n = nl.item(i); + if (n.getNodeType()==Node.ELEMENT_NODE) + { // make sure we've got a value element here! + if (!(n.getNodeName().equals("member"))) + throw new XmlRpcFault(XmlRpcFault.INVALID_REQUEST, + "non-member element found inside \"struct\" element"); + DOMElementHelper h = new DOMElementHelper((Element)n); + String my_name = loader.postGetSubElementText(h,"name").trim(); + Element my_val = loader.postGetSubSection(h,"value"); + rc.put(my_name,parseValue(my_val)); + + } // end if + + } // end for + + if (rc.isEmpty()) + return Collections.EMPTY_MAP; + else + return Collections.unmodifiableMap(rc); + + } // end parseStruct + + /*-------------------------------------------------------------------------------- + * External operations + *-------------------------------------------------------------------------------- + */ + + public final String getMethod() + { + return method_name; + + } // end getMethod + + public final int getParamCount() + { + return method_params.size(); + + } // end getParamCount + + public final List getParams() + { + return method_params; + + } // end getParams + + public final Object getParam(int ndx) + { + return method_params.get(ndx); + + } // end getParam + +} // end class XmlRpcRequest diff --git a/src/com/silverwrist/venice/ui/rpc/XmlRpcSelfSerializer.java b/src/com/silverwrist/venice/ui/rpc/XmlRpcSelfSerializer.java new file mode 100644 index 0000000..c4194b9 --- /dev/null +++ b/src/com/silverwrist/venice/ui/rpc/XmlRpcSelfSerializer.java @@ -0,0 +1,24 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +public interface XmlRpcSelfSerializer +{ + public abstract String serializeXmlRpc() throws XmlRpcFault; + +} // end interface XmlRpcSelfSerializer diff --git a/src/com/silverwrist/venice/ui/rpc/XmlRpcSerializer.java b/src/com/silverwrist/venice/ui/rpc/XmlRpcSerializer.java new file mode 100644 index 0000000..2169bbd --- /dev/null +++ b/src/com/silverwrist/venice/ui/rpc/XmlRpcSerializer.java @@ -0,0 +1,471 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +import java.beans.*; +import java.io.*; +import java.lang.ref.*; +import java.lang.reflect.*; +import java.util.*; +import javax.mail.*; +import javax.mail.internet.*; +import org.apache.log4j.*; +import com.silverwrist.util.*; + +public class XmlRpcSerializer +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static Category logger = Category.getInstance(XmlRpcSerializer.class); + + private static XmlRpcSerializer self = null; + + private static SimpleTimeZone utc = new SimpleTimeZone(0,"UTC"); + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + private XmlRpcSerializer() + { // do nothing + } // end constructor + + /*-------------------------------------------------------------------------------- + * External operations + *-------------------------------------------------------------------------------- + */ + + public final String serialize(boolean b) + { + return "" + (b ? "1" : "0") + ""; + + } // end serialize + + public final String serialize(byte b) + { + return this.serialize((int)b); + + } // end serialize + + public final String serialize(char c) + { + return "" + c + ""; + + } // end serialize + + public final String serialize(double d) + { + return "" + d + ""; + + } // end serialize + + public final String serialize(float f) + { + return this.serialize((double)f); + + } // end serialize + + public final String serialize(int i) + { + return "" + i + ""; + + } // end serialize + + public final String serialize(long l) + { + return this.serialize((double)l); + + } // end serialize + + public final String serialize(short s) + { + return this.serialize((int)s); + + } // end serialize + + public final String serialize(Object obj) throws XmlRpcFault + { + if (obj==null) + return serializeString(null); + + // self-serializing objects + if (obj instanceof XmlRpcSelfSerializer) + return ((XmlRpcSelfSerializer)obj).serializeXmlRpc(); + + // types from java.io.* + if (obj instanceof InputStream) + return serializeInputStream((InputStream)obj); + + // types from java.sql.* + if (obj instanceof java.sql.Blob) + { // serialize the blob as a binary stream + try + { // just get its input stream + return serializeInputStream(((java.sql.Blob)obj).getBinaryStream()); + + } // end try + catch (java.sql.SQLException e) + { // fault on error here + throw new XmlRpcFault(XmlRpcFault.INTERNAL_ERROR,"unable to save binary data"); + + } // end catch + + } // end if + + // types from java.util.* + if (obj instanceof Calendar) + return serializeCalendar((Calendar)obj); + if (obj instanceof Collection) + return serializeCollection((Collection)obj); + if (obj instanceof java.util.Date) + return serializeDate((java.util.Date)obj); + if (obj instanceof Enumeration) + return serializeEnumeration((Enumeration)obj); + if (obj instanceof Iterator) + return serializeIterator((Iterator)obj); + if (obj instanceof Map) + return serializeMap((Map)obj); + + // types from java.lang.ref.* + if (obj instanceof Reference) // for a reference, encode its referent + return this.serialize(((Reference)obj).get()); + + // types from java.lang.* + if (obj instanceof Boolean) + return this.serialize(((Boolean)obj).booleanValue()); + if (obj instanceof Character) + return this.serialize(((Character)obj).charValue()); + if ((obj instanceof Byte) || (obj instanceof Short) || (obj instanceof Integer)) + return this.serialize(((Number)obj).intValue()); + if ((obj instanceof Long) || (obj instanceof Float) || (obj instanceof Double)) + return this.serialize(((Number)obj).doubleValue()); + // String and StringBuffer are handled properly by the fallback mechanism below + + // last-ditch fallback method - use toString, get the string, and encode it + return serializeString(obj.toString()); + + } // end serialize + + public final String serialize(boolean[] ba) + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize(ba[i])).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serialize(byte[] ba) throws XmlRpcFault + { + return this.serializeInputStream(new ByteArrayInputStream(ba)); + + } // end serialize + + public final String serialize(char[] ca) + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize(ca[i])).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serialize(double[] da) + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize(da[i])).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serialize(float[] fa) + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize((double)(fa[i]))).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serialize(int[] ia) + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize(ia[i])).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serialize(long[] la) + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize((double)(la[i]))).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serialize(short[] sa) + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize((int)(sa[i]))).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serialize(Object[] arr) throws XmlRpcFault + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + for (int i=0; i").append(this.serialize(arr[i])).append("\r\n"); + b.append("\r\n"); + return b.toString(); + + } // end serialize + + public final String serializeBean(Object obj, BeanInfo binf) throws XmlRpcFault + { + PropertyDescriptor[] props = binf.getPropertyDescriptors(); + StringBuffer b = new StringBuffer("\r\n"); + final Object[] no_params = new Object[0]; + for (int i=0; i\r\n").append(StringUtil.encodeHTML(props[i].getName())); + b.append("\r\n").append(this.serialize(mread.invoke(obj,no_params))); + b.append("\r\n\r\n"); + + } // end try + catch (IllegalAccessException iae) + { // unable to access that method + throw new XmlRpcFault(XmlRpcFault.INTERNAL_ERROR,iae); + + } // end catch + catch (InvocationTargetException ite) + { // the method we invoked threw an exception + throw new XmlRpcFault(XmlRpcFault.INTERNAL_ERROR,ite.getTargetException()); + + } // end catch + + } // end if + + } // end for + + b.append("\r\n"); + return b.toString(); + + } // end serializeBean + + public final String serializeBean(Object obj) throws XmlRpcFault + { + try + { // get the BeanInfo via introspection + return serializeBean(obj,Introspector.getBeanInfo(obj.getClass())); + + } // end try + catch (IntrospectionException e) + { // introspection failed + throw new XmlRpcFault(XmlRpcFault.INTERNAL_ERROR,e); + + } // end catch + + } // end serializeBean + + public final String serializeCalendar(Calendar cal) + { + // Create the two string buffers converting the date. + StringBuffer rc = new StringBuffer(""); + StringBuffer conv = new StringBuffer(); + String c; + + // Encode the year first. + conv.append("0000").append(cal.get(Calendar.YEAR)); + c = conv.toString(); + rc.append(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(); + rc.append(c.substring(c.length()-2)); + + // And the day... + conv.setLength(0); + conv.append("00").append(cal.get(Calendar.DAY_OF_MONTH)); + c = conv.toString(); + rc.append(c.substring(c.length()-2)).append('T'); + + // And the hour... + conv.setLength(0); + conv.append("00").append(cal.get(Calendar.HOUR_OF_DAY)); + c = conv.toString(); + rc.append(c.substring(c.length()-2)).append(':'); + + // And the minute... + conv.setLength(0); + conv.append("00").append(cal.get(Calendar.MINUTE)); + c = conv.toString(); + rc.append(c.substring(c.length()-2)).append(':'); + + // And the second... + conv.setLength(0); + conv.append("00").append(cal.get(Calendar.SECOND)); + c = conv.toString(); + rc.append(c.substring(c.length()-2)).append(""); + + // This is the resulting date/time value. + return rc.toString(); + + } // end serializeCalendar + + public final String serializeCollection(Collection coll) throws XmlRpcFault + { + return serializeIterator(coll.iterator()); + + } // end serializeCollection + + public final String serializeDate(java.util.Date date) throws XmlRpcFault + { + GregorianCalendar cal = new GregorianCalendar(utc); + cal.setTime(date); + return serializeCalendar(cal); + + } // end serializeDate + + public final String serializeEnumeration(Enumeration enum) throws XmlRpcFault + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + while (enum.hasMoreElements()) + b.append("").append(this.serialize(enum.nextElement())).append(""); + b.append("\r\n"); + return b.toString(); + + } // end serializeIterator + + public final String serializeInputStream(InputStream stm) throws XmlRpcFault + { + String rc = null; + + try + { // convert the data bytes to encoded bytes first + ByteArrayOutputStream internal_stm = new ByteArrayOutputStream(); + OutputStream encode_stm = MimeUtility.encode(internal_stm,"base64"); + IOUtil.copy(stm,encode_stm); + encode_stm.flush(); + + // turn our encoded output into an InputStream + ByteArrayInputStream internal2_stm = new ByteArrayInputStream(internal_stm.toByteArray()); + IOUtil.shutdown(encode_stm); + IOUtil.shutdown(internal_stm); + + // build a StringWriter containing the converted contents + StringWriter wr = new StringWriter(); + wr.write(""); + InputStreamReader rd = new InputStreamReader(internal2_stm,"US-ASCII"); + IOUtil.copy(rd,wr); + IOUtil.shutdown(rd); + IOUtil.shutdown(internal2_stm); + wr.write(""); + + // send out the complete string + rc = wr.toString(); + IOUtil.shutdown(wr); + + } // end try + catch (IOException ioe) + { // this is an internal error + throw new XmlRpcFault(XmlRpcFault.INTERNAL_ERROR,"unable to save binary data"); + + } // end catch + catch (MessagingException me) + { // and so is this + throw new XmlRpcFault(XmlRpcFault.INTERNAL_ERROR,"unable to encode binary data"); + + } // end catch + + return rc; + + } // end serializeInputStream + + public final String serializeIterator(Iterator it) throws XmlRpcFault + { + StringBuffer b = new StringBuffer("\r\n\r\n"); + while (it.hasNext()) + b.append("").append(this.serialize(it.next())).append(""); + b.append("\r\n"); + return b.toString(); + + } // end serializeIterator + + public final String serializeMap(Map m) throws XmlRpcFault + { + StringBuffer b = new StringBuffer("\r\n"); + Iterator it = m.entrySet().iterator(); + while (it.hasNext()) + { // serialize each entry in turn + Map.Entry ntry = (Map.Entry)(it.next()); + b.append("\r\n").append(StringUtil.encodeHTML(ntry.getKey().toString())); + b.append("\r\n").append(this.serialize(ntry.getValue())); + b.append("\r\n\r\n"); + + } // end while + + b.append("\r\n"); + return b.toString(); + + } // end serializeMap + + public final String serializeString(String s) + { + if (s==null) + return ""; + return "" + StringUtil.encodeHTML(s) + ""; + + } // end serializeString + + /*-------------------------------------------------------------------------------- + * External static operations + *-------------------------------------------------------------------------------- + */ + + public static final synchronized XmlRpcSerializer get() + { + if (self==null) + self = new XmlRpcSerializer(); + return self; + + } // end get + +} // end class XmlRpcSerializer diff --git a/src/com/silverwrist/venice/ui/rpc/XmlRpcServlet.java b/src/com/silverwrist/venice/ui/rpc/XmlRpcServlet.java new file mode 100644 index 0000000..a5ceae1 --- /dev/null +++ b/src/com/silverwrist/venice/ui/rpc/XmlRpcServlet.java @@ -0,0 +1,198 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +import java.io.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import org.apache.regexp.*; +import com.silverwrist.util.*; +import com.silverwrist.venice.core.*; +import com.silverwrist.venice.ui.*; +import com.silverwrist.venice.ui.config.RootConfig; +import com.silverwrist.venice.ui.servlet.BaseServlet; +import com.silverwrist.venice.ui.servlet.RequestImpl; + +public class XmlRpcServlet extends BaseServlet +{ + /*-------------------------------------------------------------------------------- + * Inner class that implements the actual "normal" return value + *-------------------------------------------------------------------------------- + */ + + static class XmlRpcReturnValue implements ContentExecute + { + private Object obj; + + XmlRpcReturnValue(Object obj) + { + this.obj = obj; + + } // end constructor + + public void execute(RequestExec req) throws IOException + { + StringBuffer b = + new StringBuffer("\r\n\r\n"); + try + { // serialize the returned object + XmlRpcSerializer serializer = XmlRpcSerializer.get(); + b.append(serializer.serialize(obj)); + + } // end try + catch (XmlRpcFault f) + { // if we get a fault here, just execute THAT instead + f.execute(req); + return; + + } // end catch + + b.append("\r\n\r\n"); + byte[] raw = b.toString().getBytes("UTF-8"); + req.sendBinary("text/xml",raw); + + } // end execute + + } // end class XmlRpcReturnValue + + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static final String METHOD_LIST_ATTR = "ui.xmlrpc.MethodList"; + + public static final String OBJECT_CLASS_CACHE_ATTR = "ui.xmlrpc.class.ObjectCache"; + + /*-------------------------------------------------------------------------------- + * Overrides from class BaseServlet + *-------------------------------------------------------------------------------- + */ + + protected void init(ServletConfig config, ServletContext ctxt, VeniceEngine engine, RootConfig root, + String root_file_path) + { + List methods = root.getXmlRpcMethods(); + RequestImpl.setAppAttribute(ctxt,METHOD_LIST_ATTR,methods); + RequestImpl.setAppAttribute(ctxt,OBJECT_CLASS_CACHE_ATTR,Collections.synchronizedMap(new HashMap())); + + } // end init + + protected VeniceUISessionFactory getSessionFactory() + { + return NullSession.get(); // null session by default + + } // end getSessionFactory + + protected Object translateServletException(RequestInput ri, Exception e) + { + return null; + + } // end translateServletException + + public Object process(RequestInput req) + { + XmlRpcRequest xreq; + try + { // get the XML-RPC request structure + xreq = new XmlRpcRequest(req.getRequestDocument()); + + } // end try + catch (XmlRpcFault f) + { // return the fault structure + return f; + + } // end catch + + // Prepare the parameters map + int i; + HashMap param_repl_map = new HashMap(); + for (i=0; i. + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.rpc; + +import java.util.*; +import com.silverwrist.venice.ui.*; + +public class XmlRpcTestHandler implements XmlRpcDispatch +{ + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + public XmlRpcTestHandler() + { // do nothing + } // end constructor + + /*-------------------------------------------------------------------------------- + * Implementations from interface XmlRpcDispatch + *-------------------------------------------------------------------------------- + */ + + public Object dispatch(RequestInput req, XmlRpcRequest xreq, Map environment) throws Exception, XmlRpcFault + { + if (xreq.getMethod().equals("venice:test.sumDifference")) + { // do the sumdifference API + if (xreq.getParamCount()!=2) + throw new XmlRpcFault(XmlRpcFault.INVALID_PARAMS,"parameter count mismatch"); + + Integer n1, n2; + try + { // cast parameters to Integer + n1 = (Integer)(xreq.getParam(0)); + n2 = (Integer)(xreq.getParam(1)); + + } // end try + catch (ClassCastException e) + { // class cast exception! + throw new XmlRpcFault(XmlRpcFault.INVALID_PARAMS,"parameter type mismatch"); + + } // end catch + + HashMap rc = new HashMap(); + rc.put("sum",new Integer(n1.intValue() + n2.intValue())); + rc.put("difference",new Integer(n1.intValue() - n2.intValue())); + return rc; + + } // end if + + return null; + + } // end dispatch + +} // end class XmlRpcTestHandler diff --git a/src/com/silverwrist/venice/ui/servlet/BaseServlet.java b/src/com/silverwrist/venice/ui/servlet/BaseServlet.java index 1d00e7c..4cd2f54 100644 --- a/src/com/silverwrist/venice/ui/servlet/BaseServlet.java +++ b/src/com/silverwrist/venice/ui/servlet/BaseServlet.java @@ -11,7 +11,7 @@ * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are - * Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ @@ -34,6 +34,38 @@ import com.silverwrist.venice.ui.script.ScriptManagerContainer; public abstract class BaseServlet extends HttpServlet { + /*-------------------------------------------------------------------------------- + * Internal session factory object + *-------------------------------------------------------------------------------- + */ + + static class HttpSessionFactory implements VeniceUISessionFactory + { + private static final String ATTR_NAME = VeniceUISession.class.getName(); + + HttpSessionFactory() + { // do nothing + } // end constructor + + public VeniceUISession createSession(ServletContext ctxt, HttpServletRequest request, + HttpServletResponse response, VeniceEngine engine, + RootConfig config) throws ServletException + { + HttpSession session = request.getSession(true); + VeniceUISession rc = (VeniceUISession)(session.getAttribute(ATTR_NAME)); + if (rc==null) + { // return a new session + rc = new HttpVeniceUISession(request,session,engine); + session.setAttribute(ATTR_NAME,rc); + + } // end if + + return rc; + + } // end createSession + + } // end class HttpSessionFactory + /*-------------------------------------------------------------------------------- * Static data members *-------------------------------------------------------------------------------- @@ -49,6 +81,8 @@ public abstract class BaseServlet extends HttpServlet private static Category logger = Category.getInstance(BaseServlet.class); + private static VeniceUISessionFactory factory = new HttpSessionFactory(); + /*-------------------------------------------------------------------------------- * Internal operations *-------------------------------------------------------------------------------- @@ -56,14 +90,16 @@ public abstract class BaseServlet extends HttpServlet private Object translateException(RequestInput req, Exception e) { + // try the servlet first + Object rc = translateServletException(req,e); + if (rc!=null) + return rc; + + // otherwise, go it alone logger.info("BaseServlet.translateException translating exception",e); if (e instanceof ScriptingException) return new ErrorBox("Scripting Error",e,null); - // Last-ditch effort: get the specific servlet to translate the exception. - Object rc = translateServletException(req,e); - if (rc!=null) - return rc; return new ErrorBox("Unhandled Exception Detected!",e.toString(),e,null); } // end translateException @@ -77,13 +113,41 @@ public abstract class BaseServlet extends HttpServlet try { // create the actual request implementation ServletContext ctxt = getServletContext(); - RequestImpl the_request = - new RequestImpl(ctxt,request,response,(VeniceEngine)(ctxt.getAttribute(ENGINE_ATTRIBUTE)), - (RootConfig)(ctxt.getAttribute(UICONFIG_ATTRIBUTE))); + RequestImpl the_request = null; + try + { // create the request object + the_request = new RequestImpl(ctxt,request,response, + (VeniceEngine)(ctxt.getAttribute(ENGINE_ATTRIBUTE)), + (RootConfig)(ctxt.getAttribute(UICONFIG_ATTRIBUTE)), + getSessionFactory()); + + } // end try + catch (ValidationException ve) + { // error in formatting of the request - bug out + response.sendError(HttpServletResponse.SC_BAD_REQUEST,ve.toString()); + return; + + } // end catch + String default_location = the_request.getLocation(); // log the username with all log messages, if the user is logged in - boolean record_user = the_request.getUser().isLoggedIn(); + boolean record_user = false; + if (the_request.sessionBound()) + { // has the session been bound? + try + { // find out whether they're logged in + record_user = the_request.getUser().isLoggedIn(); + + } // end try + catch (IllegalStateException e) + { // if not, just forget about it + record_user = false; + + } // end catch + + } // end if + if (record_user) NDC.push(the_request.getUser().getUserName()); @@ -176,6 +240,12 @@ public abstract class BaseServlet extends HttpServlet { // default does nothing } // end init + protected VeniceUISessionFactory getSessionFactory() + { + return factory; + + } // end getSessionFactory + protected Object translateServletException(RequestInput ri, Exception e) { return null; // does nothing by default diff --git a/src/com/silverwrist/venice/ui/servlet/HttpVeniceUISession.java b/src/com/silverwrist/venice/ui/servlet/HttpVeniceUISession.java new file mode 100644 index 0000000..51c8b34 --- /dev/null +++ b/src/com/silverwrist/venice/ui/servlet/HttpVeniceUISession.java @@ -0,0 +1,206 @@ +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at . + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is the Venice Web Communities System. + * + * The Initial Developer of the Original Code is Eric J. Bowersox , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.ui.servlet; + +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import org.apache.log4j.*; +import com.silverwrist.venice.core.*; +import com.silverwrist.venice.except.*; +import com.silverwrist.venice.ui.*; + +class HttpVeniceUISession implements VeniceUISession +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static final String SESSION_ATTRIBUTE_STEM = "venice.vars."; + + private static Category logger = Category.getInstance(HttpVeniceUISession.class); + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private HttpSession session; + private UserContext user; + private Cookie venice_cookie = null; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + HttpVeniceUISession(HttpServletRequest request, HttpSession session, VeniceEngine engine) + throws ServletException + { + this.session = session; // save off the session variable + try + { // tell the engine to create us a user context + user = engine.createUserContext(request.getRemoteAddr()); + + // Did the user send a Venice authentication cookie? If so, try to use it. + Cookie[] cookies = request.getCookies(); + Cookie venice_cookie = null; + for (int i=0; (venice_cookie==null) && (i, * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are - * Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ @@ -39,6 +39,7 @@ import com.silverwrist.venice.ui.menus.CommunityMenu; import com.silverwrist.venice.ui.menus.Menu; import com.silverwrist.venice.ui.menus.MenuComponent; import com.silverwrist.venice.ui.script.*; +import com.silverwrist.venice.util.XMLLoader; public class RequestImpl implements RequestInput { @@ -553,9 +554,6 @@ public class RequestImpl implements RequestInput private static final String STYLESHEET_ATTRIBUTE = "com.silverwrist.venice.rendering.StyleSheet"; private static final String APP_ATTRIBUTE_STEM = "com.silverwrist.venice.ui.variables."; - private static final String USERCTXT_ATTRIBUTE = "user.context"; - private static final String SESSION_ATTRIBUTE_STEM = "venice.vars."; - public static final String REQUEST_CONTENT = "com.silverwrist.venice.ui.Content"; public static final String REQUEST_INPUT = "com.silverwrist.venice.ui.RequestInput"; public static final String REQUEST_OUTPUT = "com.silverwrist.venice.ui.RequestOutput"; @@ -569,10 +567,9 @@ public class RequestImpl implements RequestInput private ServletContext ctxt; // the servlet context private HttpServletRequest request; // the servlet request data private HttpServletResponse response; // the servlet response data - private HttpSession session; // the current HTTP session + private VeniceUISession session; // the current HTTP session private VeniceEngine engine; // the Venice engine context private RootConfig config; // the UI configuration data - private UserContext user; // the current user context private ServletMultipartHandler mphandler = null; // if this is a multipart/form-data POST private ArrayList new_cookies = null; // cookies to be added to the response private boolean end_response = true; // do we need to properly end the response? @@ -585,6 +582,7 @@ public class RequestImpl implements RequestInput private DateFormat activity_time = null; // format to use for activity string times private CommunityContext community = null; // the current community private LinkedList auto_cleanup = null; // auto-cleanup callbacks + private Document request_doc = null; // request parsed as an XML document /*-------------------------------------------------------------------------------- * Constructor @@ -592,94 +590,88 @@ public class RequestImpl implements RequestInput */ RequestImpl(ServletContext ctxt, HttpServletRequest request, HttpServletResponse response, - VeniceEngine engine, RootConfig config) throws ServletException + VeniceEngine engine, RootConfig config, VeniceUISessionFactory factory) + throws ServletException, ValidationException { // Set up the basic variables. this.ctxt = ctxt; this.request = request; this.response = response; - this.session = request.getSession(true); this.engine = engine; this.config = config; - // Create or retrieve the user context. - user = (UserContext)(session.getAttribute(USERCTXT_ATTRIBUTE)); - if (user==null) - { // the user context isn't present yet + if (request.getMethod().equals("POST")) + { // POSTs can have special handling for the request data + if (request.getContentType().startsWith("text/xml")) + { // this is some sort of XML-based request - parse it into a DOM tree + XMLLoader loader = XMLLoader.get(); + try + { // load the document + request_doc = loader.loadPostData(request.getInputStream()); // may throw ValidationException + + } // end try + catch (IOException ioe) + { // IO exception...sigh + logger.error("IO error loading request document",ioe); + throw new ServletException("IO error loading request document: " + ioe.toString(),ioe); + + } // end catch + + } // end if + else if (ServletMultipartHandler.canHandle(request)) + { // if this is a multipart/form-data POST, create the handler object + try + { // use the multipart handler and get something + mphandler = new ServletMultipartHandler(request); + + } // end try + catch (ServletMultipartException smpe) + { // unable to parse POST data for some reason + logger.error("Multipart data acquisition failed: " + smpe.getMessage(),smpe); + throw new ValidationException("invalid multipart request: " + smpe.getMessage(),smpe); + + } // end catch + + } // end else if + + } // end if + + // Create the UI session. + session = factory.createSession(ctxt,request,response,engine,config); + session.preprocess(this); + + if (!(session instanceof NullSession)) + { // read the user's preferred locale try - { // tell the engine to create us a user context - user = engine.createUserContext(request.getRemoteAddr()); - - // Did the user send a Venice authentication cookie? If so, try to use it. - Cookie[] cookies = request.getCookies(); - Cookie venice_cookie = null; - for (int i=0; (venice_cookie==null) && (i document (actual root tag: <" + + rc.getTagName() + "/>)"); + throw new ValidationException("root element is not \"" + expected_name + "\""); + + } // end postGetRootElement + public final String configGetText(DOMElementHelper h) throws ConfigException { String rc = h.getElementText(); @@ -189,7 +200,7 @@ public class XMLLoader logger.fatal("<" + h.getElement().getTagName() + "/> has no value"); throw new ConfigException("no data value found in <" + h.getElement().getTagName() + "/>",h.getElement()); - } // end configGetSubElementText + } // end configGetText public final String configGetText(Element elt) throws ConfigException { @@ -208,12 +219,29 @@ public class XMLLoader } // end configGetSubElementText + public final String postGetSubElementText(DOMElementHelper h, String elt_name) throws ValidationException + { + String rc = h.getSubElementText(elt_name); + if (rc!=null) + return rc; // we're OK + logger.fatal("<" + h.getElement().getTagName() + "/> has no <" + elt_name + "/> element"); + throw new ValidationException("no \"" + elt_name + "\" element found in \"" + + h.getElement().getTagName() + "\""); + + } // end postGetSubElementText + public final String configGetSubElementText(Element elt, String subelt_name) throws ConfigException { return configGetSubElementText(new DOMElementHelper(elt),subelt_name); } // end configGetSubElementText + public final String postGetSubElementText(Element elt, String subelt_name) throws ValidationException + { + return postGetSubElementText(new DOMElementHelper(elt),subelt_name); + + } // end postGetSubElementText + public final Element configGetSubSection(DOMElementHelper h, String sect_name) throws ConfigException { Element rc = h.getSubElement(sect_name); @@ -225,12 +253,29 @@ public class XMLLoader } // end configGetSubElementText + public final Element postGetSubSection(DOMElementHelper h, String sect_name) throws ValidationException + { + Element rc = h.getSubElement(sect_name); + if (rc!=null) + return rc; // we're OK + logger.fatal("<" + h.getElement().getTagName() + "/> has no <" + sect_name + "/> element"); + throw new ValidationException("no \"" + sect_name + "\" element found in \"" + + h.getElement().getTagName() + "\""); + + } // end postGetSubSection + public final Element configGetSubSection(Element sect, String subsect_name) throws ConfigException { return configGetSubSection(new DOMElementHelper(sect),subsect_name); } // end configGetSubSection + public final Element postGetSubSection(Element sect, String subsect_name) throws ValidationException + { + return postGetSubSection(new DOMElementHelper(sect),subsect_name); + + } // end postGetSubSection + public final void configVerifyNodeName(Node n, String name, Element enclosing_sect) throws ConfigException { if (n.getNodeName().equals(name))