You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xmlrpc-auto@ws.apache.org by jo...@apache.org on 2010/02/16 22:59:40 UTC
svn commit: r910716 - in /webservices/xmlrpc/trunk: pom.xml
src/changes/changes.xml src/site/apt/advanced.apt
src/site/apt/handlerCreation.apt src/site/fml/faq.fml src/site/site.xml
Author: jochen
Date: Tue Feb 16 21:59:35 2010
New Revision: 910716
URL: http://svn.apache.org/viewvc?rev=910716&view=rev
Log:
Added example documentation on request processor creation.
Submitted-By: Teemu Kanstren <tk...@gmail.com>
Added:
webservices/xmlrpc/trunk/src/site/apt/handlerCreation.apt
Modified:
webservices/xmlrpc/trunk/pom.xml
webservices/xmlrpc/trunk/src/changes/changes.xml
webservices/xmlrpc/trunk/src/site/apt/advanced.apt
webservices/xmlrpc/trunk/src/site/fml/faq.fml
webservices/xmlrpc/trunk/src/site/site.xml
Modified: webservices/xmlrpc/trunk/pom.xml
URL: http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/pom.xml?rev=910716&r1=910715&r2=910716&view=diff
==============================================================================
--- webservices/xmlrpc/trunk/pom.xml (original)
+++ webservices/xmlrpc/trunk/pom.xml Tue Feb 16 21:59:35 2010
@@ -195,6 +195,10 @@
<email>Catalin.Hritcu@gmail.com</email>
</contributor>
<contributor>
+ <name>Teemu Kanstren</name>
+ <email>tkanstren@gmail.com</email>
+ </contributor>
+ <contributor>
<name>Brad Karp</name>
<email>bkarp@cs.ucl.ac.uk</email>
</contributor>
Modified: webservices/xmlrpc/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/src/changes/changes.xml?rev=910716&r1=910715&r2=910716&view=diff
==============================================================================
--- webservices/xmlrpc/trunk/src/changes/changes.xml (original)
+++ webservices/xmlrpc/trunk/src/changes/changes.xml Tue Feb 16 21:59:35 2010
@@ -23,6 +23,12 @@
<title>Changes in Apache XML-RPC</title>
</properties>
<body>
+ <release version="3.1.4" date="Not yet released">
+ <action dev="jochen" type="add" due-to="Teemu Kanstren" due-to-email="tkanstren@gmail.com">
+ Added example documentation on request processor creation.
+ </action>
+ </release>
+
<release version="3.1.3" date="2010-Feb-06">
<action dev="jochen" type="fix">
The version number in the clients user agent string is now
Modified: webservices/xmlrpc/trunk/src/site/apt/advanced.apt
URL: http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/src/site/apt/advanced.apt?rev=910716&r1=910715&r2=910716&view=diff
==============================================================================
--- webservices/xmlrpc/trunk/src/site/apt/advanced.apt (original)
+++ webservices/xmlrpc/trunk/src/site/apt/advanced.apt Tue Feb 16 21:59:35 2010
@@ -287,4 +287,30 @@
}
}
-----------------------------------------------------------------------------------
-
\ No newline at end of file
+
+* Handler creation
+
+ Handlers are POJO's created by the XML-RPC server, which are called to serve
+ requests. By default, a new instance is created for any request.
+
+ While this makes sense for most cases, it doesn't fit others.
+
+ * The model doesn't support stateful handlers.
+
+ * Request can be slow, if handler initialization is expensive. In that
+ case a pool of reusable request handlers would be required.
+
+ * Access to shared resources can be difficult.
+
+ The solution is to implement a factory for handlers, which means implementing
+ an instance of
+ {{{apidocs/org/apache/xmlrpc/server/RequestProcessorFactoryFactory}RequestProcessorFactoryFactory}}.
+ The default implementation is a
+ {{{apidocs/org/apache/xmlrpc/server/RequestProcessorFactoryFactory.RequestSpecificProcessorFactoryFactory}RequestSpecificProcessorFactoryFactory}}:
+ It creates a new instance for any request.
+ An alternative implementation is the
+ {{{apidocs/org/apache/xmlrpc/server/RequestProcessorFactoryFactory.StatelessProcessorFactoryFactory}StatelessProcessorFactoryFactory}},
+ which creates a singleton instance upon startup and uses this singleton for
+ all requests.
+
+ A good example is given in {{{handlerCreation.html}another document}}.
Added: webservices/xmlrpc/trunk/src/site/apt/handlerCreation.apt
URL: http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/src/site/apt/handlerCreation.apt?rev=910716&view=auto
==============================================================================
--- webservices/xmlrpc/trunk/src/site/apt/handlerCreation.apt (added)
+++ webservices/xmlrpc/trunk/src/site/apt/handlerCreation.apt Tue Feb 16 21:59:35 2010
@@ -0,0 +1,239 @@
+~~
+~~
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements. See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership. The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied. See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+~~
+ -------------------------------
+ Custom Request Handler Creation
+ -------------------------------
+
+Custom Request Handler Creation
+
+ By default, Apache XML-RPC creates a new object for processing each request
+ received at the server side. For example, in the Calculator example, each
+ time a new request is received, a new Calculator object is created to handle
+ the request. This has some advantages such as requiring no built-in
+ synchronization mechanisms inside the processor class. On the other hand, in
+ many cases it is necessary to share some state between the requests or
+ access non-static resources inside the host application. Some of this can
+ be addressed by use of static resources (e.g. Singleton design pattern) but
+ this can complicate code. Further, it gets even more complicated to handle
+ this when several XML-RPC servers need to be started inside one JVM, each
+ expecting unique state, or when request specific processing and state is
+ needed based on some request parameter values. Effectively addressing these
+ types of scenarios requires having custom control over the creation of the
+ processor objects. With Apache XML-RPC, this is supported by extending the
+ org.apache.xmlrpc.server.RequestProcessorFactoryFactory class.
+
+ Consider the following example of an Echo service. We have a simple service
+ interface that we want to invoke called EchoService and its implementation:
+
+------------------------------------------------------------------
+ public interface EchoService {
+ public void echo(String msg);
+ }
+
+ public class EchoServiceImpl implements EchoService {
+ private volatile int index = 1;
+
+ public void echo(String msg) {
+ System.out.println(index+": "+msg);
+ index++;
+ }
+ }
+------------------------------------------------------------------
+
+ To invoke this service over XML-RPC we need a server to accept incoming
+ requests. We call this the EchoServer:
+
+
+
+------------------------------------------------------------------
+ public class EchoServer {
+ public static void main(String[] args) throws Exception {
+ WebServer webServer = new WebServer(8080);
+ XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();
+ PropertyHandlerMapping phm = new PropertyHandlerMapping();
+ phm.setVoidMethodEnabled(true);
+ phm.addHandler(EchoService.class.getName(), EchoServiceImpl.class);
+ xmlRpcServer.setHandlerMapping(phm);
+
+ XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl)
+ xmlRpcServer.getConfig();
+
+ serverConfig.setEnabledForExtensions(true);
+ serverConfig.setContentLengthOptional(false);
+ webServer.start();
+ }
+ }
+------------------------------------------------------------------
+
+ Finally, we need a client application to invoke the server. Lets call this
+ EchoClient.
+
+------------------------------------------------------------------
+ public class EchoClient {
+ public static void main(String[] args) throws Exception {
+ XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
+ config.setServerURL(new URL("http://127.0.0.1:8080/xmlrpc"));
+ config.setEnabledForExtensions(true);
+ config.setConnectionTimeout(60 * 1000);
+ config.setReplyTimeout(60 * 1000);
+ XmlRpcClient client = new XmlRpcClient();
+ client.setConfig(config);
+ ClientFactory factory = new ClientFactory(client);
+ EchoService echo = (EchoService) factory.newInstance(EchoService.class);
+ echo.echo("Hello");
+ echo.echo("World");
+ }
+ }
+------------------------------------------------------------------
+
+ Now we start first the EchoServer and the the EchoClient. The output is:
+
+------------------------------------------------------------------
+ 1: Hello
+
+ 1: World
+------------------------------------------------------------------
+
+ This is because the following happens by default:
+
+ * Client calls <<<echo.echo("Hello");>>>
+
+ * A new EchoServiceImpl object is created by the server to handle the
+ request. This is initialized with <<<index = 1>>>, the call is made,
+ "1: Hello" is printed and the object is garbage-collected.
+
+ * Client calls <<<echo.echo("World");>>>
+
+ * A new EchoServiceImpl object is created by the server to handle the
+ request. This is initialized with <<<index = 1>>>, the call is made,
+ "1: World" is printed and the object is garbage-collected.
+
+ []
+
+ What we would like to see as output is
+
+------------------------------------------------------------------
+ 1: Hello
+
+ 2: World
+------------------------------------------------------------------
+
+ To make this happen, we create a new class to create the processor
+ (EchoServiceImpl) objects. Lets call this EchoRequestProcessorFactoryFactory:
+
+------------------------------------------------------------------
+ public class EchoRequestProcessorFactoryFactory implements
+ RequestProcessorFactoryFactory {
+ private final RequestProcessorFactory factory =
+ new EchoRequestProcessorFactory();
+ private final EchoService echo;
+
+ public EchoRequestProcessorFactoryFactory(EchoService echo) {
+ this.echo = echo;
+ }
+
+ public RequestProcessorFactory getRequestProcessorFactory(Class aClass)
+ throws XmlRpcException {
+ return factory;
+ }
+
+ private class EchoRequestProcessorFactory implements RequestProcessorFactory {
+ public Object getRequestProcessor(XmlRpcRequest xmlRpcRequest)
+ throws XmlRpcException {
+ return echo;
+ }
+ }
+ }
+------------------------------------------------------------------
+
+ Now we need to take this factory into use. To do this we modify the server
+ to create the factory and the EchoService object the factory will serve.
+
+
+------------------------------------------------------------------
+ public class EchoServer {
+ public static void main(String[] args) throws Exception {
+ WebServer webServer = new WebServer(8080);
+ XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();
+ PropertyHandlerMapping phm = new PropertyHandlerMapping();
+ EchoService echo = new EchoServiceImpl();
+ phm.setRequestProcessorFactoryFactory(new EchoRequestProcessorFactoryFactory(echo));
+ phm.setVoidMethodEnabled(true);
+ phm.addHandler(EchoService.class.getName(), EchoService.class);
+ xmlRpcServer.setHandlerMapping(phm);
+
+ XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
+ serverConfig.setEnabledForExtensions(true);
+ serverConfig.setContentLengthOptional(false);
+ webServer.start();
+ }
+ }
+------------------------------------------------------------------
+
+ Re-running the example now with the new server and the old client we get the
+ following output:
+
+------------------------------------------------------------------
+ 1: Hello
+
+ 2: World
+------------------------------------------------------------------
+
+
+ This is because all invocations will now share the same non-static
+ implementation object of EchoServiceImpl. This can access non-static
+ objects if so configured and share state between requests.
+
+ Thats it for customizing the creation of processor objects. It is possible
+ to customize the process in different ways, such as selecting a different
+ processor based on request parameters, starting several servers with
+ different processors or whatever. Through the processor objects it is also
+ possible to access any non-static state of the overall system itself.
+
+ It is also possible to have the factory check if it is asked for the factory
+ for Echo class or something else, and resort to the default Apache XML-RPC
+ factory in these cases. In the example this is not needed as only the Echo
+ class is registered and supported.
+
+* ABSTRACTION
+
+ Using custom processor object factories can have a benefit from abstraction
+ perspective as well. An additional change is also visible in the modified
+ server above that was not yet discussed. This is the use of the interface
+ class in the definition of the PropertyHandler:
+
+------------------------------------------------------------------
+ phm.addHandler(EchoService.class.getName(), EchoService.class);
+------------------------------------------------------------------
+
+ This allows one to more clearly parameterize the server with the processor
+ object to be given to the factory as any implementation of the interface.
+ With the default implementation giving an interface as a second parameter to
+ the <<<addHandler()>>> call will result in an exception such as
+
+------------------------------------------------------------------
+ org.apache.xmlrpc.XmlRpcException:
+ Failed to instantiate class fi.vtt.noen.mfw.echo.EchoService.
+------------------------------------------------------------------
+
+ For the customized factory this is not a problem. With the default implementation it
+ is still possible to parameterize this through the service class type but
+ the interface approach can make for cleaner code. This can be useful, for
+ example, for unit testing with services stubs.
Modified: webservices/xmlrpc/trunk/src/site/fml/faq.fml
URL: http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/src/site/fml/faq.fml?rev=910716&r1=910715&r2=910716&view=diff
==============================================================================
--- webservices/xmlrpc/trunk/src/site/fml/faq.fml (original)
+++ webservices/xmlrpc/trunk/src/site/fml/faq.fml Tue Feb 16 21:59:35 2010
@@ -222,6 +222,8 @@
}
</source>
+ <p>A good example on creating request processors is given in
+ <a href="handlerCreation.html">this document</a>.</p>
</answer>
</faq>
Modified: webservices/xmlrpc/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/webservices/xmlrpc/trunk/src/site/site.xml?rev=910716&r1=910715&r2=910716&view=diff
==============================================================================
--- webservices/xmlrpc/trunk/src/site/site.xml (original)
+++ webservices/xmlrpc/trunk/src/site/site.xml Tue Feb 16 21:59:35 2010
@@ -48,6 +48,7 @@
<item name="SSL" href="/ssl.html"/>
<item name="Introspection" href="/introspection.html"/>
<item name="Advanced Techniques" href="/advanced.html"/>
+ <item name="Handler Creation" href="/handlerCreation.html"/>
<item name="XML-RPC Types" href="/types.html"/>
<item name="FAQ" href="/faq.html"/>
<item name="Javadocs" href="/apidocs/index.html"/>