Set up a basic command

Commands are simple requests sent from a client for the service to execute a given function. For example, you could use a command to request the service to clear the screen, take a screenshot, or save the user's name. Commands are event-based.

This section describes how to set up basic commands. It's a straightforward process. On the service, you register a handler so that the service will know which function to run on receiving the command, and you define this handler. On the client, you simply send the command.

In this section, we show simple commands with no optional arguments; for more advanced examples, see Work with command parameters and Work with command callbacks.

Steps

Register a handler on the service

APIs:

CommandManager.AddUiHandler() | C++ | .Net | Java
CommandManager.AddIoHandler() | C++ | .Net | Java

Before a client can send a command, a handler for that command must be registered on the service. Registering a command handler consists of a single line of code which gives the command a unique name, and associates a handling function that the service will run when it receives the command.

The unique name given to the command during registration is used by clients when sending that command.

Command handlers are usually registered on the UI thread (using the AddUiHandler method), but it's also possible to register them on the I/O thread (AddIoHandler).

 

The IO thread is intended for internal use by the APIs, but you do have the option of using this thread to handle something not directly related with the UI if it suits your needs. If you do register commands on both threads, keep in mind that order of commands is guaranteed on the individual threads, but not between threads.

You cannot add two separate handlers for the same command. If you do, only the last handler will be fired.

To ensure that all commands are correctly caught and handled by the service application, command handlers should be added early on in the program initialization. Similarly, they should be removed early in the termination of the service application (the APIs provide RemoveUiHandler and RemoveIoHandler methods).

In the snippets below, we chose the name "NiftyCommand"; when the service receives this command, it will run the corresponding handling function, which we named "OnReceivingNiftyCommand".

C++

MyApp::StateManager().CommandManager().AddUiHandler("NiftyCommand", Bind(this, &MyClass::OnReceivingNiftyCommand));

.Net

MyProgram.StateManager.CommandManager.AddUiHandler("NiftyCommand", OnReceivingNiftyCommand);

Java

stateManager.getCommandManager().addUiHandler("NiftyCommand", new OnReceivingNiftyCommand());

Define the handler

The syntax for the handler itself (the function that will be triggered by the command) requires three objects as arguments, all of which are automatically created and managed by PureWeb: sessionId (the unique identifier of the session that issued the command), command, and responses.

The command and responses are XML objects, represented in the native XML data type for the programming language: Typeless (C++), XElement (C#) or Element (Java).

The handler's syntax will look something like this:

C++

void MyApp::OnReceivingNiftyCommand(Guid sessionId, Typeless command, Typeless& responses)
{
    // Do something useful
}

.Net

void OnReceivingNiftyCommand(Guid sessionId, XElement command, XElement responses)
{
    // Do something useful
}

Java

private class OnReceivingNiftyCommand implements CommandHandler
    public void invoke(UUID sessionID, Element command, Element responses)
    {
        // Do something useful
    }


Send a command from the client

APIs:

WebClient.queueCommand() | HTML5 | Android
PWWebClient.queueCommand() | iOS

In the client application, commands are sent to the service using the queueCommand method. The only mandatory argument is the command name.

Optionally, you can also specify key-value pairs as additional command parameters, and a callback.

  The command name provided in queueCommand must match exactly the name as it was registered on the service, otherwise the command will not be handled.

In the snippets below, the client sends a command called "NiftyCommand".

HTML5

pureweb.getClient().queueCommand('NiftyCommand');

iOS (Obj-C)

[[PWFramework sharedInstance].client queueCommand:@"NiftyCommand"];

Android

framework.getWebClient().queueCommand("NiftyCommand");			

Example

Clearing the canvas in Scribble

All versions of the sample Scribble application provide end users with a means to clear the screen. For example, in the HTML5 client, there is an Erase All button for this, while in the Android client, there is a Clear function available from the menu. This functionality is achieved through the use of a PureWeb command.

On the service

C++

The line below registers the command handler; the command is given the name "Clear", and its associated handling function is called "OnExecuteClear".

CScribbleApp::StateManager().CommandManager().AddUiHandler("Clear", Bind(this, &CScribbleView::OnExecuteClear));

The OnExecuteClear function is defined to clear the screen. In this instance, the necessary code is implemented directly in the function:

void CScribbleView::OnExecuteClear(Guid sessionId, Typeless command, Typeless responses)
{
    CBrush br(RGB(255,255,255));
    m_dcOffscreen.SelectObject(&br);
    CRect rect(0,0,m_Width,m_Height);
    CBrush *pbr = &br;
    m_dcOffscreen.FillRect(&rect,pbr);
    m_startpt = -1;
}			

.Net

The line below registers the command handler; the command is given the name "Clear", and its associated handling function is called "OnExecuteClear".

Program.StateManager.CommandManager.AddUiHandler("Clear", OnExecuteClear);

The OnExecuteClear function is defined to clear the screen. In this instance, there is already an existing ClearStrokes function for this purpose elsewhere in the code, and so the command handler simply calls it:

private void OnExecuteClear(Guid sessionId, XElement command, XElement responses)
{
    ClearStrokes();
}

The ClearStrokes function is what actually clears the screen:

private void ClearStrokes()
{
    EndStroke();
    m_strokes.Clear();
    if (m_offscreen != null)
    {
        Graphics.FromImage(m_offscreen).Clear(Color.Black);
    }
}

Java

The line below registers the command handler; the command is given the name "Clear", and its associated handling function is called "OnExecuteClear".

stateManager.getCommandManager().addUiHandler("Clear", new OnExecuteClear());

The OnExecuteClear function is defined to clear the screen.

private class OnExecuteClear implements CommandHandler
{
    public void invoke(UUID sessionID, Element command, Element responses)
    {
        erase();
        repaint();
    }
}										

On the client

HTML5

In the user interface, there is an Erase All button, which calls the clearCanvas() method when clicked:

<button onclick="clearCanvas();">Erase All</button>

The clearCanvas() method queues the "Clear" command that was earlier registered on the service:

function clearCanvas() {
    pureweb.getClient().queueCommand("Clear");
}

iOS (Obj-C)

In the user interface, there is a Clear button connected (using XCode's Interface Builder) to an action called clearButtonPressed; this action defines the button's behavior when the end user taps on it.

The clearButtonPressed action queues the "Clear" command that was earlier registered on the service:

- (IBAction)clearButtonPressed:(UIBarButtonItem *)sender
{
    [self.scribbleView.framework.client queueCommand:@"Clear"];
}

Android

The user interface provides a menu, where one of the options is the "clear" menu item:

public boolean onPrepareOptionsMenu(Menu menu) {
    boolean connected = framework.getWebClient().isConnected();
    menu.findItem(R.id.clear).setEnabled(connected);
    menu.findItem(R.id.change_color).setEnabled(connected);
    menu.findItem(R.id.share).setEnabled(connected);
    return true;
}

This menu item, when selected, queues the "Clear" command that was earlier registered on the service:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
         case R.id.clear:
            framework.getWebClient().queueCommand("Clear");
            view.refresh();
            return true;