Categories

Archives

Integrating Native Android with .NET via Publish/Subscribe API

A few days ago we published an example demonstrating .NET data push to a native iPhone application. In that example the backend service was a .NET application hosted in WebORB for .NET. The application used WebORB as an RTMP server to deliver real-time updates to the client devices. In addition to the RTMP clients (like an iOS devices or cialis without prescription Flex apps), a slightly modified version of the same code can easily support clients connecting via publish/subscribe API. An example of a such client can be a native Android application using our client-side library. We put together a native Android application and extended the server-side code to support publish/subscribe clients. The video below demonstrates the example in action and provides a brief code review. The instructions for setting up and running the example follow the video.

Follow the steps below to deploy and run the example:

  1. Download and install the latest version of WebORB for .NET. (This post assumes the product is installed in the default installation directory. For the version 4.4, the installation directory is: c:/Program Files/WebORB for .NET/4.4.0.0/)
  2. Download the client-side project from:
    http://examples.themidnightcoders.com/blog/StockExchangeAndroidClient.zip
  3. Download the server-side project from:
    http://examples.themidnightcoders.com/blog/StockExchangeWithPubSub-server.zip
  4. Open the server-side project in Visual Studio. Compile the project and make sure the compiled assembly is copied into the /bin folder in the WebORB installation directory (c:/Program Files/WebORB for .NET/4.4.0.0/bin)
  5. Open messaging-config.xml from c:/Program Files/WebORB for .NET/4.4.0.0/WEB-INF/flex in a text editor.
  6. Add the following XML block before the closing </service> tag:
    <br />
      &lt;destination id=&quot;StockExchangeDestination&quot;&gt;<br />
        &lt;properties&gt;<br />
          &lt;server&gt;<br />
            &lt;durable&gt;false&lt;/durable&gt;<br />
          &lt;/server&gt;<br />
          &lt;message-service-handler&gt;Weborb.Messaging.PubSub.Memory.MessagingServiceHandler&lt;/message-service-handler&gt;<br />
          &lt;message-storage-policy&gt;Weborb.Messaging.PubSub.Memory.MemoryStoragePolicy&lt;/message-storage-policy&gt;<br />
        &lt;/properties&gt;<br />
        &lt;channels&gt;<br />
          &lt;channel ref=&quot;my-polling-amf&quot; /&gt;<br />
        &lt;/channels&gt;<br />
      &lt;/destination&gt;<br />
    
  7. Create “StockExchange” directory under the “Applications” folder located at: c:/Program Files/WebORB for .NET/4.4.0.0/Applications)
  8. Create the app.config file in the StockExchange directory with the following contents:
    <br />
    &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;<br />
    &lt;configuration&gt;<br />
    &lt;application-handler&gt;StockExchange.AppHandler&lt;/application-handler&gt;<br />
    &lt;/configuration&gt;<br />
    
  9. Compile and run the Android project. Once the client application runs enter the WebORB remoting endpoint URL (for example for the local installation it may be http://localhost/weborb4/weborb.aspx). Click the ‘Connect’ button to establish a connection with the server-side application.

.NET Data Push to iPhone application

One of my most favorite features in the Communication Library for iOS is the support for server-side data push to iOS. We put together an example demonstrating the feature in action where a .NET server pushes real-time updates to an iPhone application. The example is demonstrated and reviewed in the video below. The instructions for running the example and the links for the source code are available below the video in this blog post. Enjoy!

Follow the steps below to deploy and run the example:

  1. Download and install the latest version of WebORB for .NET. (This post assumes the product is installed in the default installation directory. For the version 4.4, the installation directory is: c:/Program Files/WebORB for .NET/4.4.0.0/)
  2. Download the client-side project from:
    http://examples.themidnightcoders.com/blog/StockExchangeClient.zip
    (for additional examples, you can also  download the Communication Library for iOS).
  3. Download the server-side project from:
    http://examples.themidnightcoders.com/blog/StockExchange-server.zip
  4. Open the server-side project in Visual Studio. Compile the project and make sure the compiled assembly is copied into the /bin folder in the WebORB installation directory (c:/Program Files/WebORB for .NET/4.4.0.0/)
  5. Create “StockExchange” directory under the “Applications” folder located at: c:/Program Files/WebORB for .NET/4.4.0.0/Applications)
  6. Create the app.config file in the StockExchange directory with the following contents:
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    <application-handler>StockExchange.AppHandler</application-handler>
    </configuration>
    
  7. Open the WebORB Management Console. Switch to the ‘Messaging Server’ tab and make sure the StockExchange application is listed under the Applications node in the tree.
  8. Run the iOS client application, enter the hostname for the server where WebORB for .NET is running and click Connect to establish a connection with the server-side application.

Integrating native iOS applications with Flash Media Server

The Communication Library for iOS which we have recently released enables developers to integrate native iPhone and iPad applications with various server-side technologies. Since the library implements the RTMP protocol, it can easily connect the iOS applications with any RTMP-enabled media server. One of the most popular media servers is Adobe Flash Media Server. The video below provides an overview of the integration. Specifically, it demonstrates ability to do invocations of the server-side ActionScript running in FMS from the iOS apps using the library. Additionally, there is an example of the FMS data push implemented as an invocation of the client-side Objective-C functions from the code running in FMS.

In addition to the features reviewed in the video, the same library supports Remote Shared Objects. Currently, the integration enables data messaging, but we’re also working on adding support for video and audio broadcast and server-side recording. This new functionality will enable any iOS application to broadcast or record video stream from the device’s camera and audio from the microphone.

Enjoy!

Follow the steps below to configure your own FMS installation to run the same examples:

  1. Download and install Flash Media Server
  2. Create “CallbackDemo” folder under [FMS-INSTALL]/applications
  3. Download and extract CallbackDemo-servercode.zip into [FMS-INSTALL]/applications/CallbackDemo
  4. Create “MethodInvocation” folder under [FMS-INSTALL]/applications
  5. Download and extract MethodInvocation-servercode.zip into [FMS-INSTALL]/applications/MethodInvocation
  6. Download Communication Library for iOS, extract and the examples and open the examples project in XCode

New samples fro WebORB Messaging

I’ve posted three new samples for WebORB Messaging. Each is designed to show how to set up and use a given feature in the most basic way, so that you can get started easily.

  1. Simple text chat: Shows instances of the same client-side app sharing information using a Remote Shared Object.
  2. Even simpler text chat: Shows instances of the same client-side app sharing information using Publish-Subscribe.
  3. Data Push: Server CPU Usage via Remote Shared Object (RSO): Shows server-side code pushing data to (any client) using a Remote Shared Object.

Happy coding!

:)

New samples: WebORB Data Management (WDM) for Flex (WDMF)

Most of these samples are minor variations of our CEO Mark Piller’s previous WDMF samples, which were installed with WebORB 4.x for .NET. These new versions include minor bug fixes, additional comments, and (most importantly) they are hosted on our Internet server, so that anyone, anywhere, can run them. Each sample has a descriptive web page, including a list of pre-requisites, key points, things to try, references, and links to any related screencasts.

The new samples are:

All of the samples share the same FoodAndDrinks database on our Web server, and so do all users. That’s realistic, but it also means that if you add a record to the database, it’s there fore everyone else to see, too. Likewise, if you delete a record (or all of the records), it will be deleted from the common database. We expect to deal with this by refreshing the database daily, but still…please play nicely.

If you’re using WebORB for .NET, but you’re not yet using WDM for Flex despite needing to access server-side data, then I encourage you to check out the first sample (at least). Watch its screencast and see what you’re missing.

Whee! :)

WebORB for .NET Remoting: even more samples

