//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package mx.core { import flash.display.LoaderInfo; import flash.display.MovieClip; import flash.events.ErrorEvent; import flash.events.Event; import flash.events.IEventDispatcher; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.events.TimerEvent; import flash.system.ApplicationDomain; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.utils.Dictionary; import flash.utils.Timer; import flash.utils.getDefinitionByName; import mx.core.RSLItem; import mx.core.RSLListLoader; import mx.events.ModuleEvent; import mx.events.Request; import mx.events.RSLEvent; import mx.managers.SystemManagerGlobals; import mx.resources.IResourceManager; import mx.resources.ResourceManager; import mx.utils.LoaderUtil; use namespace mx_internal; [ExcludeClass] /** * @private */ public class FlexModuleFactory extends MovieClip implements IFlexModuleFactory { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class constants // //-------------------------------------------------------------------------- /** * @private */ private static const INIT_STATE:int = 0; /** * @private */ private static const RSL_START_LOAD_STATE:int = 1; /** * @private */ private static const APP_LOAD_STATE:int = 2; /** * @private */ private static const APP_START_STATE:int = 3; /** * @private */ private static const APP_RUNNING_STATE:int = 4; /** * @private */ private static const ERROR_STATE:int = 5; /** * @private */ private static const RSL_LOADING_STATE:int = 6; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * @private */ public function FlexModuleFactory() { super(); mixinList = info()["mixins"]; stop(); // Make sure to stop the playhead on the currentframe loaderInfo.addEventListener(Event.INIT, moduleInitHandler); loaderInfo.addEventListener(Event.COMPLETE, moduleCompleteHandler); var docFrame:int = totalFrames == 1 ? 0 : 1; addEventListener(Event.ENTER_FRAME, docFrameListener); timer = new Timer(100); timer.addEventListener(TimerEvent.TIMER, timerHandler); timer.start(); } private function docFrameListener(event:Event):void { if (currentFrame == 2) { removeEventListener(Event.ENTER_FRAME, docFrameListener); if (totalFrames > 2) addEventListener(Event.ENTER_FRAME, extraFrameListener); docFrameHandler(); } } private function extraFrameListener(event:Event):void { if (lastFrame == currentFrame) return; lastFrame = currentFrame; if (currentFrame + 1 > totalFrames) removeEventListener(Event.ENTER_FRAME, extraFrameListener); extraFrameHandler(); } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private */ private var rslListLoader:RSLListLoader; /** * @private */ private var mixinList:Array; /** * @private */ private var state:int = INIT_STATE; /** * @private */ private var appReady:Boolean = false; /** * @private */ private var appInitDone:Boolean = false; /** * @private */ private var appLoaded:Boolean = false; /** * @private */ private var timer:Timer = null; /** * @private * Track which frame was last processed */ private var lastFrame:int; /** * @private */ private var nextFrameTimer:Timer = null; /** * @private */ private var errorMessage:String = null; /** * @private * * This exists only to provide a reference to this * module's resource bundles. This module is opting * into referencing its own resource bundles so the * ResourceManager does not need to do it. This * arrangement keeps the ResourceManager from pinning * the module in memory. */ private var resourceBundles:Array; /** * @private * Array of RSLData objects that represent the list of RSLs this * module factory is loading. Each element of the Array is an * Array of RSLData. */ private var rslDataList:Array //-------------------------------------------------------------------------- // // Properties: IFlexModuleFactory // //-------------------------------------------------------------------------- //---------------------------------- // allowDomainsInNewRSLs //---------------------------------- /** * @private */ private var _allowDomainsInNewRSLs:Boolean = true; /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 10.2 * @playerversion AIR 2.6 * @productversion Flex 4.5 */ public function get allowDomainsInNewRSLs():Boolean { return _allowDomainsInNewRSLs; } /** * @private */ public function set allowDomainsInNewRSLs(value:Boolean):void { _allowDomainsInNewRSLs = value; } //---------------------------------- // allowInsecureDomainsInNewRSLs //---------------------------------- /** * @private */ private var _allowInsecureDomainsInNewRSLs:Boolean = true; /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 10.2 * @playerversion AIR 2.6 * @productversion Flex 4.5 */ public function get allowInsecureDomainsInNewRSLs():Boolean { return _allowInsecureDomainsInNewRSLs; } /** * @private */ public function set allowInsecureDomainsInNewRSLs(value:Boolean):void { _allowInsecureDomainsInNewRSLs = value; } //---------------------------------- // preloadedRSLs //---------------------------------- /** * @inheritDoc * */ public function get preloadedRSLs():Dictionary { // Overridden by compiler generate code. return null; } //-------------------------------------------------------------------------- // // Methods: IFlexModuleFactory // //-------------------------------------------------------------------------- /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 4.5 */ public function addPreloadedRSL(loaderInfo:LoaderInfo, rsl:Vector.):void { preloadedRSLs[loaderInfo] = rsl; if (hasEventListener(RSLEvent.RSL_ADD_PRELOADED)) { var rslEvent:RSLEvent = new RSLEvent(RSLEvent.RSL_ADD_PRELOADED); rslEvent.loaderInfo = loaderInfo; dispatchEvent(rslEvent); } } /** * @private * This method is overridden in the autogenerated subclass. * It is part of TLF's ISWFContext interface. * Although this class does not declare that it implements this interface, * the autogenerated subclass does. */ public function callInContext(fn:Function, thisArg:Object, argArray:Array, returns:Boolean = true):* { return undefined; } /** * @private * This method is overridden in the autogenerated subclass. */ public function create(... params):Object { var mainClassName:String = info()["mainClassName"]; if (mainClassName == null) { var url:String = loaderInfo.loaderURL; var dot:Number = url.lastIndexOf("."); var slash:Number = url.lastIndexOf("/"); mainClassName = url.substring(slash + 1, dot); } var mainClass:Class = Class(getDefinitionByName(mainClassName)); return mainClass? new mainClass() : null; } /** * @private */ public function info():Object { return {}; } /** * Calls Security.allowDomain() for the SWF associated with this FlexModuleFactory. * plus all the SWFs assocatiated with RSLs preloaded by this FlexModuleFactory. * */ public function allowDomain(... domains):void { // Overridden by compiler generated code. } /** * Calls Security.allowInsecureDomain() for the SWF associated with this FlexModuleFactory * plus all the SWFs assocatiated with RSLs preloaded by this FlexModuleFactory. * */ public function allowInsecureDomain(... domains):void { // Overridden by compiler generated code. } /** * @private * A map of fully-qualified interface names, * such as "mx.managers::IPopUpManager", * to instances, */ private var implMap:Object = {}; /** * @private * Adds an interface-name-to-implementation-class mapping to the registry, * if a class hasn't already been registered for the specified interface. * The class must implement a getInstance() method which returns * its singleton instance. */ public function registerImplementation(interfaceName:String, impl:Object):void { var c:Object = implMap[interfaceName]; if (!c) implMap[interfaceName] = impl; } /** * @private * Returns the singleton instance of the implementation class * that was registered for the specified interface, * by looking up the class in the registry * and calling its getInstance() method. * * This method should not be called at static initialization time, * because the factory class may not have called registerImplementation() yet. */ public function getImplementation(interfaceName:String):Object { var c:Object = implMap[interfaceName]; return c; } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getDefinitionByName(name:String):Object { const domain:ApplicationDomain = info()["currentDomain"] as ApplicationDomain; var definition:Object; if (domain.hasDefinition(name)) definition = domain.getDefinition(name); return definition; } /** * @private */ private function update():void { switch (state) { case INIT_STATE: { if (!appInitDone) return; getRSLInfo(); if (rslListLoader.isDone()) state = APP_LOAD_STATE; else state = RSL_START_LOAD_STATE; break; } case RSL_START_LOAD_STATE: { // start loading all the rsls rslListLoader.load(null, rslCompleteHandler, rslErrorHandler, rslErrorHandler, rslErrorHandler); state = RSL_LOADING_STATE; break; } case RSL_LOADING_STATE: { if (rslListLoader.isDone()) { rslListLoader = null; state = APP_LOAD_STATE; } break; } case APP_LOAD_STATE: { if (appLoaded) { deferredNextFrame(); state = APP_START_STATE; } break; } case APP_START_STATE: { if (appReady) { if (mixinList && mixinList.length > 0) { var n:int = mixinList.length; for (var i:int = 0; i < n; i++) { var c:Class; try { c = Class(getDefinitionByName(mixinList[i])); c["init"](this); } catch(e:Error) { } } } state = APP_RUNNING_STATE; timer.removeEventListener(TimerEvent.TIMER, timerHandler); // Stop the timer. timer.reset(); dispatchEvent(new Event("ready")); loaderInfo.removeEventListener(Event.COMPLETE, moduleCompleteHandler); } break; } case ERROR_STATE: { if (timer != null) { timer.removeEventListener(TimerEvent.TIMER, timerHandler); // stop the timer timer.reset(); } var tf:TextField = new TextField(); tf.text = errorMessage; tf.x = 0; tf.y = 0; tf.autoSize = TextFieldAutoSize.LEFT; addChild(tf); dispatchEvent(new ModuleEvent(ModuleEvent.ERROR, false, false, 0, 0, errorMessage)); loaderInfo.removeEventListener(Event.COMPLETE, moduleCompleteHandler); break; } } } /** * @private * Get the RSL URLs and add them to the RSLListLoader. */ private function getRSLInfo():void { var rsls:Array = info()["rsls"]; var cdRsls:Array = info()["cdRsls"]; // Put cross-domain RSL information in the RSL list. var rslItemList:Array = []; var n:int; var i:int; if (cdRsls && cdRsls.length > 0) { rslDataList = LoaderUtil.processRequiredRSLs(this, cdRsls); var normalizedURL:String = LoaderUtil.normalizeURL(this.loaderInfo); var crossDomainRSLItem:Class = Class(getDefinitionByName("mx.core::CrossDomainRSLItem")); n = rslDataList.length; for (i = 0; i < n; i++) { var rslWithFailovers:Array = rslDataList[i]; // If crossDomainRSLItem is null, then this is a compiler error. It should not be null. var cdNode:Object = new crossDomainRSLItem(rslWithFailovers, normalizedURL, this); rslItemList.push(cdNode); } } // Append RSL information in the RSL list. if (rsls != null && rsls.length > 0) { if (normalizedURL == null) normalizedURL = LoaderUtil.normalizeURL(this.loaderInfo); n = rsls.length; for (i = 0; i < n; i++) { var node:RSLItem = new RSLItem(rsls[i].url, normalizedURL, this); rslItemList.push(node); } } rslListLoader = new RSLListLoader(rslItemList); } /** * @private */ public function autorun():Boolean { return true; } /** * @private */ private function displayError(msg:String):void { errorMessage = msg; state = ERROR_STATE; update(); } /** * @private */ private function docFrameHandler(event:Event = null):void { // Register singleton classes. // Note: getDefinitionByName() will return null // if the class can't be found. Singleton.registerClass("mx.managers::IBrowserManager", Class(getDefinitionByName("mx.managers::BrowserManagerImpl"))); Singleton.registerClass("mx.managers::ICursorManager", Class(getDefinitionByName("mx.managers::CursorManagerImpl"))); Singleton.registerClass("mx.managers::IDragManager", Class(getDefinitionByName("mx.managers::DragManagerImpl"))); Singleton.registerClass("mx.managers::IHistoryManager", Class(getDefinitionByName("mx.managers::HistoryManagerImpl"))); Singleton.registerClass("mx.managers::ILayoutManager", Class(getDefinitionByName("mx.managers::LayoutManager"))); Singleton.registerClass("mx.managers::IPopUpManager", Class(getDefinitionByName("mx.managers::PopUpManagerImpl"))); Singleton.registerClass("mx.resources::IResourceManager", Class(getDefinitionByName("mx.resources::ResourceManagerImpl"))); Singleton.registerClass("mx.styles::IStyleManager", Class(getDefinitionByName("mx.styles::StyleManagerImpl"))); Singleton.registerClass("mx.styles::IStyleManager2", Class(getDefinitionByName("mx.styles::StyleManagerImpl"))); Singleton.registerClass("mx.managers::IToolTipManager2", Class(getDefinitionByName("mx.managers::ToolTipManagerImpl"))); appReady = true; // The resources must be installed before update() creates components // (such as DateChooswer) that might need them immediately. installCompiledResourceBundles(); update(); if (currentFrame < totalFrames) deferredNextFrame(); } /** * @private */ private function installCompiledResourceBundles():void { //trace("FlexModuleFactory.installCompiledResourceBundles"); var info:Object = this.info(); var applicationDomain:ApplicationDomain = info["currentDomain"]; var compiledLocales:Array /* of String */ = info["compiledLocales"]; var compiledResourceBundleNames:Array /* of String */ = info["compiledResourceBundleNames"]; var resourceManager:IResourceManager = ResourceManager.getInstance(); resourceBundles = resourceManager.installCompiledResourceBundles( applicationDomain, compiledLocales, compiledResourceBundleNames, true); // If the localeChain wasn't specified in the FlashVars of the SWF's // HTML wrapper, or in the query parameters of the SWF URL, // then initialize it to the list of compiled locales, // sorted according to the system's preferred locales as reported by // Capabilities.languages or Capabilities.language. // For example, if the applications was compiled with, say, // -locale=en_US,ja_JP and Capabilities.languages reports [ "ja-JP" ], // set the localeChain to [ "ja_JP" "en_US" ]. if (!resourceManager.localeChain) resourceManager.initializeLocaleChain(compiledLocales); } /** * @private */ private function deferredNextFrame():void { if (currentFrame + 1 <= framesLoaded) { nextFrame(); } else { // Next frame isn't baked yet, we'll check back... nextFrameTimer = new Timer(100); nextFrameTimer.addEventListener(TimerEvent.TIMER, nextFrameTimerHandler); nextFrameTimer.start(); } } /** * @private */ private function extraFrameHandler(event:Event = null):void { var frameList:Object = info()["frames"]; if (frameList && frameList[currentLabel]) { var c:Class; try { c = Class(getDefinitionByName(frameList[currentLabel])); c["frame"](this); } catch(e:Error) { } } if (currentFrame < totalFrames) deferredNextFrame(); } //-------------------------------------------------------------------------- // // Event handlers // //-------------------------------------------------------------------------- /** * @private */ private function rslCompleteHandler(event:Event):void { if (event.target is LoaderInfo) { var rslIndex:int = rslListLoader.getIndex(); var rsl:Vector. = Vector.(rslDataList[rslIndex]); var moduleFactory:IFlexModuleFactory = this; if (rsl && rsl[0].moduleFactory) moduleFactory = rsl[0].moduleFactory; if (moduleFactory == this) preloadedRSLs[event.target] = rsl; else moduleFactory.addPreloadedRSL(LoaderInfo(event.target), rsl); } update(); } /** * @private */ private function rslErrorHandler(event:Event):void { var rsl:RSLItem = rslListLoader.getItem(rslListLoader.getIndex()); var detailedError:String; var message:String; if (event is ErrorEvent) detailedError = ErrorEvent(event).text; if (!detailedError) detailedError = ""; message = "RSL " + rsl.urlRequest.url + " failed to load. " + detailedError; displayError(message); } /** * @private */ private function moduleInitHandler(event:Event):void { loaderInfo.removeEventListener(Event.INIT, moduleInitHandler); appInitDone = true; update(); } /** * @private */ private function moduleCompleteHandler(event:Event):void { appLoaded = true; update(); } /** * @private */ private function timerHandler(event:TimerEvent):void { if (totalFrames > 2 && framesLoaded >= 2 || framesLoaded == totalFrames) { appLoaded = true; } update(); } /** * @private */ private function nextFrameTimerHandler(event:TimerEvent):void { if (currentFrame + 1 <= framesLoaded) { nextFrame(); nextFrameTimer.removeEventListener(TimerEvent.TIMER, nextFrameTimerHandler); // stop the timer nextFrameTimer.reset(); } } } }