RSS
 

South Bend Flex User Group: RIA @ the Bend

29 Dec

If your close to the South Bend, IN area, I’ll be heading up a new Adobe Flex User Group (http://groups.adobe.com/groups/3595576894/summary). Tim Eash, another local Flex developer will also help head up the group. We’ll be updating the group site over the next few weeks.

We’ll be meeting monthly at I.U.S.B. starting in January. Many thanks to Dr. Hakimzadeh, director of Informatics at I.U.S.B. for setting up the facilities.

The groups focus is Flex, Air, ActionScript, and Catalyst development. If you have any topics you’d like to discuss just let me know.

 
2 Comments

Posted in RIA

 

Flex 4 Gumbo Compiler Benchmark

21 Nov

‘Benchmark’ is being used pretty loosely here. I just got back from MAX and thought I’d check out the new compiler performance.

In addition to the exciting new display logic separation (Spark Framework), the SDK team has worked on speeding up compilation.

I compiled (incremental build) a project containing 57K lines of code (34K AS3, 23K MXML) under the 3.1 SDK via FlexBuilder. The compile took 40 seconds.

I then pointed FlexBuilder to the Flex 4.0.0 SDK. Make sure you update the ‘Require Flash Player Version’ on the Flex Compiler settings page to 10.0.0. If not you will receive errors including

1046 type was not found or was not a compile-time constant Matrix3D

After building the project I then preformed the same incremental build under 4.0.0 (Gumbo). The compile took 25 seconds.

Results:

SDK 3.1: 40 seconds
SDK 4.0.0 (Gumbo): 25 seconds

That’s not too bad, only ~62% of my original compile time.

 
 

MAX 2008 Pre-Event Summary

16 Nov

Okay, the first day of Adobe MAX 2008 is winding down. MAX is being held in San Francisco this year.

Today included registration and full day labs.

Badges

The badges got a technology upgrade this year, no bar codes this year, rather an RFID name badge. The local electronic stores are closed for the night – if I can find some time, it might be a fun project to grab an RFID reader and write up a quick AIR app (this *is* an Adobe conference after all :) to look at the data on the card. The information kiosks include RFID reader/writers that you use to ‘update’ your badge as you change / update your session schedule.

Tidbits

A few of the new features of the next FlexBuilder and AIR Runtime did slip out today. It’s not my place to ‘scoop’ that info – so I’ll wait to post until the general / official announcements are made in the next few days :)

Looks like Max 2009 will be on the West Coast again, this time in Los Angeles (Oct 4-7).

For those PureMVC developers out there, Cliff Hall will be broadcasting on Tuesday afternoon from the Marriott.

If your attending Max this year, feel free to drop me a line.

 
No Comments

Posted in MAX

 

Refactoring, Error #1065

23 Oct

I received the following runtime error in a flex project recently:

Error #1065 Variable package::Component_inlineComponent1 is not defined.

I was refactoring away from some static MXML to a dynamically loaded module. I had commented out the static MXML to test the dynamic module. Everything worked great. When I un-commented the previously working static module the #1065 error was thrown.

Problem:
[Cache causing] Error #1065 Variable is not defined error.

Solution:
Project -> Clean
:)

 
1 Comment

Posted in RIA

 

Revisiting one of my first RIAs

17 Oct

I spent some time updating on of my *first* RIAs today.

IEP RIA

The application allows special needs teachers to create IEPs (Individual Education Plans) for students. The teachers fill out various (20+) forms that compose the students’ IEPs.

During the initial interviews, it was identified that the forms would be revised annually and new forms would be added. Dynamically generated forms were *beyond* the project’s scope, so some easy-to-update forms were needed.

So back today, it’s always fun going back to revisit old code. I got a kick out of looking back at the approach taken on the RIA, hence this post. I wouldn’t necessarily recommend this “architecture” but it did make my job today extremely easy/fast to add some new forms & update some existing forms.

The Architecture

  • The teachers fill out their forms in a MDI Flex interface.
  • Form data is persisted for subsequent use.
  • All forms where mapped to Flex Accordion controls for a consistent user experience.
  • PDFs forms are utilized for printing.
  • I created a Flex component based on MX:Accordian. This component exposes a function ‘getData’ that when called recursively extracts data the user had entered in the form. This includes any data entered in datagrids, combo boxes, etc. The data is returned as a loosely typed ActionScript object.

    The object graph is sent to PHP via AMFPHP and persisted in MySQL via a PHP “ORM” class that can persist (& reconstruct) any PHP object graph. The object graph is not serialized rather, a modified preorder tree traversal algorithm is used. This provides for simple SQL queries, when / if needed.

    On the PDF form the form field is simply set to the desired attribute name of the object graph.

    So today, to add any form fields, I simply drop on an input (textbox for example), give that input an id and set the text property using databinding. (eg. id=”iep_firstName” text=”{dp.iep_firstName}”).

    That’s it.

    The new field will be persisted with no other work required :) The field can be added to the PDF should the field need to be printed.

    We have 8 Million+ records to date, and things seem to be scaling well.

     
    No Comments

    Posted in RIA

     

    Open Source ESBs… it’s here !!

    17 Oct

    I was excited to find an unexpected package on my doorstep last weekend. I had enrolled in Manning’s early access to Open Source ESBs quite a while ago (last year???). Well the books in print and I’ve got my copy in hand.

    I’m currently reading this book right now and loving it!!. I’ll make sure I update this post once I’ve finished the book.

    For those not familiar with ESBs (Enterprise Service Bus), suffice it to say the Enterprise Integration field is one of the most rewarding areas to be in software right now, IMHO.

    EI is full of architecture (which I love) so it’s a blast working in this field. Add data warehousing some RIA and you’ve got a snapshot of my past three months :)

     
    No Comments

    Posted in books

     

    The Data Warehouse Toolkit

    17 Oct

    I’ve read some really great books the past few months and thought I’d post a review.

    I’d highly recommend Ralph Kimball’s The Data Warehouse Toolkit.

    I’d normally opt for an architecture book over a [dry] database book without a second thought. Well I was pleasantly surprised to find this great resource.

    Kimball gives the reader a GREAT introduction to dimensional data modeling. For those ‘big picture’ developers out there, you owe to yourself to take a look at this work.

    I’ll leave the lengthy reviews to those more eloquent writes out there :)

    Two thumbs up.

     
    No Comments

    Posted in RIA

     

    Pipes Source Code

    17 Oct

    I’ve been heads down in development the past few months. During that time I’ve had numerous requests for the full source on the dynamically loaded modules ‘Pipes’ demo,MortgageApp.

    I *finally* had time to upload that source, simply use the ‘View Source’ on the demo to view the source.

    I’ve implemented a few enterprise RIAs using PureMVC pipes now. They work great, but I’m working on engineering (architecting) a new approach that I’ll post on the blog when it’s ready :)

     
    No Comments

    Posted in Pipes

     

    AdvancedDataGrid: Adventures in binding

    18 Sep

    Quick post on AdvancedDataGrid dataProviders.

    If your using a HierarchicalData provider for you AdvancedDataGrid (Flex) binding changes may (will) not be picked up by the AdvancedDataGrid.

    For example


    <mx:AdvancedDataGrid id="grid" bottom="10" top="40" left="10"
    designViewDataType="tree" width="379">
    <mx:dataProvider>
    <mx:HierarchicalData source="{grades}"
    childrenField="assignments"/>
    </mx:dataProvider>
    <mx:columns>
    <mx:AdvancedDataGridColumn headerText="Course" dataField="title"/>
    <mx:AdvancedDataGridColumn headerText="Score" dataField="scoreString" width="80"/>
    </mx:columns>
    </mx:AdvancedDataGrid>

    Won’t pickup the update to ‘grades’. Instead you’ll need to update the dataProvider itself…


    var hd:HierarchicalData = new HierarchicalData();
    hd.childrenField = "assignments";
    hd.source = grades;
    grid.dataProvider = hd;

     
    4 Comments

    Posted in Flex

     

    Bindable Read Only Getters

    08 Sep

    I had the opportunity to clear up some confusion on ‘bindable’ read-only ‘getters’ so I thought I’d post.

    If you mark your ActionScript class [Bindable], the compiler will generate propertyChange events for the class’s public variables and properties exposed through getters and setters.

    When a property exposed through a get / set pair is modified, a propertyChange event will be dispatched (from the setter). Use the comiplers -keep flag to inspect this for yourself.

    If you have a property exposed through a getter but no matching setter, data binding will not detect changes to the ‘get’ value.

    For example, you might have a getter value that is calculated from two other fields. To enable data binding on the ‘getter’ value, simply dispatch an event whenever the fields in the calculation are updated. You can then mark the getter function Bindable on those event names.

    Here’s a working example


    package
    {
    import flash.events.Event;

    [Bindable]
    public class BindingDemo
    {
    private var _numerator:Number = 0;
    private var _denominator:Number = 1;

    public function get numerator():Number
    {
    return _numerator;
    }

    public function set numerator(value:Number):void
    {
    if(value != _numerator)
    {
    _numerator = value;
    this.dispatchEvent(new Event('numeratorChanged'));
    }
    }

    public function get denominator():Number
    {
    return _denominator;
    }

    public function set denominator(value:Number):void
    {
    if(value != denominator)
    {
    _denominator = value;
    this.dispatchEvent(new Event('denominatorChanged'));
    }
    }

    [Bindable(event='numeratorChanged')]
    [Bindable(event='denominatorChanged')]

    public function get ratio():Number
    {
    if(_denominator == 0)
    return 0;
    return _numerator / _denominator;
    }
    }
    }

    And some MXML to try it out


    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
    <![CDATA[

    [Bindable] public var bdemo:BindingDemo = new BindingDemo();

    ]]>
    </mx:Script>
    <mx:Button x="193" y="23" label="Update" click="bdemo.numerator=Number(nvalue.text)"/>
    <mx:Label x="20" y="25" text="Numerator"/>
    <mx:Label x="20" y="51" text="Denominator"/>
    <mx:Label x="30" y="90" text="Numerator" fontWeight="bold"/>
    <mx:Label x="17" y="116" text="Denominator" fontWeight="bold"/>
    <mx:Label x="62" y="142" text="Ratio" fontWeight="bold"/>
    <mx:Label x="105" y="90" text="{bdemo.numerator}" id="num"/>
    <mx:Label x="105" y="116" text="{bdemo.denominator}" id="den"/>
    <mx:Label x="105" y="142" text="{bdemo.ratio}" id="ratio"/>
    <mx:TextInput x="105" y="23" width="80" id="nvalue"/>
    <mx:TextInput x="105" y="49" width="80" id="dvalue"/>
    <mx:Button x="193" y="49" label="Update" click="bdemo.denominator=Number(dvalue.text)"/>

    </mx:Application>

    Try it out below.

     
    No Comments

    Posted in binding

     

    PHP ODBC Across Networked Drives

    20 Aug

    While integrating some backend services needed by our RIA I ran across a small hiccup that was easily fixed but I thought I’d post in case someone else get’s stumped by this (apparently some already have ).

    Problem:

    PHP needed access to and ODBC connection that pointed to a dBase III database on a remote server. While local applications could use this ODBC connection flawlessly, connection via PHP failed.

    Symptons:

    Warning: odbc_connect() [function.odbc-connect]: SQL error: [Microsoft][ODBC dBase Driver] ‘(unknown)’ is not a valid path.

    Solution:

    You need to enable rights for the Apache Service to have access to the remote directory.

    For my particluar situation the server running apache and php was not part of the domain, so I simply right clicked on the apache service, navigated to the Log On tab and selected “This Account” (and filled in the administrator credentials) as opposed to the default “Local System Account.”

     
    1 Comment

    Posted in PHP

     

    Flex Modules Watch Your Scope

    14 Aug

    Here’s another help hint for those working with Modules in Flex: Watch your variable scope!!

    When loading modules, you have a number of options for loading the SWF including the ModuleLoader and ModuleManager. If neither of those fit your needs you always have access to Flash’s Loader class. ModuleManger can be used for fine grained control of the loading process. Either way, variable scope plays a crucial roll in the loading process.

    Here’s an example using ModuleLoader…

    public function loadSWFModule(swfURL:String):void
    {
    var moduleLoader:ModuleLoader = new ModuleLoader();
    moduleLoader.url = swfURL;

    moduleLoader.addEventListener(ModuleEvent.READY,onModuleLoaded);
    moduleLoader.addEventListener(ModuleEvent.ERROR,onModuleError);
    moduleLoader.addEventListener(ModuleEvent.PROGRESS,onProgress);
    moduleLoader.loadModule();
    }

    The moduleLoader is declared as a local variable. As it turns out this will cause problems, even with the ‘strong’ event listeners. For those not wanting to read the technical details to follow, simply use avoid using a locally scoped variable.

    The following are some of the symptoms you may run into using the latter locally scoped variable:

    To help those searching the net, I’ll be a bit redundant in the ‘symptom’ descriptions so hopefully you’ll find this post if you’ve stumbled upon this problem

    Symptons

  • The module fails to load the first time, but loads successfully the second time.
  • The ModuleEvent.READY is never dispatched
  • The ModuleInfoProxy never picks up the ModuleEvent.READY dispatched by ModuleInfo
  • ModuleInfo.clearLoader() throws an error (which is quietly caught), Error #2029: This URLStream object does not have a stream opened when calling loader.close()
  • The problem comes in when the Loader finishes loading the SWF. ModuleInfo’s internal listener list (listeners attached during ModuleInfoProxy’s constructor) are lost (i.e. null) when ModuleInfo finally reaches it’s readyHandler( ) method. At the end of the readyHandler( ), a ModuleEvent.READY event is dispatched.

    dispatchEvent(new ModuleEvent(ModuleEvent.READY));

    With the listener list being null, the event is never picked up by the ModuleInfoProxy and the initial load fails.

    On subsequent loads (i.e. the second time) ModuleInfoProxy’s load( ) method checks to see if the info has already been loaded and dispatches the ModuleEvent.READY event directly.

    else if (info.loaded)
    {
    //trace("Module[", url, "] load is already loaded");
    if (info.setup)
    {
    ...
    if (info.ready)
    {
    ...
    dispatchEvent(new ModuleEvent(ModuleEvent.READY));
    }
    }
    }

    Causing the load to ‘work’ the second time.

    My understanding is that Garbage Collection is often invoked when a module is loaded. It looks like it’s the cause of this behavior (the listeners being lost). I assumed that the ‘strong’ listeners would be enough to keep the GC away, oh well.

    Again the solution is simple, make sure your not using a locally scoped variable when loading modules.

     
    13 Comments

    Posted in Flex, Modules

     

    Flex, Java Remoting, and JMS [null message body]

    07 Aug

    So I was pounding out some code this afternoon, ran into a small snag and thought I’d post. Neuro-physiologists tell us that we better remember what we write down so here goes.

    Similar to my post a few months ago, I made a simple omission in my coding flurry.

    I was working with a backend Java class that published messages to [ActiveMQ] JMS. I wrote up a simple VO class to publish via JMS.


    package com.dl.sifagents.vo;

    import java.io.Serializable;

    public class ZISEventVO implements Serializable
    {
    public String eventType = "";
    public String payloadPackage = "";
    public String payloadElement = "";
    public String xml = "";
    }

    On the Flex side, I wrote up an AS3 implementation


    package com.dl.sifagents.vo
    {
    [RemoteClass(alias="com.dl.sifagents.vo.ZISEventVO")]
    [Bindable]
    public class ZISEventVO
    {
    public var eventType:String;
    public var payloadPackage:String;
    public var payloadElement:String;
    public var xml:String;
    }
    }

    I published the VO to JMS…


    public void publishObjectToJMS(Serializable o)
    {
    try {
    ObjectMessage message = _pubSession.createObjectMessage();
    message.setObject(o);
    _publisher.publish(message, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, 5 * 60 * 1000);
    } catch (JMSException e1) {
    e1.printStackTrace();
    }
    }

    I received the JMS message in Flex (via BlazeDS) but the message body was null. I checked and doubled checked my Java VO implementation vs AS3 VO implementation and couldn’t find any naming conflicts or errors.

    Then it hit me, in my haste I’d forgotten to upload the Java VO class to BlazeDS (i.e. to the WEB-INF/classes folder)!

    That’s my piece of humble pie for the week :) Back to work.

     
    3 Comments

    Posted in BlazeDS, JMS, Java

     

    Dashboards…Flex’s Sweet Spot

    06 Aug

    Thanks Adobe!!!

    I’ve taken on a number of Flex projects over the past 2-3 years. In that time I’ve used Flex to meet many types of business needs. I’ve spent the last few months working on a enterprise dashboard application built with Flex. This past week the time came for the executives’ ‘sneek peek’ of the project’s progress. The feedback, in their words,

    “Beyond all expectation.”

    I can’t remember having more fun architecting and implementing a project. Dashboards seem to be Flex’s ‘sweet spot’, IMHO. Adobe [Flex] provides so rich a toolset for this type of project, one can’t help but have fun working on dashboards with Flex. Talking with other local Flex developers only resonates the view that Flex + Dashboards are a perfect fit. So once again, thanks to Adobe for this great product, it’s been an absolute joy to work with.

    FYI, the project is using Flex, AMFPHP 1.9, ActiveMQ JMS + BlazeDS, Multicore PureMVC, PureMVC’s Pipes, MySQL to name a few (i.e. a mouthful of open source technologies). BTW, it scales beautifully with dynamic modules using PureMVC Pipes. Thanks too, to Cliff Hall for PureMVC!!

    For those pessimists our there, I can post again once I’ve developed the printouts (Printing is notoriously painful in Flex :) ).

     
    No Comments

    Posted in Flex

     

    [Tunkey] BlazeDS JMS ActiveMQ

    01 Aug

    I spent some time this week with BlazeDS and JMS. I wanted to integrate a Flex RIA with some [existing] backend Java classes. One goal was to interface the two in a loosely coupled fashion, enter Java Message Service (JMS).

    The RIA uses a mx:producer to publish messages to a JMS topic which the backend Java class is listening in on [consuming] elsewhere in the enterprise. I used an ‘external install’ of ActiveMQ.

    I downloaded the turnkey BlazeDS server to get things rolling.

    I came across a few great posts in looking into this…

    Michael Martin’s Simplified BlazeDS and JMS

    Christophe Coenraets
    Flex and JMS: Portfolio Viewer (LCDS jRun)
    30 Minutes Flex Test-Drive for Java Developers (FDS)

    To be helpful, I’ve included some error messages and their causes:

    Flex Runtime Error:
    There was an unhandled failure on the server. MessageClient has been invalidated.
    Cause: ActiveMQ not running.

    Flex Runtime Error:
    Client.Message.Encoding
    Type ‘com.dl.samples.PersonVO’ not found.
    Cannot create class of type ‘com.dl.samples.PersonVO’.
    Cause: Java classes not on server.

    Java Runtime Error
    javax.naming.NameNotFoundException: messageTopic
    at org.apache.activemq.jndi.ReadOnlyContext.lookup(ReadOnlyContext.java:225)
    at javax.naming.InitialContext.lookup(Unknown Source)
    at Chat.(Chat.java:55)
    at Chat.main(Chat.java:27)
    Cause: jndi.properties not present for java class

    Java Runtime [BlazeDS] Error
    [BlazeDS] JMS consumer for JMS destination ‘[destinationName]‘ is being removed from the JMS adapter due to the following error: Name jms is not bound in this Context
    [BlazeDS] JMS consumer for JMS destination ‘[destinationName]‘ is stopping.
    [BlazeDS] The corresponding MessageClient for JMS consumer for JMS destination ‘[destinationName]‘ is being invalidated

    Cause: context.xml Resource names do not match messaging-config.xml connection-factory / destination-jndi-name tags. (i.e. the ‘org.apache.activemq.ActiveMQConnectionFactory’ resource name in context.xml should match the connection-factory value in messaging-config and the ‘org.apache.activemq.command.ActiveMQTopic’ resource name in context.xml should match the destination-jndi-name value in messaging-config).

    Adding the logging pattern ‘Service.Message.JMS’ to your services-config.xml can be very helpful in debugging BlazeDS JMS problems.

    Here are the config files

    C:/blazeds/tomcat/webapps/MyApp/WEB-INF/flex/services-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <services-config>
    <services>
    <service-include file-path="messaging-config.xml" />
    </services>
    <security/>
    <channels>
    <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://localhost:8400/BlazeTest/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
    </channel-definition>
    </channels>
    <logging>
    <target class="flex.messaging.log.ConsoleTarget" level="Debug">
    <properties>
    <prefix>[BlazeDS] </prefix>
    <includeDate>false</includeDate>
    <includeTime>false</includeTime>
    <includeLevel>false</includeLevel>
    <includeCategory>false</includeCategory>
    </properties>
    <filters>
    <pattern>Endpoint.*</pattern>
    <pattern>Service.*</pattern>
    <pattern>Configuration</pattern>
    <pattern>Service.Message.JMS</pattern>
    </filters>
    </target>
    </logging>
    </services-config>

    C:/blazeds/tomcat/webapps/MyApp/WEB-INF/flex/messaging-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <service id="message-service" class="flex.messaging.services.MessageService">
    <adapters>
    <adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
    <adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/>
    </adapters>
    <default-channels>
    <channel ref="my-amf"/>
    </default-channels>
    <destination id="simpleJMS">
    <properties>
    <jms>
    <destination-type>Topic</destination-type>
    <!--<message-type>javax.jms.TextMessage</message-type>-->
    <message-type>javax.jms.ObjectMessage</message-type>
    <connection-factory>java:comp/env/TopicConnectionFactory</connection-factory>
    <destination-jndi-name>java:comp/env/messageTopic</destination-jndi-name>
    <delivery-mode>NON_PERSISTENT</delivery-mode>
    <message-priority>DEFAULT_PRIORITY</message-priority>
    <acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
    <initial-context-environment>
    <property>
    <name>Context.INITIAL_CONTEXT_FACTORY</name>
    <value>org.apache.activemq.jndi.ActiveMQInitialContextFactory</value>
    </property>
    <property>
    <name>Context.PROVIDER_URL</name>
    <value>tcp://localhost:61616</value>
    </property>
    </initial-context-environment>
    </jms>
    </properties>
    <channels>
    <channel ref="my-amf"/>
    </channels>
    <adapter ref="jms"/>
    </destination>
    </service>

    C:/blazeds/tomcat/webapps/MyApp/WEB-INF/web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
    <display-name>BlazeDS</display-name>
    <description>BlazeDS Application</description>
    <!-- Http Flex Session attribute and binding listener support -->
    <listener>
    <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>
    <!-- MessageBroker Servlet -->
    <servlet>
    <servlet-name>MessageBrokerServlet</servlet-name>
    <display-name>MessageBrokerServlet</display-name>
    <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
    <init-param>
    <param-name>services.configuration.file</param-name>
    <param-value>/WEB-INF/flex/services-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>MessageBrokerServlet</servlet-name>
    <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    </web-app>

    C:/blazeds/tomcat/webapps/MyApp/META-INF/context.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <Context path="/BlazeTest">
    <Resource name="TopicConnectionFactory"
    type="org.apache.activemq.ActiveMQConnectionFactory"
    description="JMS Connection Factory"
    factory="org.apache.activemq.jndi.JNDIReferenceFactory"
    brokerURL="tcp://localhost:61616"
    brokerName="myBroker"/>
    <Resource name="messageTopic"
    type="org.apache.activemq.command.ActiveMQTopic"
    description="a simple topic"
    factory="org.apache.activemq.jndi.JNDIReferenceFactory"
    physicalName="messageTopic"/>
    </Context>

    Using the above messaging-config’s destination the message will come across as an ObjectMessage in Java :)

     
    2 Comments

    Posted in BlazeDS, JMS

     

    Ensuring Windows Services can access Novell NetWare directories

    01 Aug

    Ended up spending some time getting this to get this to work last week. We had some Windows services running on a Windows Server (Server 2003) that needed to access data on a NetWare volume. While a logged in user could access the data on the NetWare server, the windows service could not (or was intermittent at best).

    Here’s what I found – hope someone finds it helpful.

    Per Microsoft – Windows services should use UNC paths not Mapped Drives
    http://support.microsoft.com/kb/180362/EN-US/

    Novell’s direction on getting MS Service applications to access NetWare volumes if the service was written in a non-novell-aware manner.
    http://www.novell.com/support/viewContent.do?externalId=7000312

    After following the latter directions everything is working great.

    Time to get back to some RIA development :)

     
    1 Comment

    Posted in Novell

     

    AMFPHP Class Mapping Primer [1.9 beta]

    01 Jul

    Thought I’d post a simple AMFPHP class mapping primer.

    I ran into a wall after re-arranging my VO / DAO package structure on the server, learned a few things in the process and thought I’d post .

    I’m assuming your using AMFPHP 1.9 beta.

    Class mapping allows your php backend and actionscript frontend to pass strongly typed variables back and forth. The benefits are obvious so I won’t cover them here.

    If your not after any detailed information here’s a quick set of samples classes to get you going.

    PHP

    
    // LoginVO.php is saved as {$voPath}/com/dl/app/LoginVO.php
    class LoginVO
    {
       var $_explicitType="com.dl.app.LoginVO";
       public $username;
       public $password;
    }
    

    AS

    package com.dl.common.Login.model.vo
    {
       [RemoteClass(alias="com.dl.app.LoginVO")]
       public class LoginVO
       {
          public var username:String;
          public var password:String;
       }
    }

    That’s it. If your after more options and detailed info, keep reading.

    Sending Strongly Typed Objects from PHP to ActionScript via AMFPHP

    In PHP

    You have a few options (choose one).

  • Your class can declare a variable named $_explicitType;
  • The most common approach is to use the $_explicitType class member:

    class LoginVO
    {
       var $_explicitType="com.dl.app.LoginVO";
       public $username;
       public $password;
    }
    
  • You can set $GLOBALS['amfphp']['outgoingClassMappings']['localclass'] = ‘remoteclassAlias‘;
  • e.g.

    $GLOBALS['amfphp']['outgoingClassMappings']['myclass'] = "com.dl.myapp.MyClass";

    Note that the local class name associative key (‘myclass’ above) must be in lowercase with the current release of AMFPHP.

  • Rely on the reflection class (PHP 5+)
  • If your install of PHP has the ReflectionAPI you can let AMFPHP do the work *for* you. I found a few cavets using this approach on servers who’s OS uses backslashes natively. If this is the case, AMFPHP will only send the name of the class and not include any package info. There are two simple code changes you can make in AMFPHP to get around this, just drop me a line if your interested (hopefully they’ll be commited in the next release of AMFPHP).

    In actionscript

    Here to, you have a some options,

  • Use [RemoteClass] metadata tag to specify the remote class alias
  • package com.dl.common.Login.model.vo
    {
       [RemoteClass(alias="com.dl.app.LoginVO")]
       public class LoginVO
       {
          public var username:String;
          public var password:String;
       }
    }
  • Use registerClassAlias()
  • registerClassAlias(“com.dl.app.LoginVO”,LoginVO);

    Make sure your actionscript project contains a reference to the class. See my previous post for more info.


    Sending Strongly Typed Objects from ActionScript to PHP via AMFPHP

    In PHP

    Rely on the class having been registed in ActionScript with the server’s correct package [directory] structure (relative to AMFPHP’s VO base path $GLOBALS['amfphp']['customMappingsPath']). If this is the case you, your all set.

    Define $GLOBALS['amfphp']['incomingClassMappings']['remoteclassAlias'] = ‘localclassPackage‘. (e.g. $GLOBALS['amfphp']['incomingClassMappings']['com.dl.as3.userVO'] = ‘com.dl.userVO’);

    In ActionScript

    Again, you’ll need to use one of the two following…

  • Use [RemoteClass] metadata tag to specify the remote class alias
  • Use registerClassAlias()

    For more info check out

    AMFBaseSerializer.php’s getClassName() function

    AMFBaseDeserializer.php’s mapClass() function




     

    AMFPHP Complex Classes – Yeah I knew that

    19 Jun

    Just blew half an hour tracking down something I *knew* I’d done before. Thought I’d post here for future ‘lapses.’

    To return a typed object from PHP to the flashplayer the process is simple, declare a variable called $_expicitType in your PHP class
    e.g.
    class SummaryVO
    {
    var $_explicitType = "com.dl.SummaryVO";
    $standards = array();
    $levels = array()
    }

    In your corresponding ActionScript class use the RemoteClass metadata tag

    package com.dl
    {
    [RemoteClass(alias="com.dl.SummaryVO")]
    public class SummaryVO
    {
    public var standards:Array;
    public var levels:Array;
    }
    }

    Note the values for $_explicitType and alias are arbitrary, they can be what ever you’d like, as long as their the same in AS and PHP (provided your only conerned with PHP=>AS mapping).

    Okay, so what happens when you have ‘complex classes’ you’d like to return? Complex meaning a class who’s members are made up of other ‘custom’ class instances.

    Let’s say, for example, that in our later code example ‘standards’ was an array of ‘StandardVO.’ The problem I ran into was that I was getting a typed ‘SummaryVO’ back from AMFPHP, however my class members were not typed, just generic objects. I checked and I had taken the necessary steps to use strongly typed SummaryVO and StandardVO classes, yet the StandardVO was coming back as a plain old Object.

    We’ll it turned out in my development flurry I hadn’t used a reference to the ‘StandardVO’ class yet!! Simply declaring an instance of StandardVO did the trick (i.e. var placeHolder:StandardVO). You could also you the includes class [...] compiler option.

    Moral of the story, be sure the complier includes a reference to any class you want strongly typed from your RPCs.

     

    Pipe Demo: Mortgage App

    17 Jun

    I’ve posted a pipes version of the mortgage app.

    Things to note:

    You can load / unload the modules dynamically.

    A junction mediator is defined for each ‘player.’ In the mortgage app context that’s a mediator for the application itself, the Acme widget and the Foo widget.

    ApplicationJunctionMediator
    ModuleJunctionMediator (Acme)
    ModuleJunctionMediator (Foo)

    To make our lives easier when it comes time to unload the module, the module caches the app’s pipe fitting it’s connected to. This allows the module to easily ‘cleanup’ (disconnect our fittings) should we want to unload the module. You may find a cleaner approach to this, feel free to post in comments – the ‘caching approach’ was simple and thus the road taken for the demo.

     
     

    Understanding PureMVC Pipes

    15 Jun

    Disclaimer: This a bit of a longer post!!

    The pipes utility is newer to PureMVC and as such, I’ve seen questions on the blogosphere regarding it’s use.

    The plumbing metaphor should help wrap you head around this utility and it’s use. Keep in mind that a pipe allows for one-way message flow.

    So let’s take a look at how the utility can be used.

    One great features of ‘Pipes’ is that they can use used on top of an existing app. That is, you’ll simply need to define a JunctionMediator at/for each integration point.

    Let’s look at the simplest case, an application that loads and communicates with a module. We’ll assume that at some point you’ll want to use this same app to use multiple modules down the road. You’ll need to create a JunctionMediator for the application and a JunctionMediator for the module. We’ll dive into the details for those mediators but at a high level, that’s it – we simply define a ‘JunctionMediator’ for each ‘player.’

    Here’s a simple diagram

    Simple Pipe

    Our JunctionMediator’s will be connected together with pipes. We’ll have one pipe that allows for application-to-module message flows and another pipe that allows for module-to-application flows.

    On the receiving end of a pipe, we’ll want a pipe listener (you’ll have only one pipe listener for a given pipe). We’ll use pipe listeners to handle incoming pipe messages.

    To send messages down a pipeline, we’ll normally use the Junction’s ‘sendMessage’ function.

    Back to our simple example, our app’s JunctionMediator would be responsible for creating the app’s pipe fittings, creating pipes to connect to those fittings to the module.

    So the first thing our app’s JunctionMediator would do would be to create a new junction at creation.


    public class ApplicationJunctionMediator extends JunctionMediator
    {
    public function ApplicationJunctionMediator()
    {
    super(NAME, new Junction());
    }

    Once this mediator is registered with our facade, we’d want to create the PipeFittings. We’ll use a TeeSplit for outgoing and TeeMerge for incoming. The TeeSplit will allow us to connect to multiple modules for outbound messages. The TeeMerge will allow multiple modules to send messages up to our main app. We’ll also want to add a pipe listener on our TeeMerge. This listener will allow us to handle the messages being sent up from the modules to the app.


    override public function onRegister():void
    {
    junction.registerPipe( PipeAwareModule.APP_TO_MODULE_PIPE, Junction.OUTPUT, new TeeSplit() );
    junction.registerPipe( PipeAwareModule.MODULE_TO_APP_PIPE, Junction.INPUT, new TeeMerge() );
    junction.addPipeListener( PipeAwareModule.MODULE_TO_APP_PIPE, this, handlePipeMessage );
    }

    Our handlePipeMessage function is responsible for handling the messages coming up from our modules to our app.


    function handlePipeMessage(message:IPipeMessage):void

    Being a Mediator, we can define what application-level notifications we’re interested in and how to handle those notifications. That is, we’ll want to utilize listNotificationInterests() and handleNotification(note:INotification). We’ll use these to listen for notifications and turn desired notifications into messages to pass down our pipes.

    For example, our Mortgage App would listens for request for loan notifications and turn those notifications into messages.


    override public function handleNotification(note:INotification):void
    {

    switch( note.getName() )
    {
    case MortgageAppEventNames.REQUEST_FOR_LOAN:
    var loanMessage:Message = new Message(MortgageAppEventNames.REQUEST_FOR_LOAN,null,note);
    junction.sendMessage(PipeAwareModule.APP_TO_MODULE_PIPE,loanMessage);
    break;
    }
    }

    Our application JunctionMediator will also typically listen for a notification that a module has been loaded. Our app’s JunctionMediator will then create new pipes to connect the app’s junctionMediator to the modules junctionMediator. Something along the lines of…


    override public function handleNotification(note:INotification):void
    {

    switch( note.getName() )
    {
    case MortgageAppEventNames.REQUEST_FOR_LOAN:
    var loanMessage:Message = new Message(MortgageAppEventNames.REQUEST_FOR_LOAN,null,note);
    junction.sendMessage(PipeAwareModule.APP_TO_MODULE_PIPE,loanMessage);
    break;

    case ModuleEvents.CONNECT_MODULE_JUNCTION:
    var module:IPipeAwareModule = note.getBody() as IPipeAwareModule;

    // Create the pipe
    var moduleToApp:Pipe = new Pipe();
    // Connect the pipe to our module
    module.acceptOutputPipe(PipeAwareModule.MODULE_TO_APP_PIPE, moduleToApp);

    // Connect the pipe to our app
    var appIn:TeeMerge = junction.retrievePipe(PipeAwareModule.MODULE_TO_APP_PIPE) as TeeMerge;
    appIn.connectInput(moduleToApp);

    // Create the pipe
    var appToModule:Pipe = new Pipe();
    // Connect the pip to our module
    module.acceptInputPipe(PipeAwareModule.APP_TO_MODULE_PIPE,appToModule);

    // Connect the pipe to our app
    var appOut:TeeSplit = junction.retrievePipe(PipeAwareModule.APP_TO_MODULE_PIPE) as TeeSplit;
    appOut.connect(appToModule);

    break;

    // And let super handle the rest (ACCEPT_OUTPUT_PIPE, ACCEPT_INPUT_PIPE, SEND_TO_LOG)
    default:
    super.handleNotification(note);

    }
    }

    Finally our application’s JunctionMediator will handle the incoming pipe messages.


    override public function handlePipeMessage(message:IPipeMessage):void
    {
    // Handle our Module->Application integration
    trace(message);
    var note:INotification = message.getBody() as INotification;

    switch(note.getName())
    {
    case MortgageAppEventNames.LOAN_QUOTE_READY:
    sendNotification(note.getName(),note.getBody(),note.getType());
    break;
    default:
    sendNotification(note.getName(),note.getBody(),note.getType());
    break;
    }
    }

    That covers the basic responsibilities for our app’s JunctionMediator.

    Our module’s JunctionMediator would listen for messages coming in on the APP_TO_MODULE named pipe and send [outbound] messages on the MODULE_TO_APP pipe.


    override public function handleNotification(note:INotification):void
    {
    // Handle our Module->Application integration
    switch( note.getName() )
    {
    case ModuleFacade.QUOTE_GENERATED:
    // convert our *local* notification into the application format
    var quoteMessage:Message = new Message(MortgageAppEventNames.LOAN_QUOTE_READY,null,
    new Notification(MortgageAppEventNames.LOAN_QUOTE_READY,note.getBody(),note.getType()));
    junction.sendMessage(PipeAwareModule.MODULE_TO_APP_PIPE,quoteMessage);
    break;
    }
    }

    override public function handlePipeMessage( message:IPipeMessage ):void
    {
    // Handle our Application->Module integration
    var note:INotification = message.getBody() as INotification;
    switch(note.getName())
    {
    case MortgageAppEventNames.REQUEST_FOR_LOAN:
    sendNotification(ModuleFacade.QUOTE_REQUESTED,note.getBody(),note.getType());
    break;
    }

    }

    If the app was to load another module our diagram would become…
    Pipes App with Two Modules

    If your still have questions – just ask :)