|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThe scope of this article is to introduce the basics of XML-RPC communication by demonstrating an application written in Visual C# .NET and Java. The application is a self running demonstration using features of the The downloadable source code provided includes the example application. I am using Visual Studio .NET 2003 with Framework SDK 1.1 to create this example. Pre-RequisitesThis article assumes the reader to have j2sdk1.4.2 (At least j2sdk1.4) and .NET Framework SDK 1.1 installed on his machine. This application also uses two separate XML-RPC libraries for communication. These libraries are provided as a part of the download for convenience purposes only. Any related documentation for these libraries can be obtained from the website URLs provided in the References section.
What is XML-RPC?XML-RPC is a set of implementations (per XML-RPC specification) that allow software running on disparate operating systems in different environments to make procedure calls over the Internet. It uses Remote Procedure Calls using HTTP as the transport and XML as the encoding. XML-RPC is designed to be as simple as possible while allowing complex data structures to be transmitted, processed and returned. Let us now look at some of the basic features of XML-RPC used for developing the example demonstration. Although XML-RPC is typically used to communicate between two different machines running in disparate environments via HTTP; This article demonstrates a client running on the same machine as the server but making use of a feature offered by the Java programming language to develop automated testing applications. An XML-RPC message is a HTTP-POST request, the body of which should be well-formed XML. A procedure executes on the server and returns a value formatted in XML. Parameters supplied to the method can be scalars, numbers, strings, dates, etc. and list structures. Following is the format of a simple XML-RPC request which is sent by the client to the server for execution. POST /RPC2 HTTP/1.0 // RPC2 Responder
User-Agent: Home/5.00.21 (Win2K) // Required
Host: www.roundsquare.com // Required
Content-Type: text/xml
Content-length: 204 // Required and should be correct
<?xml version="1.0"?> // XML payload
<methodCall>
<methodName>robot.click</methodName> // Name of the method to invoke
<params> // Required element if parameters have to be supplied
<param> // Parameter containing a value element
<value><int>400</int>
</value> // Element specifying the type and corresponding value
</param>
<param> // Multiple parameters are possible
<value><int>200</int></value>
</param>
</params>
</methodCall>
Following is a response to an XML-RPC request which the server generates upon method execution. A HTTP/1.1 200 OK // Always return 200 OK unless there is a lower level error
Connection: close
Content-Length: 151 // Required and should be correct
Content-Type: text/xml
Date: Mon, 22 Sep 2003 19:55:08 GMT
Server: Tuff Home/5.00.21-Win2K
<?xml version="1.0"?> // XML payload
<methodResponse>
<params>
<param> // Single return value
<value>
<string>Clicked</string>
</value> // Element specifying the type and value
</param>
</params>
</methodResponse>
A Quick Look at the java.awt.Robot ClassTo quote from the Java 2 Platform, Standard Edition, v 1.4.2 API Specification "This class is used to generate native system input events for the purposes of test automation, self-running demos, and other applications where control of the mouse and keyboard is needed. The primary purpose of Robot is to facilitate automated testing of Java platform implementations e.g. Let us look at some of the important methods of this class some of which are used by our application. Refer to the Java documentation for more details.
Wrapping the RobotHaving looked at the methods on the // Package
package com.robot;
// Robot wrapper to provide functionality to Auto-Run applications
public class AutoRunner {
{
/** The Robot instance */
private static Robot ROBOT;
/** Initialize the Robot */
static {
try {
ROBOT = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
}
/** Type the specified text at the current screen location */
public String type(String s) {
char[] keys = s.toCharArray();
for (int i = 0; i < keys.length; i++) {
type(keyCodes(keys[i]));
}
return "Typed";
}
/** Click the left mouse button at the specified screen location */
public String click(int x, int y) {
ROBOT.mouseMove(x, y); // Mouse Move
ROBOT.mousePress(InputEvent.BUTTON1_MASK); // Mouse Press
ROBOT.mouseRelease(InputEvent.BUTTON1_MASK); // Mouse Release
return "Clicked";
}
/**
* Type the codes provided. Multiple codes can result
* if the character is uppercase
* or special e.g. SHIFT + a (A) or SHIFT + 2 (@)
*
* param code An array of key codes.
*/
private void type(int[] code) {
int count = code.length;
int pos = 0;
// Keep the first key pressed in case of multiple codes
while (count > 1 && pos < count - 1) {
ROBOT.keyPress(code[pos++]);
}
ROBOT.keyPress(code[pos]); // Key Press
ROBOT.keyRelease(code[pos]); // Key Release
// Release the pressed key
while (count > 1 && pos > 0) {
ROBOT.keyRelease(code[--pos]);
}
}
/**
* Maps the specified character to key code acceptable
* to the Robot. The keys
* are mapped corresponding to the code from the
* java.awt.event.KeyEvent associated
* with the SHIFT key (if necessary).
*
* @param key the character code to be converted.
*
* @return the array of key codes. If the character
* is uppercase or special,
* the first code returned in the array is the SHIFT key.
*/
private int[] keyCodes(char key) {...}
/**
* Maps the specified character to key code
* acceptable to the Robot. This key
* can be directly mapped to the code from
* the java.awt.event.KeyEvent class.
*
* @param key the character code to be converted.
*
* @return the corresponding code mapped from the
* java.awt.event.KeyEvent class.
*/
private int keyCode(char key) {...}
}
Writing the XML-RPC Server and Client
The client is written using Visual C# .NET platform while the server is implemented using the Java programming language. The client will invoke RPC on the server using XML-RPC for interacting with the UI. The server will parse these requests and translate them into appropriate user actions. XML-RPC ServerThe code for the // Import the necessary class from the library
import marquee.xmlrpc.handlers.ReflectiveInvocationHandler;
// Extend the marquee.xmlrpc.handlers.ReflectiveInvocationHandler
public class AutoRunner extends ReflectiveInvocationHandler {...}
Creating a server is pretty straightforward as shown below. An instance of XML-RPC calls to the server will be parsed and corresponding methods on the registered object (if found) will be invoked using Java Reflection e.g. Sending a request with the name of the method as try {
// Create a new XML-RPC server
XmlRpcServer server = new XmlRpcServer();
// Register the AutoRunner object as robot to handle client requests
server.registerInvocationHandler("robot", new AutoRunner());
// Start the server on port 1971
server.runAsService(1971);
} catch(Exception e) {
e.printStackTrace();
}
XML-RPC ClientThe namespace Robot
{
public class AutoRunForm : System.Windows.Forms.Form
{
// Members
// Auto run the application. Invoked using the
// Activated event on the form
private void AutoRun(DemoData data)
{
// Create the endpoint proxy object
RobotProxy proxy = new RobotProxy();
// Connect to the port 1971 where the XML-RPC server is running
proxy.Url = "http://localhost:1971";
// Timeout if the connection fails
proxy.Timeout = 3000;
// Click on the Name TextBox
ClickControl(proxy, this.Username);
// Enter username in the Name TextBox
proxy.Type(data.username);
}
// Perform a mouse click on the specified control
private void ClickControl(RobotProxy proxy, Control control)
{
// Locate the screen position of the control
int x = control.RectangleToScreen(control.ClientRectangle).Left;
int y = control.RectangleToScreen(control.ClientRectangle).Top;
// Perform the mouse click using RPC through the proxy
proxy.Click(x, y);
}
}
}
Please refer to the CookComputing documentation for details about mapping .NET data types to XML-RPC types. A proxy can be created using CookComputing XML-RPC library in two ways as described below.
We will use the latter technique in our example application. // Attribute to denote the URL on which the XML-RPC server is running.
[XmlRpcUrl(null)]
// Define the interface for the proxy object to be created.
public interface IRobotProxy
{
// Attribute used to specify that a method is being
// exposed as an XML-RPC method.
// The name of this method will be used for the RPC
// if the default constructor for
// XmlRpcMethod is used.
[XmlRpcMethod("robot.click")]
public string Click(int x, int y);
}
using CookComputing.XmlRpc;
// Create the proxy object
IRobotProxy proxy = (IRobotProxy) XmlRpcProxyGen.Create(typeof(IRobotProxy));
OR
// URL is specified during server startup
[XmlRpcUrl(null)]
// Alternative technique
public class RobotProxy : XmlRpcClientProtocol
{
// The method name here has to match the registered name on the server
// Since we have registered the AutoRunner with the name robot, using
// robot.click will invoke the click method on
// the instance of AutoRunner
[XmlRpcMethod("robot.click")]
public string Click(int x, int y)
{
// The first argument to invoke has to be the name of this method
// and not the remote method. The parameters that
// need to be passed are
// supplied as an array of objects. The return value
// corresponds to whatever
// is returned by the server invocation.
return (string)Invoke("Click", new object[] {x, y});
}
}
Running the ApplicationFollow the procedure below to run the example application.
An Attempt to run the client without starting the XML-RPC server results in a message box displaying "The operation has timed out." message. Closing NoteAdditional methods to press special keys such as Function (F1, F2 etc.), Alt or Ctrl keys can be incorporated into the wrapper. Java is a registered trademark of Sun Microsystems. References/Links
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||