Dynamic loading in Rich UI

Instead of deploying all the Rich UI handlers into a single HTML file, you can control the downloading of Rich UI handler code at run time. For large applications, you gain significant advantage in scalability and performance. Dynamic loading is not supported in version .7.

Each dynamic load is asynchronous. You code listener functions to respond when the load completes, and until the load completes, the user continues to interact with the web page.

By way of background, consider that one handler can refer to another handler in either of two ways:
If you want to ensure that a handler is loaded from the application server only at run time, do as follows:

If you specify a type reference and do not configure the EGL deployment descriptor for dynamic loading, the type reference causes the referenced handler to be included in the immediately downloaded code.

As noted in a later code example, a type reference is necessary if your code directly accesses fields or functions in the dynamically loaded handler. However, a type reference is not necessary if your code accesses only the widget array assigned to the initialUI field of the dynamically loaded handler.

Dynamic loads are handled at run time by an EGL dedicated service named ModuleLoaderService. Do not change this service, which deals with internal details that might change in future versions of the product.

Additional details are in the following sections:

For a sample use of the dynamic loader, see “EGL Dojo widgets”; and, in particular, the GalleryDynamicLoading.egl file there.

DynamicLoader functions

The DynamicLoader library has the following functions, along with listener functions (described later) that respond to your invocation:
  • loadHandler (handlerName String in)

    This function loads a handler.

    handlerName
    Fully qualified name of the handler to load dynamically, as in the example shown earlier.
  • loadHandlerNoInstantiation (handlerName String in)

    This function loads the handler type definition but not a handler instance. You might use this function for better runtime performance. For example, you might want a handler type to be available in your application but to create the handler itself only if the user clicks a menu item that requires the handler.

    handlerName
    Fully qualified name of the handler to load dynamically.
  • unloadHandler (handlerName String in)

    This function unloads a handler but does not destroy the instances of that handler. You cannot unload EGL libraries, which are available until an application ends.

    A handler instance cannot be removed from memory if either of the following statements is true:
    • The handler is referenced by type in another handler that is not being removed from memory.
    • The handler is subscribed to the Infobus, as described in “Rich UI Infobus.”

    In most cases, memory is freed by the EGL runtime code. However, the following topic describes a case in which you are in greater control of memory management: “Rich UI memory management for Microsoft™ Internet Explorer.”

    handlerName
    Fully qualified name of the handler to unload.
  • showDebugView()

    This function ensures that details are displayed to show what is happening inside the dynamic loader. You might set this in the on-construction function of your main handler.

DynamicLoader listener arrays

The DynamicLoader library provides a mechanism by which you code listeners in accordance with a Delegate part and then assign those listeners to an array and in this way respond to events at run time. Here is an example use:
function start()
   // Set handler for the event that the page has been loaded
   DynamicLoader.loadDoneListeners ::= processLoadDone;

   DynamicLoader.loadHandler("myPkg.Secondary");
end

function processLoadDone (event HandlerLoadedEvent in)
   
   // attach the initialUI widgets to the current page.
   // this step does not require use of a type reference.
   div.children = event.initialUI;

   // access a function in the loaded handler
   theHandler any = event.theHandler;

   // the use of a handler (or other container) of type any requires
   // a type reference so that your code can directly access a field 
   // or function that is embedded in that container
   if (theHandler isa Secondary)
      p1 Page1 = theHandler as Secondary;
      p1.doTask();
   end
end
Here is the HandlerLoadedEvent Record part, which identifies what is available from the event parameter for processLoadDone:
record HandlerLoadedEvent

   // The name of the handler
   name String;

   // The widgets defined by the Rich UI handler.
   initialUI Widget[];

   // A reference to the Rich UI handler
   theHandler any;
end
Here are the listeners and related Delegate parts that are provided by the DynamicLoader library:
  • DynamicLoader.loadDoneListeners
    This array specifies a set of listeners that are invoked after the handler is loaded. The delegate part is here:
    delegate
       LoadDoneListener (event HandlerLoadedEvent in)
    end
    event
    As shown earlier. However, if a listener is running in response to your having invoked the loadHandlerNoInstantiation function, the initialUI parameter receives an empty array, and the theHandler parameter receives a null.
  • DynamicLoader.loadFailListeners
    This array specifies a set of listeners that are invoked if the load fails. The delegate part is here:
    delegate
       LoadFailListener (handlerName string in, msg string in) 
    end
    handlerName
    The fully qualified name of the handler that failed to load.
    msg
    An error message.
    Here is an example:
    function start()
       DynamicLoader.loadFailListeners ::= processLoadFail;
       DynamicLoader.loadHandler("myPkg.Secondary");
    end    
    
    Function processLoadFail (handlerName string in, msg string in)    
       Syslib.writeStdErr(handlerName + “ failed to load. ” + msg);
    end
  • DynamicLoader.loadInfoListeners
    This array specifies a set of listeners that are invoked from the dynamic loader and are used for tracing download and unload behavior at run time. The set is invoked once for every downloaded or unloaded resource, which might be any of the following units:
    • Parts: 
      • Rich UI handlers
      • Basic handlers
      • Widgets
      • Libraries, including Rich UI properties libraries
      • Records
    • Other resources:
      • JavaScript™ include files, whether globally defined or referenced in an external type
      • Properties files related to a Rich UI properties library
      • Service-binding files related to an EGL deployment descriptor
    The delegate part is here:
    delegate
       LoadInfoListener (handlerName string, resourceName string, 
                         code string, msg string)
    end
    handlerName
    The fully qualified name of the handler that was passed to a load or unload function.
    resourceName
    The name of a downloaded or unloaded resource.
    code
    One of the following codes, each of which identifies a type of information:
    • DynamicLoader.INFO_LOAD indicates that the resource was loaded.
    • DynamicLoader.INFO_UNLOAD indicates that the resource was unloaded.
    • DynamicLoader.INFO_UNLOAD_SKIP indicates that the resource was not unloaded; for example, because the resource was a library.
    • DynamicLoader.INFO_DEBUG is a generic message from the dynamic loader.
    msg
    A message.
    Here is an example:
    function start()
       DynamicLoader.loadInfoListeners ::= processLoadInfo;
       DynamicLoader.loadHandler("myPkg.Secondary");
    end
    
    function processLoadInfo (handlerName string, 
       resourceName string, code string, msg string)
       if (code == DynamicLoader.INFO_UNLOAD)
          Syslib.writeStdErr(resourceName + “ unloaded.”);
       end
    end

Handler instances

You can create new instances of a handler after the handler is loaded, as shown here:
function createPage1() returns (Secondary)
   anotherPage1 Secondary = new Secondary{};
   return(anotherPage1);
end  
Do not try to create a new instance before the handler is loaded. Here is an example:
handler MainHandler type RUIhandler {onConstructionFunction = start }

   // error!
   anotherPage1 Page1 = new Secondary{};   
end

Considerations for using CSS files at run time

When the EGL deployer creates the HTML file for a handler, the file includes a list of all the CSS files that are used in the Rich UI application. CSS files are not loaded dynamically.

The order of priority for the CSS definitions is as follows:
  • At the highest level are the definitions in the topmost handler.
  • Next are the definitions in the other handlers that are in the HTML file.
  • At the lowest level are the definitions in the handlers that are loaded dynamically.

Considerations for using the Preview pane of the Rich UI editor

When you run a handler in the Preview pane of the Rich UI editor, the following rules apply:
  • The workbench builds an HTML file that includes all resources that are referenced by type in the handler being edited, or are referenced by type in a handler that is referenced by one of those second-level handlers, and so forth, to any level of reference.
  • The only handlers that are loaded dynamically are those that are identified by string and not by type reference.
For the handlers that are loaded dynamically in the Preview pane, the following considerations apply:
  • The CSS and include files that are specified in the dynamically loaded handlers are not available to the Preview pane. You must reference those files from the handler being edited or from a handler that is directly or indirectly loaded by type reference from the handler that you are editing.
  • You need to handle JavaScript runtime files, even if you would not otherwise reference them. For example, if Handler A does not use EGL Dojo widgets and refers to Handler B only by string, and if Handler B uses EGL Dojo widgets, you must set the includeFile field of Handler A to reference the Dojo runtime code, as shown here:
    { includeFile = "config/includeDojo.html" }