Tutorial: Building a chat program in Flex 3 with Adobe's project Cocomo

Post to Twitter

At Adobe MAX 2008 I seen several blog postings about something called “Cocomo“. It seems Adobe has been busy adding more and more content to their already powerful Acrobat.com site (Buzzword is one of my favorites). Today we will take a look at building a chat program in Flex Builder 3 that will use Cocomo as the back end.

You will need the following to complete this tutorial:
1. A Cocomo account which will then let you download the Cocomo SDK. (I used beta version 0.9 for this tutorial)
2. A copy of Flex Builder 3 (the trial version will work if you want to test it out)
3. Adobe AIR 1.5 (needed for the localhost testing server)

Once you have extracted the Cocomo SDK somewhere you can take a look through it and right away you may notice that there is already a simple chat program example included. We’ll be taking that general idea and code but building it ourselves so we actually understand what is going on.

I’ll assume your have the Cocomo SDK installed and will be working with Flex Builder 3. If the SDK is not installed yet then check out the “docs” folder in the SDK and read over the PDF Adobe has put together on Cocomo because it has a good section on getting your development environment up and running.

Create a new Flex Builder 3 project and call it “CocomoChat”.

Make sure to link the Cocomo SWC file into your library. Navigate to the appropriate SWC file (which in this case is the Flash Player 9 one) which is located where your extracted the SDK (which should be in the plugins folder of Flex Builder):

In my case (using Windows Vista) the SWC was located here:


C:/Program Files/Adobe/Flex Builder 3/plugins/com.adobe.cocomo/CoCoMo/lib/player9/cocomo.swc

We will quickly design the user interface. It will be very basic and minimal. Here is what the finished layout looks like:

Drag an mx:Panel onto the Flex Builder designer and give it the following settings:
id: cocomoChat_pnl
title: Cocomo Chat
width: 450
height: 307
font: Verdana 14 (I like big fonts, adjust as you want of course)
font color: black
Contraints: See screenshot below

Drag an mx:TextArea onto the panel with these settings:
id: chatOutput_txt
editable: false
width: 237
height: 201
x: 10
y: 14

Drag an mx:List next to the textarea control:
id: roster_lst
height: 201
width: 163
x: 257
y: 14

Drag an mx:TextInput below the main chat textarea control:
id: chatInput_txt
max chars: 100
width: 237
height: 29
x: 10
y: 223

Finally we need to add a connect button, drag an mx:Button next to the TextInput control you just added:
id: connect_btn
label: Connect
height: 29
width: 165
x: 255
y: 223

Here is the MXML so far:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Panel width="450" height="307" layout="absolute" horizontalCenter="0" verticalCenter="0" title="Cocomo Chat" id="cocomoChat_pnl" fontSize="14" fontFamily="Verdana" color="#000000">
		<mx:TextInput x="10" y="223" borderStyle="solid" maxChars="100" id="chatInput_txt" width="237" height="29"/>
		<mx:TextArea x="10" y="14" width="237" height="201" id="chatOutput_txt" editable="false" color="#000000"/>
		<mx:List x="257" y="14" id="roster_lst" height="201" width="163"></mx:List>
		<mx:Button x="255" y="223" label="Connect" height="29" id="connect_btn" width="165"/>
	</mx:Panel>

</mx:Application>

Looking at the MXML it might be obvious if you’ve been messing with the Cocomo SDK that the namespace is missing. Lets go ahead and add that in before we forget:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:rtc="CocomoNameSpace" layout="absolute">

Time for the script, go ahead and add an mx:script tag and add the following imports:

import com.adobe.rtc.pods.simpleChatClasses.ChatMessageDescriptor;
import com.adobe.rtc.events.ChatEvent;
import com.adobe.rtc.pods.simpleChatClasses.SimpleChatModel;

You can look each of these up in the Cocomo API docs for more information, for now suffice to say we need these to get a minimal chat working with as little effort on our part as possible.

Below the imports we need to declare a variable of SimplechatModel which will allow us to use the binding goo Flex is famous for. We will add this code:

[Bindable]
public var simpleChatModel:SimpleChatModel;

Now we can add the handler for the “Connect” button. Lets add the code for the click event via MXML:

<mx:Button click="onConnectClicked();" x="255" y="223" label="Connect" height="29" id="connect_btn" width="165"/>

