On Wed, Nov 4, 2009 at 6:21 PM, Nicklas Widlund Bjurman <lordmetroid@gmail.com> wrote:
I am writing an appmod that processes requests in order to execute an
appropriate action.

<server localhost>
   port = 8080
   listen = 0.0.0.0
   docroot = /home/dev/hp
   appmods = </, conductor>
</server>

the conductor appmod takes foo and bar from a request such as
"localhost:8080/foo/bar", loads the foo module from an applications
directory in docroot and calls the function bar if there exists a
module foo with a function bar in the applications directory.

However I don't want any modules to crash into other virtualhost's
modules if they happen to have the same name is there a way to load a
module in such a manner that they will not interfere?

If you're using R13, note that you can compile a module with the no_error_module_mismatch option to allow the module to have a different name than its filename (see http://erlang.org/doc/man/compile.html). Maybe you could use that option via the compile module to compile the files on the fly and assign them unique module names based on now() or some combination of the URI path plus the virtual server name?

Alternatively, if you can guarantee your compiled modules contain debug info, you can get the same effect as no_error_module_mismatch with a little more work. First, get the object code of the module:

{_Mod,Beam,_File} = code:get_object_code(foo),

Next, extract the abstract code from it (this is why you need to have compiled the module with +debug_info):

{ok,{_,[{abstract_code,{_,Forms}}]}} = beam_lib:chunks(Beam,[abstract_code]),

Now change the module name in the abstract code:

{value,{attribute,Line,module,foo}} = lists:keysearch(module,3,Forms),
NewModuleName = newfoo,
Forms2 = lists:keyreplace(module,3,Forms,{attribute,Line,module,NewModuleName}),

Then compile the new abstract code and load it:

{ok,NewModuleName,NewBeam,_} = compile:forms(Forms2, [return]),
NewFile = atom_to_list(NewModuleName) ++ ".erl",
{module, NewModuleName} = code:load_binary(NewModuleName, NewFile, NewBeam).

You can then call functions in this newly-loaded module via NewModuleName. You probably want to keep a per-virtual-server map somewhere of the original module name taken from the URI to the name under which you loaded the module.

The accuracy of the NewFile name isn't important; see the code man page.

Note that if the code in question has any references to itself, they'll still try to call the original module and so they won't work the way you want them to, though I suppose with some more pawing around in the abstract code you could find and patch those too. The approach shown here replaces only the module name but doesn't patch up any other module self-references.

--steve