Wednesday, May 4, 2011

SMS chat application using Flex for Android, Iphone and Blackberry devices


In this article, you will learn how to build a simple SMS chat application using Flex, ColdFusion, BlazeDS, and the Twilio SMS service. Twilio is a company that helps developers build applications that interact with phone calls and text messages. Twilio provides a simple API that emulates http Form POSTs and XML documents to simplify dialing and texting phone numbers. In the example application described in this article, the Twilio SMS service will communicate with a ColdFusion Server, which will then use the built-in BlazeDS service to push messages out to a Flex application. The sample application uses BlazeDS because it is important for the client to receive the messages as soon as it is received.
Note: The sample application works with ColdFusion 9, as well as with ColdFusion 8 Enterprise edition or ColdFusion 8 Developer edition.

The Twilio service and its free trial

The Twilio service enables you, as a developer, to interact with voice calls and SMS messages as if they were a part of your web service. Twilio makes a call to your web application, which responds with a specially formatted XML document telling Twilio what to do. You can also initiate phone calls or text messages by making calls out to the Twilio service.
Twilio is not free, but there is no charge to sign up as a developer. At the time of writing, when you sign up, they will give you a $30 credit, which is enough for thousands of SMS messages. If you are in the United States, you can also purchase phone numbers in your home area code for $1 per month.

Signing up for Twilio

To sign up for an account, follow these steps:
  1. Visit www.twilio.com.
  2. Click the "Free Trial" link.
  3. Follow the on-screen instructions. You will need to provide your email address and set a password.
  4. Once you have your account set up, login to the Twilio developer dashboard.
The dashboard displays some important information such as your account balance, your Account SID, your Auth Token, your sandbox phone number, and your PIN for the sandbox. All of the documentation for the Twilio service is available from the Documentation link near the top of the screen.

Pointing Twilio to your ColdFusion server

Follow these steps to configure Twilio to communicate with your ColdFusion server:
  1. On the Twilio developer dashboard, make a note of your Account SID and your Auth Token (you will need to click the lock icon to see this).
  2. In the Developer Dashboard area (see Figure 1), update the SMS URL to where you plan on storing your CFM on your ColdFusion server. (Later, you will create twiliosms.cfm in the sms folder of your wwwroot.)
  3. Set the API version to 2010-04-01.
    You do not need to change the Voice URL for the purposes of this article.
  4. Click Save after you make your changes.
Figure 1. The Twilio developer dashboard.

Setting up ColdFusion, BlazeDS, and the event gateway

ColdFusion 8 and ColdFusion 9 both have BlazeDS bundled in so if you have one of those installed you can continue without installing any additional software. If you installed ColdFusion 8, and opted not to have LiveCycle Data Services (the full-featured bigger brother of BlazeDS) installed, you can follow the instructions in Aaron West's postIntegrating BlazeDS with ColdFusion 8 to install it.
When a message comes into your CFM from Twilio, it will tell ColdFusion to build a message and send it out to BlazeDS via an event gateway. Before that happens though, you'll need to configure this event gateway.

Setting up the configuration files

The first step is to create a new Destination on which the application will communicate. Think of the Destination as a dedicated conduit between your clients and server.
  1. Start by navigating to your BlazeDS configuration directory. Go to the [coldfusion-install-directory]\wwwroot\WEB-INF\flex\ directory.
    Note: This is not a directory that would be maintained under your web server's root if you were using a normal installation of ColdFusion.
  2. Open the messaging-config.xml document in your favorite XML editor or text editor.
  3. Add a new <destination> entry within the <service> node:
<destination id="sms"> <adapter ref="cfgateway"/> <properties> <gatewayid>sms</gatewayid> </properties> <channels> <channel ref="my-cfamf"/> </channels> </destination>
Note the name of the <destination> that you are creating, as well as the name of the gatewayid. I have kept these names the same—in this case, sms— to avoid any confusion later on.
Next, you need to write the configuration for the event gateway.
  1. Go to the [coldfusion-install]\gateway\config directory and make a copy of the flex-messaging-gateway.cfg file and name it sms.cfg.
  2. Open sms.cfg and set the destination property as follows:
destination=sms
  1. Restart ColdFusion to activate the configuration changes.
I suggest starting ColdFusion either from the command line or from ColdFusion Builder so you can see the console output.
Alternatively, you can check the server.log file located in the ColdFusion log directory for any error messages resulting from the configuration changes you just made.

Configuring the event gateway in ColdFusion

Now that you have set up the BlazeDS configuration, you need to set up ColdFusion to use it.
  1. First, create an empty CFC that will be called from the event gateway. Name it sms_processor.cfc and place it in a new folder named sms under your wwwroot.
  2. Next, login to ColdFusion Administrator, and select Gateway Instances from the Event Gateways menu.
  3. Add a new event gateway with the following properties (see Figure 2):
    • Gateway ID: sms
    • Gateway Type: DataServicesMessaging
    • CFC Path: [The path to the empty CFC you just created]
    • Configuration File:[path to your ColdFusion directory]\gateway\config\sms.cfg
    • Startup Mode: manual
Figure 2. Adding a new event gateway instance.
I prefer to set the startup mode to Manual when working on my development server, but if you plan on deploying this configuration on a production server, you should set that option to Automatic.
  1. Click Add Gateway Instance.
  2. Start the gateway by clicking the green Start button next to its entry in the event gateway list.
  3. Check the ColdFusion console, or view the logs, to verify that the event gateway started up successfully.

Writing the ColdFusion code to interact with event gateway

Now that you have set up the back-end configuration, you are ready to write the ColdFusion code to handle the incoming messages and outgoing messages. You will end up with two ColdFusion files (a CFM and a CFC), one for each direction.

Handling messages from Twilio

  1. First, create a new file named twiliosms.cfm in the sms folder in your wwwroot.
  2. Insert the following contents into the CFM file and save it:
<cfscript> msg = structNew(); msg.headers = structNew(); msg.headers.gatewayid = "sms"; msg.headers['TYPE'] = "SMS"; msg.body = structNew(); msg.body['fromNumber'] = form.From; msg.body['toNumber'] = form.To; msg.body['message'] = form.Body; msg.body['serial'] = now(); msg.destination = "sms"; sendGatewayMessage("sms",msg); </cfscript> <cfcontent type="text/xml"><?xml version="1.0" encoding="UTF-8"?> <Response> </Response>
This is the file that you configured Twilio to call when an incoming SMS message is received. The purpose of this file is to package up the data Twilio passes in and send it over to the event gateway.
When Twilio calls the CFM file, it will pass what appears to the ColdFusion server to be a form submission with about two dozen fields, including the phone number of the person who sent the SMS (form.FROM), the message(form.BODY), the number they sent the message to (form.TO), and a few fields dealing with the location of the phone number's registered owner. For this request, you do need to reply to the Twilio service with what you want to do with the conversation/thread. In this case, however, you will tell Twilio that you don't want to do anything.
Sending the data to the event gateway involves creating a new structure that includes properties that the gateway will be expecting. You need to implement the BODYHEADERSHEADERS.GATEWAYID, and DESTINATIONproperties of this structure. Both the body and the headers are structures themselves, and can contain any data you wish to pass along to the end client. The code above sets the HEADERS.TYPE property to "SMS", so you can parse for that later on. It also sets the BODY.FROMNUMBERBODY.TONUMBER, and BODY.MESSAGE properties to the proper fields coming in from Twilio. The CFM also appends a unique serial number to the message, as BlazeDS will not pass along messages that appear to be duplicates (seemingly duplicate messages are common with SMS messages). After assembling the structure, the code above sends it to the event gateway by invokingsendGatewayMessage().
Lastly, you will need to tell Twilio what to do with the message. Since Twilio won't need to do anything further with the message, the CFM responds with essentially an empty XML document. If you do not do this, subsequent calls from Twilio may fail.

Sending messages to Twilio

When the Flex application publishes a message to BlazeDS, it will be picked up by the blank CFC that you created earlier. So, the next step is to add to the CFC a function that will pass on the message from BlazeDS to Twilio. Luckily, sending messages to Twilio is just as easy as receiving them. You simply have to do Form POST to the Twilio service with the proper fields filled out.
  1. Open sms_processor.cfc (the empty file you created earlier).
  2. Insert the following code:
<cfcomponent output="false"> <cffunction name="onIncomingMessage" returntype="any"> <cfargument name="event" type="struct" required="true" /> <cfif arguments.event.data.headers.type EQ "SMS"> <cfhttp method="post" username="AC00000000000000000000000" password="350000000000000000000000" url="https://api.twilio.com/2010-04-01/Accounts/AC00000000000000000000000/SMS/Messages"> <cfhttpparam name="From" type="formfield" value="4150000000"> <cfhttpparam name="To" type="formfield" value="#arguments.event.data.body.toNumber#"> <cfhttpparam name="Body" type="formfield" value="#arguments.event.data.body.message#"> </cfhttp> </cfif> <cfreturn arguments.event.data> </cffunction> </cfcomponent>
  1. Update the usernamepassword, and URL in the cfhttp tag to reflect the values you received when you signed up for a Twilio account.
  2. Update the cfhttpparam named from with the Twilio phone number you were assigned.
  3. Save your changes.
The CFC code starts with the function that is required for all event gateway CFCs: onIncomingMessage. This function is passed a single structure (named event) that contains the message that is published by the Flex client. To send the message out, the CFC uses the CFHTTP tag, which will make the REST based call to Twilio, and theCFHTTPPARAM tags to pass along the FROMTO, and BODY form parameters. The URL portion of the CFHTTP will need to include the Twilio Account SID you were assigned earlier (after the /Accounts/). You also need to pass in your Account SID as the username for the request and your Auth Token as the password. Finally, be sure to set the FROM value to the Twilio phone number you were assigned.

Writing a Flex application to send and receive live SMS messages

With the entire back end set up and working, you can turn your attention to the client-side code. The Flex application simply displays the incoming messages in a List control, and enables the user to respond to messages typed in a TextInput control. The example below uses Spark components (Flex SDK 4.0+), but the concepts apply to Flex 2 or Flex 3 as well.
Note: A completed Flex application is included with the sample files for this article. If you prefer, you can import the SMSChatApp.fxp Flex project file into Flash Builder instead of building the application with the steps that follow.
  1. In Flash Builder, choose File > New > Flex Project to start a creating your application.
  2. Select Web as the Application Type, as AIR projects require some additional work in the BlazeDS configuration files.
  3. Type a project name and set the SDK version as you wish.
  4. Select ColdFusion as the Application Server Type.
  5. Select BlazeDS as the remote object access service (see Figure 3).
  6. Click Next.
Figure 3. Creating the Flex project.
  1. Update the ColdFusion Server location and web root as necessary.
  2. Click Finish.

Designing the UI

Now it's time to create the Flex application's user interface.
  1. Once the project is created, switch to the Design View.
  2. Add a Label, a List, a TextArea, and an HGroup component aligned vertically from top to bottom. For each item, set the left and right boundaries to 0 (so they are pinned to the sides), and set their top and bottom properties appropriately.
    Alternatively, you can insert the following MXML in Source View:
<s:Label y="10" horizontalCenter="0"/> <s:List left="0" right="0" top="34" bottom="111"></s:List> <s:TextArea left="0" right="0" bottom="39" height="64"/> <s:HGroup left="0" right="0" bottom="0" height="32" verticalAlign="middle"> </s:HGroup>
  1. Set the label text to read "Connected to Server : False".
  2. Set the <s:Application> tag's width property to 350.
    The user will type messages in the TextArea element, and received messages will be displayed in the List element.
  3. Within the HGroup, add a Label control (with the text set to "Send To"), a TextInput control, and a Button control (with the label set to "Send"):
<s:Label text="Send To:"/> <s:TextInput/> <mx:Spacer width="100%" height="10"/> <s:Button label="Send"/>
The user will type the phone number (to send the SMS message to) in the TextInput control, and the Button control will act as the send button (see Figure 4).
Figure 4. The application’s UI layout.

Connecting to BlazeDS

Next, you will connect the application to the BlazeDS server within ColdFusion. This is done through two tags in the Flex SDK: Producer and Consumer. The Producer tag is used to send data to BlazeDS (and in this case the event gateway), and the Consumer tag is used to receive data.
  1. Switch to Code View and add <Consumer> and <Producer> tags to the <fx:Declarations> section of your code.
  2. Give the tags IDs (as shown below) and set the destination property of both tags to "sms" to reflect the BlazeDS destination you set up earlier:
<fx:Declarations> <s:Producer id="sendToServer" destination="sms" /> <s:Consumer id="gotFromServer" destination="sms" /> </fx:Declarations>
  1. Next, start a script block and create a public function named initApp(), which will be called when the application starts:
<fx:Script> <![CDATA[ public function initApp():void { gotFromServer.subscribe(); } ]]> </fx:Script>
This function calls the consumer's subscribe() function to connect to the BlazeDS server. The producer will automatically connect when the first message is publish.
  1. Add applicationComplete="initApp()" to the Application root tag so that the initApp() function is called when the application starts.
    Next, you need to adjust the top label's text property to reflect the application's actual connection status with the BlazeDS server.
  2. Set the label's text to the following binding statement:
text="Connected to Server : {gotFromServer.subscribed}"
  1. Run the application and make sure your Flex application connects to the BlazeDS server.
  2. You should see the top Label change to "Connected to Server = True" if it connected properly. If this doesn't happen, go to the ColdFusion console and check to see if there are any error messages. Often, it is a misspelling or missed step that caused the issue.

Sending a message

Sending a message is straightforward. Simply assemble an asynchronous data packet containing the SMS message and send it off to the BlazeDS server.
  1. Start by creating a new function that will be called when the user clicks the Send button. Add the following code to the script block:
import mx.messaging.messages.AsyncMessage; protected function sendMessage():void { var msg:AsyncMessage = new AsyncMessage(); msg.headers.TYPE = "SMS"; msg.body.toNumber = toNumber.text; msg.body.message = messageToSend.text; msg.body.serial = new Date(); sendToServer.send(msg); messageToSend.text = ""; }
  1. Add click="sendMessage()" to the Send button:
<s:Button label="Send" click="sendMessage()"/>
  1. Add the following IDs to the TextArea and TextInput controls:
<s:TextArea left="0" right="0" bottom="39" height="64" id="messageToSend"/> <s:TextInput id="toNumber"/>
The sendMessage() function builds the message packet in the structure that the ColdFusion code is expecting. This includes setting the headers.TYPE property to "SMS", as well as setting the toNumber and messageproperties of the body. The function sets the serial property so that BlazeDS doesn't ignore any subsequent similar messages that the user sends.
After the packet is built, sendMessage() passes the asynchronous data packet to the Producer's send() method. The Producer will connect to BlazeDS (if it is not already connected), and send the message to the destination. The code will then be processed by ColdFusion, and passed back to the application via the Consumer once ColdFusion processes it.
As a last step, sendMessage() clears the message text box so that the user does not inadvertently send the same message again.

Receiving a message

Receiving messages from the BlazeDS server is also really easy. All that's needed is a new function that takes a single MessageEvent parameter. This function is set as the message event handler for the Consumer. When any message comes in from BlazeDS within the SMS destination, this function is invoked. The MessageEvent's messageproperty contains the message just as it was processed by ColdFusion.
Follow these steps to set up message reception:
  1. Create a new bindable ArrayCollection for the received messages:
import mx.collections.ArrayCollection; [Bindable] protected var messageList:ArrayCollection = new ArrayCollection();
  1. Bind it to the List control, so messages are displayed to the user:
<s:List left="0" right="0" top="34" bottom="111" dataProvider="{messageList}">
The default item renderer for the Spark List component is set up for strings, which makes it easy to display the SMS messages in the List control.
  1. Create the gotMessage() function, which takes the MessageEvent as a parameter:
import mx.messaging.events.MessageEvent; protected function gotMessage(e:MessageEvent):void { messageList.addItem('[' + e.message.body.fromNumber + '] ' + e.message.body.message); toNumber.text = e.message.body.fromNumber; }
This function creates a new string containing the message's BODY and fromNumber properties and adds it to the ArrayCollection.
It also sets the toNumber control's text property to the message sender's phone number to make it easy for the user to respond.
  1. Lastly, set gotMessage() as the Consumer's event handler:
<s:Consumer id="gotFromServer" destination="sms" message="gotMessage( event )" />

Testing your implementation

The application is now complete. To test it, follow these steps:
  1. Start by launching the Flex client application.
  2. Verify that within a few seconds the "Connected to Server" label changes to "True".
    Next, try sending a message to your cell phone.
  3. Type a short message and then type your phone number in the Send To text input in the bottom of the screen and click Send.
    It should not take more than a few seconds for your message to arrive on your cell phone.
    Receiving messages should be just as simple.
If you are using the sandbox account with Twilio, you will need to prefix your sandbox PIN to each message you send back. Since Twilio uses a cloud infrastructure to communicate to your application, the address the service sends messages from may change. So if you are using a Developer edition of ColdFusion (not the 30-day trial or full version), you may need to restart ColdFusion on occasion to get around the two IP address limitation. If you have any difficulties, check your ColdFusion console, application logs, and the Twilio Debugger, which is available when you login to Twilio.

No comments:

Post a Comment