Archive for the 'development' Category

Model Adapters - A binding pattern using an Adapter

Binding in Flex is great. It’s an ultra convienent way to get information from your data model to show up in your views. But it does have some limitations, and to work around those limitations I’ve been using the “Model Adapter” aka the “Wrapper” or just plain “Adapter” pattern (some info, and more).

The basic idea is you shouldn’t have to modify your data model to use it in a specific view. If you need to filter, sort, or summarize the data for a view you can do that through an Adapter so your model doesn’t need to understand that logic and you’re view isn’t reliant on a specific implementation of your model.

Example: If you had a list of books in an array, and you want to filter by some property of books (say publisher) you shouldn’t apply the filter directly to the model. Instead, create an adapter that can watch that array, and have that adapter apply the filter (or sort, or whatever).

More Examples: Consider Timeliner XE, a product I’ve been working on at my day-job. The main data model is a list of events. There are several views for that data. We have a text based / grid view, and some graphical views. Here’s a couple screenshots:

Each of those screenshots has 2 views active at a time, the grid, and then a seperate graphical view. That makes 3 views that all want to bind to our data model. But, notice the grid has 5 events in it, while the graphical views only have 3. This is because only 3 of those events are valid to plot (they have a date). It’d be nice if we only had to bind to a list of events that actually has the data we want.

Now take a look at these three screenshots from AgileAgenda, my project scheduling application.

In all of these the data we have is a list of tasks. The first two show one view with two different filters applied to the data. The third shows a large grid with all of our tasks, and a much shorter pulldown that only has the tasks that are also milestones. (A milestone is a specific type of task)

To create an adapter:

  • Create a new adapter class
  • Create a constructor for that class that takes in the “source” data model, and any options that might be specific to the adapter.
  • Add event listeners to the “source” model.
  • Write event handlers in the adapter to update the adapter’s internal state when the source changes.
  • Write accessors in the adapter, so other components can get data from it.

A simple example…

Click here to run a simple example. View-source is enabled in that. Here’s a screenshot of the example:

When you run the example, it creates a simple data model, populates that data model with 4 sample items, and then creates 4 panels. Each of those panels represents a view. The example also creates 4 different model adapters all from the same data model, but with different options set. Then each panel gets a different adapter.

As you add items to the data model, you can see that the 4 views update depending on whether or not they are filtered and sorted.

Our Data Model:

package
{
    public  DataItemExample
    {
        public var name:String;
        public var amount:Number;
        public var active:Boolean;
    }
}

—-

package
{
    import mx.collections.ArrayCollection;

    public  DataModelExample
    {
        [Bindable] public var myDataItems:ArrayCollection = new ArrayCollection();

    }
}

As you can see, it’s a pretty simple data model. There are items with a name, amount and active properties, and then there is DataModelExample class with an array of those. Notice that no view-specific data is in there.

Now, lets create our adapter and name it “AdapterExample”

