Working with yFiles FLEX and BlazeDS

Tips & Tricks

Summary

This article shows how a yFiles FLEX client can communicate with a BlazeDS server component.

Description

Usually, a yFiles FLEX client communicates with a yFiles FLEX server component by using class RoundtripHandler (client)/GraphRoundtripSupport (server) to transfer the graph and any additional data between client and server. These support classes take care of automatic (de)serialization of the graph instance.

However, in a BlazeDS application, client-server communication is usually handled using RemoteObjects that allow to invoke server-side functionality directly from the client. When parameters are passed to the remote methods, or when the method has a return value, these values are serialized using the AMF format. Because the default yFiles FLEX IGraph implementation cannot be serialized automatically using the AMF format, the yFiles FLEX API provides a ExternalizableGraph implementation, that can be used as a parameter/return value for remote object calls instead.

Example: Layout Calculation

The following example code demonstrates how to perform an automatic layout calculation on the BlazeDS/yFiles FLEX server for a graph displayed on the client.

Calculating a Layout: Server

The following code snippet shows how to perform a layout calculation on the server using class ExternalizableGraph

public class TestService {

  public ExternalizableGraph layout( ExternalizableGraph inputGraph ) {
    // retrieve the deserialized LayoutGraph
    LayoutGraph graph = inputGraph.getGraph();
    // calculate a layout
    new BufferedLayouter( new IncrementalHierarchicLayouter() ).doLayout( graph );
    // wrap the modified graph in an ExternalizableGraph for automatic serializaiton
    ExternalizableGraph outputGraph = new ExternalizableGraph();
    outputGraph.setGraph( graph );
    // and return the graph to the client
    return outputGraph;
  }

}

Calculating a Layout: Client

On the client, we need a RemoteObject that calls the methods provided by the server-side Class:

<mx:RemoteObject id="remoteService" destination="flextest" result="handleResult(event);" fault="handleFault(event);"/>

Here, the "destination" parameter corresponds to the destination defined in the BlazeDS remoting-config.xml.

To send the request to the server, we can just use the name of the server-side method:

private function sendRequest( evt:Event=null ):void {

  // wrap the graph in a ExternalizableGraph for serialization ..
  var extGraph:ExternalizableGraph = new ExternalizableGraph();
  extGraph.graph = graphCanvas.graph;

  // .. and pass it to the remote method
  remoteService.layout( extGraph );
}

In the handleResult() event handler, we update the layout of the graph that is shown in the client-side GraphCanvasComponent:

// a layout result was received: update the graph shown in the canvas
private function handleResult( evt:ResultEvent ):void {

  // unwrap the graph..  
  var result:ExternalizableGraph = evt.result as ExternalizableGraph;
  if( null != result ) {
    var resultGraph:IGraph = result.graph;

    // .. and morph the graph to the new layout
    graphCanvas.morphGraph( resultGraph );
  } 
}

Adding Custom Data

Data that is associated with graph elements through mappers will also be (de)serialized automatically using the AMF format, if no custom serializer/deserializer has been registered for the data type. Assume there is a simple bean class like this:

Custom Data: Server

package demo; public class CustomData { private String myProperty = null; public String getCustomProperty() { return myProperty; } public void setCustomProperty(String myProperty) { this.myProperty = myProperty; } }

Custom Data: Client

package demo { public class CustomData { private var _myProperty:String = "DefaultString"; public function get customProperty():String { return this._myProperty; } public function set customProperty( value:String ):void { this._myProperty = value; } } }

Since this class is available both on the client and server, has only a no-arg constructor and simple getter/setter properties, it can be automatically (de)serialized by the Flex/BlazeDS framework using the AMF format.

Add the custom data on the client:

// Create a DictionaryMapper that is configured for automatic serialization
var mymapper:IMapper = new DictionaryMapper( false, "mytag", GraphMLConstants.SCOPE_NODE,
                                               GraphMLConstants.ATTR_TYPE_COMPLEX, true );

// register the mapper with the graph's mapper registry
graph.mapperRegistry.addMapper( "mytag", mymapper );

// map instances of the custom data class to some nodes
mymapper.mapValue( node1, new CustomData() );
mymapper.mapValue( node2, new CustomData() )

Retrieve and modify the custom data on the server:

// add these lines to the layout method defined above:

// retrieve the DataProvider
DataProvider myDP = graph.getDataProvider("mytag");
for( NodeCursor nc = graph.nodes(); nc.ok(); nc.next() ) {
  CustomData thing = (CustomData) myDP.get(nc.node());
  thing.setCustomProperty( "server modified property");
}

The modified data will now be available in the client's handleResult() function:

var mapper:IMapper = resultGraph.mapperRegistry.getMapper( "mytag" );
for each( var node:INode in resultGraph.nodes ) {
  if( null != mapper ) {
    trace("tag value: "+CustomData( mapper.lookupValue( node ) ).customProperty);
  }
}

Categories this article belongs to:
yFiles FLEX > Communicating with the Server > Remote API
yFiles FLEX > Communicating with the Server
yFiles FLEX > Communicating with the Server > Remote Communication in yFiles FLEX
Applies to:
yFiles FLEX: 1.5, 1.6, 1.7, 1.8
Keywords:
Flex - BlazeDS - RemoteObject