Twitter: raymondcamden


Address: Lafayette, LA, USA

Crazy Flex, Mobile, ColdFusion, BlazeDS experiment

09-02-2011 8,312 views Mobile, Flex, ColdFusion 14 Comments

After lunch today I decided to embark on a little test. Folks know - or should know - that ColdFusion ships with an incredibly powerful Server Monitor. If you haven't yet played with it, I highly encourage taking a look at Charlie Arehart's four part article over on the Adobe Developer connection for a review. One of the features he talks about is the Alerts system. For folks who don't want to spend all day staring at a computer screen (wait, people don't?), then the Alerts feature is a powerful way to have the monitor tell you when something is wrong as opposed to you keeping a constant eye on it. Alerts can do a variety of things, but when the built in functionality doesn't meet your needs, you can also have it run a CFC for you - and that's where this experiment began.

I began by creating a simple data services messaging gateway in my ColdFusion Administrator. This is a pretty deep topic (and some of my readers will share that it's not always as easy as I'm going to make out), but for the most part, I simply created the event gateway and I was done with that part. On the Flex side, it's a simple matter of setting up code to connect to that event gateway. So here for example is a one page Flex Mobile app that let's me send a message to the gateway.

view plain print about
1<?xml version="1.0" encoding="utf-8"?>
2<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
3        xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView" viewActivate="init(event)" xmlns:mx="library://ns.adobe.com/flex/mx">

4    
5    <fx:Declarations>
6        <mx:Consumer id="mainConsumer" destination="ColdFusionGateway" message="msgResponder(event)" />
7        <mx:Producer id="mainProducer" destination="ColdFusionGateway" />
8    </fx:Declarations>
9
10    <fx:Script>
11        <![CDATA[
12            import mx.messaging.ChannelSet;
13            import mx.messaging.channels.AMFChannel;
14            import mx.messaging.events.MessageEvent;
15            import mx.messaging.messages.AsyncMessage;
16            
17            import spark.events.ViewNavigatorEvent;
18
19            private var pollChannel:AMFChannel = new AMFChannel("cf-polling-amf", "http://127.0.0.1/flex2gateway/cfamfpolling");
20            private var amfChannelSet:ChannelSet = new ChannelSet();
21
22            protected function init(event:ViewNavigatorEvent):void {
23                amfChannelSet.addChannel(pollChannel);
24                
25                mainConsumer.channelSet = amfChannelSet;
26                mainProducer.channelSet = amfChannelSet;
27                mainConsumer.subscribe();
28            }
29
30            
31            protected function msgResponder(event:MessageEvent):void
32            {
33                trace("got something");
34                debug.text += event.message.body.MESSAGE + '\n';
35            }
36            
37            protected function btnClick(event:MouseEvent):void
38            {
39                var msgString:String = inputText.text;
40                var msg:AsyncMessage = new AsyncMessage();
41                msg.body.MESSAGE = msgString;
42                msg.headers.gatewayid="MobileGateway1";
43                mainProducer.send(msg);
44                trace("sent "+msgString);
45            }
46            
47        ]]>

48    </fx:Script>
49        
50    <s:layout>
51        <s:VerticalLayout />
52    </s:layout>
53    
54    <s:TextInput id="inputText" />
55    <s:Button label="Send" click="btnClick(event)" />
56    
57    <s:Label id="debug" />
58</s:View>

On the ColdFUsion side, my CFC listened for messages and echoed them back:

view plain print about
1component {
2
3    remote struct function onIncomingMessage(required any event) {
4        writelog(file="application", text="gateway - #serializejson(event)#");
5        event.data.body.MESSAGE = "Sent back " & event.data.body.MESSAGE;
6        return event.data;
7    }
8    
9}

Notice I modify the message a bit just so I can see it working right. Here's a screen shot of it working.

To be clear - that's Flex talking to BlazeDS and ColdFusion on the server. If I had more devices, they all would have gotten the message. So - with me so far? Because here is where things get interesting.

As I mentioned before, the Server Monitor allows you to specify alerts, and allows you to specify CFCs to run. The docs, unfortunately, are completely lacking in useful information here. For example, they don't tell you how to specify the CFC. You can only use a file name (no directory!) and it must live in cfusioninstall\runtime\bin. (Thanks to Charlie's article on that.) And while you are told what methods your CFC must have, they don't tell you what the data looks like when your CFC is run. I ended up using writeDump to a directory just to see this! Here is an example:

Ok, so given that I've got some basic info there - I wrote my CFCs then to send messages to my event gateway.

view plain print about
1component {
2
3    remote function onAlertStart(struct alert) {
4        writelog(file="application", text="START - #serializejson(alert)#");
5        writedump(output="c:\raytest\#createUUID()#.html", var=alert, format="html", label="START");
6        var s = {
7            destination="ColdFusionGateway",
8            body={
9                type=alert.alerttype,
10                message=alert.alertmessage,
11                start=true
12            }
13        };
14    
15        sendGatewaymessage("MobileGateway1", s);
16    }
17    
18    remote function onAlertEnd(struct alert) {
19        writelog(file="application", text="END - #serializejson(alert)#");
20        writedump(output="c:\raytest\#createUUID()#.html", var=alert, format="html", label="END");
21
22        var s = {
23            destination="ColdFusionGateway",
24            body={
25                type=alert.alerttype,
26                message=alert.alertmessage,
27                start=false
28            }
29        };
30    
31        sendGatewaymessage("MobileGateway1", s);
32        
33    }
34    
35}

To be clear, the first two lines in both methods was just for testing purposes. You can see though that I take a few values from the alert and send it to the gateway. Now for the front end.

view plain print about
1<?xml version="1.0" encoding="utf-8"?>
2<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
3        xmlns:s="library://ns.adobe.com/flex/spark" title="Server Monitor" viewActivate="init(event)" xmlns:mx="library://ns.adobe.com/flex/mx">

4    
5    <fx:Declarations>
6        <mx:Consumer id="mainConsumer" destination="ColdFusionGateway" message="msgResponder(event)" />
7        <mx:Producer id="mainProducer" destination="ColdFusionGateway" />
8    </fx:Declarations>
9    
10    <fx:Style>
11        @namespace s "library://ns.adobe.com/flex/spark";
12        @namespace mx "library://ns.adobe.com/flex/mx";
13        
14        .inactiveBtn {
15            backgroundColor:#c0c0c0;
16        }
17        
18        .activeBtn {
19            backgroundColor:red;
20        }
21    </fx:Style>
22    <fx:Script>
23        <![CDATA[
24            import mx.messaging.ChannelSet;
25            import mx.messaging.channels.AMFChannel;
26            import mx.messaging.events.MessageEvent;
27            import mx.messaging.messages.AsyncMessage;
28            
29            import spark.events.ViewNavigatorEvent;
30            
31            private var pollChannel:AMFChannel = new AMFChannel("cf-polling-amf", "http://192.168.1.108/flex2gateway/cfamfpolling");
32            private var amfChannelSet:ChannelSet = new ChannelSet();
33            
34            protected function init(event:ViewNavigatorEvent):void {
35                amfChannelSet.addChannel(pollChannel);
36                
37                mainConsumer.channelSet = amfChannelSet;
38                mainProducer.channelSet = amfChannelSet;
39                mainConsumer.subscribe();
40            }
41            
42            
43            protected function msgResponder(event:MessageEvent):void
44            {
45                trace("got something");
46                switch(event.message.body.TYPE) {
47                    
48                    case "Timeouts Alert": {
49                            ssa.styleName = 'inactiveBtn';
50                            usa.styleName = 'inactiveBtn';
51                            jma.styleName = 'inactiveBtn';
52                            if(event.message.body.START == "true") toa.styleName = 'activeBtn';
53                            else toa.styleName = 'inactiveBtn';
54                            break;
55                    }
56                    case "Slow Server Alert": {
57                        if(event.message.body.START == "true") ssa.styleName = 'activeBtn';
58                        else ssa.styleName = 'inactiveBtn';
59                        usa.styleName = 'inactiveBtn';
60                        jma.styleName = 'inactiveBtn';
61                        toa.styleName = 'inactiveBtn';
62                    }
63                }
64                //only log if starting
65                if(event.message.body.START == "true") messageArea.text = event.message.body.MESSAGE + '\n' + messageArea.text;
66            }
67            
68        ]]>

69    </fx:Script>
70    
71    <s:layout>
72        <s:VerticalLayout paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" verticalAlign="middle" horizontalAlign="center" />
73    </s:layout>
74
75    <s:Label id="ssa" width="100%" height="60" styleName="inactiveBtn" text="Slow Server Alert"
76             textAlign="center" verticalAlign="middle"/>

77
78    <s:Label id="toa" width="100%" height="60" styleName="inactiveBtn" text="Timeout Alert"
79             textAlign="center" verticalAlign="middle"/>

80
81    <s:Label id="usa" width="100%" height="60" styleName="inactiveBtn" text="Unresponsive Server"
82             textAlign="center" verticalAlign="middle"/>

83
84    <s:Label id="jma" width="100%" height="60" styleName="inactiveBtn" text="JVM Memory"
85             textAlign="center" verticalAlign="middle"/>

86
87    <s:Label id="messageArea" width="100%" height="100%" />
88    
89</s:View>

Yeah - a bit more code there. It may help if I run it so you can see it first:

Basically - my application has 4 labels. When a message is received (notice this version never actually sends anything - I can get rid of the Producer) - I highlight various fields based on what the alert type was. I only wrote code for two of the types, but you can imagine what support for the other two would do. And what happens? Check out this horrible, shaky, YouTube video. I apologize in advance. Oh, and it's boring too. You will have to wait a bit to see the results. That isn't Flex or BlazeBS being slow, it's me trying to force a slow server alert on my box by reloading a very large Model-Glue site in 5-6 tabs at once.

14 Comments

  • Commented on 09-02-2011 at 4:59 PM
    BlazeDS? What's that? You should have used ADEP Data Services! :D
  • Commented on 09-02-2011 at 9:53 PM
    I know I know. :) It's not my fault BlazeDS ships with CF. ;)
  • Commented on 09-06-2011 at 9:30 AM
    Ray,

    By any chance have you tried to subscribe with a client id(like consumer.subscribe(id)). I am working on a web app and am using BlazeDS for longpolling. Every time I try to subscribe, I get a DuplicateSessionError.
    I tracked down the point of error, and found it to be when I subscribe the consumer. Looking deeper, I found that when the flex app subscribes, it sends a clientId of null, which(I think) creates the duplicate session. There is an argument of clientId(defualts to null) in the function subscribe, but I tried entering what I think was the client ID and get a out of channels error.
    Here is the general workflow of the application: sign in through RemoteObject, then subscribe the consumer with the appropriate subtopic. In your app the subscribe comes first, which creates the clientId for the rest of your session. There must be a way to subscribe with a specified session.

    Let me know if you have any ideas on a way to approach this. Thanks for the help.
  • Commented on 09-06-2011 at 4:09 PM
    No sorry I have not seen this.
  • Commented on 09-07-2011 at 7:28 PM
    So just as an update. I figured it out. When I first set up the connection of Flex and BlazeDS, I used the project setting > Flex Server to set the location of my Server Configuration. This added the flag to the compiler, and I figured it would only use the setting on compile time. But in fact some of it is used at runtime as well.

    When I changed the location of the server when I deployed to my production machine, it couldn't find the .xml files. And that caused the channelset to be set as null. It connected at without it being set. Anyways, I added the channel set like the example above and everything seems to be working.

    Thanks for the example above. Compared everything and it helped me find my answer. Cheers.
  • Commented on 09-07-2011 at 7:40 PM
    Darn good find there - thanks for posting back.
  • Commented on 10-18-2011 at 7:10 PM
    Hi,

    Sorry for asking this here, but is there a place I can look for answers regarding a CF to AIR connection error:

    Send Failed
    Channel.Connect.Failed error
    NetConnection.Call.Failed: HTTP: Status 500
    url: '[url]/flex2gateway/'

    It only happens on occasion & the info I've found on the web leads to nowhere.

    Many thanks for any clue,

    Tomas
  • Commented on 10-18-2011 at 8:53 PM
    All I can recommend is checking the logs. 500 implies an error of some sort and something should be logged.
  • Commented on 10-19-2011 at 7:39 AM
    Hey, thanks. That has given me a new path to work in.
  • Alexander Smith #
    Commented on 03-22-2013 at 1:20 PM
    You know Raymond if you don't post the xml config files it"s of no use but your own. Seems nice but as you said setting up a messaging channel is no as easy as it sounds however it is not all that complicated neither the logic is to diagram the channels the names get confusing because it is always a combination my,cf,amf and polling spread across the 4 messaging,services,proxy and remotting config files. A few lines of code will get it working. Nice article but without the config files it's kinda useless really unless you want to spend one afternoon on this witch defeats the purpose of putting it out there...Thanks anyway
  • Commented on 03-22-2013 at 1:32 PM
    Sorry to disappoint you, Alexander. This post is almost 2 years old, so I don't exactly remember everything about it, but I believe I used the default settings for Blaze inside of CF. In other words, I don't think I edited any XML files. So be my guest to try it w/ the defaults and let us know.
  • Commented on 03-22-2013 at 1:47 PM
    Alexander, it is nice that you tried to comment, but without proper spelling, grammar, and punctuation, it's really kind of useless; because I cannot understand a thing you meant, which defeats the purpose of putting it out there. Thanks anyway.
  • Alexander Smith #
    Commented on 03-22-2013 at 3:39 PM
    @Jason Nice pretty funny. XD

    Don`t worry not offended I have a sense of humor...

    @Raymond Let me ask you, do you do consulting work?
  • Commented on 03-22-2013 at 4:21 PM
    I do a bit of side work, but I've got a full time gig with Adobe. I definitely don't do any Flex work though.

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty