Dynamically Setup Flex Runtime Configuration Services using FlashVars

By using FlashVars and a SiteConfigurationModel class, a Flex application can be setup to dynamically define the server configurations needed to communicate with a php backend at runtime. This allows us to eliminate the need for hardcoding the -services compiler argument value and using a services-config.xml file at compile time.

As a result of being able to read and use server communication based settings at runtime instead of compile time, Flex applications can be easily moved to other websites without the requirement/need of recompilation.

To read flashVars in Flex, an initialization function is called upon the applicationComplete event defined in the mxml files Application tag.

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
              xmlns:sides="sides.*"
		      xmlns:mxeffects="com.adobe.ac.mxeffects.*"
		      backgroundGradientColors="[#53667, #ffffff]"
		      applicationComplete="init()">

This init() function is called after the applicationComplete event and not after the creationComplete event.

This is done due to the fact that the init() function is dependent on the SiteConfigModel class which utilizes the URLUtil class. The URLUtil class is unable to get the server name at the creationComplete stage.

Example init() function defined below:

/*
 *	init() method is called after the flex application has been created
 *
 * @return	void
 */ 
 private function init():void {
   //lets grab the current url information and setup amf channel
   var paramString:String;
   var num:Number;
 
   //create reference to Application object
   var app:Application = Application.application as Application;
	
   //this will output to the console the parameters passed to this application			
	num=0;
	trace("Application parameters: ");
	for (var i:String in Application.application.parameters) {
	    paramString += i + ":" + Application.application.parameters[i] + "\n";
	    trace(paramString);
	    num++;
	}
	trace("Number of parameters passed is " + num);
				
    //this is a static function which grabs 
    //the server host data and contentRoot data
    //passed from php using flashvars
	this.serverURL = SiteConfigModel.serverURL;
	trace("AdminNim::init server url is " + serverURL);
				
	contextRoot = SiteConfigModel.contextRoot;
	trace("AdminNim::init server url is " + contextRoot);
				
	//create an amf channel dynamically here
	trace("AdminNim::init amf endpoint " + SiteConfigModel.amfEndPoint);
	trace("AdminNim::init channel id " + SiteConfigModel.CHANNELID);
	_amfChannel = new AMFChannel(SiteConfigModel.CHANNELID,SiteConfigModel.amfEndPoint);
	amfChannelSet = new ChannelSet();
	amfChannelSet.addChannel(_amfChannel);
								
}

I’ve encapsulated the server configuration elements in the SiteConfigModel class. The SiteConfigModel class is geared for a php based server and a ContextRoot value which is passed as a constant value to the flex application. (Note: php does not currently have a ContextRoot function capability).

This class uses static methods to grab the application parameters which were passed. It is used to store and/or configure the application server url path settings and the FlashRemoting channel and endpoint url settings. As a result, I will not need to define a -services compiler argument or a services-config.xml file for the project.

// SiteConfigModel.as, created 5/5/2009 by Margo Powell
// Copyright 2009(C) NIM project
package model
{
    import mx.core.Application;
    import mx.controls.Alert;
    import mx.utils.ObjectUtil;
    import mx.utils.URLUtil;
    
    /**
     * Class used to store and/or return Application config settings such as
     * the server name and port for the website along with the
     * FlashRemoting channel and amf endpoint uri settings
     * 
     * This class allows you to dynamically set your configuration for 
     * your flex/swf file on a website of your choice.
     * 
     * You do not need a -services compiler argument for the project and
     * therefore no need to recompile your project code if you
     * shift your code to different websites.
     * 
     * A context root default value is provided as a constant.
     * 
     * An amfphp endpoint default value is also provided as a constant.
     * 
     * The following flashVar variables can be passed if user wants
     * to override default values. Examples below
     * 1) contextRoot="/nimphp/";
     * 
     * NOTE: This class is called after applicationComplete and not 
     * creationComplete(URLUtil unable to get server name at this stage).
     *
     * This class is geared for a php based server where a ContextRoot 
     * function currently does not exist(whereas these functions
     * do apparently exist for Java and coldfusion based servers).
     * 
     * To bypass this function limitation, the contextRoot should be
     * defined as a constant in a php include file and then have the
     * include file loaded in the php calling file using the 
     * require_once feature. This constant can then be passed in as a 
     * flashVar value if needed(if different from the default value
     * defined below)
     * 
     * @author: Margo Powell
     *  
     **/
   
    public class SiteConfigModel
    {
       //declare the amfphp channel id
		public static const CHANNELID:String = "my-amfphp";     
		
		// Default context root value,
		//adjust as needed for your server using flashVars
        private static const DEFAULT_CONTEXT_ROOT:String = "/";
		
		//default amfphp directory path
		private static const DEFAULT_AMF_DIR:String = "amfphp2.0/gateway.php";
		
		//url to use when running within the ide
		private static const DEFAULT_IDE_URL:String = "localhost:8080";

       
		 /**
         * Return the serverURL name and port value 
         * for the application. The value returned depends
         * on whether you are running locally from the IDE
         * or are running live from a website.
         * 
         * Currently also passing the flashVar: serverURL 
         * whose value is set to the following in php:
         * $serverPath = $_SERVER['HTTP_HOST']
         * 
         **/      
        public static function get serverURL():String
        {
        	var serverName:String;
        	var urlString:String;
        	
        	//create reference to Application object
        	var app:Application = Application.application as Application;
        		
        	if( app.url != null && app.url.indexOf("http:") != -1 )
	        {
				
				serverName = URLUtil.getServerNameWithPort(app.loaderInfo.url);
				urlString = "http://" + serverName + SiteConfigModel.contextRoot;
	        }
	        else
	        {
                
				urlString = "http://" + DEFAULT_IDE_URL + SiteConfigModel.contextRoot;
	        }
	     	
        	
	        return urlString;
        }
        
        // return the correct endpoint, if this is server from an HTTP request
        // return the default localhost:8080 for development, if FlexBuilder launches
        // the application locally with an absolute path (file://c:\...)
        /**
         * Return the amfEndPoint for the application. 
         * The value returned depends on whether you are running 
         * locally from the IDE or are running live from a website.
         * 
         * Currently also passing the flashVar: serverURL 
         * whose value is set to the following in php:
         * $serverPath = $_SERVER['HTTP_HOST']
         * 
         * return the default localhost:8080 for development, if
         * the application launched locally with an absolute path (file://c:\...)
         * 
         **/      
        public static function get amfEndPoint():String
        {
        	var amfPath:String;
        	
        	//create reference to Application object
            var app:Application = Application.application as Application;
            
            //will return appropriate path depending on whether running from server or ide
            amfPath = SiteConfigModel.serverURL + SiteConfigModel.DEFAULT_AMF_DIR;
            
            return amfPath;
        }
        
         /*
         * Return the DEFAULT_CONTEXT_ROOT value unless 
         * overridden by flashVar value of contextRoot.
         * 
         * Pull the context-root out of the flash var, 
		 * if it's defined in your <object/> or  tags.
		 * I use swfobject variables to set these values
         * ex: contextRoot=/flex
         **/        
        private static function get contextRoot():String
        {
        	var contextRootRef:String;
        	
        	//create reference to Application object
            var app:Application = Application.application as Application;
            
            //check to see if context root should be overriden
            //by value passed in as flashVar
            if( app.parameters.contextRoot != null )
            {
                //Alert.show( ObjectUtil.toString(app.parameters) );
                contextRootRef = app.parameters.contextRoot;
            } else {
            	//use default
            	contextRootRef = SiteConfigModel.DEFAULT_CONTEXT_ROOT;
            }
            return contextRootRef;
        }
       

    }
}

This approach was based on the approach taken by Mike Nimer available at this link “Bye bye -services” which had a cold fusion based backend. I modified his approach to work with an amfphp based backend.

Note to self: For future reference – this code is located at G:\Flex\NimAdmin

Advertisements

2 Responses to Dynamically Setup Flex Runtime Configuration Services using FlashVars

  1. Andrew says:

    Your code won’t even compile. Line 36 of the Application object will throw an ‘Access of undefined property’ error to begin with.

  2. ogrampowell says:

    The example code displayed on this page were just snippets of my actual code contained in my Script section of my mxml code. I posted this information to jog my memory when I reused it in the future.
    The actual code was quite involved which is why I just included the snippets. Missing from this page are import statements such as:
    import flash.net.URLRequest;
    import mx.messaging.ChannelSet;
    import mx.messaging.channels.AMFChannel;
    import model.SiteConfigModel;

    as well as variable declarations etc:
    [Bindable]
    private var serverURL:String;

    private var contextRoot:String;

    private static var _amfChannel:AMFChannel = null;

    [Bindable]
    public var amfChannelSet:ChannelSet = null;

    At the moment I don’t have time to repost the complete working streamlined working code – I am sorry.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: