Jan 24 2008

Integrating Flex, BlazeDS, and Scala/Lift

Tag: AMF, Flex, Remoting, Server Push, blazeds, lift, scala, tutorialDerek Wischusen @ 6:00 am

A short while ago Adobe announced that they would be releasing an open source version of LiveCycle Data Services called BlazeDS. In short, BlazeDS is Java technology that makes it really easy to do HTTP streaming and server-side push to Flex and AIR applications. While this announcement is definitely welcome news, there may be a lot of people out there who thought to themselves, “That’s great, but I don’t use Java.” Well, the good news is that just because BlazeDS uses Java the platform doesn’t mean that you necessarily need to use Java the language to take advantage of it.

In fact, Java the platform supports several different languages, including Groovy, Python, Ruby, and Scala. And, of course, ColdFusion. In theory, it should be pretty straight-forward to integrate any of these languages with BlazeDS.

For the rest of this post I am going to focus on just one of them, Scala. Why Scala? Well, it is because recently I decided that I wanted to broaden my programming language horizons and I’ve found that Scala is both extremely interesting and very powerful. It’s both object-oriented and functional, it has mixin style composition, it has an exceptional implementation of Erlang style Actors for handling concurrency, and much more. Lastly, and perhaps most important for my purposes, there is an excellent webapp framework for Scala called Lift.

All right, let’s get started with integrating Flex, BlazeDS, and Scala/Lift.

Prerequisites – latest versions of:

—–

If you’d like to follow along with source files, here they are.

Source Code:

—–

First, let’s create a Lift project named LiftBlaze:

1. Open a terminal and navigate to the directory where you want to create the project.

2. Enter the following command:

mvn archetype:create -U                                    \
-DarchetypeGroupId=net.liftweb                             \
-DarchetypeArtifactId=lift-archetype-blank                 \
-DarchetypeVersion=0.4                                     \
-DremoteRepositories=http://scala-tools.org/repo-releases  \
-DgroupId=org.rxr.liftblaze -DartifactId=liftblaze

3. Next enter:

cd liftblaze

4. Lastly, enter:

mvn jetty:run

If everything worked properly, then you should see a “Hello World” welcome page at http://localhost:8080/

—–

Next, let’s use Maven to create an eclipse project for us:

1. In a terminal, go to lift linkblaze project and enter:

mvn eclipse:eclipse

You should now be able to import the linkblaze project into Eclipse. Once you have the project imported you will need to add the BlazeDS jars to your build path. These jars are located in {blazeds_folder}\tomcat\webapps\blazeds\WEB-INF\lib.

—–

Now let’s start setting up the Lift project to work with Flex and BlazeDS.

1. Open the web.xml file located in {blazeds_folder}\tomcat\webapps\blazeds\WEB-INF

2. Open the web.xml file located in liftblaze\src\main\webapp\WEB-INF.

3. Copy the contents of the web.xml file from the BlazeDS folder into the web.xml file in the liftblaze Lift project.

At this point, it would be useful to talk a bit about how lift handles HTTP requests. Lift is a view first framework. What this means is that by default lift will try to match an HTTP request against one its views. If it finds one it will do some processing on it, and then render it our as HTML. For more info on how Lift handles HTTP requests, check out this page.

For this project, the entire view is going to be in Flex, so we don’t really Lift want to concerned about the view we just want it to handle our web service calls. To achieve this do the following:

4. Inside you newly merged web.xml file, modify the filter-mapping tag like so:

<filter-mapping>
  <filter-name>LiftFilter</filter-name>
  <url-pattern>/webservices/*</url-pattern>
</filter-mapping>

Now Lift will only handle requests that start with webservices. In a later step we will tell Lift how to route these calls so that they invoke methods on a class that we will define.
5. Copy {blazeds_folder}\tomcat\webapps\blazeds\WEB-INF\flex into liftblaze\src\main\webapp\WEB-INF

6. Inside the flex folder, open the messaging-config.xml file and add the following:

 <destination id="notifications">
     <channels>
         <channel ref="my-streaming-amf"/>
     </channels>
 </destination>

This is the messaging destination that our Lift app will publish to and that our Flex app will subscribe to.

—–

All right, let’s start adding some Scala code to our lift project.

1. In Eclipse, create a package called org.rxr.liftblaze.actor

2. In this package, create a Scala Class called Notifier and add the following code to it:

package org.rxr.liftblaze.actor;

import flex.messaging.MessageBroker
import flex.messaging.messages.AsyncMessage
import flex.messaging.util.UUIDUtils
import scala.actors._
import scala.actors.Actor._
import compat.Platform._
import net.liftweb.util._
import org.rxr.liftblaze.model.Notification

class Notifier extends Actor {

  val msgBroker = MessageBroker.getMessageBroker(null)
  val clientID = UUIDUtils.createUUID()
  val msg = new AsyncMessage() 

  var notificationsSent = 0;

  def act{

    ActorPing.schedule(this, Notify, 500L)

    loop {
      react {

        case Notify =>
          msg.setDestination("notifications")
          msg.setClientId(clientID)
          msg.setMessageId(UUIDUtils.createUUID())
          msg.setTimestamp(currentTime)
          msg.setBody(new Notification(notificationsSent, "Hello from Scala/Lift", new java.util.Date()))
          msgBroker.routeMessageToService(msg, null)
          notificationsSent+=1
          println("notification sent at " + currentTime)
          ActorPing.schedule(this, Notify, 500L)       

        case "stop" =>
          exit()
      }
    }
  }

}

case object Notify

This is class that does the majority of the work in this simple application. The first thing to note about it is that it is a Scala Actor. I don’t want to go into too much detail about Actors here. For this tutorial we can grossly oversimplify and say that an Actor is kind of like a thread that can send and receive messages. If you want to get the full story you can click on the preceding link.

Here is a very brief explanation of what is happening in this class. When the Notifier Actor is started (you’ll see where this happens later) the act method is called. The first thing inside the act method is a call to the ActorPing.schedule helper method. This method basically says that I want to send a Notify message to this Actor in 500 milliseconds. Next comes loop which simply creates a loop and then react which has case statements that are used to handle incoming messages. So, when react receives a Notify or a “stop” message all of the code for that case is executed.

When a Notify is received a message is published to the “notifications” destination that we created earlier in the message-config.xml file. Once the message is sent, there is another call to ActorPing.schedule which will send another Notify message in 500 milliseconds. So, until a “stop” method is received, the Notifier Actor will publish a notification every 500 milliseconds.

The body of the message that is being published is a custom Scala class called Notification. One of the benefits of BlazeDS is that you can use the AMF protocol to send strongly typed objects from the server to your Flex client. So I can have BlazeDS serialize my Notification class in Lift down into AMF binary and then have it reappear as a Notification class in Flex, which is pretty handy. Though I have found that there is one small trick to creating classes in Scala that will serialize properly. To illustrate, let’s create the Notification class next.

3. Create a Scala Class named Notification in 0rg.rxr.liftblaze.model and add the following code,

package org.rxr.liftblaze.model

import java.util.Date

class Notification(var id: Int, var message: String, var timesent: Date)
{
    def getId = id
    def setId(id: Int) = this.id = id

    def getMessage = message
    def setMessage(m: String) = message = m

    def getTimesent = timesent
    def setTimesent(t: Date) = timesent = t
}

The main thing to take note of here is that I am using methods that are named like Java (the language) getters and setters, rather than variables. This is because the Scala compiler takes variables defined in Scala and turns them into methods in Java. So,

val greeting = "Hello"

in Scala becomes

public String greeting()
{
  return "Hello"
}

in Java. The same goes for var (FYI, vals are immutable variables, while vars are mutable). So, member variables in Scala won’t serialized by BlazeDS because they turn into methods in Java. The solution, as I have already shown, is just to use methods in Scala that are named like Java getters and setters.

Now that we’ve seen who is sending the messages in Lift (the Notifier Actor) and what is being sent (the Notification class), let’s create the class that starts and stops the Notifier.

4. In org.rxr.liftblaze.controller create a Scala Class called WebServices and then add the following code

package org.rxr.liftblaze.controller

import net.liftweb.http._
import javax.servlet.http.{HttpServlet, HttpServletRequest , HttpServletResponse, HttpSession}
import org.rxr.liftblaze.actor.Notifier

class WebServices (val request: RequestState,val httpRequest: HttpServletRequest) extends SimpleController {

  def start_feed = {
    WebServices.notifier.start()
    XmlResponse(<start_feed success="true"/>)
  }

  def stop_feed = {
    WebServices.notifier ! "stop"
    XmlResponse(<stop_feed success="true"/>)
  }
}

object WebServices {
  val notifier = new Notifier()
}

This is class is pretty much self explanatory. The start_feed method calls start on our Notifier Actor, which as we discussed causes the Notifier to send out a Notification every 500 milliseconds. The stop_feed method sends a “stop” message to the Notifier, which causes it to exit. Both methods return a simple XML response.

We’re almost done with the Lift app, just one more thing to do. In a previous step we modified the web.xml file so that Lift would only handle requests that start with webservices. Now we just need to tell Lift how to process/route those request so that they call the method in our WebServices class. To do this we need to modify the Boot class.

5. Open the Boot class located in bootstrap.liftweb and modify it thusly

package bootstrap.liftweb

import net.liftweb.util._
import net.liftweb.http._
import Helpers._
import org.rxr.liftblaze.controller.WebServices
import javax.servlet.http.{HttpServlet, HttpServletRequest , HttpServletResponse, HttpSession}

/**
  * A class that's instantiated early and run.  It allows the application
  * to modify lift's environment
  */
class Boot {
  def boot {

    val dispatcher: LiftServlet.DispatchPf = {
     // if it's a web service, pass it to the web services invoker
     case RequestMatcher(r, ParsePath("webservices" :: c :: _, _,_),_, _) => invokeWebService(r, c)
    }
    LiftServlet.addDispatchBefore(dispatcher)

  }

  private def invokeWebService(request: RequestState, methodName: String)(req: HttpServletRequest): Can[ResponseIt] =
    createInvoker(methodName, new WebServices(request, req)).flatMap(_() match {
    case Full(ret: ResponseIt) => Full(ret)
    case _ => Empty
  })
}

This code is taken directly from the examples included with the Lift source code. In Basic terms, this code matches a request that starts with webservices and passes the request and method name to be invoked to the invokeWebService method. This method the calls createInvoker which invokes the method on our WebServices class. So, for example http://localhost:8080/webservices/start_feed would call the start_feed method on the WebServices class. You can read more about how this code works here.

That’s it for the Lift App. All in all there really isn’t that much code. Though, of course, this app is pretty simple. Regardless of how simple this app is, I would say that in the short time that I have been using Scala I have found it to be the most concise statically typed language that I have ever used.

—–

Now let’s create the Flex App in Flex Builder.

1. Create a new Flex Project (File -> New -> Flex Project)

2. Fill in the rest as follows:

Project name: LiftBlaze

Application type: Web Application

Application server type: J2EE

Use remote object access service: check this

Root folder: {liftblaze_lift_app}\src\main\webapp

Root URL: http://localhost:8080/

Context root: /

Output folder: {liftblaze_lift_app}\src\main\webapp

Output folder URL: http://localhost:8080/

3. Once you have everything filled out, click Finish

All right, now that we have the project created let’s add some code to it.

4. Open LiftBlaze.mxml and add the following code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" >
    <mx:Script>
        <![CDATA[
        	import org.rxr.liftblaze.model.Notification;
          	import mx.messaging.events.MessageEvent;

            private function messageHandler(message: MessageEvent): void
            {
            	var notification : Notification = message.message.body as Notification;
                pushedValue.htmlText = "<b>id:</b> " + notification.id + " <b>Date:</b> " + notification.timesent;
            }    

        ]]>
    </mx:Script>

    <mx:Consumer
    	id="consumer"
    	destination="notifications"
    	message="messageHandler(event)"
    	channelConnect="trace(event)"
        channelFault="trace(event)"
        fault="trace(event)" />

    <mx:HTTPService
    	id="startFeed"
    	url="webservices/start_feed"
    	result="consumer.subscribe()" />
    <mx:HTTPService
    	id="stopFeed"
    	url="webservices/stop_feed"
    	result="consumer.unsubscribe()" />

 	<mx:Button
 		label="Subscribe to 'notifications'"
 		click="startFeed.send({stop_cache: new Date().getMilliseconds()})"
 		enabled="{!consumer.subscribed}"/>

	<mx:Button
		label="Unsubscribe from 'notifications'"
		click="stopFeed.send({stop_cache: new Date().getMilliseconds()})"
		enabled="{consumer.subscribed}"/>

    <mx:TextInput id="pushedValue" width="300"/>
</mx:Application>

What we’ve create here is an app that has a very simple UI that consists of two buttons and a text input field. The app also has two HTTPServices and Consumer. A couple of things to take note of here. First, the Consumer subscribes to the “notifications” destination, the same destination that our Notifier Actor publishes its messages to. Second, the HTTPServices make calls to webservices/start_feed and webservices/stop_feed. If you’ll recall we set up our Lift app so that these calls would be routed to invoke the methods in our WebServices class.

We just need to add one last piece of code to get everything working properly. In our Lift app the Notifier Actor sends out instances of the Notification class that we created. Now we need to create a corresponding Notification class in our Flex app so that when we receive the data in Flex it will show up as strongly typed class.

5. Create a Class named Notification in org.rxr.liftblaze.model and add the following code

 package org.rxr.liftblaze.model
{
    [Bindable]
    [RemoteClass(alias="org.rxr.liftblaze.model.Notification")]
    public class Notification
    {
        public var id : int;
        public var timesent : Date;
        public var message: String;

        public function Notification()
        {
            super();
        }

    }
}

You’ll notice that this class has the same attributes as the Scala Notification class in our Lift app. The key to mapping this class to our Scala class is the RemoteClass metadata tag located just above the class definition. This tag is used to tell Flex the fully qualified name of the server side class that this class maps to.

—–

That should be it. You now be able to boot up you Lift app, launch the Flex app, click the “Subscribe to ‘notifications’” to start the Notifier Actor and subscribe to the Consumer to the notifications destination. You should then see id number and the time in the text input field get automatically updated every 0.5 seconds. You can the click the “Unsubscribe from ‘notifications’” to stop the Notifier actor and the Consumer to unsubscribe from the notifications destination.

Pretty exciting. With these three technologies it’s really easy to automatically push data from the server to the client in real time. This is obviously a trivial example, but I think it should be relatively straight forward to scale this approach up for more sophisticated apps.

That wraps this up. Please let me know if you have any questions.


Jun 14 2007

Flex and RESTful Rails tutorial en francais

Tag: Flex and Rails, tutorialDerek Wischusen @ 9:03 pm

If you are interested and in Flex and Rails, and you know french, then be sure to check out this tutorial by Laurent Bois.


Jan 13 2007

Part 4 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Invoking ActiveRecord Methods Directly From Flex

Tag: Flex and Rails, tutorialDerek Wischusen @ 11:52 pm

This is the fourth post in a series that covers certain features of Issue Tracker sample app (view, source) that I added to the Flex RoR SDK.

The first post explained how to set up the application.

The second post covered how you can get WebORB for Rails to return typed objects to Flex using the [RemoteClass] metadata tag.

The third post covered how to use ActiveRecord Associations with WebORB.

This post explains how you can invoke ActiveRecord methods directly inside of a Flex client.

WebORB gives you the ability call ActiveRecord methods from inside of Flex. Here is all you have to do to make this happen:

1. To do this you first set up a RemoteObject in Flex just like you would for any other service. For example, the following code is from the Services.mxml file in flex_issue_tracker2 project:

<mx:RemoteObject id="userService" destination="userServiceImpl"
		    showBusyCursor="true
                       result="event.token.resultHandler( event );"
		    fault="event.token.faultHandler( event );">
</mx:RemoteObject>

2. Open up the remoting-config.xml file (located in C:\rails\rails_issue_tracker2\config\WEB-INF\flex) and map the RemoteObject directly to an ActiveRecord class. This is the mapping for the userService RemoteObject:

    <destination id="userServiceImpl">
        <properties>
            <source>User</source>
        </properties>
    </destination>

Now when you make a method call on the userService RemoteObject it as though you are making the call directly on the User ActiveRecord class. This makes it possible to do some interesting things, such as calling ActiveRecord dynamic finder methods directly on the userService, which is what is currently happening in the UserDelegate class in Flex:

package com.rxr.issuetracker.business
{
import mx.rpc.IResponder;
import com.adobe.cairngorm.business.ServiceLocator;

public class UserDelegate
{
	private var responder : IResponder;
	private var service : Object;

	public function UserDelegate(responder : IResponder)
	{
	      this.service = ServiceLocator.getInstance().getService( "userService" );
	      this.responder = responder;
	}

	public function loginUser(username : String, password : String) : void
	{
	      var call : Object = service.find_by_username_and_password(username, password);
	      call.resultHandler = responder.result;
	      call.faultHandler = responder.fault;
	}

	public function registerUser(username : String, password : String) : void
	{
	      var call : Object = service.find_or_create_by_username_and_password(username, password);
	      call.resultHandler = responder.result;
	      call.faultHandler = responder.fault;
	}
}
}

ActiveRecord dynamic finders are finder methods that are automatically generated by Rails based on the column names in the table that the ActiveRecord wraps. For example, the users table has three columns: id, username, and password. So, the User ActiveRecord class automatically generates a method called find_by_username, and a method called find_by_username_and_password, and so on. Click here to read an article that provides an in-depth explanation of how dynamic finders work.

As you can see, there are two dynamic finders that are currently being used in the UserDelegate class: find_by_username_and_password(username, password); in the loginUser method which finds an existing user, and find_or_create_by_username_and_password(username, password); in the registerUser method which creates a new user if it does not find one that matches the provided username and password.

Ok, now that you know how invoke ActiveRecord methods inside of Flex I should note that I think that you should only do this where it really makes sense to do so. The obvious drawback to this approach is that you have to make a call to the server for each method that you invoke. In general, it is best to keep this type of logic in a server-side service class (like the ProjectService and the IssueService). I’ve only included this functionality in Issue Tracker Sample app to show that it is possible. I plan to remove this code in the next update of the application and move into a UserService class.


Jan 09 2007

Part 3 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Using ActiveRecord Associations with WebORB