Here are six new samples, each describing a single aspect of Remoting (that is, the use of remote procedure calls) from a Flex client to a .NET service using WebORB 4.x for .NET. The name of each sample, below, links to a descriptive Web page, in which the running sample is embedded, and from which code (for both client and server) can be downloaded.

Custom serializer

Binding data grid to array result

Collection mapping with WebORBArrayCollection (class)

Collection mapping with IWebORBArrayCollection (interface)

ReturnType of DataTable’s records*

ReturnType of DataSet’s records*

With these basic Remoting samples out of the way, I’m going to switch my focus over to creating more WDMF samples.

Happy coding!   :)

— Jim

* At the time I posted these samples, the samples marked with an asterisk didn’t work, because I couldn’t update a DLL on the Midnight Coders’ “examples” server. When I can update the DLL, I’ll verify that the samples are working, and remove this comment.

WebORB for .NET Remoting: more samples

Gentlepersons,

I’ve recently posted nine more new samples on basic remoting (that is, making remote procedure calls) from Flex clients to .NET services using WebORB for .NET 4.x.

Each sample is accompanied by a web page that

  • describes the sample,
  • lists its key points,
  • lists things to try for yourself,
  • provides links to that sample’s code,
  • provides references to relevant documentation and supporting information,
  • embeds the running sample, and
  • embeds any screencasts that walk through the sample.

I have not yet made screencasts for these new samples, however.

These nine new samples, while still very basic, should be studied only after the four “Hello, World!” samples are understood, because those samples present the most basic fundamentals of using WebORB.

Here are the nine new samples:

Each sample’s web page has a section labeled “Errata,” describing known problems with the samples…so please let me know if you find any errors in them (jim@themidnightcoders.com).

BTW, a previous blog post, announcing the first of our new samples/screencasts, have emerged as a top result when using Google to search for “WebORB”. That’s encouraging.

Thanks!

— Jim :)

“Hello, World!” screencast

Below, please find the screencast version of this “Hello, World!” blarticle.

It’s not the spiffiest screencast I’ve ever seen. I made it using TechSmith’s Camtasia, which has far more features than I know how to use. As I learn more about Camtasia, these screencasts will improve accordingly. Lots of new stuff to learn!

Whee!   ;-)

Hello, World!

My first WebORB for .NET app, as is traditional, simply displays the message “Hello, World!” — but with a client/server twist.

The server side code is implemented as a C# class library:

using System;
using System.Web;

namespace HelloWorldServer
{
    public class HelloWorldService
    {
        public string getHelloString()
        {
            return "Hello, World!";
        }
    }
}

Compiling that in VisualStudio 2008 produces an assembly called “HelloWorldServer.dll”, at \Visual Studio 2008\Projects\samples\HelloWorldServer\HelloWorldServer\bin\Debug.

[Why VisualStudio 2008 instead of VisualStudio's new, über-cool 2010 version? Because, as a former Microsoft employee, I can buy Visual Studio 2010 Professional super-cheap through the Microsoft Company Store...but it's on back-order there now. Until it's back in stock, I'll stick with the older version.]

One way to make this service available to WebORB for .NET clients is to copy the service’s DLL into WebORB’s \bin directory. For my installation, that’s C:\Program Files\WebORB for .NET\4.0.0.5\bin; your mileage may vary, depending on where you’ve installed WebORB for .NET and what version you have installed.

To verify that the service is exposed properly, I can then launch WebORB for .NET’s management console,
…click in its SERVICES tab,
…click on .NET Assemblies, and click through to the method getHelloString(), which is exposed by WebORB for .NET as a service.

Note that the console’s Test Drive tab is selected, exposing (among other things) a button labelled “Invoke”. In the list control at the left of the screen, select the getHelloString() method. Then, click on the “Invoke” button to invoke getHelloString().

As you can see, the “Name,” “Type,” and “Value” columns’ first row contain, respectively,

  • “Result” (the name of getHelloString()’s result),
  • “String” (the type of getHelloString()’s result), and
  • “Hello, World!” (the value of getHelloString()’s result).

