| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.modules |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import flash.events.Event; |
| import flash.system.ApplicationDomain; |
| import flash.system.SecurityDomain; |
| import flash.utils.ByteArray; |
| import mx.containers.VBox; |
| import mx.core.FlexVersion; |
| import mx.core.IDeferredInstantiationUIComponent; |
| import mx.events.FlexEvent; |
| import mx.events.ModuleEvent; |
| |
| //-------------------------------------- |
| // Events |
| //-------------------------------------- |
| |
| /** |
| * Dispatched when the ModuleLoader starts to load a URL. |
| * |
| * @eventType mx.events.FlexEvent.LOADING |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="loading", type="flash.events.Event")] |
| |
| /** |
| * Dispatched when the ModuleLoader is given a new URL. |
| * |
| * @eventType mx.events.FlexEvent.URL_CHANGED |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="urlChanged", type="flash.events.Event")] |
| |
| /** |
| * Dispatched when information about the module is |
| * available (with the <code>info()</code> method), |
| * but the module is not yet ready. |
| * |
| * @eventType mx.events.ModuleEvent.SETUP |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="setup", type="mx.events.ModuleEvent")] |
| |
| /** |
| * Dispatched when the module is finished loading. |
| * |
| * @eventType mx.events.ModuleEvent.READY |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="ready", type="mx.events.ModuleEvent")] |
| |
| /** |
| * Dispatched when the module throws an error. |
| * |
| * @eventType mx.events.ModuleEvent.ERROR |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="error", type="mx.events.ModuleEvent")] |
| |
| /** |
| * Dispatched at regular intervals as the module loads. |
| * |
| * @eventType mx.events.ModuleEvent.PROGRESS |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="progress", type="mx.events.ModuleEvent")] |
| |
| /** |
| * Dispatched when the module data is unloaded. |
| * |
| * @eventType mx.events.ModuleEvent.UNLOAD |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="unload", type="mx.events.ModuleEvent")] |
| |
| //-------------------------------------- |
| // Other metadata |
| //-------------------------------------- |
| |
| /* NOTE: This class does not use the "containers" resource bundle. This |
| * metadata is here to add the "containers" resource bundle to an |
| * application loading a module. We do this because we know a Module will |
| * pull in the "containers" resource bundle and if the Module uses a resource |
| * bundle that is not already in use it will cause the module to be leaked. |
| * |
| * This is only an issue for Spark applications because they do not link in |
| * the CanvasLayout class, which has the "containers" resource bundle. Halo |
| * applications always use the CanvasLayout class. This can be removed |
| * after the module leak caused by the ResourceManager has been fixed. |
| * |
| */ |
| [ResourceBundle("containers")] |
| |
| // Resource bundles used by this class. |
| [ResourceBundle("modules")] |
| |
| [IconFile("ModuleLoader.png")] |
| |
| [Alternative(replacement="spark.modules.ModuleLoader", since="4.5")] |
| |
| /** |
| * ModuleLoader is a component that behaves much like a SWFLoader except |
| * that it follows a contract with the loaded content. This contract dictates that the child |
| * SWF file implements IFlexModuleFactory and that the factory |
| * implemented can be used to create multiple instances of the child class |
| * as needed. |
| * |
| * <p>The ModuleLoader is connected to deferred instantiation and ensures that |
| * only a single copy of the module SWF file is transferred over the network by using the |
| * ModuleManager singleton.</p> |
| * |
| * <pre> |
| * <mx:ModuleLoader |
| * <strong>Properties</strong> |
| * url="<i>No default</i>" |
| * trustContent="false|true" |
| * |
| * <strong>Events</strong> |
| * error="<i>No default</i>" |
| * loading="<i>No default</i>" |
| * progress="<i>No default</i>" |
| * ready="<i>No default</i>" |
| * setup="<i>No default</i>" |
| * unload="<i>No default</i>" |
| * /> |
| * </pre> |
| * |
| * @see mx.modules.ModuleManager |
| * @see mx.controls.SWFLoader |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class ModuleLoader extends VBox |
| implements IDeferredInstantiationUIComponent |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function ModuleLoader() |
| { |
| super(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var module:IModuleInfo; |
| |
| /** |
| * @private |
| */ |
| private var loadRequested:Boolean = false; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // applicationDomain |
| //---------------------------------- |
| |
| /** |
| * The application domain to load your module into. |
| * Application domains are used to partition classes that are in the same |
| * security domain. They allow multiple definitions of the same class to |
| * exist and allow children to reuse parent definitions. |
| * |
| * @see flash.system.ApplicationDomain |
| * @see flash.system.SecurityDomain |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var applicationDomain:ApplicationDomain; |
| |
| //---------------------------------- |
| // child |
| //---------------------------------- |
| |
| /** |
| * The DisplayObject created from the module factory. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var child:DisplayObject; |
| |
| //---------------------------------- |
| // trustContent |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the trustContent property. |
| */ |
| private var _trustContent:Boolean = false; |
| |
| [Bindable("trustContentChanged")] |
| [Inspectable(defaultValue="false")] |
| |
| /** |
| * If <code>true</code>, the content is loaded |
| * into your security domain. |
| * This means that the load fails if the content is in another domain |
| * and that domain does not have a crossdomain.xml file allowing your |
| * domain to access it. |
| * This property only has an affect on the next load, |
| * it will not start a new load on already loaded content. |
| * |
| * <p>The default value is <code>false</code>, which means load |
| * any content without failing, but you cannot access the content. |
| * Most importantly, the loaded content cannot |
| * access your objects and code, which is the safest scenario. |
| * Do not set this property to <code>true</code> unless you are absolutely sure of the safety |
| * of the loaded content</p> |
| * |
| * @default false |
| * @see flash.system.SecurityDomain |
| * @see flash.system.ApplicationDomain |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10.2 |
| * @playerversion AIR 2.6 |
| * @productversion Flex 4.5.1 |
| */ |
| public function get trustContent():Boolean |
| { |
| return _trustContent; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set trustContent(value:Boolean):void |
| { |
| if (_trustContent != value) |
| { |
| _trustContent = value; |
| |
| invalidateProperties(); |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("trustContentChanged")); |
| } |
| } |
| |
| //---------------------------------- |
| // url |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the url property. |
| */ |
| private var _url:String = null; |
| |
| /** |
| * The location of the module, expressed as a URL. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get url():String |
| { |
| return _url; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set url(value:String):void |
| { |
| if (value == _url) |
| return; |
| |
| var wasLoaded:Boolean = false; |
| |
| if (module) |
| { |
| module.removeEventListener(ModuleEvent.PROGRESS, |
| moduleProgressHandler); |
| module.removeEventListener(ModuleEvent.SETUP, moduleSetupHandler); |
| module.removeEventListener(ModuleEvent.READY, moduleReadyHandler); |
| module.removeEventListener(ModuleEvent.ERROR, moduleErrorHandler); |
| module.removeEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler); |
| |
| module.release(); |
| module = null; |
| |
| if (child) |
| { |
| removeChild(child); |
| child = null; |
| } |
| } |
| |
| _url = value; |
| |
| dispatchEvent(new FlexEvent(FlexEvent.URL_CHANGED)); |
| |
| if (_url != null && _url != "" && loadRequested) |
| loadModule(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: Container |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function createComponentsFromDescriptors( |
| recurse:Boolean = true):void |
| { |
| super.createComponentsFromDescriptors(recurse); |
| |
| loadRequested = true; |
| loadModule(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Loads the module. When the module is finished loading, the ModuleLoader adds |
| * it as a child with the <code>addChild()</code> method. This is normally |
| * triggered with deferred instantiation. |
| * |
| * <p>If the module has already been loaded, this method does nothing. It does |
| * not load the module a second time.</p> |
| * |
| * @param url The location of the module, expressed as a URL. This is an |
| * optional parameter. If this parameter is null the value of the |
| * <code>url</code> property will be used. If the url parameter is provided |
| * the <code>url</code> property will be updated to the value of the url. |
| * |
| * @param bytes A ByteArray object. The ByteArray is expected to contain |
| * the bytes of a SWF file that represents a compiled Module. The ByteArray |
| * object can be obtained by using the URLLoader class. If this parameter |
| * is specified the module will be loaded from the ByteArray and the url |
| * parameter will be used to identify the module in the |
| * <code>ModuleManager.getModule()</code> method and must be non-null. If |
| * this parameter is null the module will be load from the url, either |
| * the url parameter if it is non-null, or the url property as a fallback. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function loadModule(url:String = null, bytes:ByteArray = null):void |
| { |
| |
| if (url != null) |
| _url = url; |
| |
| if (_url == null || _url == "") |
| { |
| //trace("loadModule() - null url or empty string url"); |
| return; |
| } |
| |
| if (child) |
| { |
| //trace("loadModule() - already created the child"); |
| return; |
| } |
| |
| if (module) |
| { |
| //trace("loadModule() - load already initiated"); |
| return; |
| } |
| |
| dispatchEvent(new FlexEvent(FlexEvent.LOADING)); |
| |
| module = ModuleManager.getModule(_url); |
| |
| module.addEventListener(ModuleEvent.PROGRESS, moduleProgressHandler); |
| module.addEventListener(ModuleEvent.SETUP, moduleSetupHandler); |
| module.addEventListener(ModuleEvent.READY, moduleReadyHandler); |
| module.addEventListener(ModuleEvent.ERROR, moduleErrorHandler); |
| module.addEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler); |
| |
| // If an applicationDomain has not been specified and we have a module factory, |
| // then create a child application domain from the application domain |
| // this module factory is in. |
| // This is a change in behavior so only do it for Flex 4 and newer |
| // applications. |
| var tempApplicationDomain:ApplicationDomain = applicationDomain; |
| |
| if (tempApplicationDomain == null && moduleFactory && |
| FlexVersion.compatibilityVersion >= FlexVersion.VERSION_4_0) |
| { |
| var currentDomain:ApplicationDomain = moduleFactory.info()["currentDomain"]; |
| tempApplicationDomain = new ApplicationDomain(currentDomain); |
| } |
| |
| module.load(tempApplicationDomain, |
| trustContent ? SecurityDomain.currentDomain : null, |
| bytes, |
| moduleFactory); |
| } |
| |
| /** |
| * Unloads the module and sets it to <code>null</code>. |
| * If an instance of the module was previously added as a child, |
| * this method calls the <code>removeChild()</code> method on the child. |
| * <p>If the module does not exist or has already been unloaded, this method does |
| * nothing.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function unloadModule():void |
| { |
| if (child) |
| { |
| removeChild(child); |
| child = null; |
| } |
| |
| if (module) |
| { |
| module.removeEventListener(ModuleEvent.PROGRESS, |
| moduleProgressHandler); |
| module.removeEventListener(ModuleEvent.SETUP, moduleSetupHandler); |
| module.removeEventListener(ModuleEvent.READY, moduleReadyHandler); |
| module.removeEventListener(ModuleEvent.ERROR, moduleErrorHandler); |
| |
| module.unload(); |
| module.removeEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler); |
| module = null; |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function moduleProgressHandler(event:ModuleEvent):void |
| { |
| dispatchEvent(event); |
| } |
| |
| /** |
| * @private |
| */ |
| private function moduleSetupHandler(event:ModuleEvent):void |
| { |
| // Not ready for creation yet, but can call factory.info(). |
| |
| dispatchEvent(event); |
| } |
| |
| /** |
| * @private |
| */ |
| private function moduleReadyHandler(event:ModuleEvent):void |
| { |
| child = module.factory.create() as DisplayObject; |
| dispatchEvent(event); |
| |
| if (child) |
| { |
| var p:DisplayObjectContainer = parent; |
| // p.removeChild(this); |
| addChild(child); |
| } |
| else |
| { |
| var message:String = resourceManager.getString( |
| "modules", "couldNotCreateModule", [ module.factory.info()["mainClassName"] ]); |
| var moduleEvent:ModuleEvent = new ModuleEvent( |
| ModuleEvent.ERROR, false, false, |
| event.bytesLoaded, event.bytesTotal, |
| message, event.module); |
| dispatchEvent(moduleEvent); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function moduleErrorHandler(event:ModuleEvent):void |
| { |
| unloadModule(); |
| dispatchEvent(event); |
| } |
| |
| /** |
| * @private |
| */ |
| private function moduleUnloadHandler(event:ModuleEvent):void |
| { |
| dispatchEvent(event); |
| } |
| } |
| |
| } |