Developer Resources:

Customer Quotes:

Introduction

This articles describes approach and the sample code for invoking client side ActionScript functions from the server application code. The example requires WebORB Enterprise Edition and also works in the product's development mode. The functionality is based on the real-time messaging (RTMP) implementation, it uses a dedicated connection between the client and server.

Running the Client Application

Below is a live instance of the example. Start multiple clients using the link below. As you open/close browser windows with the client application, connections to the server are established and torn down. The server informs all connected clients via a server-to-client invocation:

Open additional client(s) in a new window

Getting Started - WebORB Application Overview

A messaging application on the server-side must be represented through a directory under the /Applications folder. The directory may contain application configuration. Additionally, WebORB stores application instances (rooms) , shared objects and streams.

Application custom logic must reside in the application handler class. The class must implement the Weborb.Messaging.Api.IScopeHandler interface or can extend the Weborb.Messaging.Server.Adapter.ApplicationAdapter class (recommended).

Application handler receives the following callbacks from the WebORB server:

public virtual bool appStart( IScope app );
public virtual bool appStop( IScope app );

public virtual bool roomStart( IScope room );
public virtual void roomStop( IScope room );

public virtual bool appConnect( IConnection conn, Object[] parms );
public virtual bool roomConnect( IConnection conn, Object[] parms );

public virtual
void appDisconnect( IConnection conn );
public virtual void roomDisconnect( IConnection conn );

public virtual bool appJoin( IClient client, IScope app );
public virtual void appLeave( IClient client, IScope app );

public virtual bool roomJoin( IClient client, IScope room );
public virtual void roomLeave( IClient client, IScope room );

Suppose your application needs to notify other connected clients when a new client joins or leaves the application. The notification can be done as an invocation of the client side ActionScript function. The code below demonstrates the API:

using System;
using System.Collections.Generic;
using System.Text;

using Weborb.Messaging.Api;
using Weborb.Messaging.Api.Service;
using Weborb.Messaging.Server.Adapter;

namespace Weborb.Examples.ClientCallback
{
  public class AppHandler : ApplicationAdapter
  {
    public override bool appConnect( IConnection conn, object[] parms )
    {
      // get the connections for the scope (scope comes from the base class)
      IEnumerator<IConnection> connections = scope.getConnections();
      Object[] args = new Object[] { conn.getClient().getId() };

      // iterate over the connections

      while( connections.MoveNext() )
      {
        IConnection connection = connections.Current;

        // invoke client side function via the client connection
        if( connection is IServiceCapableConnection )
          ((IServiceCapableConnection)connection).invoke( "clientConnected",
                                                          args
);
      }

      //notify client about his ID
      if( conn is IServiceCapableConnection )
        ((IServiceCapableConnection)conn).invoke( "setClientID", args );

      return true;
    }

    public override void appDisconnect( IConnection conn )
    {
      IEnumerator<IConnection> connections = scope.getConnections();
      Object[] args = new Object[] { conn.getClient().getId() };

      while( connections.MoveNext() )
      {
       IConnection connection = connections.Current;

       if( connection is IServiceCapableConnection )
        ((IServiceCapableConnection)connection).invoke( "clientDisonnected",
                                                       
args
);
      }
    }
  }
}

Download full source code listing here.

Compile the application handler class and place it into the WebORB's /bin folder. If WebORB runs inside of IIS, the /bin folder is the same where all class libraries for the given ASP.NET application are deployed. If WebORB runs standalone, the /bin folder is where weborb.dll resides.

Create "CallbackDemo" folder under /Applications. The name of the folder will be used in the client code to connect to the application. Place app.config into /Applications/CallbackDemo. The file must contain the following contents:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <application-handler>   
     Weborb.Examples.ClientCallback.AppHandler
  </application-handler>
</configuration>

The server side of the application is ready.

Developing Flex/ActionScript Code

The client side for this example uses Flex, however the same approach is applicable to the Flash applications.

Create a Flex Builder project as described in this article. The approach is to use the NetConnection api to establish a connection to the WebORB server. When the client establishes a connection, WebORB invokes the appConnect method used in the C# example above. Similarly, when a client disconnects from the application, WebORB invokes the appDisconnect method on the associated handler class.

The code below shows how to establish a connection with WebORB:

private var m_connection:NetConnection;

public function InitConnection() : void
{
  var uri:String = ServerConfig.getChannel( "my-rtmp" ).endpoint;
  m_connection = new NetConnection();
  m_connection.client = this;
  m_connection.objectEncoding = ObjectEncoding.AMF0;
  m_connection.addEventListener( NetStatusEvent.NET_STATUS, handleNetStatus );
  m_connection.connect( uri + "/CallbackDemo" );
}

Add a creationComplete handler for your application and wire it up with the InitConnection() method as shown below:

<mx:Application
     xmlns:mx="http://www.adobe.com/2006/mxml"
     layout="absolute"
     xmlns:local="*"
     creationComplete="InitConnection()" >
....
....
</mx:Application>

When you run the client, it connects to the "CallbackDemo" application. The next step is to add the functions invoked from the server:

public function setClientID( myID:String ) : void
{
   // log event somewhere
}

public function clientConnected( clientID:String ) : void
{
   // log event somewhere
}

public function clientDisconnected( clientID:String ) : void
{
  // log event somewhere
}

Below is a full MXML markup for the sample application:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="absolute" width="351" height="351"
   creationComplete="InitConnection()" >
   <mx:Script>
    <![CDATA[
      import mx.messaging.config.ServerConfig;
      private var m_connection:NetConnection;

      public function InitConnection() : void
      {
        var uri:String = ServerConfig.getChannel( "my-rtmp" ).endpoint;
        m_connection = new NetConnection();
        m_connection.client = this;
        m_connection.objectEncoding = ObjectEncoding.AMF0;
        m_connection.connect( uri + "/CallbackDemo" );
      }

      public function setClientID( myID:String ):void
      {
        clientID.text = myID;
      }

      public function clientConnected( clientID:String ) : void
      {
        output.text = "Client connected - " + clientID + "\n" + output.text;
      }

      public function clientDisconnected( clientID:String ) : void
      {
        output.text = "Client disconnected - " + clientID + "\n" + output.text;
      }
      ]]>
   </mx:Script>

  <mx:Panel x="10" y="10"
            width="331" height="331" layout="absolute"
            title="Server to client callback demo">
    <mx:Label x="10" y="19" text="Client ID:"/>
    <mx:Text x="77" y="19" id="clientID"/>
    <mx:TextArea x="10" y="72" width="291" height="209" id="output"/>
    <mx:Label x="10" y="49" text="Events:"/>
  </mx:Panel>
</mx:Application>

Source Code