SSR 2 Breakdown

John Farrar had asked about SSR 2 – more information on SSR and what benefits / things you get with it. I thought I’d be a little more specific and outline what it is and what you get. Bare with me if I start out by pointing out the obvious.

So, I guess here’s the obvious. SSR is a small AS3 remoting library. Stands for “Super Simple Remoting” because it’s simple. My goal when writing it was to make one library that works in Flash and Flex and handle logic that should be in every application. Personally I like using this in both Flash and Flex because I don’t forget how to use it. I always forget how to use RemoteObject so this makes a standard library for either.

So here’s an example of a bare minimum setup of SSR to make a remoting call.

import com.niarbtfel.remoting.RemotingConnection;
import com.niarbtfel.remoting.RemotingService;
import com.niarbtfel.remoting.events.FaultEvent;
import com.niarbtfel.remoting.events.ResultEvent;

var rc:RemotingConnection = new RemotingConnection("http://localhost/myGateway",3);
//gateway
//3 is the amf format

var rs:RemotingService = new RemotingService(rc,"MyService",4000,3,true);
//rc is the remoting connection to use for this service
//"MyService" is the service target on the server.
//4000 is the amount of time a call waits before retrying the call.
//3 is the amount of retries to attempt per call.
//true turns on call limiting, which means that the same exact call can't be made while one is waiting for a response or timeout.

//callbacks for calls, keep reading.
function onr(re:ResultEvent):void{}
function onf(fe:FaultEvent):void{}

//callbacks for calls, keep reading.
function onrArgs(re:ResultEvent,args:Array):void{}
function onfArgs(fe:FaultEvent,args:Array):void{}

rs.myMethod([],onr,onf,false); //make a call
//[] = call arguments
//onr is the result callback
//onf is the fault callback
//false - don't return the original arguments sent in the request to the callback functions

var mym:String = "myMethod";
rs.apply(mym,[],onrArgs,onfArgs,true); //make a call
//[] = call arguments
//onr is the result callback
//onf is fault callback
//true - return the original arguments sent in the request to the callback functions

This is the simplest form of setting up flash remoting with SSR without any event listeners on the RemotingConnection or RemotingService. Events for RemotingConnection and RemotingService are documented in the class files. You get events for things like disconnects, retries, timeouts, etc.

Each RemotingService can have a timeout specified for each call going to that service, as well as a maximum attempts allowed per call. If one call is made, but doesn’t receive a response within the timeout specified, it’s tried again. This happens over and over until the maximum attempts is reached, and a timeout event is dispatched.

RemotingService has an option to turn on call limiting. Which makes the remoting service smart about what to call and what not to call. If you made a call to “MyService.myMethod” with parameters ["something","something else"], it would not let you make that same call until the first one has completed, or has timed out. You’d still be able to make calls to any other service method.

Another new feature is caching. Say you make calls to some service numerous times, but the data is always the same. Instead of doing that you can enable the service to use caching. Here’s a snippet from above with caching in place:

var rs:RemotingService = new RemotingService(rc,"MyService",4000,1,true);
rs.remotingCache = new RemotingCache(-1);
//-1 specifies that the cache should never expire. (supply a time in milliseconds for an expiration if needed)

Now every call made through this remoting service will be cached. If the exact same call is made, the results are pulled from cache instead.

SSR also has paging built in with a RemotingPager. Here’s a snippet on how that works:

import com.niarbtfel.remoting.RemotingConnection;
import com.niarbtfel.remoting.RemotingService;
import com.niarbtfel.remoting.events.FaultEvent;
import com.niarbtfel.remoting.events.ResultEvent;
import com.niarbtfel.remoting.paging.RemotingPager;
import com.niarbtfel.remoting.paging.PageResponder;

var rc:RemotingConnection = new RemotingConnection("http://localhost/myGateway",3);
var rs:RemotingService = new RemotingService(rc,"MyService",4000,3,true);
var rp:RemotingPager;
var pr:PageResponder // just to include in compilation

var totalRecordsOnServer:int = 400; //should come from server instead.

//callbacks for calls, keep reading.
function onrArgs(re:ResultEvent,args:Array):void
{
  rp = new RemotingPager(rs,"myMethod",PageResponder,["someParameter"],re.result as Array,totalRecordsOnServer,50,2,1);
  myButton.addEventListener(MouseEvent.CLICK, onbc);
}
function onfArgs(fe:FaultEvent,args:Array):void{}

function onbc(me:MouseEvent):void
{
   if(rp.hasNext())
   {
     trace(rp.next());
   }
   else
   {
     trace("no more pages");
   }
}

rs.myMethod(["someParameter",0,50],onrArgs,onfArgs,true); //make a call to get the initial data.
//0 is the offset
//50 is the pagesize

In this example, a remoting pager is created in the result callback of the first call. A remoting pager needs at least the first page in order to be created. The RemotingPager takes care of “pre-fetching” pages with buffer options. In the above example, where the RemotingPager is created, 50 is the pagesize to grab, 2 is the amount of pages to buffer / pre-fetch. And 1 is the amount of pages that are left in the buffer before triggering another buffer fill / pre-fetch. This is the simplest form of paging, but the RemotingPager has methods for getting certain pages, getting them all, seeking, etc.

UPDATE: I forgot to mention RemotingService.MaxTimeoutsBeforeHault.

With RemotingService.MaxTimeoutsBeforeHault, you can control how many timeouts are allowed from any call, before all remoting calls are stopped. Here’s a snippet:

RemotingService.MaxTimeoutsBeforeHault = 3;
var rs:RemotingService = new RemotingService(rc,"MyService",4000,3,true);
rs.addEventListener(CallEvent.SERVICES_HALTED, onch);
function onch(ce:CallEvent):void{}
rs.myMethod([],onR,onF,true);

When you set this property, any call that causes a timeout, is kept track of, and if 3 timeouts happen from any call, no other remoting calls will be made. Each attempt after the services are halted, dispatches the CallEvent.SERVICES_HALTED event.

In conclusion – SSR gives you logic out of the box that should be available anytime we are using Flash Remoting. And gives you numerous other features. SSR 2 is documented very well in the source files.

CarnageBlood said,

January 29, 2008 @ 09:49

I understand the basic idea behind this but can you please show me an example or a tutorial with Ruby AMF in Rails.What are the changes to be done?
Please help by showing an example! I find Ruby AMF poorly documented and don’t know were to start!
Thanks in advance!

aaron said,

January 29, 2008 @ 10:17

@CarnageBlood,

This actually doesn’t have anything to do with RubyAMF. This is just a remoting package in general. It’s AS3 so you can use this with any remoting gateway.

As far as RubyAMF docs. Yeah it’s gone downhill. I’d suggest looking at some of the downloads on the rubyamf google code page. Sorry. -A

CarnageBlood said,

January 29, 2008 @ 11:11

Aren’t the the downloads from google code page made with SSR1? There is a difference between them?
Anyway if i’m on Rails I should do:
var rc:RemotingConnection = new RemotingConnection(“http://localhost/rubyamf/gateway”,3)
and then :
var rs:RemotingService = new RemotingService(rc,”PeopleController”,4000,3,true);
in people_controler I have a index method
where there is:
format.amf { render :amf => @people }
To call the function i will do:
rs.apply(“index”,[],onR,onF,true);
Is this the way to go cause my app didn’t dispach a ConnectionEvent.CONNECTED
????

;

aaron said,

January 29, 2008 @ 12:02

Yeah there is a difference between them. it’s pretty much re-written. And organized better.

So you’re case:

import com.niarbtfel.remoting.RemotingService;
import com.niarbtfel.remoting.RemotingConnection;
import com.niarbtfel.remoting.events.FaultEvent;
import com.niarbtfel.remoting.events.ResultEvent;
import com.niarbtfel.remoting.events.ConnectionEvent;
import com.niarbtfel.remoting.events.CallEvent;

var rc:RemotingConnection = new RemotingConnection(”http://localhost/rubyamf/gateway”,3);

rc.addEventListener(ConnectionEvent.CONNECTED, onCConnect);
rc.addEventListener(ConnectionEvent.FAILED, onCFail);
rc.addEventListener(ConnectionEvent.DISCONNECT, onCDisconnection);
rc.addEventListener(ConnectionEvent.FORMAT_ERROR, onCFormatError);
rc.addEventListener(ConnectionEvent.SECURITY_ERROR, onCSecurityError);

function onCFail(ce:ConnectionEvent):void{}
function onCConnect(ce:ConnectionEvent):void{}
function onCDisconnect(ce:ConnectionEvent):void{}
function onCFormatError(ce:ConnectionEvent):void{}
function onCSecurityError(ce:ConnectionEvent):void{}

var rs:RemotingService = new RemotingService(rc,”PeopleController”,4000,3,true);
rs.addEventListener(CallEvent.RETRY, onRetry);
rs.addEventListener(CallEvent.TIMEOUT, onTimeout);

function onRetry(ce:CallEvent):void{}
function onTimeout(ce:CallEvent):void{}

//call the method.  (these two lines doe the same thing)
rs.index([],onR,onF,true);
//rs.apply("index",[],onR,onF,true);

function onR(re:ResultEvent,args:Array):void{}
function onF(fe:FaultEvent,args:Array):void{}

CarnageBlood said,

January 29, 2008 @ 13:01

It works!Thanks alot!
Thow I have another quetion:
When does the ConnectionEvent.CONNECTED dispached because in that setup I managed to get data from PeopleController and the CONNECTED event didn’t dispach? In fact no RemotingConnection event was realy dispached!

CarnageBlood said,

January 29, 2008 @ 13:06

The ResultEvent dispached!

Freddy said,

February 6, 2008 @ 03:31

SSR2 works in flash cs3?

Freddy said,

February 6, 2008 @ 03:32

I tell that because I seen this: “[Event(name=CallEvent.RETRY,type="com.niarbtfel.remoting.events.CallEvent")];”

aaron said,

February 6, 2008 @ 12:13

@freddy,

yes it works in CS3.

Not sure what you’re getting at with pointing out the CallEvent.RETRY. That is just meta data about what events are dispatched from RemotingService.

-Aaron

Freddy said,

February 7, 2008 @ 04:09

ok… I thought that format only work in flex (had not proven)… some example with setcredentials?

CarnageBlood said,

February 9, 2008 @ 16:51

How can i get the downloading progress of an return ActiveRecord object? This is useful when retrieving alot of data ?
Can someone please explain me how pagging works and give an example?

giorgos said,

April 15, 2008 @ 11:18

hi i am almost there, please need your help. trace(re.result) gives me back [object object]. In old days we used to do this trace(re.result[0].memberID); now what is the proper approach?

cheers

prism said,

July 8, 2008 @ 20:20

giorgos, try with

re.result[0].attributes.memberID

prism said,

July 8, 2008 @ 21:07

You might want to look at this though

http://groups.google.com/group/rubyamf/browse_thread/thread/93825befb2f8bb09

For me, this works with Rails 2.1.0 (SQLite3), AMFRuby 1.6.2 + SSR2. I’m building with Flash CS3.

Following the other tutorials on this, you have to remember to:

- Add ClassMappings to config/rubyamf_config.rb
- Modify controllers to support AMF

If it helps, here’s my basic AS3:

[code]
package
{
import com.niarbtfel.remoting.RemotingService;
import com.niarbtfel.remoting.RemotingConnection;
import com.niarbtfel.remoting.events.FaultEvent;
import com.niarbtfel.remoting.events.ResultEvent;
import com.niarbtfel.remoting.events.ConnectionEvent;
import com.niarbtfel.remoting.events.CallEvent;
import flash.display.Sprite;
import fl.data.DataProvider;
import fl.controls.DataGrid;

public class Main extends Sprite {
private var rc:RemotingConnection;
private var rs:RemotingService;
private var acdp:ArrayCollectionDP;

public function Main():void
{
rc = new RemotingConnection("http://localhost:3000/rubyamf/gateway",3);
rc.addEventListener(ConnectionEvent.CONNECTED, onCConnect);
rc.addEventListener(ConnectionEvent.FAILED, onCFail);
rc.addEventListener(ConnectionEvent.DISCONNECT, onCDisconnect);
rc.addEventListener(ConnectionEvent.FORMAT_ERROR, onCFormatError);
rc.addEventListener(ConnectionEvent.SECURITY_ERROR, onCSecurityError);

rs = new RemotingService(rc,"UsersController",4000,3,true);
rs.addEventListener(CallEvent.RETRY, onRetry);
rs.addEventListener(CallEvent.TIMEOUT, onTimeout);

//call the method. (these two lines doe the same thing)
rs.index([],onR,onF,true);
// rs.apply("index",[],onR,onF,true);
}

private function onCFail(ce:ConnectionEvent):void
{
trace("onCFail");
}
private function onCConnect(ce:ConnectionEvent):void
{
trace("onCConnect");
}
private function onCDisconnect(ce:ConnectionEvent):void
{
trace("onCDisconnect");
}
private function onCFormatError(ce:ConnectionEvent):void
{
trace("onCFormatError");
}
private function onCSecurityError(ce:ConnectionEvent):void
{
trace("onCSecurityError");
}

private function onRetry(ce:CallEvent):void
{
trace("onRetry");
trace(ce);
}
private function onTimeout(ce:CallEvent):void
{
trace("onTimeout");
}

private function onR(re:ResultEvent, args:Array):void
{
trace("onResult");
var dp:DataProvider = new DataProvider(re.result);
var dg:DataGrid = new DataGrid();
dg.width = 400;
dg.height = 200;
dg.dataProvider = dp;
addChild(dg);
}
private function onF(fe:FaultEvent, args:Array):void
{
trace("onFault");
}

}
}
[/code]

Thanks Aaron for RubyAMF and all the rest. :)

RSS feed for comments on this post · TrackBack URI

Leave a Comment