Tag: Flex and Rails, tutorialDerek Wischusen @ 2:13 am

Ok, I am finally back from vacation.

This is the third post in a series that covers certain features of Issue Tracker sample app (view, source) that I added to the Flex RoR SDK.

The first post explained how to set up the application.

The second post covered how you can get WebORB for Rails to return typed objects to Flex using the [RemoteClass] metadata tag.

This post covers how to use ActiveRecord Associations with WebORB.

What is an ActiveRecord?

For those of you who are new to Rails, let’s start with a quick discussion of ActiveRecords and ActiveRecord Associations. The ActiveRecord class in Rails is an implementation of Martin Fowler’s Active Record design pattern. Martin defined an Active Record as:

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.

The Rails ActiveRecord class obviously does a lot more than this, but for this tutorial all you need to know is that an ActiveRecord is an object that wraps a table in a database.

What is an ActiveRecord Association?

So, what is an ActiveRecord Association? Well, as you can probably guess, it is association between ActiveRecord objects, or in other words it is an association between tables in a database.

Rails Conventions

To understand how ActiveRecord associations work we need to cover a couple of Rails conventions. As you might know, part of the power of Rails framework is that it favors convention over configuration. This means that if you adhere to Rails conventions it will take less code to get your apps up and running.

Here are two Rails conventions that are relevant to this discussion:

  • A tables primary key column should be named id.
  • Foreign keys should be named <class>_id.
  • For example, in the Issue ActiveRecord class in the Issue Tracker Sample App there is a attribute named project_id. This attribute contains the value in the id attribute for the project that the issue belongs to.

    foreign key convention

    Types of Associations

    There are several different types of relationships that you can create between tables using ActiveRecord Associations. They include:

  • has_one – one to one
  • has_many or belongs_to  - one to many
  • has_and_belongs_to_many – many to many
  • You can use ActiveRecord Associations to quickly create complex relationships. For example,

    has_many :contributors, :through => :contributions, :uniq => true

    This tutorial focuses on the has_many association.

    Creating an Active Record Association

    To see how to create a has_many association between to two ActiveRecord objects, open up the Project class. The class file is located in C:\rails\rails_issue_tracker2\app\models.

    Inside the Project class file you will see the following:

    class Project < ActiveRecord::Base
          has_many :issues, :dependent => :delete_all
    end
    

    This tiny piece of code does a couple of things. The first half (has_many :issues) creates a has_many association between the Project ActiveRecord and the Issue ActiveRecord. The second half (:dependent => :delete_all) states that the issues associated with a project are dependent on that project and that they should be deleted if the project is deleted. In other words, if you a delete a given project, this piece of code tells Rails that all the issues associated with the project should be deleted also.

    Now, to see how we can put this association to work, open up the ProjectService class. The ProjectService class file is located in C:\rails\rails_issue_tracker2\app\Services.

    In the ProjectService class you will see the following method:

    def getProjects(user_id)
         projects = Project.find(:all, :include => [:issues],
     				    :conditions => ['user_id = ?', user_id])
    end
    

    Pay special attention to this bit of code: :include => [:issues]. This argument tells the find method that for each project it finds, it should also go out and get all of the issues that are associated with that project. Rails knows how to do this because of the conventions that I discussed above. For each project that the find method returns, Rails inspects the value in the id column, then it goes out and finds all of the issues that have this value in the project_id column. Now each project will have an attribute named issues that contains an array of all the issues that are a part of that project.

    So, now with this code in place, when you run the Issue Tracker Sample App and log in, the GetProjectsCommand gets executed on the Flex side of the app. This command calls the getProjects method in Rails. The getProjects methods finds all of the projects where the value in the user_id column equals the user_id for the current user. At the same time, the find method goes out and finds the issues for each project and packs them up into an array. WebORB wraps all of this up and returns the projects to Flex as ProjectVOs using the [RemoteClass] metadata tag.

    By default, WebORB takes objects that are typed as arrays in Rails and sends them to Flex as arrays. So, the issue array that is part of each project ActiveRecord instance in Rails is sent to Flex as an array. This is fine for most purposes, but if you want to be able to do databinding then you need to use a collection of some sort (e.g., ArrayCollection, XMLCollection, etc). My simple solution to this problem was to write a setter function that takes the issues array and stores it in a ArrayCollection named issuesCollection. Now you can bind your components to the issueCollection and they will be automatically updated when the collection is updated.

    package com.rxr.issuetracker.vo
     {
     	import com.adobe.cairngorm.vo.IValueObject;
     	import mx.collections.ArrayCollection;
      	[Bindable]
     	[RemoteClass(alias="com.rxr.issuetracker.vo.Project")]
     	public class ProjectVO implements IValueObject
     	{
     	         public var id : int;
      		public var user_id : int;
      		public var title : String;
      		public var issueCollection : ArrayCollection = new ArrayCollection();
      		public function set issues ( value : Array ) : void
     		{
     			issueCollection = new ArrayCollection(value);
     		}
    	  }
     }
    

    ActiveRecord Association in Action

    When you run the Issue Tracker Sample App and log in the Flex app runs the GetProjectsCommand, which calls the getProjects method in the ProjectsService (see above) in Rails. Now that there is a has_many association between the Project ActiveRecord and the Issue ActiveRecord, this single service call returns all of the projects for a given user, and all of the issues associated with each project. So now you can take the result of this single service call (see below) and cache it on the client, which will significantly reduce the number of calls that you have to make to server for the rest of the session.

    active record association

    As always, drop me a line if any of this is unclear or incorrect.


    Dec 17 2006

    Part 2 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Getting Typed Objects from Rails using [RemoteClass]

    Tag: Flex and Rails, tutorialDerek Wischusen @ 1:41 am

    This is the second post in a series that covers certain features of Issue Tracker sample app that I added to the Flex RoR SDK.

    The first post explained how to set up the application.

    This post covers how you can get WebORB for Rails to return typed objects to Flex using the [RemoteClass] metadata tag.

    One of the many design patterns that comprises the Cairngorm microarchitecture is the Value Object pattern.  Value Objects are used to represent the ‘things’ that you are working with in your application.  For example, in the Issue Tracker sample app (view, source) there are currently Value Objects for Users, Projects, and Issues.  The class definitions for all of these objects can be found in com.rxr.issuetracker.vo package.

    Value Objects on the client generally map to server-side objects.  In the Issue Tracker sample app all of the Value Objects listed above map to ActiveRecord classes in Rails, which in turn wrap tables in the database.  For instance, the IssueVO class in Flex maps to the Issue class in Rails (see C:\rails\rails_issue_tracker2\app\models\issue.rb) which wraps the issues table in the database.

    This is the IssueVO class in Flex:

    package com.rxr.issuetracker.vo
    {
             import com.adobe.cairngorm.vo.IValueObject;
    
      	[Bindable]
     	[RemoteClass(alias="com.rxr.issuetracker.vo.Issue")]
     	public class IssueVO implements IValueObject
     	{
      		public var id : int;
      		public var project_id : String;
      		public var reportedby : String;
      		public var assignedto : String;
      		public var description : String;
      		public var status : String;
      		public var priority : String;
      	}
     }
    

    Which maps to:


    class Issue < ActiveRecord::Base
    end



    Which wraps the issues table:

    issue_table2

    Prior to WebORB 1.0.9 this mapping was only conceptual, in that Rails would only return untyped objects or ObjectProxys that would have to be 'manually' converted to Value Objects on the client side. Since WebORB 1.0.9 it is now possible to directly map ActiveRecord classes to classes on the Flex side using the [RemoteClass] metadata tag in Flex.

    Making this happen is pretty straight-forward:

    First, you need to add a [RemoteClass(alias="")] metadata tag just above the class definition of the ActionScript class that you want mapped to an ActiveRecord class.

    [Bindable]
    [RemoteClass(alias="com.rxr.issuetracker.vo.Issue")]
     public class IssueVO implements IValueObject
    {
    

    Next, go to C:\rails\rails_issue_tracker2\config and open weborb-config.xml. In this file you need to specify the mapping between your client-side class and your server-side class. For example, the following xml maps the IssueVO class on the client to the Issue class on the server. Note that you use the string specified in the alias of the [RemoteClass] metadata tag as the value of the clientClass in the class mapping.

    <classMapping>
          <clientClass>com.rxr.issuetracker.vo.Issue</clientClass>
          <serverClass>Issue</serverClass>
          <source>Issue</source>
    </classMapping>
    

    That's it. Now when you make a service call to a method that returns Issue objects in Rails, those objects are automatically returned as IssueVOs to Flex.

    vo_debugger


    Dec 11 2006

    Part 1 – Flex Cairngorm/WebORB Issue Tracker Tutorial

    Tag: Flex and Rails, tutorialDerek Wischusen @ 1:34 am

    This is the first in a series of posts/tutorails that will cover certain features of the Issue Tracker sample app that I recently released.

    Future posts will cover:

    • How to return typed objects from Ruby on Rails using WebORB.
    • How to use active record associations.
    • How to use dynamic finders inside of Flex.
    • Anything else that you tell me you would like me to cover….

    This post will cover how to set up and run the application in Flex.

     

    Prerequisites

    Recommended

    First, if you haven’t already, download the source for the application: http://flexonrails.net/flex_ror_sdk_issue_tracker2.zip. 

    Unzip it, then put the rails_issue_tracker2 folder into C:\rails

    Next, start up Flex Builder.  Click on the File menu and select New->Flex Project

    In the interface that appears, select Flex Data Services and Compile Application locally in Flex Builder. 

    Then click Next>

     

    Step 1

     

    Fill in the next screen as follows:

    Then click Next>

     

    Step 2

     

    On the following screen, enter flex_issue_tracker2 for the Project name.

    Click Next>

     

    Step 3

     

    You need to add the Cairngorm.swc to your libraries for this project.  The Cairngorm.swc was is included in the source files for this project.  You can find it here: flex_ror_sdk_issue_tracker2\Flex_Source\flex_issue_tracker2\cairngorm. 

    Take the .swc file and put it in a folder of your choice.

    Then click Add SWC and browse to folder that you put the swc in.

     

    Step 4 

     

    On the same screen, fill in the form as follows:

    Click Finish

     

    Step 5

     

    Next, open the following folder in the source files: flex_ror_sdk_issue_tracker2\Flex_Source\flex_issue_tracker2

    Select the folders and files shown below and add them to the flex_issue_tracker2 project that you just created.

    That takes care of the Flex side of things.  Now all you need to do is set up the database and tell the Rails app how to access it.

     

    Step 6 

     

    If you are using MySQL, open up the MySQL Command Line Client and enter:

    CREATE DATABASE issue_tracker;

     

    Step 7

     

    Next, go to the config folder in your Rails app (rails_issue_tracker2\config) and open database.yml.

    Fill in your username and password for your database where indicated below.

     

    Step 8 

     

    Now that your Rails app can access your database, it’s time to create the tables using Rails migrations.  You can see the files that define the tables by going to rails_issue_tracker2\db\migrate.

    Open a command line and point it to your Rails app folder (c:rails\rails_issue_tracker2) and enter

    rake migrate

    Ok, the tables have been created and the app is ready to go.  All that remains to do is to boot up the server and test it out.  On command line enter

    ruby script/server (or mongrel_rails start if you are using Mongrel).

     

    Step 9

     

    Lastly, go back into Flex Builder, click Run Debug(F11), and you should see the screen displayed below.

     

    Step 10

     

    Let me know if you have any questions, or if anything in this post is unclear or incorrect.


    Best viagra dose
    40 mg prednisone side effects
    5mg valium
    Cialis
    Viagra discount prices
    Tramadol dosage
    Best price phentermine
    Dosage of valium
    Cheap levitra pills
    Tramadol price
    Cialis 20mg effects
    Buy prednisone
    Buy valium roche online
    Cheap generic xanax
    Canadian viagra prices
    Discount generic viagra
    Buying levitra in australia
    Propecia dosages
    Viagra in the philippines
    Generic cialis online canada
    Cheap levitra
    Order viagra online no prescription
    Cheap online xanax
    Valium in uk
    Canada viagra prescription
    Valium for sale uk
    Generic viagra sales
    Buying cialis without a prescription
    Online prescription for xanax
    Tramadol generic
    Buy cheap tramadol online without prescription
    Prescription cialis online
    Buy cheap viagra pills
    Order xanax online without prescription
    Uk viagra over the counter
    Viagra online without prescription free shipping
    Discount phentermine 37.5 without prescription
    Viagra prices
    Buy valium no prescription
    Viagra 50mg side effects
    Tramadol online no prescription
    Brand name viagra online without prescription
    Cialis 20mg tablets
    Dosage of prednisone
    Viagra pfizer price
    Viagra online without prescription overnight
    Cialis soft tablets
    Generic propecia for sale
    Buy viagra online cheap
    Propecia cheapest price
    Genuine pfizer viagra
    Purchase viagra canada
    Viagra online sales
    Buy cheap tramadol without prescription
    Cialis without prescription overnight
    Generic viagra professional
    Canada pharmacy phentermine
    Online prescriptions xanax
    Cialis prescription canada
    Where to buy xanax
    Cheap phentermine 37.5 without prescription
    Phentermine 37.5 reviews
    Cod tramadol overnight
    Buy viagra without a prescription
    Order viagra overnight
    Phentermine hcl 37.5 no prescription
    Canada generic viagra
    Where to buy phentermine 37.5 without prescription
    Buy viagra uk without prescription
    Buy viagra without prescription online
    Levitra lowest price
    Viagra dosage information
    Drug valium
    Cialis professional 20 mg
    Viagra usa online
    Generic viagra online pharmacy
    Valium 20mg
    Discount tramadol
    Propecia by mail
    Propecia prices uk
    Cialis information
    Cialis medicine
    Phentermine 37.5 tablets
    Cialis online canada
    Free viagra samples online
    Buy viagra online uk
    Xanax with no prescription
    Viagra in canada without prescription
    Cialis 10mg price
    No prescription phentermine
    Buy viagra london
    Generic viagra in india
    Cheapest phentermine
    Valium for sale in the uk
    Buy propecia without a prescription
    Buy tramadol hcl
    Discount xanax
    Price propecia
    Buy brand viagra online
    Where can i buy viagra without prescription
    Phentermine no prescription
    Buy generic phentermine
    Buying viagra
    Cheap tramadol online overnight delivery
    Prednisone dosages
    Buy real viagra online without prescription
    Buy tramadol hydrochloride

    Cheap generic valium
    Prednisone side effects
    Valium uk delivery
    Buy phentermine adipex
    Fast shipping viagra
    Phentermine online canada
    Generic tramadol no prescription
    Viagra prescriptions
    Viagra sale uk
    Canada pharmacy viagra
    Phentermine online pharmacy
    Cheap cialis generic
    Buy viagra without prescription
    Where can i buy tramadol
    Brand cialis without prescription
    Viagra cost in canada
    Brand valium
    Phentermine 37.5 lowest price
    Where can i buy phentermine online without a prescription
    Order cheap phentermine
    Cialis for sale online
    Buy female viagra without prescription
    Tramadol online cheap
    Xanax drug dosage
    Phentermine 37.5 pills
    Cialis online overnight
    Free samples of viagra
    Generic viagra in the us
    37.5mg phentermine
    Order phentermine online without a prescription
    Prescription xanax
    Xanax canadian pharmacy
    Cialis generic 5mg
    Ordering phentermine online
    Cheap propecia canada
    Viagra soft tablets
    Discount levitra
    Cheap online tramadol
    Buy cialis brand
    Buy cheap valium online
    Viagra online cheap
    Cialis uk online
    Viagra in usa
    Overnight viagra
    Get viagra prescription online
    Cheap cialis prices
    Cheap cialis viagra
    Buy viagra online australia
    Best prices for viagra
    Cialis professional generic
    Online xanax no prescription
    Buy cheap viagra
    Best place to buy xanax
    Price of phentermine
    Cialis 10mg tablets
    Cialis online pharmacy canada
    Cialis cost
    Buy cialis online cheap
    Online prescription phentermine
    Generic cialis professional
    Cialis overnight shipping
    Valium online order
    Brand levitra
    Buying phentermine without a prescription
    Best viagra online
    Order cialis from canada
    Phentermine 37.5mg diet pills
    Where to buy xanax without prescription
    Cialis buy online
    Canada phentermine 37.5
    Viagra without rx
    Valium online fast delivery
    Cialis uk supplier
    Best way to take tramadol
    Propecia buy canada
    50 mg viagra online
    Cialis buy uk
    Order generic viagra
    Cialis price canada
    Prescription phentermine 37.5 mg
    Phentermine 37.5 diet pills
    Valium online no prescription
    Viagra discount coupons
    Generic viagra cheap
    10mg valium
    Where can i buy viagra cheap
    Generic cialis no prescription
    Order generic cialis
    Buy prednisone dose pack
    Buying cheap viagra
    Online xanax pharmacy
    Phentermine in the uk
    Discount xanax no prescription
    50mg cialis
    Buy viagra uk
    Xanax prescription prices
    Viagra express shipping
    Buy cialis generic
    Generic cialis information
    Where to buy propecia in canada
    Cheap levitra uk
    Cheap tramadol overnight delivery
    Discount propecia
    Tramadol hcl 200mg
    Female viagra uk
    Buy tramadol online canada
    Get viagra in canada
    Where to buy propecia in australia
    Price of viagra tablets in india
    Valium for sale in uk
    Cialis 10
    Buying generic cialis online
    Cialis pricing
    Tramadol 200mg
    Phentermine 37.5 results
    Phentermine 37.5 capsules
    Canadian pharmacy for cialis
    50 mg viagra
    Phentermine rx
    Tramadol no prescription overnight
    Canadian cialis online
    100mg tramadol buy
    Phentermine without a prescription
    Buying valium uk
    Cheapest online tramadol
    Buy viagra with no prescription
    Cheap viagra from india
    Buy viagra pills
    Xanax overnight delivery
    Generic phentermine 37.5 without prescription
    Tramadol hcl 50mg side effects
    Get tramadol online
    Overnight viagra delivery
    Buy viagra online safely
    Cheap xanax no prescription
    Where to buy phentermine online
    Viagra without prescription
    Where can i buy generic viagra
    Buy levitra online without prescription
    Get viagra without a prescription
    Buy cheap generic viagra online
    Buy phentermine direct pharmacy cheap