/** * com.project.core.Bootstrap * @version 1.0.0 * @author jason m horwitz | sekati.com | tendercreative.com * Copyright (C) 2007 jason m horwitz, Sekat LLC. All Rights Reserved. * Released under the MIT License: http://www.opensource.org/licenses/mit-license.php */ import com.sekati.core.App; import com.sekati.core.CoreObject; import com.sekati.convert.BoolConversion; import com.sekati.data.XML2Object; import com.sekati.except.FatalOperationException; import com.sekati.events.Broadcaster; import com.sekati.log.Logger; import com.sekati.net.NetBase; import com.sekati.services.Urchin; import com.sekati.ui.ContextualMenu; import com.sekati.utils.Delegate; import com.sekati.validate.StringValidation; import TextField.StyleSheet; /** * Bootstrap runs thru the {@link _sequenceChain) of methods to prepare * {@link com.sekati.core.App} by loading config, data, stylesheet, as * well as any other custom methods needed to bootstrap the application * and firing the {@code onAppConfigured } event. * * @see {@link http://en.wikipedia.org/wiki/Bootstrapping_%28computing%29} */ class com.project.core.Bootstrap extends CoreObject { /** * App bootstrap props * _bootstrapChain (Array) list of methods to run to bootstrap App * _bootstrapCounter (Number) bootstrap stage counter */ private var _this:Bootstrap; private static var _sequenceChain:Array = [ 'loadConfig', 'loadData', 'loadStyle' ]; private static var _sequenceCount:Number = 0; private static var RETRY_ATTEMPT:Number = 0; private static var RETRY_MAX:Number = 5; /** * Constructor */ public function Bootstrap() { super( ); _this = this; trace( "*** - Bootstrap Initialized ...\n" ); Broadcaster.$.broadcast( "onAppBootstrap" ); Urchin.track( "home" ); run( ); } /** * Iterate through _sequenceChain method array * @return Void */ private function run():Void { if (_sequenceCount < _sequenceChain.length - 1) { var methodName:String = _sequenceChain[_sequenceCount]; Logger.$.trace( _this, "running method [" + _sequenceCount + "]" + methodName ); _this[methodName]( ); _sequenceCount++; } else { Broadcaster.$.broadcast( "onAppConfigured" ); Logger.$.status( _this, "@@@ Application Configured: auto-initialization via broadcast event ..." ); } } /** * A method in the sequence chain failed - make retry attempts * at each phase or die with fatal exception. * @return Void * @throws FatalOperationException */ private function retry():Void { if (RETRY_ATTEMPT < RETRY_MAX) { Logger.$.warn( _this, "Bootstrap attempt failed in sequence chain " + _sequenceCount + ": " + _sequenceChain[_sequenceCount] + "()\n Retry Attempt: [" + RETRY_ATTEMPT + " of " + RETRY_MAX + "]" ); RETRY_ATTEMPT++; _this[_sequenceChain[_sequenceCount]]( ); } else { 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."; Logger.$.fatal( _this, msg ); throw new FatalOperationException( _this, msg, arguments ); } } // SEQUENCED BOOTSTRAP METHODS /** * loads and parses config.xml then broadcasts "onConfig" * @return Void */ private function loadConfig():Void { var oXML:XML = new XML( ); var o:Object = new Object( ); oXML.ignoreWhite = true; var parseConfiguration:Function = function (success:Boolean):Void { if (!success) { retry( ); return; } o = new XML2Object( ).parseXML( oXML ); App.db.config = o.config; // dump core config values into static App constants App.APP_NAME = o.config.attributes.name + " v" + o.config.attributes.version; App.CROSSDOMAIN_URI = (o.config.crossdomain_uri.data != undefined) ? o.config.crossdomain_uri.data : "crossdomain.xml"; App.CROSSDOMAIN_URI = (StringValidation.isURL( App.CROSSDOMAIN_URI )) ? App.CROSSDOMAIN_URI : NetBase.getPath( ) + App.CROSSDOMAIN_URI; App.DATA_URI = o.config.data_uri.data; App.CSS_URI = o.config.css_uri.data; App.DEBUG_ENABLE = BoolConversion.toBoolean( o.config.debug_enable.data ); App.FLINK_ENABLE = BoolConversion.toBoolean( o.config.flink_enable.data ); App.TRACK_ENABLE = BoolConversion.toBoolean( o.config.track_enable.data ); App.KEY_ENABLE = BoolConversion.toBoolean( o.config.key_enable.data ); App.FLV_BUFFER_TIME = Number( o.config.flv_buffer_time.data ); if (App.DEBUG_ENABLE == true) { App.log = Logger.getInstance( ); Logger.$.isIDE = true, Logger.$.isLC = true, Logger.$.isSWF = false; Logger.$.info( _this, "@@@ Debug enabled ..." ); } // enable context menu Logger.$.info( _this, "@@@ Setting ContextMenu ..." ); App.cmenu.addItem( App.APP_NAME ); // load crossdomain policy Logger.$.info( _this, "@@@ loading crossdomain policy: " + App.CROSSDOMAIN_URI ); System.security.loadPolicyFile( App.CROSSDOMAIN_URI ); delete oXML; delete o; Logger.$.status( _this, "$$$ - Config loaded ..." ); Broadcaster.$.broadcast( "onLoadAppConfig" ); run( ); }; oXML.onLoad = Delegate.create( this, parseConfiguration ); oXML.load( App.CONF_URI ); } /** * load App data from {@code DATA_URI} during {@link bootstrap} sequence. * @return Void */ private function loadData():Void { var dXML:XML = new XML( ); var d:Object = new Object( ); dXML.ignoreWhite = true; var parseData:Function = function(success:Boolean):Void { if(success) { d = new XML2Object( ).parseXML( dXML ); // non-destructive write: App.db.data = d.data; delete dXML; delete d; Broadcaster.$.broadcast( "onLoadAppData" ); Logger.$.status( _this, "$$$ - Data loaded (App.db) ..." ); //Logger.$.object("App.db", App.db); run( ); } else { retry( ); } }; dXML.onLoad = Delegate.create( _this, parseData ); dXML.load( App.DATA_URI ); } /** * load App stylesheet css from {@code CSS_URI} during {@link bootstrap} sequence. * @return Void * {@code Usage: * tf.styleSheet = App.css; * tf.htmlText = "Hello World"; * } */ private function loadStyle():Void { var _styleSheet:TextField.StyleSheet = new StyleSheet( ); _styleSheet.load( App.CSS_URI ); _styleSheet.onLoad = function (success:Boolean):Void { if (!success) { retry( ); return; } App.css = _styleSheet; Logger.$.status( _this, "$$$ - Styles loaded (App.CSS) ..." ); Broadcaster.$.broadcast( "onLoadAppStyle" ); run( ); }; } }