Monday July 23, 2007
Parsing the Command Line to Disable a Module
Yesterday we looked at how to disable a menu item, based on the presence/absence of an option on the command line. However, let's now go a whole step further and... disable a module based on something parsed from the command line. Let's assume we have a module that provides an Admin window, invoked from a menu item in the Help menu, as shown below:

Now, if anyone other than the admin user starts up the application, the window above, as well as the menu item that shows it, should not be there. So, unless the bit in bold below is present, the window and menu item above should be absent:
/bin/sh "/home/geertjan/netbeans-6.0m10/bin/netbeans" --name admin
Everything is the same as yesterday, i.e., create an OptionProcessor and register it in META-INF/services. At this point, you need to know about an XML file that conforms to the http://www.netbeans.org/dtds/module-status-1_0.dtd. Each installed module has such a file, written to the config/Modules folder in the application's user directory. This is how it looks for the module that installs the Admin window above:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//NetBeans//DTD Module Status 1.0//EN"
"http://www.netbeans.org/dtds/module-status-1_0.dtd">
<module name="org.netbeans.modules.adminwindowmodule">
<param name="autoload">false</param>
<param name="eager">false</param>
<param name="enabled">true</param>
<param name="jar">/home/geertjan/NetBeansProjects/
AdminWindowModule/build/cluster/modules/
org-netbeans-modules-adminwindowmodule.jar</param>
<param name="reloadable">true</param>
<param name="specversion">1.0</param>
</module>
I highlighted the 'enabled' parameter above because that's what we need to set to 'false', if the name set on the command line is not admin. How to do it? Regular readers of this blog will (or at least should) now immediately think "Hurray, we get to use the JAXB Wizard again!" Well, guess what? You're wrong. Initially I thought so too, until I learned about the brand new 6.0 API called Auto Update Services. Basically, this provides an abstraction layer on top of the Module XML file, so that you don't need to deal directly with JAXB, or some other XML parsing alternative. To give you a feel for it, here's my new implementation of the OptionProcessor.process method:
public void process(Env env, Map values) throws CommandException {
String[] args = (String[]) values.get(name );
//First check if the user specified 'admin',
//if NOT, continue with disabling the module:
if (args.length > 0 && !args[0].equals("admin")) {
//Get all the modules in the Plugin Manager:
List updateUnit = UpdateManager.getDefault().getUpdateUnits(UpdateManager.TYPE.MODULE);
for (int i = 0; i < updateUnit.size(); i++) {
//Get all the modules that are installed:
UpdateElement el = updateUnit.get(i).getInstalled();
//Of those that are installed, if it has the code name base
//of the module we are interested in, and it is enabled,
//continue with this procedure to disable it:
if (el != null && el.getCodeName().equals
("org.netbeans.modules.adminwindowmodule")
&& el.isEnabled()) {
try {
//Specify how we want to handle the module;
//here, we want to disable it:
OperationContainer oc = OperationContainer.createForDisable();
oc.add(el);
//Finally, do the operation,
//passing a progress handle or, as in this case, null:
OperationSupport supp = (OperationSupport) oc.getSupport();
supp.doOperation(null);
} catch (OperationException ex) {
Exceptions.printStackTrace(ex);
}
}
}
//Here, if the user DID specify 'admin',
//we do the same as the above, except that we enable
//the module if it is found to be disabled:
} else if(args[0].equals("admin")) {
List updateUnit = UpdateManager.getDefault().
getUpdateUnits(UpdateManager.TYPE.MODULE);
for (int i = 0; i < updateUnit.size(); i++) {
UpdateElement el = updateUnit.get(i).getInstalled();
if (el != null && el.getCodeName().equals
("org.netbeans.modules.adminwindowmodule")
&& !el.isEnabled()) {
try {
OperationContainer oc = OperationContainer.createForEnable();
oc.add(el);
OperationSupport supp = (OperationSupport) oc.getSupport();
supp.doOperation(null);
} catch (OperationException ex) {
Exceptions.printStackTrace(ex);
}
}
}
}
}
As a result of the above, the 'enabled' parameter is set to false, as shown below, whenever the user is not called admin:
<param name="enabled">false</param>
So now, without JAXB or any XML parsing whatsoever, I've changed one parameter in the Module XML file, based on something typed in the command line. Plus, the change is reflected immediately, i.e., the module is reinstalled. How cool is that? I think that's really exactly what I was looking for. No need to parse the XML directly. And no need to reinstall the module via some workaround after making the change. All that is handled by the aforementioned Auto Update Services API. Thanks a lot to the developers who helped me out with this today.
Jul 23 2007, 09:16:26 AM PDT Permalink


