<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html" />
  <link rel="self" type="application/atom+xml" href="http://www.insideria.com/atom.xml" />
  <id>tag:www.insideria.com,2009://34/tag:www.insideria.com,2008://34.23328-</id>
  <updated>2009-11-16T15:46:40Z</updated>
  <title>Comments for Anatomy of an Enterprise Flex RIA Part 14: Services and Delegates (http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2008://34.23328</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=23328" title="Anatomy of an Enterprise Flex RIA Part 14: Services and Delegates" />
    <published>2008-04-21T14:30:00Z</published>
    <updated>2008-10-01T01:05:39Z</updated>
    <title>Anatomy of an Enterprise Flex RIA Part 14: Services and Delegates</title>
    <summary>Last time we looked at Cairngorm and its role in our application.  This installment of Anatomy of an Enterprise Flex RIA, we&apos;re going to look at Cairngorm&#8217;s business delegates and how to set up a service oriented architecture in Flex.  Join us every Monday for the next installment in our series: Anatomy of an Enterprise Flex RIA.</summary>
    <author>
      <name>Tony Hillerson</name>
      
    </author>
    
    <category term="Features" />
    
    <content type="html" xml:lang="en" xml:base="http://www.insideria.com/">
      <![CDATA[<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex/riaseries_part14.jpg" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex/riaseries_part14.jpg" alt="riaseries_part14.jpg" title="Click to enlarge" width="148"/></a></div>

<p>Last time we looked at Cairngorm and its role in our application.  This installment of Anatomy of an Enterprise Flex RIA, we're going to look at Cairngorm&#8217;s business delegates and how to set up a service oriented architecture in Flex.  </p>

<p><strong>Services and Delegates</strong></p>
<p>The ServiceLocator and delegates for Bookie are the last stop on the Flex side for calls to the services. Figure 18 shows where they&#8217;re located.</p>


<div class="ap_c"><a href="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex/anatomy14_fig18.jpg" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex/anatomy14_fig18.jpg" alt="anatomy14_fig18.jpg" title="Click to enlarge" width="400"/></a><div class="acaption">Figure 18. Location of the ServiceLocator and delegates for Bookie</div></div>




<p>The ServiceLocator definition for Bookie is fairly simple and declarative:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 60px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
&lt;?xml <span class="category2">version</span>="<span class="quote">1.0</span>" encoding="<span class="quote">utf-8</span>"?&gt;
&lt;cairngorm:ServiceLocator...&gt;
    &lt;mx:RemoteObject  id="<span class="quote">bookSearchService</span>"
                    destination="<span class="quote">bookSearchService</span>"
                    showBusyCursor="<span class="quote">true</span>"&gt;
     &lt;/mx:RemoteObject&gt;    
     &lt;mx:DataService id="<span class="quote">bookDataService</span>" destination="<span class="quote">bookService</span>" /&gt;
     &lt;mx:DataService id="<span class="quote">subjectDataService</span>" destination="<span class="quote">subjectService</span>" /&gt;
     &lt;mx:DataService id="<span class="quote">personDataService</span>" destination="<span class="quote">personService</span>" /&gt;
     &lt;mx:DataService id="<span class="quote">reservationDataService</span>" destination="<span class="quote">reservationService</span>" /&gt;
     &lt;mx:Consumer id="<span class="quote">reservationConsumer</span>" destination="<span class="quote">outstandingReservationTopic</span>" /&gt;
&lt;/cairngorm:ServiceLocator&gt;</pre>
</code>
 
</div></div>
<p>Each tag points to a destination defined in an LCDS configuration file: data-management-config.xml for the DataServices, which map to our assemblers; and remoting-config.xml for the RemoteObject, which points to lcds.examples.bookie.service.BookSearchExample. We&#8217;ll see how to get a reference to these services from the delegates next.</p>
<p>There are two delegates in Bookie, the BookieDelegate and the AdminDelegate, corresponding to the service calls needed for each part of the application. The delegates are simple, and again, they act mostly as a buffer to change in the service layer. </p>
<p>Let&#8217;s look at the BookieDelegate, which uses both data services and a remote object:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 60px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
package lcds.examples.bookie.business {
 ...
     <span class="category1">public</span> <span class="category1">class</span> BookieDelegate {
  ...
           <span class="category1">private</span> <span class="category1">var</span> responder:IResponder;
           <span class="category1">private</span> <span class="category1">var</span> bookSearchService:RemoteObject;
           <span class="category1">private</span> <span class="category1">var</span> subjectService:DataService;
           <span class="category1">private</span> <span class="category1">var</span> personService:DataService;
           <span class="category1">private</span> <span class="category1">var</span> reservationService:DataService;
           <span class="category1">private</span> <span class="category1">var</span> services:ServiceLocator =
                      ServiceLocator.getInstance();
  
           <span class="category1">public</span> <span class="category1">function</span> BookieDelegate(responder:IResponder=<span class="category1">null</span>) {bookSearchService =
                     services.getRemoteObject("<span class="quote">bookSearchService</span>");
                 subjectService =
                     services.getDataService("<span class="quote">subjectDataService</span>");
                 personService =
                     services.getDataService("<span class="quote">personDataService</span>");
                 reservationService =
                     services.getDataService("<span class="quote">reservationDataService</span>");
                 <span class="category1">this</span>.responder = responder;
            }
  ...</pre>
</code>
 
</div></div>
<p>First, in the constructor, we take an argument of a responder, which is a simple interface that looks like this:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 60px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">interface</span> IResponder {
     <span class="category1">function</span> result(<span class="category2">data</span>:<span class="category2">Object</span>):<span class="category1">void</span>;
     <span class="category1">function</span> fault(info:<span class="category2">Object</span>):<span class="category1">void</span>;
}</pre>
</code>
 
</div></div>
<p>Each command that calls a delegate implements this interface, which gets the callback from any service calls to the result method if the call went well, and to fault if the call went south.</p>
<p>Each command is responsible for instantiating its own delegate, and the delegate keeps a reference to the responder that called it. In the constructor, the delegate also sets up a reference to all the services:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 60px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
...
<span class="category1">public</span> <span class="category1">function</span> findPersonByCardNumber(cardNumber:<span class="category2">String</span>):<span class="category1">void</span> {
     <span class="category1">var</span> <span class="category2">call</span>:AsyncToken = bookSearchService.findPersonByCardNumber(cardNumber);
     <span class="category2">call</span>.addResponder(responder);
}</pre>
</code>
 
</div></div>
<div class="ap_r" style="width:180px;"><a href="http://www.oreilly.com/catalog/9780596514402/?CMP=ILC-dm_nav_related-books" target="_blank"><img border="0" src="http://www.oreilly.com/catalog/covers/9780596514402_cat.gif" width="180" height="233" /></a>
<div class="apcaption"><a href="http://www.oreilly.com/catalog/9780596514402/?CMP=ILC-dm_nav_related-books" target="_blank">Get your copy of Tony Hillerson's Enterprise Application Development with Flex.</a></div></div><p>Next, we see one example of a delegate call, findPersonByCardNumber. It simply takes a card number as a string, calls the method of the same name on the bookSearchService RemoteObject, and gets a reference to the AsyncToken returned by that call, which acts as a handler to the call and knows how to call back to a registered responder. Calling addResponder registers the responder with the token. Once the call returns, one of the result or fault methods of the responder will be called.</p>
<p>How does Flex know there&#8217;s a method called findPersonByCardNumber on the RemoteObject? Well, strictly speaking, it doesn&#8217;t, so you could get an exception at runtime if there were a spelling mistake. What really happens when you call any method on a RemoteObject is that a method of the same name is invoked on the object the RemoteObject points at through a destination. This works because RemoteObject is a subclass of flash.utils.Proxy, which is a class that knows how to deal with calls to methods that don&#8217;t exist on the object. It seems like magic, but it works great, and it&#8217;s a lot better than trying to deal with web services and all that packing and unpacking of XML. Now let&#8217;s look at a call to a DataService:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 60px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
...
<span class="category1">public</span> <span class="category1">function</span> getAllSubjects(collection:ListCollectionView):<span class="category1">void</span> {subjectService.fill(collection);
}
...</pre>
</code>
 
</div></div>
<p>This method on the delegate is pretty darn simple, right? That&#8217;s LCDS. All we do is to pass in a reference to a collection we want to fill with a set of data, and then call the fill method on a data service with that collection. The rest happens automatically. Now that collection is managed, and because we&#8217;ve left on the default auto-sync behavior of the DataServices, any changes to managed items in the collection or changes to the collection itself, such as additions or removals, will be sent to the assembler, on through the session bean the assembler wraps, and into the database.</p>
<p>Remember that the code samples have RemoteObject services mixed with DataServices to provide an example of each. It&#8217;s easy to see that for most &#8220;save this object&#8221; use cases, a DataService is the way to go. For other use cases that rely on communication with a POJO, RemoteObject is the way to go.</p>
<p>Make note of the delegate methods in BookieDelegate that call methods on the BookSearchService RemoteObject:</p>
<ul><li>findPersonByCardNumber</li><li>findBooksByAuthor</li><li>findBooksByTitle</li><li>findBooksBySubject</li></ul>

<p>The remaining methods in BookieDelegate and AdminDelegate all use various DataServices. I&#8217;ve left some methods in the BookSearchService to do some of the same things that are done with the DataServices. Feel free to experiment with changing between the RemoteObject and the DataService services.</p>





<p>Next time we'll see how Cairngorm commands, the workhorse of the micro-architecture, fit into our application. You can always find the entire series <a href="http://www.insideria.com/series-anatomy-flex.html">here</a>.</p>
]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.23328-comment:2017228</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.23328" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html#comment-2017228" />
    <title>Comment from Andre Dekker on 2008-05-19</title>
    <author>
        <name>Andre Dekker</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>Hello Tony,</p>

<p>You have done a great job with these series about Flex. <br />
Especially Cairngorm in combination with LCDS is very interesting for me.</p>

<p>However there is one problem i've got reproducing your code in my own project.</p>

<p>These lines of code in the delegate won't work:</p>

<p>private var services:ServiceLocator =<br />
                      ServiceLocator.getInstance();<br />
subjectService =                    services.getDataService("subjectDataService");</p>

<p><br />
the method "getDataService" does not exist in my ServiceLocator :((</p>

<p>I am using the latest version of Cairngorm (2.2.1)</p>

<p>Do i miss something ?</p>

<p>Please help me out.</p>

<p></p>

<p><br />
</p>]]>
    </content>
    <published>2008-05-19T10:23:08Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.23328-comment:2017230</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.23328" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html#comment-2017230" />
    <title>Comment from Tony Hillerson on 2008-05-19</title>
    <author>
        <name>Tony Hillerson</name>
        <uri>http://thillerson.blogspot.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://thillerson.blogspot.com">
        <![CDATA[<p>@andre - If you updated to the latest version of Cairngorm, make sure you got the Enterprise version, since that has the data service methods.</p>

<p>Try here: <a href="http://labs.adobe.com/wiki/index.php/Cairngorm:Cairngorm2.2.1:Download">http://labs.adobe.com/wiki/index.php/Cairngorm:Cairngorm2.2.1:Download</a></p>]]>
    </content>
    <published>2008-05-19T14:41:05Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.23328-comment:2020571</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.23328" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-8.html#comment-2020571" />
    <title>Comment from Joel Hooks on 2008-08-10</title>
    <author>
        <name>Joel Hooks</name>
        <uri>http://joelhooks.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://joelhooks.com">
        <![CDATA[<p>Specifically you want to use EnterpriseServiceLocator to make use of LCDS DataService.</p>]]>
    </content>
    <published>2008-08-11T01:04:29Z</published>
  </entry>

</feed
