Sibling Domains and Multiversioning

By now, it should be clear that applications, modules, and libraries (albeit bootstrapped as applications) are simply different forms of packaging .swf files. Libraries assume the tightest coupling with the loading code, and that’s why they get preloaded (by the application’s code generated by the Flex compiler). Modules get loaded and unloaded on demand, because they are needed only conditionally and only temporarily. Applications are similar to modules, in that they get loaded and unloaded on demand. The important advantage of applications over modules (as units of modularization) is that applications are self-sufficient, which allows you to mix multiple application .swfs compiled against different versions of the Flex framework (Flex 3.1, Flex 3.2, Flex 4.0, and so on).

Let’s elaborate. As you already know, libraries get loaded into the same domain as the application: ApplicationDomain.currentDomain. Accordingly, to avoid conflicts, a library has to be compiled against the same version of the Flex framework as the enclosing application. With modules, you get to choose between the same domain or a child domain (new ApplicationDomain(ApplicationDomain.currentDomain)), but even in the latter case, the class search starts with the parent domain. Again, to avoid conflicts, modules have to be compiled against the same version of the Flex framework as the consuming application. When it comes to applications, you still may use same-domain or child-domain techniques, provided that the loading application and subapplication are compiled against the same version of the Flex framework. What if you can’t recompile the Flex 3.2 subapplication and you want to load it from the Flex 4 main application? Then you need to load into the domain that is the sibling of the main application domain (new ApplicationDomain(null)).

Sibling domains allow ultimate separation of classes; you absolutely have to load the sub into the sibling domain to support multiversioning. That said, you may want to indiscriminately use sibling domains even when multiversioning is not an issue. A typical use case for this is portals, when you have to integrate portlets, perhaps developed by a third party. In brief:

  • If you can compile from sources, make modules and load them into the same domain or a child domain.

  • If you are integrating compiled applications, use sibling domains.

To simplify the discussion, the following sections will use the term “portlet” instead of the subapplication and “portal” instead of the loading application.

Four Scenarios of Loading Portlets

To load and unload a portlet, you have to use SWFLoader (unless you are into writing your own loader). As you remember, SWFLoader is a wrapper around flash.display.Loader. As such, SWFLoader exposes the loaderContext property that controls the application domain precisely, like it does it for Loader. For instance, Example 7-31’s MXML illustrates the loading of the RemoteApplication.swf portlet using the default loaderContext.

Example 7-31. Using SWFLoader with default LoaderContext

<mx:SWFLoader id="swfLoader"
   source="http://localhost:8080/RemoteSite/RemoteApplication.swf"
/>

Identical results can be achieved by Example 7-32’s script.

Example 7-32. Using SWFLoader with explicit LoaderContext

private function loadApplication():void {
   swfLoader.loaderContext = new LoaderContext(
      false,
      new ApplicationDomain(ApplicationDomain.currentDomain)
   );
   swfLoader.source = "http://localhost:8080/RemoteSite/RemoteApplication.swf";
}

In both cases, the portlet’s classes get loaded in the child domain of the portal, according to the default loaderContext of a flash.display.Loader. However, there is more to loaderContext than controlling the application domain.

When a Flex application is loaded from a web domain, Flash Player, by default, assigns it a security sandbox. Applications coming from the different web domains get assigned different sandboxes. As an example, consider that the portal comes from http://localhost and loads the portlet from http://127.0.0.1. Unless you deviate from the default settings, these two applications will be assigned different sandboxes. Remember that class definitions get loaded into application domains and that application domains form a tree. There is one and only one tree per sandbox.

You can read more about sandboxes in the Flash documentation (Adobe often refers to them as security domains as well), but a few important points should be noted here:

  • You can indicate the sandbox preference in the constructor of the LoaderContext. For instance, Example 7-33’s code snippet results in loading classes into the current security sandbox.

    Example 7-33. Forced loading into the current sandbox

    swfLoader.loaderContext = new LoaderContext(
        false,
        new ApplicationDomain(
           ApplicationDomain.currentDomain
        )
        SecurityDomain.currentDomain
    )
  • Although you can easily load portlets from other web domains into the current sandbox, there is no way you can programmatically load the portlet from the same web domain into the different sandbox. In other words, you can admit strangers into your family, but you can’t expel your kin. And the only way to load a portlet into a different sandbox is to host it in a different web domain or subdomain.

  • Assigning a different sandbox means a totally different tree of application domains.