This simple test verifies that:

  • getHelloString() is deployed where WebORB for .NET can find it, and
  • getHelloString() is returning the value I intended (that is, “Hello, World!”).

…which is a good “reality check” before starting to work on the client-side code.

Now, in the DEPLOYED ASSEMBLIES area on the upper-left corner of the console, go up one level to select HelloWorldService.

This automatically selects the console’s “Generate Code” tab, which, IMHO, is one of the coolest features of WebORB, because it can save an incredible amount of time writing, testing, and debugging code.

It’s not just that WebORB generates code for you; it’s not just that generating code saves you time; and it’s not just that time is money, so that using generated code saves you money — although all of that is true, and important. Even more important, however, is that the generated code encapsulates years of experience in client/server software development. Every time The Midnight Coders’ resident geniuses figure out how to handle another kind of bug, that handling goes into the code generator, so that you don’t have to deal with it yourself.

I’m not saying that WebORB generates perfect code; not at all. Indeed, this blarticle will expose a significant imperfection in WebORB’s code generation….but not quite yet.

Look at the right-hand side of the console. It should look like the image at right. Note that, of the set of “Code format/style” radio buttons, the one for “Flex Remoting/AS3″ is selected, indicating that Flex-compatible code will be generated. Try selecting other radio buttons. The generated code, shown in the middle of the console, changes to reflect the “Code format/style” radio button currently selected, changes as you select different radio buttons.

Below the stack of radio buttons is another UI section, entitled “Generated code structure:”. It lists the folder(s) and files(s) that can be generated. Select one file, and you’ll see its code appear in the console’s central box. Select a different file, and its code will appear in that box instead.

Now, you could just copy the generated code out of that box and then paste it into your own project. That would be pretty cool. In this blarticle, however, we’re going to do something even cooler.

First, make sure that the “Flex Remoting/AS3″ radio button is selected. Next, look right below the stack of radio buttons. See the checkbox labelled “Generate project files”? Click on it, so that it is checked. Now, press the “Download Code” button.

Windows will throw up a “File Download” dialog, asking you to select the location at which to save the file “weborb.codegen.zip”. Save it wherever is convenient (once you unzip it, you can throw it away, so it doesn’t much matter where you save it).


Now comes the fun part. Open up Flex Builder 4, and in the “File” menu, choose “Import…”. That will bring up the Import screen shown at left.

Find the entry named “Flash Builder”, as highlighted at left. Click on the little ‘+’-sign to its left to reveal more choices.

Select “Flash Builder Project”, as highlighted at right.

Press the “Next” button and you’ll be taken to the “Import Flash Builder Project” screen, shown below.

Wow, these images are really overwhelming this blarticle.  I like to use lots of graphics, though, because I find it hard to follow other people’s instructions if they leave steps out, or don’t make them brain-dead simple to follow (which tells you more about my brain than about their instructions, I fear).

In the “Import Flash Builder Project” screen above, click on the upper “Browse…” button at right. That will bring up the standard “Open” directory browser. Use it to navigate to the “weborb.codegen.zip” file you downloaded a couple of steps ago. Select it; press the “Open” button; and you’ll be taken back to the “Import Flash Builder Project” screen above…but this time, the “Finish” button is enabled. Click “Finish”.

That will bring you to yet another screen, this one entitled “Choose Flex SDK Version”. All of my sample apps will use Flex SDK 4 unless otherwise noted (until a future major upgrade is released, anyway) — so be sure that you choose Flex SDK 4 in this screen, too. Click the screen’s “OK” button.

Yet another screen appears — this one entitled “Project Will Be Upgraded,” informing me that “Project HelloWorldService was created with a previous version of Flash Builder. If you save it, you will no longer be able to open this project with older versions of Flash Builder. Continue?” It offers two choices, “OK” and “Cancel”. Click “OK”. That ends the importation of the generated project.