Move back up into the scripting area and add the function for this:

private function onConnectClicked():void
{

}

We can now almost add the code needed for our connection but first we have to take care of something. We need to add the LocalAuthenticator as well as a ConnectSessionContainer controls. We will add the LocalAuthenticator first:

<rtc:LocalAuthenticator id="cocomoAuthenticator"  />

This can be added right below the ending mx:script tag. This next bit of code though needs to wrap the entire mx:Panel like so:

<rtc:LocalAuthenticator id="cocomoAuthenticator"  />
<rtc:ConnectSessionContainer roomURL="ChatRoomUrl" id="cocomoChatSession" authenticator="{cocomoAuthenticator}" width="100%" height="100%">
	<mx:Panel width="450" height="307" layout="absolute" horizontalCenter="0" verticalCenter="0" title="Cocomo Chat" id="cocomoChat_pnl" fontSize="14" fontFamily="Verdana" color="#000000">
		<mx:TextInput x="10" y="223" borderStyle="solid" maxChars="100" id="chatInput_txt" width="237" height="29"/>
		<mx:TextArea x="10" y="14" width="237" height="201" id="chatOutput_txt" editable="false" color="#000000"/>
		<mx:List x="257" y="14" id="roster_lst" height="201" width="163"></mx:List>
		<mx:Button click="onConnectClicked();" x="255" y="223" label="Connect" height="29" id="connect_btn" width="165"/>
	</mx:Panel>
</rtc:ConnectSessionContainer>

Its probably pretty obvious what the authenticator does. One thing I did leave out was the “userName” property. Since I want to test this project from multiple browsers I want to have random usernames than one hardcoded one. If a username is not specified then Cocomo will generate a random one automatically. Keep in mind we are using the localhost authenticator for this project, meaning we will be connecting to an Adobe AIR based server on our local machine. We could easily substitute out the local authenticator for one that could connect to Cocomo at cocomo.acrobat.com by using this:

<rtc:AdobeHSAuthenticator
	id="cocomoAuthenticator"
	userName="AdobeIDusername"
	password="AdobeIDpassword"  />

Notice that the ConnectSessionContainer binds to the authenticator. This makes sense since this is where the actual session magic happens. Check out chapter 2 of the “cocomo.pdf” in the SDK for all the details on sessions and authenticators. Towards the end of the PDF you will also see how you can swap in your own custom authentication so you are not just limited to Adobe.com accounts.

I want to note that I will be loosely borrowing some of the code from the Cocomo SDK chat example so if some of this looks familiar that is why.

We will move back to the “Connect” button click handler now and add the rest of the code:

simpleChatModel = new SimpleChatModel(true);
simpleChatModel.sharedID = "simpleChatModel";
simpleChatModel.subscribe();
simpleChatModel.addEventListener(ChatEvent.HISTORY_CHANGE, onIncomingChatMessage);
chatInput_txt.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
connect_btn.enabled = false;
roster_lst.dataProvider = cocomoChatSession.userManager.userCollection;
roster_lst.labelField = "displayName";

First we actually create the SimpleChatModel object and then set the “sharedID” property. The “sharedID” property assigns an id of the “CollectionNode” which is used by the component. We then subscribe which lets the component know it needs to begin synchronizing with the service. Next, we add two event handlers, one to catch the “enter” key when the user is chatting away and the other event is used to capture new incoming chat messages. We will have to add two functions as well. One will handle the incoming chats and the other will handle the keyboard events. Finally, we setup the binding for the roster_lst control so we can see who is connected to the chat server.

private function onIncomingChatMessage(chatEvent:ChatEvent):void
{
	if(chatEvent.message != null && chatEvent.message.msg != null && chatEvent.message.displayName != null)
		chatOutput_txt.htmlText += "<b>" + chatEvent.message.displayName + ":</b> " + chatEvent.message.msg + "<br>";
}

private function onKeyUp(evt:KeyboardEvent):void
{
	if(evt.keyCode == Keyboard.ENTER)
	{
		var chatMessageDescriptor:ChatMessageDescriptor = new ChatMessageDescriptor();
		chatMessageDescriptor.displayName = cocomoChatSession.userManager.getUserDescriptor(cocomoChatSession.userManager.myUserID).displayName;
		chatMessageDescriptor.msg =  chatInput_txt.text;
		simpleChatModel.sendMessage(chatMessageDescriptor);
		chatInput_txt.text = "";
	}
}

In the “onIncomingChatMessage” function we are checking to make sure the incoming message doesn’t have any “nulls” in it, if so, we ignore the message. If we do have a valid message then we display it in the chatOutput_txt control and give it a little HTML formatting to make it look nicer.

The “onKeyUp” function is where we actually send out our messages to any other connected user. We create a new ChatMessageDescriptor object and then set the display name to what was set in the session. We then grab the message from out chatInput_txt control and send it via the SimpleChatModel object. After the message is sent we clear the chatInput_txt control.

Time to test it out. First, we need to get the localhost server running. Go into the SDK folder and locate the file called: “LocalConnectionServer.air”. Mine was located here:

C:\Program Files\Adobe\Flex Builder 3\plugins\com.adobe.cocomo\CoCoMo\extras

If AIR isn’t installed it will be when you double click on the AIR file. The server should start with little fuss.

The final code should look like this:

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

				import com.adobe.rtc.pods.simpleChatClasses.ChatMessageDescriptor;
				import com.adobe.rtc.events.ChatEvent;
				import com.adobe.rtc.pods.simpleChatClasses.SimpleChatModel;


				[Bindable]
				public var simpleChatModel:SimpleChatModel;

				private function onConnectClicked():void
				{
					simpleChatModel = new SimpleChatModel(true);
					simpleChatModel.sharedID = "simpleChatModel";
					simpleChatModel.subscribe();
					simpleChatModel.addEventListener(ChatEvent.HISTORY_CHANGE, onIncomingChatMessage);
					chatInput_txt.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
					connect_btn.enabled = false;
					roster_lst.dataProvider = cocomoChatSession.userManager.userCollection;
					roster_lst.labelField = "displayName";
				}

				private function onIncomingChatMessage(chatEvent:ChatEvent):void
				{
					if(chatEvent.message != null && chatEvent.message.msg != null && chatEvent.message.displayName != null)
						chatOutput_txt.htmlText += "<b>" + chatEvent.message.displayName + ":</b> " + chatEvent.message.msg + "<br>";
				}

				private function onKeyUp(evt:KeyboardEvent):void
				{
					if(evt.keyCode == Keyboard.ENTER)
					{
						var chatMessageDescriptor:ChatMessageDescriptor = new ChatMessageDescriptor();
						chatMessageDescriptor.displayName = cocomoChatSession.userManager.getUserDescriptor(cocomoChatSession.userManager.myUserID).displayName;
						chatMessageDescriptor.msg =  chatInput_txt.text;
						simpleChatModel.sendMessage(chatMessageDescriptor);
						chatInput_txt.text = "";
					}
				}
		]]>
	</mx:Script>
	<rtc:LocalAuthenticator id="cocomoAuthenticator"  />

	<rtc:ConnectSessionContainer roomURL="ChatRoomUrl" id="cocomoChatSession" authenticator="{cocomoAuthenticator}" width="100%" height="100%">
		<mx:Panel width="450" height="307" layout="absolute" horizontalCenter="0" verticalCenter="0" title="Cocomo Chat" id="cocomoChat_pnl" fontSize="14" fontFamily="Verdana" color="#000000">
			<mx:TextInput x="10" y="223" borderStyle="solid" maxChars="100" id="chatInput_txt" width="237" height="29"/>
			<mx:TextArea x="10" y="14" width="237" height="201" id="chatOutput_txt" editable="false" color="#000000"/>
			<mx:List color="#000000" fontWeight="bold" x="257" y="14" id="roster_lst" height="201" width="163"></mx:List>
			<mx:Button click="onConnectClicked();" x="255" y="223" label="Connect" height="29" id="connect_btn" width="165"/>
		</mx:Panel>
	</rtc:ConnectSessionContainer>

</mx:Application>

Fire up multiple browsers and send messages. You should see the messages show up on all running browsers as well as an up to date roster listing of all the chat users.

Update (Dec. 3, 2008):

I’ve gotten some good feedback on how to make this even easier and better. Three suggestions were made:
1. Databind the roster list to the UserCollection:

<mx:List dataProvider="cocomoChatSession.userManager.userCollection" labelField="displayName" color="#000000" fontWeight="bold" x="257" y="14" id="roster_lst" height="201" width="163"></mx:List>

2. Databind the textarea to the ChatModel history (use the same kind of technique as above but databind to the “simpleChatModel.history”)

3. Use the Cocomo supplied EmoticonTextArea control.

<coreUI:EmoticonTextArea x="10" y="14" width="237" height="201" id="chatOutput_txt" editable="false" color="#000000"/>

Post to Twitter

This entry was posted in ActionScript, Adobe, Flex. Bookmark the permalink.

24 Responses to Tutorial: Building a chat program in Flex 3 with Adobe's project Cocomo

  1. dekpitado says:

    Nice post :D, I’ll test the code.. thanks !!!!

  2. Nguyen Viet Doan says:

    Very good . Thanks !!!!!

  3. Praneet says:

    Hi chad:

    I have an AIR application where I have my own (PHP5/MySQL5 backend) login system. So how would I use that information with the external authentication in COCOMO? I have been trying to figure how to use the external authentication and I am going nuts!

    Do I even have to authenticate or shall I log them in as guests with their display names set to the usernames they chose to enter my AIR application initially? What are your thoughts on this?

    Thanks,
    Praneet

  4. Chad Lung says:

    @Praneet,

    Take a look at the Cocomo SDK and you’ll see some example code that will be useful. Also the PDF they put in the SDK talks about external authentication.

    Chad

  5. Ryan says:

    Thanks for the tutorial, but I can not get this thing to work. I publish in FB and nothing shows up

  6. Chad Lung says:

    @Ryan,

    Can you provide some more details?

  7. FS says:

    I have the same problem as Ryan..

  8. […] In preparation for my upcoming presentation at 360|Flex, I’ve decided to write a series of simple tutorials/examples on Adobe Cocomo.

    Most or all of the existing examples seem to show only how to use built-in whiteboards and chat tools. Those are cool, but for any real app, we’re going to want to do something custom. […]

  9. smoo says:

    i have the same problem like chat and FS , its possible why iam life in Germany? I read the cocomo Forum and in a Thread was talking about restricted of USA

    do you do a Answer or its that the Problem?

    smoo

  10. Chad Lung says:

    @smoo,

    Yes, currently it is restricted to the U.S. This is apparently going to be resolved though at some point. It some legal issues Adobe is working on.

    Chad

  11. cease says:

    i’ve seen examples using this component , whats the difference vs what you’ve done

  12. cease says:

    rtc:SimpleChat got cut off from previous post

  13. Tiago says:

    Chad, it doesn’t look like there is any restriction on afcs, I’m playing with a few cocomo (AFCS) apps for a few weeks and I live in switzerland..

  14. Jack says:

    I’ve done all from above and it dont show the chat at all …

    look at this prtscrn
    http://img27.imageshack.us/img27/8585/nevaljaff5.png

    I don’t know what i did wrong?

  15. Cameron says:

    I have a question. It works and everything. I am not using the localhost but the adobehsauthenticator. I then databonded the list to cocomochatsession.usermanager.usercollection and it works. But everbody has my name. their either myname, myname2, myname3 and so forth. Is there a way to change this?

  16. Cameron says:

    It also only works in firefox

  17. Pingback: Getting Perl and Flex talking via XML « Giant Flying Saucer

  18. vamsi says:

    this code is easy to understand.
    i will try to execute, this code.

  19. Roberto Jargemboski says:

    Great job!
    But i’m getting an error!

    “Could not resolve to a component implementation”

    Which library am I forgeting to add to the project?

  20. Roberto Jargemboski says:

    Sorry I forgot a part of my post….

    Could not resolve “rtc:ConnectSessionContainer to a component implementation”

  21. Kamikaze says:

    LAN CHAT HELP
    ==========

    I need to develop an LAN chat application for use in my college network. As such, there cant be a server. its only clients that can be used to chat with users present on the LAN at that moment.

    I checked AIR…i dont think there is any chance to do this using AIR. What abt Flex? this has to be a desktop based application. Pls help

    Regards,
    Kamikaze

  22. Taiff says:

    1120: Access of undefined property cocomoChatSession

    Everthing works well except the above error. help me pls

  23. Almas says:

    Hi,
    I need to built flash chat using flash cs4. Not in flex or FB. Do we have alternative code for cs4?

    Thank u

  24. Pingback: Flex learner | Blog | Tutorial: Building a chat program in Flex 3 with Adobe's project ...

Comments are closed.