To sum up, there are only four loaderContext combinations that you can arrange either programmatically or via hosting the portlet on the different subdomain:

  • Different Sandbox Different Domain (DSDD)

  • Same Sandbox Different (sibling) Domain (SSDD)

  • Same Sandbox Child Domain (SSCD)

  • Same Sandbox Same Domain (SSSD)

Table 7-1 illustrates how you can achieve a particular combination—DSDD, SSDD, SSCD, and SSSD (in this order)—provided that the portal and the portlet are hosted by the different web domains. You can explicitly use the loaderContext property or you can manipulate loadForCompatibility and trustContent.

Table 7-1. Loading portlets across web domains

loaderContext syntax

SWFLoader syntax

swfLoader.loaderContext=new
  LoaderContext( false,
    new ApplicationDomain(null),
    null
  );
<mx:SWFLoader
id="swfLoader"
/>
swfLoader.loaderContext=new
  LoaderContext( false,
    new ApplicationDomain(null),
    SecurityDomain.currentDomain
  );
<mx:SWFLoader
id="swfLoader"
loadForCompatibility="true"
trustContent="true"
/>
swfLoader.loaderContext=new
  LoaderContext( false,
    new ApplicationDomain(
      ApplicationDomain.currentDomain
    ),
    SecurityDomain.currentDomain
  );
<mx:SWFLoader
id="swfLoader"


trustContent="true"
/>
swfLoader.loaderContext=new
  LoaderContext( false,
 ApplicationDomain.applicationDomain,
    SecurityDomain.currentDomain
  );
Not applicable

Table 7-2 illustrates how the combination SSDD, SSCD, and SSSD can be achieved, provided that the portal and the portlet are located on the same web domain.

Table 7-2. Loading portlets from the same web domain

loaderContext syntax

SWFLoader syntax

swfLoader.loaderContext=new
  LoaderContext( false,
    new ApplicationDomain(null)
  );
<mx:SWFLoader
id="swfLoader"
loadForCompatibility="true"
/>
swfLoader.loaderContext=new
  LoaderContext( false,
    new ApplicationDomain(
      ApplicationDomain.currentDomain
    )
  );
<mx:SWFLoader
id="swfLoader"
/>
swfLoader.loaderContext=new
  LoaderContext( false,
    ApplicationDomain.currentDomain
  );
Not applicable

Some of these scenarios make more sense than the others. In particular, the Same Sandbox Same Domain scenario is the one most prone to class name clashing. To reiterate: duplicate loading of a class in the tree of application domains is not possible. At the same time, sub’s code can easily and perhaps inadvertently modify static variables of the classes hosted by the parent application. This relates to classes, such as mx.core.Application and mx.messaging.config.ServerConfig, for instance, and their properties application and xml, respectively.

On the opposite end is the Different Sandbox Different Domain scenario. Here you have the ultimate class isolation, which supports multiversioning plus ultimate security (more on this a bit later), at the price of a not-so-seamless user experience. For instance, the pop ups and alerts of the portlet will appear centered and clipped relative to the portlet rather than the entire portal, as shown in Figure 7-13.

DifferentSandboxDifferentDomainDemo; pop up is centered relatively to the loaded portlet

Figure 7-13. DifferentSandboxDifferentDomainDemo; pop up is centered relatively to the loaded portlet

The remaining two scenarios are Same Sandbox Child Domain and Same Sandbox Different Domain. The latter should be considered the top choice for enterprise portals, as it supports multiversioning and delivers a seamless user experience. The simpler scenario, Same Sandbox Child Domain, is the one you’ll examine next. After that, you’ll investigate scenarios that provide multiversioning support.

Default Portlet Loading: Same Sandbox Child Domain

Same Sandbox Child Domain is the default scenario when the application and the subapplication are located in a single web domain. Unless you tell SWFLoader otherwise, portlet classes get loaded into the child application domain. To see how this works, start with a sample portlet, such as RegularApplication.mxml, in Example 7-34.

Example 7-34. RegularApplication.mxml—sample portlet

