PureMVC Architects Lounge

PureMVC Manifold => MultiCore Version => Topic started by: ricardokirkner on June 03, 2008, 12:25:33



Title: loading modules dynamically
Post by: ricardokirkner on June 03, 2008, 12:25:33
Hi,

I am writing some code to load modules dynamically. Each module is implemented as a standalone application (meaning it has it's own Facade, Model, View and Controller). I am using (in my shell application)  a ModuleProxy, which loads and unloads modules. While they are loaded, the proxy keeps a reference in an ArrayCollection.

The strange thing is, I can load a module perfectly the first time, then unload it without any problems, and if I want to load it again afterwards, I get an error in the module's main mxml (which has the Module tag), saying that it "cannot access a property or method of a null object reference". This happens in the creationComplete event handler which looks like

<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
    verticalGap="0"
    horizontalGap="0"
    creationComplete="facade.startup(this);">
    <mx:Script>
        <![CDATA[
        import my.name.space.ApplicationFacade;
        public static const NAME:String = 'MyModule';
        protected var facade:ApplicationFacade = ApplicationFacade.getInstance(NAME);
        ]]>
    </mx:Script>
...
</mx:Module>

so that means, the null object reference is the facade object, right?

Now, what does this exactly mean? Why is it null the second time I try to load the module, but not the first time?


Title: Re: loading modules dynamically
Post by: puremvc on June 03, 2008, 04:57:49
I would have to see more of your code to know. How are you doing the loading and unloading?

-=Cliff>


Title: Re: loading modules dynamically
Post by: ricardokirkner on June 04, 2008, 06:53:09
ok Cliff,

the methods I am using belong to a ModuleProxy class.

data is an ArrayCollection.

-------------------------------------------------------------------------------------

        public function loadModule(module:ModuleVO):void
        {
            var index:Number = getLoaderIndex(module);
            if (index == -1)
            {
                var loader:ModuleLoader = new ModuleLoader();
                loader.url = module.url;
                loader.addEventListener(ModuleEvent.READY, onModuleLoaded);
                data.addItem(loader);
                loader.loadModule();
            }
        }

        private function getLoaderIndex(module:ModuleVO):Number
        {
            // find loader
            var index:Number = -1;
            var tmp:ModuleLoader;
            for (var i:Number = 0 ; i < loaders.length; i++)
            {
                tmp = loaders.getItemAt(i) as ModuleLoader;
                if (tmp.url == module.url)
                {
                    index = i;
                    break;
                }
            }

            // return index found
            return index;
        }

        public function unloadModule(module:ModuleVO):void
        {
            // find loader
            var index:Number = getLoaderIndex(module);
            // loader was found
            if (index != -1)
            {
                var loader:ModuleLoader = loaders.removeItemAt(index) as ModuleLoader;
                loader.addEventListener(ModuleEvent.UNLOAD, onModuleUnloaded);
                loader.addEventListener(ModuleEvent.ERROR, onModuleError);
                loader.unloadModule();
            }
        }

        private function onModuleLoaded(event:ModuleEvent):void
        {
            if (event.module)
            {
                sendNotification(ApplicationFacade.MODULE_LOADED);
            }
        }

        private function onModuleUnloaded(event:ModuleEvent):void
        {
            if (event.module)
            {
                sendNotification(ApplicationFacade.MODULE_UNLOADED);
            }
        }

        public function get loaders():ArrayCollection
        {
            return data as ArrayCollection;
        }
    }

--------------------------------------------------------------------------

the ModuleVO object, basically has an url, a name and a description.

I hope this code is enough for you to understand how it works. If it's not, then I can send you the whole source code as an attachment.

the items are getting correctly added and removed from the ArrayCollection.


Title: Re: loading modules dynamically
Post by: puremvc on June 04, 2008, 07:13:13
Have you tried setting a breakpoint on the creationComplete and step return the first time and step into the second in order to see where its failing?


Title: Re: loading modules dynamically
Post by: ricardokirkner on June 04, 2008, 07:16:28
no, I haven't, because I am not using FlexDeveloper, but just vim. Either way, that shouldn't work (I think), since according to the error message, the problem is that the facade object didn't get created at all, the second time. I will try to put a trace or Alert message in order to debug this.


Title: Re: loading modules dynamically
Post by: ghess on June 04, 2008, 05:30:09
I had this error too. I modeled the multicore demo app and altered it to work with modules.

When I debugged it I found that the method I was using to generate the multiton key was doing:

return MODULE_URI+this.id;

In my case this.id was null. I updated my impl to:

return MODULE_URI+this;

And the issue was resolved.

It seemed that 'this' was providing a unique Id. To be honest not sure of the impact with multicore, but as far as a unique id I seem to have one.


Title: Re: loading modules dynamically
Post by: puremvc on June 04, 2008, 10:19:30
Every module instance is a unique Core and therefore needs it's own set of MVCF actors. This requires a unique Multiton Key, which is what you discovered.

-=Cliff>


Title: Re: loading modules dynamically
Post by: c64 on June 10, 2008, 02:00:03
Also you can try loading module in ApplicationDomain.currentDomain (loaded in child domain by default causing the conflict).


Title: Re: loading modules dynamically
Post by: ricardokirkner on June 23, 2008, 12:35:25
just for the record..

the issue here was not calling facade.removeCore() before unloading the module (which generated the issues when re-loading the module).

anyway, all the answers where helpful and insightful, so thank you all

this is really a community with a great feeling about it . keep on!! :-)

ricardo