The generated project is shown in Flex Builder’s “Package Explorer” window, as shown at left. (The project HelloWorldClient1, above it, is local to my machine; you won’t see it on yours.)

As you can see, WebORB’s generated source files — HellowWorldService.as and HelloWorldServiceModel.as — are in the HelloWorldServer package, which is as it should be.

However, I’m not super-happy with the name of the generated project. It’s “HelloWorldService”, but this Flex app is the client-side app. I’d rather name it HelloWorldClient. So I’ll select it, right-click it, and choose “Rename…” from the resulting pop-up menu, renaming it to “HelloWorldClient”. Much better.

Let’s look at HelloWorldClient’s main.mxml, generated by WebORB:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="onLoad()">
<mx:Script>
<![CDATA[

  public function onLoad():void
  {

  }
]]>
</mx:Script>
</mx:Application>

This code was generated for Flex SDK 3.5, but I’m using Flex SDK 4.0. At present, WebORB for .NET does not have the capability of generating code for Flex SDK 4.That’s on the “to-do” list, and should be supported Real Soon Now. Bummer. (See? I told you that WebORB generated less-than-perfect code. We are but mortal.)

No worries, though — the changes are simple enough to make. Here’s the revised code:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   initialize="onLoad()">
	<fx:Script>
		<![CDATA[

		public function onLoad():void
		{

		}
		]]>
	</fx:Script>
</s:Application>

The changes I made were:

  • defining the fx and s namespaces
  • re-defining the mx namespace
  • changing the Application tags from mx to s
  • changing the Script tags from mx to fx
  • removing the “layout=absolute” phrase from the Application’s declaration
  • changing the indentation in the Application’s declaration to make it easier to read

What is the next step? The source code in HelloWorldService.as, generated by WebORB for .NET, provides a clue. Its header comment says:

/***********************************************************************
The generated code provides a simple mechanism for invoking methods
on the HelloWorldServer.HelloWorldService class using WebORB.
You can add the code to your Flex Builder project and use the
class as shown below:

import HelloWorldServer.HelloWorldService;
import HelloWorldServer.HelloWorldServiceModel;

[Bindable]
var model:HelloWorldServiceModel = new HelloWorldServiceModel();
var serviceProxy:HelloWorldService = new HelloWorldService( model );

// make sure to substitute foo() with a method from the class
serviceProxy.foo();

Notice the model variable is shown in the example above as Bindable.
You can bind your UI components to the fields in the model object.
************************************************************************/

OK, let’s do that! Fleshing out the CDATA block as described above gives us the following:

	<fx:Script>
		<![CDATA[
			import HelloWorldServer.HelloWorldService;
			import HelloWorldServer.HelloWorldServiceModel;

			[Bindable]
			private var model:HelloWorldServiceModel
								= new HelloWorldServiceModel();
			private var serviceProxy:HelloWorldService
								= new HelloWorldService( model );

			public function onLoad():void
			{
				serviceProxy.getHelloString();
			}
		]]>
	</fx:Script>

Cool! Let’s run it! …and absolutely nothing is visible on screen. Doh! I kinda forgot to add a UI.

Let’s add a couple of labels below the Script block:

	<s:Label id="helloLabel"
			 horizontalCenter="0" verticalCenter="0"
			 text="{model.getHelloStringResult}" />

	<s:Label y="34" horizontalCenter="0" text="Result is..."/>

The only interesting bit here is the binding of helloLabel’s text field to model.getHelloStringResult, as suggested by the comment in HelloWorldService.as. When did this property get set? Let’s look at the whole main.mxml file:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   width="282" height="150"
			   initialize="onLoad()">

	<fx:Script>
		<![CDATA[
			import HelloWorldServer.HelloWorldService;
			import HelloWorldServer.HelloWorldServiceModel;

			[Bindable]
			private var model:HelloWorldServiceModel
								= new HelloWorldServiceModel();
			private var serviceProxy:HelloWorldService
								= new HelloWorldService( model );

			public function onLoad():void
			{
				serviceProxy.getHelloString();
			}
		]]>
	</fx:Script>

	<s:Label id="helloLabel"
			 horizontalCenter="0" verticalCenter="0"
			 text="{model.getHelloStringResult}" />

	<s:Label y="34" horizontalCenter="0" text="Result is..."/>