<?xml version="1.0"?>
<!-- RegularApplication.mxml-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" implements="IGreeting"
     backgroundColor="0xffeeff"   xmlns:local="*"
      creationComplete="onCreationComplete()">
<mx:Script>
<![CDATA[
   import mx.events.DynamicEvent;
   import mx.controls.Alert;
   import events.RemoteEvent;

   [Bindable] private var command:String="";
    [Bindable]  public var greeting:String = "";

   public function setGreeting(value:String):void {
      greeting = value;
   }
   public function getGreeting():String {
      return greeting;
   }

   private function onCreationComplete():void {
      Alert.show("Loaded application talks back...");
      // While you may use systemManager["swfBridge"] in the DSDD and SSDD,
      //   systemManager.loaderInfo.sharedEvents will work always
      var swfBridge:IEventDispatcher = systemManager.loaderInfo.sharedEvents;

      // Subscribe to command from the application
       swfBridge.addEventListener("command", onCommand,false,0,true );
       // Notify the application that creation has completed
      var evt:RemoteEvent = new RemoteEvent("creationComplete");
      evt.data = ". Loaded application reported createComplete!";
       swfBridge.dispatchEvent(evt);
   }

   private function onCommand(event:Event):void {
       command = event["data"] as String;
    }

]]>
</mx:Script>
    <mx:Panel title="Loaded Application - Google News {greeting}{command}."
                                width="90%" height="90%">
       <local:GoogleNews width="100%" height="100%"/>
    </mx:Panel>
</mx:Application>

RegularApplication.mxml implements the interface IGreeting from Example 7-12. Under the SSCD scenario, a portlet will see the definition of the IGreeting loaded by the portal. Accordingly, the portal will be able to cast the portlet to IGreeting, as shown in Example 7-35 (you may compare swfLoader.content with moduleLoader.child).

Example 7-35. Interface-based scripting of the portlet loaded into the child domain

public function modifyValue():void {
   var systemManager:SystemManager = SystemManager(swfLoader.content);
   var loadedApplication:IGreeting = systemManager.application as IGreeting;
   loadedApplication.setGreeting(" accessed from outside");
}

Similarly to the way you arranged event-based communication with the modules, this portlet listens to and communicates with the loading application via loaderInfo.sharedEvents (Example 7-36).

Example 7-36. Event-based portlet-portal communication via sharedEvents

private function onCreationComplete():void {
   var swfBridge:IEventDispatcher = systemManager.loaderInfo.sharedEvents;

   // Subscribe to command from the application
   swfBridge.addEventListener("command", onCommand,false,0,true );

   // Notify the application that creation has completed
   var evt:RemoteEvent = new RemoteEvent("creationComplete");
   evt.data = ". Loaded application reported createComplete!";
   swfBridge.dispatchEvent(evt);
}

Make sure to deploy RegularApplication.mxml into an entirely dedicated BlazeDS or LCDS context. This example creates a combined Flex/Java LCDS/Web Tools Platform (WTP) project called RemoteSite, as shown in Figure 7-14. (Please see the Adobe documentation on how to create a combined Flex/Java project with LiveCycle Data Services and WTP.) Having a dedicated Flex/JEE project enables you to define destinations of the portlet without affecting a portal or another portlet application.

Applications from RemoteSite will be accessed via domain 127.0.0.1

Figure 7-14. Applications from RemoteSite will be accessed via domain 127.0.0.1

To the RemoteSite/WebContent/WEB-INF/flex/proxy-config.xml file of this project, you need to add the destination GoogleNews, as shown in Example 7-37.

Example 7-37. GoogleNews proxy destination

<destination id="GoogleNews">
   <properties>
     <url>http://news.google.com/?output=rss</url>
   </properties>
</destination>

Example 7-38 presents the class GoogleNews, a descendant of DataGrid that encapsulates HTTPService and displays Google News headlines to the user. When you run the portlet, it should look like Figure 7-15.

Example 7-38. GoogleNews DataGrid

<?xml version="1.0" encoding="utf-8"?>
<!-- GoogleNews.mxml -->
<mx:DataGrid  xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="news.send()"
   dataProvider="{news.lastResult.channel.item}"
   variableRowHeight="true">
   <mx:columns>
     <mx:DataGridColumn headerText="Date"  dataField="pubDate" />
     <mx:DataGridColumn headerText="Title" dataField="title" wordWrap="true" />
   </mx:columns>


   <mx:HTTPService id="news" useProxy="true"  destination="GoogleNews"
