<?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-6.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.23324-</id>
  <updated>2009-11-16T15:47:53Z</updated>
  <title>Comments for Anatomy of an Enterprise Flex RIA Part 12: Building the Java Service Layer (http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-6.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2008://34.23324</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-6.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=23324" title="Anatomy of an Enterprise Flex RIA Part 12: Building the Java Service Layer" />
    <published>2008-04-07T14:57:56Z</published>
    <updated>2008-10-01T01:18:06Z</updated>
    <title>Anatomy of an Enterprise Flex RIA Part 12: Building the Java Service Layer</title>
    <summary>Last time we looked at testing the Java part of the application so far. In this section of the series from Tony Hillerson&apos;s Enterprise Application Development with Flex, we&apos;ll look at Maven building our service layer, and be introduced to the powerful LiveCycle Data Services assemblers, which deal with the managed data flowing in and out of Flex.  Follow along every Monday with our project!</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_part12.jpg" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex/riaseries_part12.jpg" alt="riaseries_part12.jpg" title="Click to enlarge" width="148"/></a></div>


<p><a href="http://www.insideria.com/2008/03/anatomy-of-an-enterprise-flex-5.html" target="_blank">Last time</a> we looked at testing the Java part of the application so far. In this section of the series from Tony Hillerson's Enterprise Application Development with Flex, we'll look at Maven building our service layer, and be introduced to the powerful LiveCycle Data Services assemblers, which deal with the managed data flowing in and out of Flex.  </p>

	

	<p><strong>Maven Configuration</strong></p>
<p>Here is the Maven configuration:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 220px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
&lt;?xml <span class="category2">version</span>="<span class="quote">1.0</span>"?&gt;
&lt;project ...&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;parent&gt;
         &lt;artifactId&gt;bookieProject&lt;/artifactId&gt;
         &lt;groupId&gt;lcds.examples.bookie&lt;/groupId&gt;
         &lt;<span class="category2">version</span>&gt;1.0-SNAPSHOT&lt;/<span class="category2">version</span>&gt;
    &lt;/parent&gt;
    &lt;groupId&gt;lcds.examples.bookie&lt;/groupId&gt;
    &lt;artifactId&gt;bookie-ui&lt;/artifactId&gt;
    &lt;<span class="category2">version</span>&gt;1.0-SNAPSHOT&lt;/<span class="category2">version</span>&gt;
    &lt;packaging&gt;war&lt;/packaging&gt;
    &lt;<span class="category2">name</span>&gt;Bookie Example WAR Project&lt;/<span class="category2">name</span>&gt;
    &lt;build&gt;
         &lt;finalName&gt;bookie&lt;/finalName&gt;
         &lt;plugins&gt;
              &lt;plugin&gt;
                   &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;
                   &lt;configuration&gt;
                        &lt;warSourceDirectory&gt;
                             ${basedir}/src/main/bookie.war
                        &lt;/warSourceDirectory&gt;
                   &lt;/configuration&gt;
              &lt;/plugin&gt;
...
    &lt;dependencies&gt;
         &lt;dependency&gt;
              &lt;groupId&gt;lcds.examples.bookie&lt;/groupId&gt;
              &lt;artifactId&gt;bookie-<span class="category2">data</span>&lt;/artifactId&gt;
              &lt;<span class="category2">version</span>&gt;1.0-SNAPSHOT&lt;/<span class="category2">version</span>&gt;
              &lt;scope&gt;provided&lt;/scope&gt;
         &lt;/dependency&gt;
...
&lt;/project&gt;</pre>
</code>
 
</div></div>
<p>There&#8217;s nothing too new to announce here. First we have to tell Maven that this project has a parent project, and then we have to identify the project. Next, we set the <packaging> to war to tell Maven what type of artifact we expect to build.</p>
<p>One extra step I take is to reconfigure the name of the WAR source directory to be bookie.war instead of the default webapp. I think it&#8217;s more descriptive.</p>
<p>The dependencies include some files we put directly into our repository, as well as the dependency on the bookie-data project.</p>
<p><strong>Services</strong></p>
<p>Let&#8217;s review the use cases we discussed when Iintroduced the project. First, we&#8217;ll look at the user use cases. We&#8217;re going to define an API (a set of methods that we&#8217;ll expose as a simple service for other clients&#8212;in this case, Flex) in a simple class called lcds.examples.bookie.service.BookSearchService. As you&#8217;ll see as you look at the class, it&#8217;s a set of methods that simply invoke the session beans we defined in the preceding section. The benefits of consolidating these calls into one class are as follows:</p>
<ul><li>This is a good Service-Oriented Architecture (SOA) practice whereby a service ties together classes that support a certain category of business need into one service.</li>
<li>We get a single point of access to retrieve the important methods of all the beans, which allows for better control over concerns such as role-based security.</li>
<li>We can define one RemoteObject for Flex to access as a service.</li></ul>

<p>The single point of access is important, because here we can do anything that needs to be done for every remote call. We don&#8217;t want to do anything special for our sample, but it&#8217;s a good practice to follow.</p>
<p>This service API will get us through most of the use cases for users and allow us to look at how to access Plain Old Java Objects (POJOs) from Flex. We&#8217;ll also use a feature of LCDS called an &#8220;assembler&#8221; to let us take advantage of some of the managed data features and how they can make our lives easier.</p>
<p>Note that I&#8217;ve split the implementations of the use cases in this way only to highlight the different ways we can have Flex talk to Java. Depending on the features you need for your application, you may want to stick with RemoteObjects or go whole-hog and access data through a DataService with an assembler.</p>
<p>Table 7 lists our user use cases and where they&#8217;re implemented.</p>
<table width="430"><tr><th scope="col" colspan="2" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Table 7: User use cases and where they&#8217;re implemented</th></tr><tr><th scope="col" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">User use case</th><th valign="top" scope="col" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Service method or assembler</th></tr>
<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Sign In</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">BookSearchService.findPersonByCardNumber</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Find Book by Subject</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">BookSearchService.findBooksBySubject</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Find Book by Title</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">BookSearchService.findBooksByTitle</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Find Book by Author</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">BookSearchService.findBooksByAuthor</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Find Author</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">PersonAssembler</td></tr>


<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Find Subject</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">SubjectAssembler</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Browse Titles</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">BookAssembler</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Browse Authors</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">PersonAssembler</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Browse Subjects</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">SubjectAssembler</td></tr>

</table><br />




<p>All of the administrator use cases are taken care of by the assemblers shown in Table 8.</p>




<table width="430"><tr><th scope="col" colspan="2" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Table 8: Administrator use cases and where they&#8217;re implemented</th></tr><tr><th scope="col" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Administrator use case</th><th valign="top" scope="col" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Service method or assembler</th></tr>
<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Create, Update, Delete Subjects</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">SubjectAssembler</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Create, Update, Delete Books</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">BookAssembler</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Create, Update, Delete Authors</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">PersonAssembler</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Create, Update, Delete Users</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">PersonAssembler</td></tr>

<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Check Books Out</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">BookAssembler</td></tr>


</table><br />

<p>Figure 15 shows the location of all of the ui project&#8217;s Java service classes.</p>


<div class="ap_c" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex_6/anatomy12_fig15.jpg" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex_6/anatomy12_fig15.jpg" alt="anatomy12_fig15.jpg" title="Click to enlarge" width="400"/></a><div class="acaption">Figure 15. Location of the ui project&#8217;s Java service classes
</div></div>


<p><strong>Managing Data with LCDS</strong></p>
<p>Data management is one of the coolest features of LCDS. By using a data service in Flex, you can skip having to write the explicit calls to the backend service. When Flex manages a collection of data, which can be an arbitrarily nested set of objects, any changes made to that collection can be automatically sent to the service. That means any views using managed data collections only have to hook up to the collection. Once the collection is managed, that&#8217;s all the work we have to do. We do not have to explicitly read properties into DTOs to send, figure out which properties changed, or watch for changes to know when to save. This is an incredible timesaver for data-driven application development.</p>
<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>But wait, there&#8217;s more! Not only can all of one client&#8217;s changes be automatically sent to the service, but also changes from other clients sent into the service can be automatically sent to other clients who are using the same managed data sources. As it becomes more critical for your application to avoid stale data issues, which occur when one client saves changes to some set of data that&#8217;s also in another client, only to have those changes overwritten by that second client&#8217;s next save, this feature becomes very interesting.</p>
<p>Of course, there&#8217;s no magic here. LCDS can&#8217;t automatically know in all situations that the data from the second save overwriting the first client&#8217;s changes represents the correct changes. What LCDS can do, however, is to provide a conflict management framework. As part of a data-sync operation, Flex can receive notification that a certain change message conflicts with data that has already been merged into the managed collection. This lets the Flex developer decide what the application can do automatically, whether it should show the conflicts to the user to let her choose to continue with the change, or which other actions should be taken. This lets an application work well when lots of users are editing the same data, but also allows offline applications to sync up data from a disconnected session using a framework such as Adobe&#8217;s AIR. A user could work with a set of data that had previously been downloaded, and then, when a network is available, sync that data with the service. The service, using LCDS, can take the client through the syncing process, letting the user know which data was changed since the last time the user was online. </p>
<p>As the service developer for these types of applications, you&#8217;ll hook into different parts of the data management process to provide an implementation of what should happen when data is saved, updated, queried, or deleted. The classes that fit into this part of the application&#8217;s life cycle are called assemblers.</p>
<p><strong>Assemblers</strong></p>
<p>LCDS provides an API to the data management system for Java. One way to get the data we want Flex to manage is to use custom assemblers. Assemblers are classes we can write to meet situations in which we may find our managed data, such as new objects added, objects updated, initial selection, and so on.</p>
<p>Assemblers can be simple Java classes that have a method or two which fit a certain part of the data management life cycle, such as querying data (fills) or syncing data. In this case, a POJO provides the implementation and the developer provides LCDS with the configuration to hook up these methods.</p>
<p>We&#8217;re going to take the more formal approach of implementing the assembler interface provided by LCDS to provide the data from any of our DAOs to the data management framework. Table 9 lists the methods of the class we&#8217;re going to extend, AbstractAssembler, which implements the Assembler interface.</p>

<table width="430"><tr><th scope="col" colspan="2" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Table 9: Methods of the AbstractAssembler class</th></tr><tr><th scope="col" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Method signature</th><th valign="top" scope="col" style="font-size: 11px; font-weight: bold; color: #525252; border: 1px solid #d7d7d7; letter-spacing: 2px;text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background-color: #f2f2f2;">Intended use</th></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">Object getItem(Map identity);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This is for getting one object of a certain type. The map argument should contain key/value pairs of the data needed to uniquely identify the object.</td></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">List getItems(List identityList);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This is the same as getItem, but for a list of objects. The argument should be a list of maps like those described for getItem.</td></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">void createItem(Object newItem);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This is called when a new item is added to a managed collection. The object could be typed by LCDS (we&#8217;ll see how), or it could be a map of keys and values that should be used to create an object of the assembler&#8217;s type.</td></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">void updateItem(Object newVersion, Object previousVersion, List changes);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This is called when an item is changed on the client. The object or map is the first argument, the object in its previous state is the second argument, and a list of properties changed is the third argument. The third argument may be null to indicate unknown changes.  Your assembler is responsible for throwing a flex.data.DataSynchException if it&#8217;s determined that any of the changes conflict with the persisted object.</td></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">void deleteItem(Object item);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This is called if an item is deleted.</td></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">int count(List countParameters);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This method works the same way as the fill method, but it is meant to return the count of the items matching the parameters.</td></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">void addItemToFill(List fillParameters, int position, Map identity);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This method is called when a client inserts an item in a certain position in a managed collection. You generally don&#8217;t make use of this method if your collections are set to automatically refresh.</td></tr>



<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">void removeItemFromFill(List fillParameters, int position, Map identity);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">This is the same as refreshFill, but for removing items.
</td></tr>
<tr><td valign="top" style="width: 40%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">boolean autoRefreshFill(List fillParameters);</td><td valign="top" style="width: 60%; border: 1px solid #d7d7d7; background: #fff; padding: 6px 6px 6px 12px; color: #525252;">TYou can use this method to decide whether a certain managed collection, based on parameters, should be refreshed automatically.</td></tr>


</table><br />








<p>In addition to the methods in Table 9, with configuration you can also set up custom fill methods and, along with them, custom methods to be called each time objects are added, modified, or deleted to let the assembler decide whether the changes should be added to the custom fill.</p>
<p>Let&#8217;s look at one of our assemblers, the SubjectAssembler, which is typical of all of our assemblers. We&#8217;ll just go method by method:</p>  
<div class="acode" style="overflow: auto; padding: 10px; height: 90px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
package lcds.examples.bookie.assemblers;
...
<span class="category1">public</span> <span class="category1">class</span> SubjectAssembler <span class="category1">extends</span> AbstractAssembler {
 
     @Override
     <span class="category1">public</span> <span class="category2">Object</span> getItem(Map identity) {
           Integer id = (Integer)identity.<span class="category2">get</span>("<span class="quote">id</span>");
           <span class="category1">try</span> {
                 SubjectDAO dao = getSubjectDAO();
                 <span class="category1">return</span> dao.findById(id);
            } <span class="category1">catch</span> (Exception e) {
                 <span class="category1">throw</span> <span class="category1">new</span> RuntimeException("<span class="quote">Unable to get Subject</span>", e);
            }
      }
 ...</pre>
</code>
 
</div></div>

<p>As I mentioned, we extend AbstractAssembler, which implements Assembler. AbstractAssembler provides default implementations of one or two of the methods mentioned earlier. For some of the others, it does nothing, and for yet others it throws an UnsupportedOperationException to indicate that a method of that type must be overridden. One thing to note is that AbstractAssembler isn&#8217;t actually marked abstract, so it can be the implementation class, although there&#8217;s not much it can do.</p>
<p>We&#8217;ll override getItem, which takes a map of properties that should uniquely identify an object. All we need to uniquely identify a subject is an ID. We just pass that ID into the DAO and return the result. If there&#8217;s an exception, we&#8217;ll throw a RuntimeException.</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 90px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
...
    <span class="category1">public</span> Collection getAllSubjects() {
          <span class="category1">try</span> {
                SubjectDAO dao = getSubjectDAO();
                <span class="category1">return</span> dao.getAll();
           } <span class="category1">catch</span> (Exception e) {
                <span class="category1">throw</span> <span class="category1">new</span> RuntimeException("<span class="quote">Unable to get all Subjects</span>", e);
           }
     }

    <span class="category1">public</span> Collection findByName(<span class="category2">String</span> <span class="category2">name</span>) {
          <span class="category1">try</span> {
                SubjectDAO dao = getSubjectDAO();
                <span class="category1">return</span> dao.findByName(<span class="category2">name</span>);
           } <span class="category1">catch</span> (Exception e) {
                <span class="category1">throw</span> <span class="category1">new</span> RuntimeException("<span class="quote">Unable to get Subjects by name</span>", e);
           }
     }
...</pre>
</code>
 
</div></div>
<p>These next two methods aren&#8217;t overridden; they&#8217;ll be configured to different fill methods, as we&#8217;ll see in a bit. getAllSubjects does what it says, no surprises there. findByName takes a string as an argument and passes that on to the DAO&#8217;s findByName method. </p>
<div class="acode" style="overflow: auto; padding: 10px; height: 90px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> List&lt;ChangeObject&gt; syncSubjects(List&lt;ChangeObject&gt; changes) {
     <span class="category1">try</span> {
           SubjectDAO dao = getSubjectDAO();
           Subject subject;
           <span class="category1">for</span> (ChangeObject change : changes) {
                 <span class="category1">if</span> (change.isCreate() || change.isUpdate()) {
                       subject = (Subject)change.getNewVersion();
                       change.setNewVersion(dao.merge(subject));
                  } <span class="category1">else</span> <span class="category1">if</span> (change.isDelete()) {
                       subject = (Subject)change.getPreviousVersion();
                       <span class="category1">if</span> (subject.getId() &gt; 0) 
                            dao.removeDetached(subject);
                  }
            }
           <span class="category1">return</span> changes;
  ...</pre>
</code>
 
</div></div>

<p>The syncSubjects method is a sync method, which means it&#8217;s called when there are changes to a managed collection on the client side in Flex. If your assembler uses this type of method, it&#8217;s called instead of the createItem, updateItem, and deleteItem methods. Notice that in the delete case, the syncMethod uses the removeDetached method on the DAO to avoid the problem of the client calling the method with an object that&#8217;s not in the entity manager yet.</p>
<p>The method&#8217;s arguments are a list of ChangeObjects which identify changes to a specific member of a managed data collection. If the change is a create change or an update change, we&#8217;ll merge that object into the entity manager and then set the new version on the change object that goes back to the client. If the change is a delete, the object is stored in the previousVersion property, so we&#8217;ll grab that, make sure it&#8217;s actually saved (make sure it has an ID), and then use the removeDetached method to delete it. </p>
<div class="acode" style="overflow: auto; padding: 10px; height: 90px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
...
<span class="category1">public</span> boolean shouldAddSubjectToAllCollection(<span class="category2">Object</span>[] params,
                                        <span class="category2">Object</span> item) {
     <span class="category1">return</span> <span class="category1">true</span>;
}

<span class="category1">public</span> boolean shouldAddSubjectToNameCollection(<span class="category2">Object</span>[] params,
                                        <span class="category2">Object</span> item) {
     <span class="category2">String</span> <span class="category2">name</span> = (<span class="category2">String</span>) params[0];
     Subject subject = (Subject) item;
     <span class="category1">if</span> (subject.getName().contains(<span class="category2">name</span>)) <span class="category1">return</span> <span class="category1">true</span>;
     <span class="category1">return</span> <span class="category1">false</span>;
}
...</pre>
</code>
 
</div></div>

</p>These next two methods are a little bit more complex, although simple in implementation. These methods are sync methods for specific managed data collections. Each one corresponds to a fill method, and if you&#8217;ll remember we have two of those, getAllSubjects and findByName. When a client requests these fills, or managed collections, LCDS keeps track of which clients are making use of which fills. Whenever a new object of the type this assembler manages is created, these methods are executed to allow our assembler to decide whether the new item should go in one of these fills.</p>
<p>The first method, shouldAddSubjectToAllCollection, should have a question mark after it (too bad Java doesn&#8217;t allow that, like Ruby does). Basically, it&#8217;s asking &#8220;should this new subject be added to the collection of all subjects?&#8221;, and of course, the answer is &#8220;yes&#8221;; because it&#8217;s a subject, it belongs to the collection of all subjects.</p>
<p>The next method asks &#8220;should this new subject be added to the collection of subjects matched by the name in parameter one?&#8221; In that case, we need to check that the subject&#8217;s name contains the name and, if so, return true. LCDS manages a collection of subjects for each distinct name searched through the findByName method, and if a new subject is created, it calls this method to see whether it should be added to one of those collections.</p>
<p><strong>Assembler Configuration</strong></p>
<p>Let&#8217;s look at the configuration of the LCDS services to see how assemblers are configured. Figure 16 shows the LCDS installation with a description of the important configuration files.</p>

<div class="ap_c" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex_6/anatomy12_figure16.jpg" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/04/anatomy_of_an_enterprise_flex_6/anatomy12_figure16.jpg" alt="anatomy12_figure16.jpg" title="Click to enlarge" width="400"/></a>
<div class="acaption">Figure 16. LCDS installation with a description of the important configuration files</div></div>



<p>Assembler definitions are in data-management-config.xml. Here&#8217;s a look at the SubjectAssembler definition from that file:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 90px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
 &lt;destination id="<span class="quote">subjectService</span>" &gt;
    &lt;properties&gt;
         &lt;metadata&gt;
              &lt;identity property="<span class="quote">id</span>" /&gt;
         &lt;/metadata&gt;
         &lt;source&gt;
              lcds.examples.bookie.assemblers.SubjectAssembler
         &lt;/source&gt;
         &lt;scope&gt;application&lt;/scope&gt;
         &lt;network&gt;
              &lt;paging <span class="category2">enabled</span>="<span class="quote">true</span>" pageSize="<span class="quote">10</span>" /&gt;
         &lt;/network&gt;
...</pre>
</code>
 
</div></div>

<p>This part of the document tells LCDS how to provide the subject assembler as a data service destination to the Flex service code. The ID of the destination is subjectService; the adapter is the java-dao adapter, which basically means we&#8217;re using a Java assembler. The channel is defined in services-config.xml.</p>
<p><source> tells LCDS which class contains the assembler code. <scope> says how long to keep the assembler alive&#8212;for a request, for a session, or to keep one for the whole application (that&#8217;s the one we want).</p>
<p>The <paging> setting lets us configure a very useful feature of assemblers. Have you ever had to send a lot of data in a sort of tabular form to an HTML page? The bigger the data set gotbecame, the heavier the page became, until finally you decided to implement some sort of paged approach in which the user could page through a set of data one chunk at a time. Assemblers tell LCDS how to fill a managed collection of data, but LCDS also takes care of filling the collection intelligently. That means if the user is scrolling through a grid of data from an assembler, LCDS makes sure the collection has the data the user is looking at one &#8220;page&#8221; ahead of time. The <paging> settings allow you to control that behavior.</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 140px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
...
         &lt;<span class="category2">server</span>&gt;
              &lt;fill-<span class="category1">method</span>&gt;
                   &lt;<span class="category2">name</span>&gt;getAllSubjects&lt;/<span class="category2">name</span>&gt;
                   &lt;ordered&gt;ordered&lt;/ordered&gt;
                   &lt;fill-contains-<span class="category1">method</span>&gt;
                        &lt;<span class="category2">name</span>&gt;
                             shouldAddSubjectToAllCollection
                        &lt;/<span class="category2">name</span>&gt;
                   &lt;/fill-contains-<span class="category1">method</span>&gt;
              &lt;/fill-<span class="category1">method</span>&gt;

              &lt;fill-<span class="category1">method</span>&gt;
                   &lt;<span class="category2">name</span>&gt;findByName&lt;/<span class="category2">name</span>&gt;
                   &lt;params&gt;java.lang.<span class="category2">String</span>&lt;/params&gt;
                   &lt;ordered&gt;ordered&lt;/ordered&gt;
                   &lt;fill-contains-<span class="category1">method</span>&gt;
                        &lt;<span class="category2">name</span>&gt;
                             shouldAddSubjectToNameCollection
                        &lt;/<span class="category2">name</span>&gt;
                   &lt;/fill-contains-<span class="category1">method</span>&gt;
              &lt;/fill-<span class="category1">method</span>&gt;

              &lt;sync-<span class="category1">method</span>&gt;
                   &lt;<span class="category2">name</span>&gt;syncSubjects&lt;/<span class="category2">name</span>&gt;
              &lt;/sync-<span class="category1">method</span>&gt;
         &lt;/<span class="category2">server</span>&gt;
    &lt;/properties&gt;
&lt;/destination&gt;</pre>
</code>
 
</div></div>

<p>In the &lt;server&gt; tag is where we keep information about the assembler&#8217;s data access methods. a <fill-method> is the definition of a way to get all the data a managed collection should have. The set of arguments sent by Flex tells LCDS which fill method to use, so there can be only one fill method per set of arguments, including a no-argument fill.</p>
<p>Our getAllSubjects fill should bring back all subjects, so it doesn&#8217;t need arguments. It should be kept ordered. Also, remember the addSubjectToAllCollection method? Here&#8217;s where we tell LCDS to use this method for this particular fill to check whether a new subject should be added to the fill.</p>
<p>The findByName fill method is used if there is a single string parameter. It should be kept ordered as well, and the method to choose if a new subject should be added to the fill is addSubjectToNameCollection.</p>
<p>The sync method, syncSubjects, which we just saw, is the one that&#8217;s called when there are changes to the managed collection of subjects.</p>
<p>Look at the other assemblers and the configuration files to see what&#8217;s going on in there, but note that the configuration and assembler for the subject collections are typical of what you&#8217;ll find in the others.</p>
<p><strong>Pushing Data with JMS over RTMP</strong></p>
<p>One thing is left: we want to be able to notify an administrator in real time whenever there&#8217;s a new reservation. </p>
<p>There are a few ways to do this type of thing. The obvious way is to have a timer running every few seconds to make a call to a service method to check whether there are new updates. I call this the &#8220;poor man&#8217;s push&#8221; method. If we didn&#8217;t have LCDS, we&#8217;d be stuck with this type of solution.</p>
<p>Luckily, with LCDS we have a better solution. The HyperText Transfer Protocol (HTTP), the protocol that runs the Web as we know it, creates a channel for communication with a client, and with Version 1.1 that channel can remain &#8220;alive&#8221; or ready to connect again, but it carries no information about the state of the client, and sends information only in response to a request. </p>
<p>Adobe has a protocol that powers the Flash media server: the Real Time Media Protocol (RTMP). RTMP connections stay open to allow two-way communication and streaming of media and data. LCDS makes use of RTMP to allow data and messages to be sent from the server to the client without prompting from the client.</p>
<p>The Java Messaging Service (JMS) is an API for message-oriented software development. JMS supports two messaging models: point-to-point or queue messaging, and publish/subscribe messaging. </p>
<p>Queue messaging works something like the client/server model that browsers and web servers follow, except that the server, called the producer in this case, can send messages to the client, or consumer.</p>
<p>Publish/subscribe messaging doesn&#8217;t have a one-to-one relationship between the producer and consumer. Many subscribers can subscribe to one publisher and all will receive the messages that the publisher sends.</p>
<p>We&#8217;re going to use the publish/subscribe model because that model fits so well with the case that we want to support: the server will send a message that some books have been reserved and any administration client can subscribe and get those messages. In JBoss, we can set up a topic, which is something about which messages will be sent, and then we can publish messages to that topic from anywhere.</p>
<p>Here&#8217;s how we set up the topic, in bookie-data/service-config/jboss/bookie-message-service.xml, which you need to copy to the JBoss deploy directory:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 90px;" ><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;<span class="category2">server</span>&gt;
    &lt;mbean
         code="<span class="quote">org.jboss.mq.server.jmx.Topic</span>"
         <span class="category2">name</span>="<span class="quote">jboss.mq.destination:service=Topic,
               name=outstandingReservationTopic</span>"&gt;
         &lt;depends
               optional-attribute-<span class="category2">name</span>="<span class="quote">DestinationManager</span>"&gt;
                   jboss.mq:service=DestinationManager
         &lt;/depends&gt;
    &lt;/mbean&gt;
&lt;/<span class="category2">server</span>&gt;</pre>
</code>
 
</div></div>

<p>If this application were to be deployed to production, we&#8217;d have this configuration file in the deploy directory already, but during development we have the root project&#8217;s build.xml copy this file over in the dev-deploy task.</p>
<p>In the ReservationDAOBean, when a reservation is saved, we&#8217;ll publish a message with the reservation in it to the topic. Later, we&#8217;ll see how Flex can subscribe the admin client to receive these messages and alert the administrator. Look at the message publishing code:</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 90px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
package lcds.examples.bookie.dao.beans;
...
@Stateless
@Local(value={ReservationDAO.<span class="category1">class</span>})
<span class="category1">public</span> <span class="category1">class</span> ReservationDAOBean <span class="category1">implements</span> ReservationDAO {
 
     @PersistenceContext
     <span class="category1">public</span> EntityManager entityManager;
 
     @Resource(mappedName="<span class="quote">TopicConnectionFactory</span>")
     <span class="category1">private</span> ConnectionFactory connectionFactory;
 
     @Resource(mappedName="<span class="quote">topic/outstandingReservationTopic</span>")
     <span class="category1">private</span> Topic outstandingReservationTopic;</pre>
</code>
 
</div></div>

<p>First, under the @PersistenceContext, we set up two @Resources, which point to the TopicConnectionFactory, where we get a connection to send messages to the topic, and then a reference to the topic itself.</p>
<div class="acode" style="overflow: auto; padding: 10px; height: 140px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
...
<span class="category1">public</span> <span class="category1">void</span> persist(Reservation transientInstance) throws Exception {
     entityManager.persist(transientInstance);
     sendReservationMessage(transientInstance);
}
...
<span class="category1">public</span> Reservation merge(Reservation detachedInstance) throws Exception {
     <span class="category2">Boolean</span> isNew = (detachedInstance.getId() == 0);
     Reservation result = entityManager.merge(detachedInstance);
     <span class="category1">if</span> (isNew) {
           sendReservationMessage(result);
      }
     <span class="category1">return</span> result;
}
...
<span class="category1">private</span> <span class="category1">void</span> sendReservationMessage(Reservation reservation) throws Exception {
     Connection connection = connectionFactory.createConnection();
     Session session = connection.createSession(<span class="category1">true</span>, 0);
     MessageProducer producer = session.createProducer(outstandingReservationTopic);
     ObjectMessage <span class="category2">message</span> = session.createObjectMessage();
     <span class="category2">message</span>.setObject(reservation);
     producer.<span class="category2">send</span>(<span class="category2">message</span>);
     connection.<span class="category2">close</span>();
}
...</pre>
</code>
 
</div></div>

<p>Now, whenever we get a new reservation or a reservation is somehow changed (in the persist or merge method of the ReservationDAO), we should send out a notification. The logic that does that is in the sendReservationMessage method. To do that, we get a connection from the factory, create a session, and get a MessageProducer using the topic that was injected into outstandingReservationTopic.</p>
<p>We then create an &#8220;object message,&#8221; which means that we intend to send a typed object with the message: the reservation. Then we set the reservation as the object, send the message, and close the connection. It&#8217;s fairly straightforward, if not exactly simple. The next thing you know, there&#8217;s an alert message in the administrative UI.</p>

<p>Next time we're going to look at the Flex service layer and be introduced to Cairngorm, the micro-architecture for Flex. 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.23324-comment:2055843</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.23324" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-6.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/anatomy-of-an-enterprise-flex-6.html#comment-2055843" />
    <title>Comment from Linda on 2009-03-24</title>
    <author>
        <name>Linda</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>HI</p>

<p>I m trying to connect to Data Base using SQL Assembler.</p>

<p>here is what it is.</p>

<p> <br />
        <br />
            flex.data.assemblers.SQLAssembler<br />
            application</p>

<p>            <br />
                <br />
            </p>

<p>            <br />
                <br />
            <br />
	       </p>

<p>		<br />
		<br />
		org.hsqldb.jdbcDriver<br />
		 jdbc:hsqldb:hsql://localhost:9002/flexdemodb<br />
				    sa<br />
				    <br />
			    	15<br />
				<br />
				<br />
				<br />
				</p>

<p>				Company<br />
    <br />
     			<br />
       				all<br />
       				SELECT * FROM TASKLITE ORDER BY NAME ASC<br />
     			</p>

<p>			<br />
       				by-name<br />
       				SELECT * FROM TASKLITE WHERE NAME LIKE CONCAT('%', CONCAT(#searchStr#,'%'))<br />
     			</p>

<p><br />
			<br />
					SELECT * FROM TASKLITE WHERE PRODUCT_ID = #TASKLITEID#<br />
			<br />
			<br />
			<br />
				  INSERT INTO TASKLITE <br />
				  		(NAME, ADDRESS, CITY, ZIP, STATE, INDUSTRY ) <br />
				  		VALUES (#NAME#, #ADDRESS#, #CITY#, #ZIP#, #STATE#, #INDUSTRY #)<br />
				  CALL IDENTITY() <br />
				</p>

<p>		<br />
			<br />
 <br />
    </p>

<p><br />
when i call fill method using ds.fill(comp) where comp is array collections i get an error saying  No parameters passed to fill-method for the<br />
 SQL assembler on destination 'task-lite' and there is no fill-method defined fo<br />
r zero args.</p>

<p>please help me as why get this error.</p>

<p>what is that i am doing wrong</p>

<p>Thanks and advance</p>]]>
    </content>
    <published>2009-03-24T15:55:37Z</published>
  </entry>

</feed