First, create a constructor and some variables to hold some information about the adapter. We’ll have 2 options. onlyActiveItems and sorted. For sorted, we’ll also create a Sort object to actually do the sort for us. And we’ll also create an array to hold our filtered/sorted list of items. Note that we add an event listener for the COLLECTION_CHANGE event. This is how we’ll propogate changes from the data model to our adapter. We’ll see the handler for that later.

 public  AdapterExample extends EventDispatcher
    {
        protected var model:DataModelExample;
        protected var filteredDataItems:ArrayCollection = new ArrayCollection();
        protected var _onlyActiveItems:Boolean;
        protected var _sorted:Boolean = false;
        protected var sort:Sort;        

        public function AdapterExample(dataModel:DataModelExample, onlyActiveItems:Boolean, sorted:Boolean)
        {
            _sorted = sorted;
            _onlyActiveItems = onlyActiveItems;

            model = dataModel;
            model.myDataItems.addEventListener(CollectionEvent.COLLECTION_CHANGE, onItemsChanged );    

            if(sorted)
            {
                sort = new Sort();
                sort.fields = [new SortField("name",true)];
            }

            rebuildFilteredArray();
        }

Notice that we called rebuildFilteredArray above. Lets write that next. All this method does is loop through our data model and grab all the items from it (respecting our filtering option) and adds them to our internal array. It also applies the sort if neccessary. At the end we dispatch two events which will be used for binding later.

  protected function rebuildFilteredArray() : void
        {
            var tmp:Array = [];
            for each ( var item:DataItemExample in model.myDataItems )
            {
                if( (! _onlyActiveItems ) || (item.active) )
                {
                    tmp.push(item);
                }
            }                        

            filteredDataItems = new ArrayCollection(tmp);

            if( sort )
            {
                filteredDataItems.sort = sort;
                filteredDataItems.refresh();
            }

            dispatchEvent(new Event(”dataItemsUpdated”) );
            dispatchEvent(new Event(”totalChanged”) );
        }

So now if we made an adapter it would start up, read in the source data model, and populate our internal array of items. But it wouldn’t respond to changes in the source data model. So lets create the event handler that we set up in the constructor. We’ll also create a couple helper methods

    protected function onItemsChanged(event:CollectionEvent):void
        {
            switch(event.kind)
            {
                case CollectionEventKind.ADD: addItems(event.items); break;
                case CollectionEventKind.REMOVE: removeItems(event.items); break;

                case CollectionEventKind.MOVE:
                case CollectionEventKind.REFRESH:
                case CollectionEventKind.REPLACE:
                case CollectionEventKind.RESET:    rebuildFilteredArray();
                                                break;

                case CollectionEventKind.UPDATE:  

            }

        }

        protected function addItems(items:Array):void
        {
            for each ( var item:DataItemExample in items )
            {
                if( (! _onlyActiveItems ) || (item.active) )
                {
                    filteredDataItems.addItem(item);
                }
            }
            dispatchEvent(new Event("totalChanged") );
        }

        protected function removeItems(items:Array):void
        {
            for each ( var item:DataItemExample in items )
            {
                var index:int = filteredDataItems.getItemIndex(item);
                if( index != -1 )
                {
                    filteredDataItems.removeItemAt(index);
                }
            }
            dispatchEvent(new Event("totalChanged") );
        }

For adding/removing items we’re going to our internal array and manually adding or removing items from it. We’re making sure to account for filtered items, but the sort object is taking care of the sorting for us.

For the other types of events, we’re kind of cheating. We only really care about adding / removing operations so we’ll just rebuild our entire internal array on other types of events. If your application uses those types of events often, you should implement them in the adapter in a more efficient manner.

Exposing data from the Adapter

We now have the internal state of the adapter updating as the model changes. So the only thing left to do in there is expose some properties so we can get at that info from our view. Let’s write two bindable getters. One of them will summarize the data (get total()) the other will give us our filtered list (get dataItems())

Note that we set the event=”" property in the [Bindable] tags so our views can correctly know when these properties change.

  [Bindable(event="dataItemsUpdated")]
        public function get dataItems() : ArrayCollection
        {
            return filteredDataItems;
        }

        [Bindable(event="totalChanged")]
        public function get total() : Number
        {
            var total:Number = 0;
            for each ( var item:DataItemExample in filteredDataItems )
            {
                total += item.amount;
            }    

            return total;
        }

Using the Adapter

Once you’ve done all of that, you can actually use your adapter. So create your data model, create your adapter, and use it!

 [Bindable] protected var dataModel:DataModelExample = new DataModelExample();
 [Bindable] protected var example1:AdapterExample = new AdapterExample( dataModel, true ,true);

    <mx:Panel x=”10” y=”218” width=”250” height=”200” layout=”absolute” title=”Filtered, Sorted>
        <mx:Label x=”10” y=”132” text=”Total:/>
        <mx:Label x=”56” y=”132” text=”{example1.total}/>
        <mx:List x=”10” y=”4” width=”210” height=”120” dataProvider=”{example1.dataItems}” labelField=”name></mx:List>
    </mx:Panel>

If you look at the source of the example, we actually create 4 adapters with varying options.

Beyond this basic example

If you want your adapter to respect changes to individual items, your items should implement the IPropertyChangeNotifier interface. So in our example if we edited an item so it’s active flag changed, the views would not update. To make that work we would implement that IPropertyChangeNotifier interface, and then write some code for the CollectionEventKind.UPDATE event.

Often times only one or two views are visible at a time and it’d be nice if all the views in the background weren’t madly updating themselves every change. To accomplish that I often write an enable() disable() method on the adapter. They usually look something like this:

protected function enable() : void

{

model.myDataItems.addEventListener(CollectionEvent.COLLECTION_CHANGE, onItemsChanged );

rebuildFilteredArray();

}

protected function disable() : void

{

model.myDataItems.removeEventListener(CollectionEvent.COLLECTION_CHANGE, onItemsChanged );

}

The Essential Guide to Open Source Flash Development

The book I’ve been working on, The Essential Guide to Open Source Flash Development, is now out in stores.  It’s hard to believe that I started working on it about 11 months ago!  It’s really great to see all of that hard work finally in print.

So What is it about?

The book does a few things.  First, about a third of the book introduces you to some open source tools for doing flash development.  Things like FlashDevelop, MTASC, SwfMill, ANT, and ASDT.  It’ll show you how to create an AS2 and an AS3 based flash application using completely free and open software.  This goes all the way from installing the tools, creating a sample app, writing up some unit tests for it, and then to publishing it to the web.  Along the way it’ll give you a brief introduction to each tool, explain what it does, and then give a quick example of how to use it.  (That’s the 5 chapters I wrote)

The remaining 2/3 of the book dedicates a chapter to various open source projects going into a little more detail about them.  There’s a chapter on Papervision 3D, SWX, FUSE/Go, HAXE, AMFPHP, two for Red5 and a couple more.

This was a lot of fun to work on, and my only regret is not getting to know the other authors better.

If you’re looking for a place to buy it, check out Bookpool.   I worked for them for a year and they’re really stellar guys.  They offer good prices, but more importantly;  as long as the book is in stock, they do their damndest to get it on a truck the day you order it. (Of course, you’re at the mercy of the publisher if it’s out of stock)

Xray Viewer updated

The XRayViewer has been broken for quite some time. I had originally done it with an AIR beta, and that has since stopped working. So there’s now a newly compiled version just waiting for you to grab.

What is the XRayViewer?

So you may be asking yourself What exactly is the XRayViewer?

All this little app does is host the XRay connector and let you load a local swf. Then it displays the swf with some simple controls to play/stop/advance/back. The big benefit is you can then use XRay (By John Grden + Others) to inspect the swf without changing any code around.

There’s three new (very minor) features in this version:

  1. There’s a button to launch the XRay interface in your default browser.
  2. The path to the loaded swf is displayed in the top toolbar. (You can copy & paste that into Xray so you don’t have to navigate as far into the hierarchy)
  3. New logo / icons

Now Open Source!

The entire project is now licensed under the MIT license. If you install the application and then right click on it you can “View Source” to get the source code for it.

My first Red5 experience

I’ve worked with both Chris Allen and John Grden on some projects for my employer. During that time, I can’t count the number of times I heard about Red5, but I never got a chance to try it out.

This past week I caught Chris’ “Building Red5 Applications” session at FlashForward. I finally got up the motivation to download and try it out.

Here’s my experience. It’s my first time playing with Red5 (but I have plenty of java & eclipse experience) so it’s almost guaranteed I’m not doing everything the “right way”. But this way worked for me, maybe it’ll help someone else. If it does help you, please leave a comment. Writing this up takes a while and I’m not going to bother in the future for other things if nobody gets value out of it.


Attempt #1

I wanted to try out the .tar.gz package so I would know how to deal with it on Linux as well as Windows. That way I’d be able to deploy anything I built on my webhost fairly easily.

I unpacked it, ran ant, and let it all build. So far so good.

Then I ran the red5.bat file. Lots of exceptions. Like millions, maybe billions, I lost track. Seems my sample applications weren’t found. I poked around a bit, but no good. Screw this.

Attempt #2
I went for the windows installation package. That unpacked everything and the server ran fine. I could open up a web browser to http://localhost:5080/ and view the demos, admin panel, etc.

Note: The default admin username/password is admin/admin. You can change that in conf/tomcat-users.xml I’d suggest changing it.

Eclipse

So now I want to get it rocking with eclipse. I launch eclipse (I’m lazy and like things easy so I use easy eclipse.)

I select File->Import->Existing project, then pick my Red5 project. Bamn, I got an eclipse project set up.

But there’s compile errors.

Severity and Description Path Resource Location Creation Time Id
Project red5_server is missing required source folder: ‘test’ red5_server Build path 1190574481375 173990
The project cannot be built until build path errors are resolved red5_server Unknown 1190574530687 173992

So I closed the red5 eclipse project, fired up a text editor, and looked in my .classpath file inside the red5 folder. It had the offending entry.

<classpathentry kind=”src” path=”test”/>

Note… I delete this line later on:
<classpathentry kind=”con” path=”org.jayasoft.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/ivy.xml/test,”/>
You might as well do it now since you’re in there.

So I removed it, and repopened eclipse.

A quick Project->Clean and…
3656 Errors

Ok, seems it doesn’t see some libraries. Right click on my project, select properties. Go into “Java Build Path”, select the “Libraries” tab, click the “Add Jars…” button, and add all of the .jar files in the lib directory.

A quick Project->Clean and…
0 Errors

WOOT

Running it from Eclipse

Now I go into src/org/red5/server, find the StandAlone.java, right click it, and select “Run as…”->”Java Application”.

I check my eclipse console panel and get a bunch of lines the last one being:

[INFO] 2007-09-23 15:14:20,875 main:( org.red5.server.Standalone.main ) Startup done in: 5875 ms

Nice.

I point a web browser at: http://localhost:5080/ and see that the red5 server is indeed running. I launch the ball demo and push the connect button. Then I make a new browser window and launch the demo again. When I move the red5 logo in one window, it moves in the other. That means it’s all working.

Eclipse also helpfully added an entry to my run button (the green circle with the play button) in my toolbar so I don’t have to find the StandAlone.java file again.

I want a quick launch button for debugging too, so I kill the server (click the red square on the console panel) and right click the StandAlone.java and select “Debug as java application”. The server starts in debug mode, and eclipse adds it to my debug button on the toolbar. (the green beetle button)

Making something

Now, I want to make something. But first, I want to get rid of the samples. So I kill the server, close the eclipse project, and edit the .classpath file again. I know there’s a way to do this through eclipse, but I find editing the file quicker.

I get rid of these entries:
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/echo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/tutorial/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/fitcDemo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/oflaDemo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”conf”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/test/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/midiDemo/WEB-INF/src”/>
<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/agile/WEB-INF/src”/>

And I add one for my project, I’m going to work on something for AgileAgenda, so I’ll call it agile.

<classpathentry excluding=”.svn/*” kind=”src” path=”webapps/agile/WEB-INF/src”/>

Then I go rename the “echo” example to “agile”, and delete all the other samples (I deleted admin too, not sure if that was a good idea or not)

Open up the project in Eclipse again.

And I don’t see my agile webapp. WTF? Oh yeah… Eclipse is retarded. Right Click->Refresh and it shows up.

I want to rename the Application class in my webapps folder (see the picture).

Luckily, Eclipse rocks Java more than it rocks Flex, so I can just right click, select refactor, and pick move. Then I click “Create Package” enter in com.agileagenda.services and click ok a bunch of times.

I delete the rest of the webapp echo source tree.

A project->Clean and…

I think I broke something. Oh well.

Project->Properties->Builders and remove the invalid entry.

Project->Clean and build successful.

I hit the debug button, and search the console output. No errors reported and:

[INFO] 2007-09-23 15:44:45,375 main:( /agile.invoke0 ) Initializing Spring root WebApplicationContext

So I guess it found my new app. Yay!

Kill the server.

So I go back to my Application class and make a new method.

public function login(username:String, password:String) : Boolean
{
return true;
}

Then I remember that this is Java and not Actionscript so I rewrite it…

public boolean login(String username, String password)
{
return true;
}

I go to my project menu and turn on “Build Automatically” and get…

Severity and Description Path Resource Location Creation Time Id
Unbound classpath container: ‘org.jayasoft.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/ivy.xml/test,’ in project red5_server red5_server Build path 1190576857156 182811

WTF?

Close the project, open my .classpath file, remove the offending line:
<classpathentry kind=”con” path=”org.jayasoft.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/ivy.xml/test,”/>

Open the project, Project->Clean, build success.

I have no idea why that didn’t bite me earlier.

I press the debug button. The red5 server launches.
[INFO] 2007-09-23 15:51:26,062 main:( org.red5.server.Standalone.main ) Startup done in: 4937 ms

Yay.

Writing some actionscript

Now that I have a (dumb) login method, I want to try it out in Flex.

I have a “Sandbox” AIR application set up in Eclipse that I use when I want to quickly play with something. I highly suggest everyone do that. So I open my sandbox, open the MXML and create a quick login form.

<mx:Label x="26" y="43" text="Username:"/>
<mx:TextInput x="101" y="41" id="txtUsername"/>
<mx:TextInput x=”101″ y=”71″ id=”txtPassword” displayAsPassword=”true”/>
<mx:Label x=”26″ y=”73″ text=”Password”/>
<mx:Button x=”196″ y=”101″ label=”Login” click=”onLoginClick()”/>
<mx:Label x=”58″ y=”148″ text=”Label” id=”lblResult” width=”281″/>

And then add in some code (remembering that this is Actionscript!)…

private var netConn:NetConnection;

protected function onLoginClick() : void
{
NetConnection.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;
SharedObject.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;

netConn = new NetConnection();
netConn.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus );
netConn.addEventListener( SecurityErrorEvent.SECURITY_ERROR, errorHandler );
netConn.addEventListener( AsyncErrorEvent.ASYNC_ERROR, errorHandler );
netConn.addEventListener( IOErrorEvent.IO_ERROR, errorHandler );

netConn.connect(”rtmp://localhost/agile”);

}

protected function sendLogin() : void
{
var responder:Responder = new Responder( onLoginResult );
netConn.call(”login”,responder,txtUsername.text, txtPassword.text);
}

protected function onLoginResult( result:Boolean ) : void
{
lblResult.text = result ? “Login Success!” : “Login Fail!?!”;
}

protected function onNetStatus(event:NetStatusEvent) : void
{
switch( event.info.code )
{
case “NetConnection.Connect.Success”:
lblResult.text = “Connected, sending login”;
sendLogin();
break;

default:
lblResult.text = “ERROR!! ” + event.toString();
break;
}

}

protected function errorHandler(event:Event) : void
{
lblResult.text = “ERROR! ” + event.toString();
}

I start the server, run my sandbox app, click the login button, and get a connection error. Something went wrong somewhere.

I bet it’s a configuration problem. I open webapps/agile/WEB-INF and notice 3 config files.

in web.xml I make this change:

<context-param>
<param-name>webAppRootKey</param-name>
<param-value>/agile</param-value>
</context-param>

In red5-web.xml I make this change:

<bean id=”web.handler”
class=”com.agileagenda.services.Application
singleton=”true” />

In red5-web.properties, I make this change:

webapp.contextPath=/agile

Kill the server, restart it (debug mode), try my app again. “Login Sucess” YES!

Now I head into the java class and put a breakpoint on the “return true;” line. I hit the button on my AIR app and Eclipse correctly breaks on the line. Yay!

I inspect the username and password parameters, and the values I had filled into the AIR app are present. Yay!

I’m now to the point where I can start actually writing my application.

What’s the right amount of copy protection?

I’m currently working on a piece of commercial software that will be available through a download and will use a license key to activate it. The software is aimed at helping people schedule projects and will be targeted mostly to corporate users.

With the recent Windows Vista black screen of death, it got me thinking about what sort of measures I should go through to prevent unauthorized users from using the software.

While I don’t wish to burden legitimate users, I do want to prevent most piracy. How much copy protection is appropriate?

Is it acceptable for the software to phone home? If so, what data is appropriate to report on? The license key? Software version? What about a unique installation ID?

Should I disable license keys for small amounts of piracy, like when there’s 3 active installations of the software? What about widespread piracy where we detect dozens or hundreds of uses of the same license key? Would a simple message stating the software may be pirated with instructions on how to purchase a valid license be sufficient?

As a more general question, what licensing schemes have you seen that work the best?

ObjectHandles now has mouse cursor support.

ObjectHandles, the easy way to add user resizing & movement of objects to your flex application, has been updated.

Now, when mousing over the component or the various handles an appropriate mouse cursor will be displayed.

There’s been a lot of interest from people about this component. It’s seen over 400 downloads and I’ve received quite a few emails about it. If you interested in following this project more closely, I’ve set up a google-group where I plan to announce new versions and people can ask questions. To join, go over to:
http://groups.google.com/group/objecthandles

Downloads, examples, etc can be found on the project page:
http://www.rogue-development.com/objectHandles.xml

If the example on the project page seems out of date, you may have to clear your cache. I’ve found some browsers don’t refresh i-frames like they should.

Log Viewer

I’ve started a new project to make a flex component to quickly display largish amounts of text. It’s main purpose is to display logging information on screen. It’s uses a semi-intelligent algorithm to re-use on screen components and batch UI updates in groups.


http://www.rogue-development.com/logViewer.xml

First look at a Flex Component to resize on screen objects.

I’ve been spending some time working on a flex component to add “handles” to an on screen object to allow an end-user to resize and move it. It’s exactly the same type of functionality when you’re using design mode of Flex Builder.

Below is the first look at the current progress I’ve had.

As you might have noticed it has a few bugs and is far from done feature-wise. It you’d like to keep up on it, take a look at the project page.

If anyone knows of a project doing this same type of functionality, please let me know. I hate to duplicate efforts.

Programatically add constraints through Actionscript

Flex Builder has that great “Constraints” UI that allows you to anchor components to their parent that I’m sure everyone has used.


But what happens if you create an object in actionscript and then you want add constraints to it? There is no “top” property you can set to anchor the component to the top. It turns out the constraint system is entirely based on Flex’s style system and can be used as follows:

var someComponent:SomeComponent = new SomeComponent();
var style:CSSStyleDeclaration = new CSSStyleDeclaration();
style.setStyle(”top”, 0);
style.setStyle(”horizontalCenter”, 0);
someComponent.styleDeclaration = style;

And BAMN, someComponent will be anchored to the top, center of it’s parent (assuming it’s parent is a container that supports anchors.) Available style selectors are:

  1. top
  2. left
  3. right
  4. bottom
  5. horizontalCenter
  6. verticalCenter

You could also specify the styles in a css sheet, or by adding them to an already existing style.

Edit…

As a commenter has posted you can also use the setStyle method in addition to the various other methods I mentioned. So the following would also work:

someComponent.setStyle(”top”,0);

Automated website testing

There’s some really expensive packages out there for automated website testing. These things cost thousands of dollars, usually only run on windows, and are huge bloated software packages. There great for your average QA person to quickly “record” a web session and play it back later.

But developers have different needs than QA folk, and we’d like to do automated tests as well. My requirements are as follows:

1) Cross platform (windows, osx, linux, more is nice)
2) Allows me to simulate all types of requests to a web server / service.
3) Can be integrated into ant for completely hands-off testing.
4) Can verify any element of a page.

The package I’ve been using for this is called Hatatap.

It allows you to construct o-xml programs that easily fulfill all of my requirements. o-xml is an object orientated programing language that’s written entirely in XML. If you have a good XML editor that understands XML schemas, than you get all the nice context sensitive completion you expect from a modern development environment.