Changes between Initial Version and Version 1 of HowTos/HowToUseRemoting

Show
Ignore:
Timestamp:
11/16/09 23:42:36 (16 years ago)
Author:
cfgrok (IP: 64.30.223.5)
Comment:

Renamed page for alpha sorting on home page

Legend:

Unmodified
Added
Removed
Modified
  • HowTos/HowToUseRemoting

    v1 v1  
     1= How To Use Remoting = 
     2 
     3== History == 
     4As Model-Glue came to be used more and more often for larger and larger applications, it became commonplace to have a Flex or AJAX widget that required functionality already written for another part of the application. While it is possible to structure your application to use other techniques, it's also very convenient to run a Model-Glue event as a remoting call. Unfortunately, under Model-Glue 2 the only way to accomplish this was to create a new event that used existing broadcasts and a new view to generate text in XML or JSON format. The Flex or AJAX client would then use an HTTP GET or POST operation against this event and parse the body of the response into the appropriate native container type. 
     5 
     6This particular technique wasn't very well received because it amounts to warping a view into a transfer object of a sort. While it works, it's certainly not a desired approach. While AJAX was, due to it's pure HTTP- and text-based nature, less affected by the issues with this approach, Flex and Flash applications or widgets were extremely hampered by it. This technique is entirely text-based and cannot make use of the binary protocol AMF and the !FlashRemoting gateway for the dual benefits of performance and reduced bandwidth. It required an HTTP GET or POST, requiring the Flex HTTPRequest object instead of the !RemoteObject for more efficient remote transmissions. As Flex became a bigger player in conjunction with Model-Glue applications, this solution became less and less desirable. Ultimately, a complete analasys of the ramifications of this technique is beyond the scope of this document, but it is widely considered to be a messy solution at best and a complete hack at worst. A better way for remoting clients to leverage Model-Glue's strengths was needed. 
     7 
     8Enter Model-Glue Remoting in !ModelGlue 3. This feature allows you to accomplish the exact same result without having to warp the <views /> into data packets.  
     9 
     10== The Basics == 
     11 
     12The process is simple. Model-Glue 3 has a component called "!RemotingService.cfc" that sits in the root of your project folder and uses cfmodule to run the index.cfm file of your application. The !RemotingService extends !ModelGlue.gesture.remoting.!AbstractRemotingService which provides one function: executeEvent(). When you call !RemotingService.executeEvent(...), the remoting service uses a handle on the ModelGlue instance in the application scope to run the event and then extracts values you've asked for from the Event object into a struct which is then returned to your remoting client. And because of how this is all implemented, it can be used either via a Flex !RemoteObject, directly, or as a web service. This makes it possible for Flex, AJAX, and HTML applications to all make use of common functionality.  
     13 
     14== Some basic rules regarding the !RemotingService.cfc == 
     15 
     16Regardless of any other factor, the CFC in question must follow two rules: 
     17 
     181. It must live in the root folder of a Model-Glue application. This is because it relies on the presence of an instane of !ModelGlue.cfc in the application scope to locate and run any events. It can have any name but it has to be in the root of the application. 
     191. It must extend modelglue.gesture.remoting.!AbstractRemotingService. This base class provides essential functionality (such as locating the Model-Glue instance in the application scope regardless of the name of the variable containing it).  
     20 
     21 
     22== Example Application == 
     23 
     24Before showing how the Flex and AJAX remoting works within Model-Glue, we first need to set up a very simple MG3 application which will have a single event "get.users" which will return a list of users. Feel free to use the new Model-Glue 3 "Event Generation" feature to generate some of this setup code. We're not going to explain the MG3 event handling in this article. There are specific chapters in the documentation that fully explains this process. We are assuming here that you know this process already from your standard MG3 development. 
     25 
     26 
     27First, we need to create a Users.cfc in our "model" folder. 
     28 
     29The code for this CFC 
     30{{{ 
     31#!xml 
     32        <cfcomponent output="false"> 
     33            <cfset variables.instance = StructNew()/> 
     34 
     35            <cffunction name="init" access="public" output="false" returntype="Users"> 
     36                <cfreturn this/> 
     37            </cffunction> 
     38 
     39        <cffunction name="getUsers" access="remote" output="false" returntype="any"> 
     40            <cfset var local = StructNew()/> 
     41            <cfset local.myQuery = QueryNew("name","varchar")> 
     42            <cfloop from="1" to="12" index="local.j"> 
     43                <cfset QueryAddRow(local.myQuery, 1)> 
     44                <cfset QuerySetCell(local.myQuery, "name", "Person-#local.j#", local.j)> 
     45            </cfloop> 
     46            <cfreturn local.myQuery/> 
     47        </cffunction> 
     48 
     49    </cfcomponent> 
     50}}} 
     51 
     52So this CFC has a "getUsers" method which returns a query object of users. This naturally could be altered to pull from a database. 
     53 
     54Next, we need a controller CFC called "!GetController" which will be placed in our "controller" folder. 
     55 
     56The code for !GetController.cfc is.. 
     57{{{ 
     58#!xml 
     59    <cfcomponent output="false" beans="Users" extends="ModelGlue.gesture.controller.Controller"> 
     60 
     61        <cffunction name="init" access="public" output="false" hint="Constructor"> 
     62            <cfreturn this /> 
     63        </cffunction> 
     64 
     65        <cffunction name="users" output="false"> 
     66            <cfargument name="event" /> 
     67 
     68            <cfset event.setValue("users",beans.Users.getUsers())/> 
     69        </cffunction> 
     70     
     71    </cfcomponent> 
     72}}} 
     73 
     74Notice here, we are using the new Model-Glue 3 feature called "bean injection". The controller has a scope called "beans" which contains an instance of our Users.cfc class. For this to work properly, you need to define the Users.cfc bean in the Coldspring.xml file like so.. 
     75 
     76{{{ 
     77#!xml 
     78    <bean id="Users" class="mapping_to_your_app.model.Users"/> 
     79}}} 
     80 
     81Naturally, the mapping to your application may vary. Typically it will be your project name followed by ".model.Users". So, for example, "mydemo.model.Users". 
     82 
     83We now need a listener for our new controller. We define this in our !ModelGlue.xml file. Inside the "controllers" tags, include the following.. 
     84 
     85{{{ 
     86#!xml 
     87        <controller id="!GetController" type="mapping_to_your_app.controller.!GetController"> 
     88            <message-listener function="users" message="get.users" /> 
     89        </controller> 
     90}}} 
     91 
     92Next, we need to define our event handler in our !ModelGlue.xml file. Inside our "event-handlers" tags, we include the following.. 
     93 
     94{{{ 
     95#!xml 
     96        <event-handler name="get.users"> 
     97            <broadcasts> 
     98                <message name="get.users" /> 
     99            </broadcasts> 
     100            <results /> 
     101            <views> 
     102                <include name="body" template="get/users.cfm" /> 
     103            </views> 
     104        </event-handler> 
     105}}} 
     106 
     107Ok, so when Model-Glue receives an event called "get.users". To make certain we did everything right, go ahead and create a page called "users.cfm" in "/views/get/" folder. In the users.cfm page we will simply dump the query object to make certain everything is wired up correctly. 
     108 
     109{{{ 
     110#!xml 
     111<cfdump label="My Users" var="#event.getValue("users")#"> 
     112}}} 
     113 
     114Now, if you run your application and using the following url "index.cfm??event=get.users", you should see the following. 
     115 
     116(Image in progress) 
     117 
     118Ok, we can now proceed with our Flex and AJAX remoting examples. 
     119 
     120== Flex Example == 
     121 
     122In this example, we will make a Flex remote object call to get our "users" query which will be placed in an !ArrayCollection which in turn will be the data provider for a !DataGrid. 
     123 
     124== A couple of Important Things to Note about using Flex Remoting: == 
     125 
     1261. If you have a /!ModelGlue mapping (via either Application.cfc or the ColdFusion Administrator), Flash Remoting will not work until you have edited {cfusion_home}/wwwroot/WEB-INF/flex/remoting-config.xml (on J2EE or multiserver, it's inside {jrun_home}/servers/cfusion.ear/cfusion.war/WEB-INF/flex/remoting-config.xml). You have to find the setting <use-mappings>false</use-mappings> and change it to true. Then restart your CF server. Until you've done this, calls to MG remoting from Flex applications will fail due a file not found. This only applies to Flex applications making remoting calls through the !FlashRemoting gateway. 
     127 
     1281. For the application to work properly, it will need to understand the remoting destination and endpoints. There are a number of ways to handle this, this is the simplest. In the Flex project properties in Flex Builder, go to Flex Compiler and add the following to the Additional Compiler Arguments" 
     129 
     130{{{ 
     131     -services "directory_path_to_your_flex_folder/WEB-INF/flex/services-config.xml" -context-root="" 
     132}}} 
     133 
     134For the Flex example, we will go ahead and show the complete code and then explain what is happening here. 
     135 
     136{{{ 
     137#!xml 
     138<?xml version="1.0" encoding="utf-8"?> 
     139<mx:Application 
     140    xmlns:mx="http://www.adobe.com/2006/mxml" 
     141    creationComplete="init()"> 
     142 
     143    <mx:Script> 
     144        <![CDATA[ 
     145        import mx.collections.ArrayCollection; 
     146        import mx.rpc.events.*; 
     147         
     148        [Bindable] 
     149        public var _users:ArrayCollection; 
     150 
     151        public function init():void{ 
     152 
     153            //call Model-Glue Remoting Service cfc 
     154            mgrs.executeEvent("get.users",{},"users"); 
     155        } 
     156 
     157        public function resultHandler(event:ResultEvent):void{ 
     158            _users = event.result.users as ArrayCollection; 
     159        } 
     160         
     161        ]]> 
     162    </mx:Script>     
     163 
     164    <mx:RemoteObject id="mgrs" 
     165                    destination="ColdFusion" 
     166                    source="mapping_to_your_MG3_app.RemotingService" 
     167                    result="resultHandler(event)" 
     168                    showBusyCursor="true" /> 
     169 
     170    <mx:DataGrid id="dg" dataProvider="{_users}"/> 
     171     
     172</mx:Application> 
     173}}} 
     174We define our Remote Object service with the "mx:RemoteObject" tag. In this tag, we called the standard "!ColdFusion" service defined in your remoting-config.xml in your flex folder on the !ColdFusion server. The source defines the specific cfc we will are calling which in with our MG3 app will always be the !RemotingService.cfc. When the result comes back, we have a function called "resultHandler()" which will process the data. 
     175 
     176When this Flex application runs, we start off with calling the init() function with our creationComplete() located near the top of the file. The init() makes the remote object call to the "executeEvent" method located in the !RemotingService.cfc. That method has 3 arguments. The first argument is the event string. This is exactly the same value you would use in the url in a normal MG3 application. The second argument is are values you need to submit with the event. In this example we didn't have any values to submit, but for future reference you simply can submit values as an object of name/value pairs like so, {Param1:"Hi!", Param2:76}. The third argument is the MG3 event object key we want back. MG normally returns lots of things in the "event" object. For our purposes, we just want the "users" object. 
     177 
     178The resultHandler() function simply puts the returned object into the internal _users array collection which powers our datagrid. 
     179 
     180So when we run this application, we should see the following. 
     181 
     182(Image in progress) 
     183 
     184Pretty simple example, but with this you can now understand the flow of using the MG3 remoting features. 
     185 
     186== AJAX Example with jQuery == 
     187jQuery is a popular Javascript library for building Rich Internet Applications. We're not going explain all the features of jQuery here, but this simple example will explain how it can be used to call the MG3 remoting service. As before, we'll go ahead and see the entire code and then go through it's operation. 
     188 
     189The following code is a single html file. 
     190{{{ 
     191#!xml 
     192<script type="text/javascript" src="js/jquery.js"></script> 
     193 
     194<script type="text/javascript"> 
     195$(document).ready(function() { 
     196 
     197    var mgrsURL = "/url_path_to_my_app/RemotingService.cfc?method=executeEvent&returnformat=json&queryFormat=column"; 
     198    var args = new Object(); 
     199    args.eventName = "get.users"; 
     200    args.returnValues = "users"; 
     201 
     202    //Various additional variables to pass with this request 
     203    args.orderby = "name"; 
     204    args.active = true; 
     205 
     206    $.ajax({ 
     207        type: "POST", 
     208        url: mgrsURL, 
     209        data: args, 
     210        dataType: "json", 
     211        success: function(qry){ 
     212 
     213            $('.users').empty(); 
     214 
     215            for(var i=0;i < qry.users.ROWCOUNT; i++){             
     216                var html = '<li>'+qry.users.DATA.name[i]+'</li>'; 
     217                $('.users').append(html); 
     218            }; 
     219        } 
     220    }); 
     221}); 
     222</script> 
     223 
     224<div class="users">Processing..</div> 
     225}}} 
     226 
     227The $(document).ready() fires up after the page is loaded. We start off by setting some variables. We will call the !RemotingService.cfc directly by url. When we do this, we can also specify the return format. The default is WDDX but the JSON format is prefer for AJAX applications. The "queryFormat=column" provides some additional information which we use in handling the loop later on. 
     228 
     229Like the previous Flex example, we have two critical variables to define. The first is the MG3 "event name" we wish to call and the second is the event object key (basically the returned values) we need back for the remoting call. We can also set additional arguments if required. 
     230 
     231If the call is successful, then we loop over the result and build out a html string of list items "<li>". This html string is then appended into the 'users' div area on the page. When you run this page you should initial see a single line saying "Processing.." for a second then the following result. 
     232 
     233(Image in progress) 
     234 
     235Again, this is a fairly simple example, but you can now see how the same MG3 Remoting service can power AJAX or Flex applications with ease.