Why in Mojito, renaming controller.server.js to controller.server-foo.js will have no effect? - node.js

In Mojito on top of Node.js, I followed the example on http://developer.yahoo.com/cocktails/mojito/docs/quickstart/
What I did was renaming controller.server.js to controller.server-foo.js, and created a new file controller.server.js to show "Hello World".
But when mojito is started, the old file controller.server-foo.js is being used and so the "Hello World" is not printed. How come Mojito will use the old file?
(I also tried renaming controller.server-foo.js to foo-controller.server.js and now the "Hello World" is printed, but why is controller.server-foo.js used?)

I found out that historically, the "affinity" of the controller can be two parts. The first part is common, server, or client, and the second part is optional, and it might be tests, or other words, so use other names such as controller-not-used-server.js to disable it.

#Charles, there are 3 registration processes in mojito (yes, it is confusing at first):
Affinity (server, client or common).
YUI.add when creating yui modules (controllers, models, binders, etc)
and the less common which is the registration by name (which includes soemthing that we call selectors)
In your case, by having two controllers, one of them with a custom selector named "foo", you are effectible putting in use the 3 registration at once. Here is what happen internally:
A controller is always detonated as "controller" filename from the mojit folder, which is part of the registration by name, and since you have "foo" selector for one of the controller, your mojit will have to modes, "default" and "foo". Which one of them will be use? depends on the application.json, where you can have some conditions to set the value of "selector", which by default is empty. If you set the value of selector to "foo" when, for example, device is an iphone, then that controller will be used when that condition matches.
Then the YUI.add plays an important role, it is the way we can identify which controller should be used, and its only requirement is that NO OTHER MODULE in the app can have the same YUI Module name, which means that your controllers can't be named the same when registering them thru YUI.add. And I'm sure this is what is happening in your case. If they both have the same name under YUI.add() one will always override the other, and you should probably see that in the logs as a warning, if not, feel free to open an issue thru github.
To summarize:
The names used when registering YUI modules have to be unique, in your case, you can use: YUI.add('MyMojit', function(){}) and YUI.add('MyMojitFoo', function(){}), for each controller.
Use the selector (e.g.: controller.server-mobile.js) to select which YUI module should be used for a particular request by setting selector to the proper value in application.json.

Related

Invoke a function when renaming node?

pretty straight forward Q, How do I invoke a function when the node is renamed?
I thought maybe _set() function would be invoked but it doesn't work for renaming
Setting the name from the editor bypasses _set(). You can use _set() for intercepting when you set the name from code.
Another option is to connect the "Renamed" signal (all Nodes have it).
You can connect as early as _init if you want it to happen before whatever code is instancing the Node has a chance to change its name.
However, this one only triggers if the Node is inside the scene tree.
And, finally, a way to detect changes of name regardless of how the change happens is to listen for the NOTIFICATION_PATH_CHANGED notification.
You get NOTIFICATION_PATH_CHANGED in _notification by default, no need to enable it or anything like that.
It even works when the Node is not in the scene tree, which I find surprising.
Even more surprising, it does not trigger when adding the Node to the scene tree, or removing it (those would be NOTIFICATION_ENTER_TREE and NOTIFICATION_EXIT_TREE respectively), despite those actions changing the path the node. So I believe NOTIFICATION_PATH_CHANGED is a misnomer, it should be "NOTIFICATION_NAME_CHANGED".

How to use the method named bindThread in StandardContext class?

Because I found the method named bindThread() is invoked multiple times at class named StandardContext in Tomcat 7 source code, especially in the method named startInternal(). I do not understand why need to call this method multiple times.
Actually the bindThread() is set the thread context classloader, but I don't konw why still use bindThread() and unbindThread() method pair in the startInternal() invoke multiple times.
Web application start and stop normally happens with the container class loader in effect. Some parts of the start (and stop) process (e.g. firing the application listeners) needs to take place with the web application class loader in effect. bindThread() and unbindThread() are the methods that switch to the web application class loader and back again respectively. The various elements of start and stop have to happen in a specific order so it is necessary to switch back and forth between class loaders.

boilerplate js sharing data between modules

I need a way to share information between modules - not only between components in the same module -.
I have common data to share between the different moduleContext.
-I tried using the application context (moduleContext.getParentContext().setSettings() or getSettings(), but each module context has a different moduleContext.getParentContext().
-I also tried creating a singleton object for the application, but even in this case the singleton data of the first module (landing page) are not available for the other modules.
-The third thing I tried is to pass data via notifications (notify / listen), with the same results.
Does anyone knows how to solve this problem?
Marcos
If you want to keep relationship between the module tree, it is necessary that you create your module hierarchy by calling:
parentContext.loadChildContexts(moduleContexts);
When this is done, that method ensures the 'event mediator' of child contexts is set to the exact same 'mediator' instance of the parent context. Then an event occurring at any of the modules will be notified to all the contexts in the same module tress.
It is the same for settings as well. When 'loadChildContexts' method is used, the settings of the parent context are 'copied' to child context settings.
If it still doesn't work for you, can you share your code to me? I may help you to find where the issue is.

Pattern for [lazy-loading] modules on demand

In my application I need to load modules not at the initialization stage (by enumerating them in ./modules/modules), but on demand later based on some condition (e.g. user authorization results). Imagine I want to provide User A with calculator module, and User B with text editor module.
Let's take boilerplatejs example app for simplicity, and assume that sampleModule1 and sampleModule2 are to be loaded on demand.
So I remove the modules from initial loading sequence in src\modules\modules.js:
return [
require('./baseModule/module'),
/*require('./sampleModule1/module'),
require('./sampleModule2/module')*/
];
and add a control to summary page (src\modules\baseModule\landingPage\view.html) to load them on-demand:
<div>
Congratulations! You are one step closer to creating your next large scale Javascript application!
</div>
<div>
<select id="ModuleLoader">
<option value="">Select module to load...</option>
<option value="./modules/sampleModule1/module">sampleModule1</option>
<option value="./modules/sampleModule2/module">sampleModule2</option>
</select>
</div>
Then I patch src\modules\baseModule\module.js to pass context to the LandingPageComponent (for some reason it doesn't in the original source code):
controller.addRoutes({
"/" : new LandingPageComponent(context)
});
and finally add the loading code to src\modules\baseModule\landingPage\component.js:
$('#ModuleLoader').on('change', function(){
require([this.value], function(mod){
moduleContext.loadChildContexts([mod]);
alert('Module enabled. Use can now use it.');
});
});
This appears to be working, but is this the best way to do it?
Does it handle context loading properly?
How to protect against loading the same module twice?
Smart thinking here.. I was too working on improving BoilerplateJS to lazy-load modules as plugins last few days. I did something similar, and u can access the POC code at:
https://github.com/hasith/boilerplatejs
In the POC I did, I'm trying to achieve 'lazy loading' + 'configurable ui' at the same time.
Each of the screen (called an application) is a collection of components (plugins) placed on to a layout. These application definitions are just a JSON object either dynamically returned from server API or statically defined as JSON files (as it is in the POC). In the POC, application definitions are stored at "/server/application".
These applications can be called dynamically by convention now. For example "/##/shipping-app" will look for an application definition with the same name at "/server/application".
Application loading happens via a new component I have at '/modules/baseModule/appShell'. Anything staring with '/##/' will be routed to this component and then it will try to load the application definition by convention from "/server/application" folder.
When the 'appShell' receives the application definition (as a JSON), it will try to load the components (plugins) that are defined in it dynamically too. These pluggable components are placed in 'src/plugins' and will be loaded by convention too.
Sample application definition will look like below:
{
"application-id" : "2434",
"application-name" : "Order Application",
"application-layout" : "dummy-layout.css",
"components" : [
{
"comp-name" : "OrderDetails",
"layout-position" : "top-middle"
},
{
"comp-name" : "ShippingDetails",
"layout-position" : "bottom-middle"
}
]
}
The benefit of the approach are as follows:
Applications interfaces are component driven and configurable at runtime
It is possible that different application definitions are sent to the user depending on the user role, etc (logic in backend)
Applications can be created on-the-fly by combining already existing components
There is no static code changes needed in the 'framework' either to add new applications or components since loading is based on convention
These are very initial thoughts around. Appreciate any feedback !
You can protect against multiple loading of modules by using named functions for the change event, and unbinding the function after executing it.

Is it secure to use a controller, module or action name to set include paths?

I want to set up include paths (and other paths, like view script paths) based on the module being accessed. Is this safe? If not, how could I safely set up include paths dynamically? I'm doing something like the code below (this is from a controller plugin.)
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) {
$modName = $request->getModuleName();
$modulePath = APP_PATH.'/modules/'.$modName.'/classes';
set_include_path(get_include_path().PATH_SEPARATOR.$modulePath);
}
I'm not sure whether it is safe or not, but it doesn't sound like the best practice. What if someone entered a module name like ../admin/? You should sanitize the module name before using it.
It's fine as long as you sanitize your variables before using them, but it won't be very performant. Fiddling with include paths at runtime causes a serious impact performance.
You're trying to load models/helpers per module? You should look at Zend_Application:
Zend_Application provides a bootstrapping facility for applications which provides reusable resources, common- and module-based bootstrap classes and dependency checking. It also takes care of setting up the PHP environment and introduces autoloading by default.
Emphasis by me

Resources