resultFormat="e4x" fault="onFault(event)" />
<mx:Script>
<![CDATA[
   import mx.rpc.events.*;
   private function onFault(event:FaultEvent):void {
     mx.controls.Alert.show( "Destination:" + event.currentTarget.destination +
      "
" + "Fault code:" + event.fault.faultCode + "
" +
      "Detail:" + event.fault.faultDetail, "News feed failure"
      );
   }
]]>
</mx:Script>
</mx:DataGrid>
Sample portlet of RegularApplication

Figure 7-15. Sample portlet of RegularApplication

Finally, consider the sample portal, SameSandboxChildDomainDemo.mxml, in Example 7-39. We suggest you create a separate combined Flex/Java/WTP Eclipse project, as shown in Figure 7-16. To illustrate the cross-domain specifics, you can run the portal from http://localhost while loading the portlet from the different domain, http://127.0.0.1.

Example 7-39. SameSandboxChildDomainDemo application

<?xml version="1.0"?>
<!-- SameSandboxChildDomainDemo.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" >
<mx:Script>
<![CDATA[
   import events.RemoteEvent;
    import mx.managers.SystemManager;

   private const APP_URL:String =
"http://127.0.0.1:8080/RemoteSite/RegularApplication.swf";

   public function modifyValue():void {
      // Casting to SystemManager and IGreeting is possible
      var systemManager:SystemManager = SystemManager(swfLoader.content);
      var loadedApplication:IGreeting = systemManager.application as IGreeting;
      loadedApplication.setGreeting(" accessed from outside");
    }

    private function loadApplication():void {
      swfLoader.addEventListener("complete", onLoadComplete);
         swfLoader.source = APP_URL;
   }

    [Bindable] private var applicationLoaded:Boolean;
    private var sharedEventDispatcher:IEventDispatcher;

   private function onLoadComplete(event:Event):void {
      applicationLoaded = true;
         sharedEventDispatcher = swfLoader.content.loaderInfo.sharedEvents;
         sharedEventDispatcher.addEventListener(
         "creationComplete", onLoadedApplicationCreated
      );
    }

      [Bindable] private var reply:String="";
   // Casting to RemoteEvent is possible
    private function onLoadedApplicationCreated(event: RemoteEvent):void
                    reply = event.data as String;
         var remoteEvent:RemoteEvent = new RemoteEvent("command");
         remoteEvent.data = ". Two-way communication works!";
         sharedEventDispatcher.dispatchEvent(remoteEvent);
    }
    ]]>
    </mx:Script>
    <mx:HBox>
      <mx:Button label="Load Application" click="loadApplication()" />
          <mx:Button label="Modify Value" click="modifyValue();"
         enabled="{applicationLoaded}"/>
    </mx:HBox>

    <mx:Panel title="Yahoo News{reply}" width="100%" height="50%"
              id="panel">
       <local:YahooNews width="100%" height="100%"/>
    </mx:Panel>
    <mx:SWFLoader id="swfLoader" width="100%" height="50%"
                                                trustContent="true"/>
</mx:Application>

Notice the setting trustContent="true" of the swfLoader. This guarantees that despite different web domains of the portal and portlet, class loading happens into the same sandbox and, by default, to the child application domain.

That said, you should stick to the golden Flash security rule that the .swf (of the portal) can access a resource (portlet) on the different web domain only when such domain holds a cross-domain policy file that expresses trust to the domain of the .swf. So make sure your root web application contains the file shown in Example 7-40.

ApplicationLoaders project

Figure 7-16. ApplicationLoaders project

Example 7-40. Policy file cross-domain.xml

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy
  SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
 <allow-access-from domain="*"/>
</cross-domain-policy>

Make sure that you do not use this indiscriminating policy file in production. For more information on secure cross-domain communication in Flash Player, see http://www.adobe.com/devnet/flashplayer/articles/secure_swf_apps.html.

SameSandboxChildDomainDemo.mxml has its own news grid—it displays Yahoo! News. (The code of YahooNews is identical to GoogleNews from Example 7-37, except that it uses the different destination, as presented in Example 7-41. You should add this destination to ApplicationLoaders/WebContent/WEB-INF/flex/proxy-config.xml.)

Example 7-41. Proxy destination for Yahoo! News

<destination id="YahooNews">
   <properties>
     <url>http://rss.news.yahoo.com/rss/topstories</url>
   </properties>
</destination>

When you run the application and click OK on the pop up called “Loaded application talks back,” it will look like Figure 7-17.

SameSandboxChildDomainDemo

Figure 7-17. SameSandboxChildDomainDemo

Loading Portlets for Multiversioning

What about the scenarios that support multiversioning? The default loading scenario from different web domains is Different Sandbox Different Domain. Example 7-42’s sample portal, DifferentSandboxDifferentDomainDemo, not only illustrates this scenario, it will also help you to understand the Same Sandbox Different Domain scenario.

When you examine the code, notice the seemingly redundant reference to the class PopUpManager. It’s not accidental. You always have to link the PopUpManager class to your portal to allow pop-up controls in the portlets. That’s how Adobe implemented it, and this requirement does not seem like too much to ask for.

Next, note that casting across sibling domains is out of reach. Look at the body of the modifyValue() method. You can’t cast the loadedApplication either to IGreeting or to mx.core.Application. Instead, the example declares it as flash.display.DisplayObject. For similar reasons, the declaration of the onLoadedApplicationCreated() method downcasts the type of object to flash.events.Event. If you instead try to declare loadedApplication as Application, you will receive this runtime error:

TypeError: Error #1034: Type Coercion failed: cannot convert
TrustfulApplication@c8f20a1 to mx.core.Application.

Now, examine the function onLoadComplete(). To obtain the reference to the sharedEventDispatcher, the function uses the expression swfLoader.swfBridge instead of swfLoader.content.loaderInfo.sharedEvents.

Example 7-42. DifferentSandboxDifferentDomainDemo

<?xml version="1.0"?>
<!-- DifferentSandboxDifferentDomainDemo.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" >
<mx:Script>
<![CDATA[
   import events.RemoteEvent;
    import mx.managers.PopUpManager; PopUpManager;
    import mx.managers.SystemManager;

    private const APP_URL:String =
    "http://127.0.0.1:8080/RemoteSite/TrustfulApplication.swf";

   public function modifyValue():void {
      var loadedApplication:DisplayObject = swfLoader.content["application"];
loadedApplication["setGreeting"]("loaded from outside");
    }

    private function loadApplication():void {
         swfLoader.addEventListener("complete", onLoadComplete);
            swfLoader.source=APP_URL;
    }

    [Bindable] private var applicationLoaded:Boolean;
     private var sharedEventDispatcher:IEventDispatcher;
     private function onLoadComplete(event:Event):void {
            swfLoader.removeEventListener("complete", onLoadComplete);
            applicationLoaded = true;
           // Since swfLoader.content.loaderInfo.sharedEvents=null,
           // use swfLoader.swfBridge
            sharedEventDispatcher = swfLoader.swfBridge;
            sharedEventDispatcher.addEventListener("creationComplete",
                                         onLoadedApplicationCreated);
     }

      [Bindable] private var reply:String="";
      // We cannot cast RemoteEvent across Application Domains
    private function onLoadedApplicationCreated(event:/*RemoteEvent*/ Event):void {
         if (event.hasOwnProperty("data")) {
               reply = event["data"];
         }
         var remoteEvent:RemoteEvent = new RemoteEvent("command");
         remoteEvent.data = ". Two-way communication works!";
         sharedEventDispatcher.dispatchEvent(remoteEvent);
    }

]]>
 </mx:Script>
    <mx:HBox>
      <mx:Button label="Load Application" click="loadApplication()" />
          <mx:Button label="Modify Value" click="modifyValue();"
         enabled="{applicationLoaded}"/>
    </mx:HBox>

    <mx:Panel title="Yahoo News{reply}" width="100%" height="50%" id="panel">
       <local:YahooNews width="100%" height="100%"/>
    </mx:Panel>
    <mx:SWFLoader id="swfLoader" width="100%" height="50%"/>
</mx:Application>

The same concepts hold true for the Same Sandbox Different Domain scenario as well. Specific to the cross-domain scenario, however, is that DifferentSandBoxDifferentDomainDemo loads TrustfulApplication.swf (Example 7-43), which extends the RegularApplication merely to express cross-scripting trust to the web domain of the portal via Security.allowDomain("*").

Example 7-43. TrustfulApplication

<?xml version="1.0"?>
<!-- TrustfulApplication.mxml-->
<RegularApplication xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
preinitialize="onPreinitialize(event)">
   <mx:Script>
      <![CDATA[
         // Try to use without allowDomain and see the r.t. SecurityError
         private function onPreinitialize(event:Event):void {
            Security.allowDomain("*"); //localhost, wwww.adobe.com, etc.
         }
      ]]>
   </mx:Script>
</RegularApplication>

The body of the function modifyValue() takes advantage of these cross-scripting permissions, referring to swfLoader.content. Had you loaded the untrusted RemoteApplication.swf, you would have received the error shown in Example 7-44.

Example 7-44. Example of security error

SecurityError: Error #2121: Security sandbox violation: Loader.content:
http://localhost:8080/ApplicationLoaders/DifferentSandboxCommunicationDemo.swf
cannot access http://127.0.0.1:8080/RemoteSite/RegularApplication.swf.
This may be worked around by calling Security.allowDomain.
    at flash.display::Loader/get content()
    at mx.controls::SWFLoader/get content

This is the only coding specific to the DSDD scenario versus SSDD. Of course, in the case of SSDD, the loadingForCompatibility property of the swfLoader would be set to true, and you would specify trustContent="true" to offset the domain difference.

The successfully running DSDD application was previously presented in Figure 7-16, and Figure 7-18 illustrates a problem in the SSDD scenario: the Google News panel is showing up empty. As it turns out, in the case of SSDD, you need to change your architecture and preload Flex messaging, RPC, and Data Management Services–related classes in the application domain that will parent the domain of the portal.

Same Sandbox Different Domain: Flex Messaging does not work without bootstrap loading of the messaging classes

Figure 7-18. Same Sandbox Different Domain: Flex Messaging does not work without bootstrap loading of the messaging classes

Bootstrap Class Loading

The previous section mentioned that casting is out of reach across sibling domains. That constraint is not as tight, however, as you might think. Remember how you cast loaded modules and applications to the IGreeting interface earlier in the chapter? You did not cast the IGreeting of the child to the IGreeting of the parent, because the IGreeting of the child did not exist. A child is always reusing classes loaded in the parental chain. So, two sibling domains can cast classes if they share a common parent that preloads these classes. In particular, such bootstrap class loading, as Adobe calls it, is required to maintain a common definition of the following classes from the mx.messaging.messages package per security domain:

  • ConfigMap

  • AcknowledgeMessage

  • AcknowledgeMessageExt

  • AsyncMessage

  • AsyncMessageExt

  • CommandMessage

  • CommandMessageExt

  • ErrorMessage

  • HTTPRequestMessage

  • MessagePerformanceInfo

  • RemotingMessage

  • SOAPMessage

In the Different Sandbox Different Domain scenario, the portal and portlet reside in the different sandboxes, so bootstrap loading of the Flex messaging classes is not an issue. However, in the Same Sandbox Different Domain scenario, the absence of the common bootstrap loader results in the first application that happens to load these classes into its own domain (be that portal or portlet) to block all other siblings from receiving messages from the MessageBroker.

At Farata Systems, we customized PortalBootstrapLoader, which is a separate ActionScript project (Figure 7-19).

PortalBootstrapLoader project

Figure 7-19. PortalBootstrapLoader project

As you study the code for PortalBootstrapLoader in Example 7-45, notice that in addition to linking in all classes required by Adobe, we also link in the class com.farata.portal.Message. Follow this pattern to link in any class that you want to make available for all portlets in your portal (and the portal itself).

Example 7-45. PortalBootstrapLoader.as

//PortalBootstrapLoader.as
package {
   import flash.display.Loader;
   import flash.display.Sprite;
   import flash.display.StageAlign;
   import flash.display.StageScaleMode;
   import flash.events.Event;
   import flash.net.URLRequest;
   import flash.system.ApplicationDomain;
   import flash.system.LoaderContext;
   import flash.system.SecurityDomain;

   import utils.QueryString;

   import mx.messaging.config.ConfigMap; ConfigMap;
   import mx.messaging.messages.AcknowledgeMessage; AcknowledgeMessage;
   import mx.messaging.messages.AcknowledgeMessageExt; AcknowledgeMessageExt;
   import mx.messaging.messages.AsyncMessage; AsyncMessage;
   import mx.messaging.messages.AsyncMessageExt; AsyncMessageExt;
   import mx.messaging.messages.CommandMessage; CommandMessage;
   import mx.messaging.messages.CommandMessageExt; CommandMessageExt;
   import mx.messaging.messages.ErrorMessage; ErrorMessage;
   import mx.messaging.messages.HTTPRequestMessage; HTTPRequestMessage;
   import mx.messaging.messages.MessagePerformanceInfo; MessagePerformanceInfo;
   import mx.messaging.messages.RemotingMessage; RemotingMessage;
   import mx.messaging.messages.SOAPMessage; SOAPMessage;

   import com.farata.portal.Message;Message;

   public class PortalBootstrapLoader extends Sprite {

   public function PortalBootstrapLoader() {
      super();

    if (ApplicationDomain.currentDomain.hasDefinition("mx.core::UIComponent"))
       throw new Error("UIComponent should not be in the bootstrap loader.");
    if (ApplicationDomain.currentDomain.hasDefinition("mx.core::Singleton"))
       throw new Error("Singleton should not be in the bootstrap loader.");

    if (stage) {
         stage.scaleMode = StageScaleMode.NO_SCALE;
         stage.align = StageAlign.TOP_LEFT;
    } else
         isStageRoot = false;
      root.loaderInfo.addEventListener(Event.INIT, onInit);
   }

   /**
   * The Loader that loads the main application's SWF file.
   */
   private var loader:Loader;

   /**
   * Whether the bootstrap loader is at the stage root or not,
   * it is the stage root only if it was the root
   * of the first SWF file that was loaded by Flash Player.
   * Otherwise, it could be a top-level application but not stage root
   * if it was loaded by some other non-Flex shell or is sandboxed.
   */
   private var isStageRoot:Boolean = true;

   /**
   * Called when the bootstrap loader's SWF file has been loaded.
   * Starts loading the application SWF specified by the applicationURL
   * property.
   */
   private function onInit(event:Event):void {
      loader = new Loader();

       var loaderContext:LoaderContext  = new LoaderContext(
         false,
         new ApplicationDomain(ApplicationDomain.currentDomain),
         SecurityDomain.currentDomain
       );

      addChild(loader);
      loader.load(new URLRequest(applicationUrl), loaderContext );

      loader.addEventListener(
         "mx.managers.SystemManager.isBootstrapRoot",
         bootstrapRootHandler
      );
      loader.addEventListener(
         "mx.managers.SystemManager.isStageRoot",
         stageRootHandler
      );

      loader.addEventListener(Event.ADDED, resizeHandler );
      stage.addEventListener(Event.RESIZE, resizeHandler);
   }

   private function get applicationUrl():String{
      var qs:QueryString = new QueryString();
      return qs.root + qs.parameters.app;
   }

   private function bootstrapRootHandler(event:Event):void {
      event.preventDefault();
   }

   private function stageRootHandler(event:Event):void {
      if (!isStageRoot)
         event.preventDefault();
   }

   private function resizeHandler(event:Event=null):void {
      if ( loader.content ){
         Object(loader.content).setActualSize(stage.stageWidth, stage.stageHeight);
      }
   }
  }
}

To use the bootstrap loader, we copy PortalBootstrapLoader.html and PortalBootstrapLoader.swf to the deployment folder of the portal and, in the browser, type the URL, similar to:

http://localhost:8080/ApplicationLoaders/PortalBootstrapLoader.html?app=ApplicationLoaders/SameSandboxDifferentDomain.swf

As you can see from Figure 7-20, now the Google News panel of the portlet is filled by the data. Flex Messaging works because we made the definitions of the messaging classes visible to all application domains in the portal.

SameSandboxDifferentDomain with bootstrap class loading

Figure 7-20. SameSandboxDifferentDomain with bootstrap class loading

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.137.93