</s:Application>
  • On line 06, we ensure that onLoad() gets called when the application is initialized.
  • On line 21, onLoad() calls serviceProxy.getHelloString().
  • On line 16, serviceProxy is declared to be of class HelloWorldService.

…so let’s take a look at HelloWorldService.as.

      public function getHelloString( responder:IResponder = null ):void
      {
        var asyncToken:AsyncToken = remoteObject.getHelloString();

        if( responder != null )
            asyncToken.addResponder( responder );
      }

      public virtual function getHelloStringHandler(event:ResultEvent):void
      {
          var returnValue:String = event.result as String;
          model.getHelloStringResult = returnValue;
      }

The flow of control is:

  • onLoad() calls serviceProxy.getHelloString();
  • serviceProxy.getHelloString() calls remoteObject.getHelloString();
  • WebORB calls the C# service we defined earlier;
  • If the magic is successful, then the C# service’s return value is stuffed into the “result” field of a ResultEvent;
  • getHelloStringHandler() is called asynchronously with that ResultEvent object as a parameter;
  • model’s getHelloStringResult property is set to event.result (that is, to “Hello, World!”);
  • and, finally, because helloLabel’s text field is bound to model.getHelloStringResult,
  • helloLabel’s text field is updated to match model.getHelloStringResult, which, deep in the bowels of Flex
  • forces helloLabel to be redrawn with its new contents: “Hello, World!”

Now, I would not claim that this is the simplest “Hello, World!” application ever written — far from it. It include four source code files: one on the server, and three on the client. Together, these files contain something like 170 lines of code. That’s not counting WebORB for .NET’s code, or Flex’s code. All together, we’re talking quite a bit of code.

But the thing is, I wrote hardly any of it. A few lines on the server, a few lines on the client, and — presto-chango! — I’ve got a (trivial) client-server application up and running.

I left programming for nearly a decade in the late 1990’s, in part because COM and — shudder! — DCOM made programming so complicated. I did not want to spend my hours tracking down reference counting errors, for example, or bugs in a class’ marshalling/unmarshalling. Blech. That simply wasn’t fun. I got into programming because people paid me to have fun doing it, which is a pretty awesome way to make a living…until it got so complicated that it wasn’t fun anymore.

Now, with .NET, Flex, and WebORB, programming has become fun again — so I’m delighted to get back into coding. Still, I’ve missed a lot, so if you see me making a coding mistake, or a design error, a pattern violation, a smell fault, or somesuch, please don’t hesitate to let me know. By helping me, you’ll be helping lots of other people, too; we can all learn together. You can reach me at jim [att] themidnightcoders [dott] com.

P.S.:  Before you ask…Why haven’t I included a link to this sample application’s HelloWorldService.as and HelloWorldServiceModel.as files? Because they are both generated by WebORB. You can generate them for yourself, using WebORB’s management console, as described above. That’s kinda the whole point of this blarticle. ;-)

RTMP Data Push from Java to Flex

Data push is a mechanism of data delivery from server to the connected client applications. Data push between Java and Flex can be accomplished via HTTP polling or using a dedicated connection from the client program to the server-side process. The dedicated connection can use the RTMP protocol supported by Flash and Flex and also implemented by WebORB for Java. The example reviewed in this post uses the latter approach. The example establishes a connection from a Flex client to the WebORB for Java server process. The server-side code schedules a timer task to push a Java object to all connected clients. When the client program receives the object sent by the server it updates the user interface with the received information.

The example’s server-side code runs inside of the WebORB server. For the RTMP applications, WebORB requires a Java class which is the main handler of all events and actions for the given messaging application. Consider the following server-side Java code. The code is the handler class for the example:

package samples.datapush;

import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.service.IServiceCapableConnection;
import weborb.messaging.WebORBApplication;

import java.util.*;

public class AppHandler extends WebORBApplication
  {
  private Timer pushTimer;

  public boolean appStart( IScope app )
    {
    boolean started = super.appStart( app );

    if( started )
      {
      pushTimer = new Timer( true );
      pushTimer.scheduleAtFixedRate( new DataPushTask(), 0, 1000 );
      }

    return started;
    }

  protected void pushDataToClients( StockQuote quote )
    {
    Object[] args = new Object[] { quote };
    Iterator<IConnection> connectionsIterator = this.scope.getConnections();

    while( connectionsIterator.hasNext() )
      {
      IConnection connection = connectionsIterator.next();

      if( connection instanceof IServiceCapableConnection )
        ((IServiceCapableConnection) connection).invoke( "quotePushed", args );
      }
    }

  class DataPushTask extends TimerTask
    {
    @Override
    public final void run()
      {
      Random rand = new Random( System.currentTimeMillis() );
      StockQuote quote = new StockQuote();
      quote.bid = rand.nextDouble() * 100;
      quote.ask = quote.bid + 1;
      quote.last = quote.ask - 0.5;
      quote.symbol = "MSFT";
      quote.transactionDate = new Date();
      pushDataToClients( quote );
      }
    }
  }
public class StockQuote
  {
  public double bid;
  public double ask;
  public double last;
  public String symbol;
  public Date transactionDate;
  }

The class shown above extends from weborb.messaging.WebORBApplication, so it can plug in into the product’s messaging framework. The appStart method is invoked when the WebORB server process is started (or when the application server is launched if WebORB is deployed into a 3rd party server). The implementation of the appStart method creates a timer which executes DataPushTask every second. The task creates an instance of the StockQuote class and delivers it to all connected clients by calling the pushDataToClients( StockQuote ) method. The actual data push occurs in the pushDataToClients method. The code obtains a collection of the client connections and iterates over it. For each connection the code invokes the “invoke” method. The method arguments are the name of the client-side function to invoke and the argument list to send to the client.

There are a few steps to deploy the Java code:

  1. Compile the code and copy the .class files into the corresponding folders under WEB-INF/classes. Specifically, the class files for the code shown above must be copied to the WEB-INF/classes/samples/datapush directory.
  2. Create and save the messaging application deployment file in WEB-INF/classes. Save the file with the name of datapushexample-web.xml. The file must contain the following:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    
        <bean id="datapushexample.context" class="org.red5.server.Context"
            autowire="byType" />
    
        <bean id="datapushexample.scope" class="org.red5.server.WebScope"
             init-method="register">
            <property name="server" ref="red5.server" />
            <property name="parent" ref="global.scope" />
            <property name="context" ref="datapushexample.context" />
            <property name="handler" ref="datapushexample.handler" />
            <property name="contextPath" value="/SampleDataPush" />
            <property name="virtualHosts" value="*,localhost, localhost:1935, localhost:8080, 127.0.0.1:8080" />
        </bean>
    
        <bean id="datapushexample.handler"
            class="samples.datapush.AppHandler"
            singleton="true" />
    </beans>

    Notice the “datapushexample.” prefix in various IDs throughout the document. The prefix must be unique between all deployed messaging applications. Additionally, the bean definition with the “datapushexample.handler” ID references the handler class reviewed above. Finally, the “contextPath” property specifies the path of the application which will be used in the client code.

  3. Update beanRefContext.xml located in WEB-INF/classes, so it references datapushexample-web.xml from item #2.
  4. Restart WebORB for Java. If you are using the standalone version of the product, run “java -jar weborb.jar” from the command prompt (make sure to set the current directory to the WebORB’s installation directory).

At this point you are done with the server-side, so we’re shifting to Flex. Run Flex/Flash Builder and create a new Flex application project. See the article describing how to create a Flex/Flash Builder project to work with WebORB. The code below is the complete Flex application which connects to the server and processes data push messages:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
	<mx:Script>
		<![CDATA[
		import mx.collections.ArrayCollection;
		import mx.controls.Alert;

		private var serverConnection:NetConnection;

		[Bindable]
		private var historicalQuotes:ArrayCollection = new ArrayCollection();

		public function init():void
		{
			// create new NetConnection
			serverConnection = new NetConnection();

			// set the object which will receive the callbacks from server
			serverConnection.client = this;

			// set the encoding to AMF0 - looks like RTMP requires that
	    	        serverConnection.objectEncoding = ObjectEncoding.AMF0;

	    	        // register the listener so we know if the connection has succeeded
	    	        serverConnection.addEventListener( NetStatusEvent.NET_STATUS, handleNetStatus );

	    	        // now connect to the server-side app
	    	        serverConnection.connect( "rtmp://localhost:1935/SampleDataPush" );

	    	        // initialize historical quotes to zeros
	    	        for( var i:int = 0; i < 50; i++ )
	    		  historicalQuotes.addItem( 0 );
		}

		private function handleNetStatus( event:NetStatusEvent ):void
		{
			switch( event.info.code )
			{
				case "NetConnection.Connect.Success":
					// all is good, the connection is made
					break;
				case "NetConnection.Connect.Failed":
					Alert.show( "Unable to connect to WebORB", "Connection Error" );
					break;
			}
		}

		// this method is invoked by the server-side code through WebORB
		public function quotePushed( quote:StockQuote ):void
		{
			symbolTextField.text = quote.symbol;
			bidTextField.text = usdFormatter.format( quote.bid );
			askTextField.text = usdFormatter.format( quote.ask );
			lastPriceTextField.text = usdFormatter.format( quote.last );
			lastTimestampTextField.text = quote.transactionDate.toTimeString();
			historicalQuotes.removeItemAt( 0 );
			historicalQuotes.addItem( quote.last );
		}

		]]>
	</mx:Script>
	<mx:Panel x="10" y="10" width="357" height="269" layout="absolute" title="Data Push Example">
		<mx:Label x="83" y="10" text="Stock symbol:"/>
		<mx:Text x="175" y="10" fontWeight="bold" id="symbolTextField"/>
		<mx:Label x="110" y="36" text="Bid price:"/>
		<mx:Label x="107" y="62" text="Ask price:"/>
		<mx:Label x="104" y="88" text="Last price:"/>
		<mx:Label x="10" y="114" text="Last transaction date/time:"/>
		<mx:Text x="175" y="36" id="bidTextField"/>
		<mx:Text x="175" y="62" id="askTextField"/>
		<mx:Text x="175" y="88" id="lastPriceTextField"/>
		<mx:Text x="175" y="114" id="lastTimestampTextField"/>
		<mx:LineChart x="10" y="140" id="stockPriceChart" width="317" height="79" dataProvider="{historicalQuotes}">
			<mx:series>
				<mx:LineSeries displayName="Series 1" yField=""/>
			</mx:series>
		</mx:LineChart>
	</mx:Panel>
 	<mx:CurrencyFormatter id="usdFormatter" precision="2"
        currencySymbol="$" decimalSeparatorFrom="."
        decimalSeparatorTo="." useNegativeSign="true"
        useThousandsSeparator="true" alignSymbol="left"/>
</mx:Application>

Notice the quotePushed function. The function is invoked by the server and that is where the data push takes place. The StockQuote class referenced in the code is below:

package
{
	[RemoteClass(alias="samples.datapush.StockQuote")]
	public class StockQuote
	{
		public var bid:Number;
		public var ask:Number;
		public var last:Number;
		public var symbol:String;
		public var transactionDate:Date;
	}
}

Below is a screenshot of the application in action: