1  /**
     2   * com.project.core.Bootstrap
     3   * @version 1.0.0
     4   * @author jason m horwitz | sekati.com | tendercreative.com
     5   * Copyright (C) 2007  jason m horwitz, Sekat LLC. All Rights Reserved.
     6   * Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
     7   */
     8   
     9  import com.sekati.core.App;
    10  import com.sekati.core.CoreObject;
    11  import com.sekati.convert.BoolConversion;
    12  import com.sekati.data.XML2Object;
    13  import com.sekati.except.FatalOperationException;
    14  import com.sekati.events.Broadcaster;
    15  import com.sekati.log.Logger;
    16  import com.sekati.net.NetBase;
    17  import com.sekati.services.Urchin;
    18  import com.sekati.ui.ContextualMenu;
    19  import com.sekati.utils.Delegate;
    20  import com.sekati.validate.StringValidation;
    21  import TextField.StyleSheet;
    22  
    23  /**
    24   * Bootstrap runs thru the {@link _sequenceChain) of methods to prepare
    25   * {@link com.sekati.core.App} by loading config, data, stylesheet, as
    26   * well as any other custom methods needed to bootstrap the application
    27   * and firing the {@code onAppConfigured } event.
    28   * 
    29   * @see {@link http://en.wikipedia.org/wiki/Bootstrapping_%28computing%29}
    30   */
    31  class com.project.core.Bootstrap extends CoreObject {
    32  
    33  	/**
    34  	 * App bootstrap props
    35  	 * _bootstrapChain (Array) list of methods to run to bootstrap App
    36  	 * _bootstrapCounter (Number) bootstrap stage counter
    37  	 */
    38  	private var _this:Bootstrap;
    39  	private static var _sequenceChain:Array = [ "loadConfig", "loadData", "loadStyle" ];
    40  	private static var _sequenceCount:Number = 0;
    41  	private static var RETRY_ATTEMPT:Number = 0;
    42  	private static var RETRY_MAX:Number = 5;	
    43  
    44  	/**
    45  	 * Constructor
    46  	 */
    47  	public function Bootstrap() {
    48  		super( );
    49  		_this = this;
    50  		trace( "*** - Bootstrap Initialized ...\n" );
    51  		Broadcaster.$.broadcast( "onAppBootstrap" );
    52  		Urchin.track( "home" );
    53  		run( );
    54  	}
    55  
    56  	/**
    57  	 * Iterate through _sequenceChain method array
    58  	 * @return Void
    59  	 */
    60  	private function run():Void {
    61  		if (_sequenceCount < _sequenceChain.length - 1) {
    62  			var methodName:String = _sequenceChain[_sequenceCount];
    63  			Logger.$.trace( _this, "running method [" + _sequenceCount + "]" + methodName );
    64  			_this[methodName]( );
    65  			_sequenceCount++;
    66  		} else {
    67  			Broadcaster.$.broadcast( "onAppConfigured" );
    68  			Logger.$.status( _this, "@@@ Application Configured: auto-initialization via broadcast event ..." );
    69  		}
    70  	}
    71  
    72  	/**
    73  	 * A method in the sequence chain failed - make retry attempts 
    74  	 * at each phase or die with fatal exception.
    75  	 * @return Void
    76  	 * @throws FatalOperationException
    77  	 */
    78  	private function retry():Void {
    79  		if (RETRY_ATTEMPT < RETRY_MAX) {
    80  			Logger.$.warn( _this, "Bootstrap attempt failed in sequence chain " + _sequenceCount + ": " + _sequenceChain[_sequenceCount] + "()\n Retry Attempt: [" + RETRY_ATTEMPT + " of " + RETRY_MAX + "]" );
    81  			RETRY_ATTEMPT++;
    82  			_this[_sequenceChain[_sequenceCount]]( );
    83  		} else {
    84  			var msg:String = "Bootstrap died in sequence chain " + _sequenceCount + ": " + _sequenceChain[_sequenceCount] + "()\nRetry Attempt: [" + RETRY_ATTEMPT + " of " + RETRY_MAX + "]\n Sorry, I tried but the application failed to boot.";
    85  			Logger.$.fatal( _this, msg );
    86  			throw new FatalOperationException( _this, msg, arguments );
    87  		}
    88  	}	
    89  
    90  	// SEQUENCED BOOTSTRAP METHODS
    91  
    92  	/**
    93  	 * loads and parses config.xml then broadcasts "onConfig"
    94  	 * @return Void
    95  	 */
    96  	private function loadConfig():Void {
    97  		var oXML:XML = new XML( );
    98  		var o:Object = new Object( );
    99  		oXML.ignoreWhite = true;				
   100  		var parseConfiguration:Function = function (success:Boolean):Void {
   101  			if (!success) {
   102  				retry( );
   103  				return;	
   104  			}
   105  			o = new XML2Object( ).parseXML( oXML );
   106  			App.db.config = o.config;
   107  			// dump core config values into static App constants
   108  			App.APP_NAME = o.config.attributes.name + " v" + o.config.attributes.version;
   109  				
   110  			App.CROSSDOMAIN_URI = (o.config.crossdomain_uri.data != undefined) ? o.config.crossdomain_uri.data : "crossdomain.xml";
   111  			App.CROSSDOMAIN_URI = (StringValidation.isURL( App.CROSSDOMAIN_URI )) ? App.CROSSDOMAIN_URI : NetBase.getPath( ) + App.CROSSDOMAIN_URI;
   112  			App.DATA_URI = o.config.data_uri.data;
   113  			App.CSS_URI = o.config.css_uri.data;
   114  				
   115  			App.DEBUG_ENABLE = BoolConversion.toBoolean( o.config.debug_enable.data );
   116  			App.FLINK_ENABLE = BoolConversion.toBoolean( o.config.flink_enable.data );
   117  			App.TRACK_ENABLE = BoolConversion.toBoolean( o.config.track_enable.data );
   118  			App.KEY_ENABLE = BoolConversion.toBoolean( o.config.key_enable.data );
   119  			App.FLV_BUFFER_TIME = Number( o.config.flv_buffer_time.data );
   120  			if (App.DEBUG_ENABLE == true) {
   121  				App.log = Logger.getInstance( );
   122  				Logger.$.isIDE = true, 
   123  				Logger.$.isLC = true, 
   124  				Logger.$.isSWF = false;					
   125  				Logger.$.info( _this, "@@@ Debug enabled ..." );
   126  			}
   127  				
   128  			// enable context menu 
   129  			Logger.$.info( _this, "@@@ Setting ContextMenu ..." );
   130  			App.cmenu.addItem( App.APP_NAME );
   131  			
   132  			// load crossdomain policy 
   133  			Logger.$.info( _this, "@@@ loading crossdomain policy: " + App.CROSSDOMAIN_URI );
   134  			System.security.loadPolicyFile( App.CROSSDOMAIN_URI );
   135  			delete oXML;
   136  			delete o;
   137  			Logger.$.status( _this, "$$$ - Config loaded ..." );
   138  			Broadcaster.$.broadcast( "onLoadAppConfig" );
   139  			run( );
   140  		};
   141  		oXML.onLoad = Delegate.create( this, parseConfiguration );
   142  		oXML.load( App.CONF_URI );
   143  	}
   144  
   145  	/**
   146  	 * load App data from {@code DATA_URI} during {@link bootstrap} sequence.
   147  	 * @return Void
   148  	 */
   149  	private function loadData():Void {
   150  		var dXML:XML = new XML( );
   151  		var d:Object = new Object( );
   152  		dXML.ignoreWhite = true;
   153  		var parseData:Function = function(success:Boolean):Void {
   154  			if(success) {
   155  				d = new XML2Object( ).parseXML( dXML );
   156  				// non-destructive write:
   157  				App.db.data = d.data;
   158  				delete dXML;
   159  				delete d;
   160  				Broadcaster.$.broadcast( "onLoadAppData" );
   161  				Logger.$.status( _this, "$$$ - Data loaded (App.db) ..." );
   162  				//Logger.$.object("App.db", App.db);
   163  				run( );								
   164  			} else {
   165  				retry( );	
   166  			}	
   167  		};
   168  		dXML.onLoad = Delegate.create( _this, parseData );
   169  		dXML.load( App.DATA_URI );
   170  	}	
   171  
   172  	/**
   173  	 * load App stylesheet css from {@code CSS_URI} during {@link bootstrap} sequence.
   174  	 * @return Void
   175  	 * {@code Usage:
   176  	 * 	tf.styleSheet = App.css;
   177  	 * 	tf.htmlText = "<span class='righthead_credit'>Hello World</span>";
   178  	 * }
   179  	 */
   180  	private function loadStyle():Void {
   181  		var _styleSheet:TextField.StyleSheet = new StyleSheet( );
   182  		_styleSheet.load( App.CSS_URI );
   183  		_styleSheet.onLoad = function (success:Boolean):Void {
   184  			if (!success) {
   185  				retry( );
   186  				return;	
   187  			}
   188  			App.css = _styleSheet;
   189  			Logger.$.status( _this, "$$$ - Styles loaded (App.CSS) ..." );
   190  			Broadcaster.$.broadcast( "onLoadAppStyle" );
   191  			run( );
   192  		};
   193  	}
   194  }
   195