Friday April 11, 2008
Injecting a Layer File into a NetBeans Platform Application
I tried the How to change menus, etc. after login? scenario today: "Since version 7.1 there is a way to change the content of system file system in a dynamic way. As system file systems contains various definitions (in NetBeans Platform menus, toolbars, layout of windows, etc.) it de-facto allows global change to these settings for example when user logs into some system."
The outline of what you need to do is described there, nothing I can really add. It is one new and cool way in which one module can contribute to an application. You start by creating a new module, add the XML layer defining the items you want to register in the system, then implement FileSystem, and export it to META-INF/services.
One scenario is that of a user logging into an application. On successful login, the layer file is injected and whatever is defined in the layer file is added to the application. I added a small touch—whatever the user sets as their user name determines the text in a new menu item that is added via the injected layer file. That's possible via the NbPreferences class, which can store preferences in the application's user directory.
Here's the whole module:
In the Installer, the login dialog is shown (as described elsewhere in this blog):
package org.yourorghere.addedsfs;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JButton;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.modules.ModuleInstall;
import org.openide.util.Exceptions;
import org.openide.util.NbPreferences;
import org.xml.sax.SAXException;
public class Installer extends ModuleInstall {
JButton ok = new JButton();
JButton cancel = new JButton();
NotifyDescriptor.InputLine msg;
public Installer() {
ok.addActionListener(new OkActionListener());
}
private class OkActionListener implements ActionListener {
//In real life, you'd have some login validation here!
public void actionPerformed(ActionEvent e) {
try {
//Create a preference "USER_KEY", with value set to the input text:
NbPreferences.forModule(Installer.class).put("USER_KEY", msg.getInputText());
//Specify the XML file that defines the layer you want to inject:
URL u = new URL("nbresloc:/org/yourorghere/addedsfs/newLayer.xml");
//Pass the URL to the LoginFileSystem:
LoginFileSystem.assignURL(u);
} catch (SAXException ex) {
Exceptions.printStackTrace(ex);
} catch (MalformedURLException ex) {
Exceptions.printStackTrace(ex);
}
}
}
@Override
public void restored() {
ok.setText("OK");
cancel.setText("Cancel");
msg = new NotifyDescriptor.InputLine("Login:", "User name: ",
NotifyDescriptor.OK_CANCEL_OPTION, NotifyDescriptor.QUESTION_MESSAGE);
msg.setOptions(new Object[]{ok, cancel});
DialogDisplayer.getDefault().notifyLater(msg);
}
}
And here's the LoginFileSystem (which is called by means of LoginFileSystem.assignURL(u) above):
package org.yourorghere.addedsfs;
import java.net.URL;
import org.openide.filesystems.MultiFileSystem;
import org.openide.filesystems.XMLFileSystem;
import org.xml.sax.SAXException;
public class LoginFileSystem extends MultiFileSystem {
private static LoginFileSystem INSTANCE;
public LoginFileSystem() {
// let's create the filesystem empty, because the user
// is not yet logged in
INSTANCE = this;
}
public static void assignURL(URL u) throws SAXException {
// Alternatively:
// Lookup lookup = Lookup.getDefault();
// LoginFileSystem INSTANCE = lookup.lookup(LoginFileSystem.class);
INSTANCE.setDelegates(new XMLFileSystem(u));
}
}
So then the URL that points to the newLayer.xml is used to create a new XMLFileSystem. The above class should be exported to META-INF/services, following the JDK 6 java.util.ServiceLoader approach.
And what about the preference that the user entered? Here you see the definition of the TestAction.getName method:
public String getName() {
Preferences pref = NbPreferences.forModule(TestAction.class);
String name = pref.get("USER_KEY", "");
return NbBundle.getMessage(TestAction.class, "CTL_TestAction") + name + "!";
}
So first some text (like "Hello") is retrieved from the bundle file, appended with the name that the user entered, appended with an exclamation mark. And the above menu item only appears if the login succeeds, which you'd need to make possible via hooking up your database of users to the module so that whatever the user enters can be verified against your database.
In other news. What technology evangelists really do for a living.
Apr 11 2008, 10:52:00 AM PDT Permalink
Just in case it's not clear to readers, the "version 7.1" mentioned in the first sentence refers to the version of the FileSystems API included in NetBeans 6.1. There is not yet a version 7.1 of the NetBeans IDE or Platform.
Posted by Tom Wheelerr on April 11, 2008 at 01:33 PM PDT #
Ah! Good point Tom, thanks!
Posted by Geertjan on April 11, 2008 at 01:38 PM PDT #
Hi Geertjan,
Sorry for beeing offtopic (but you are the most known NB expert :) ):
Is there a simple way to transform a Netbeans Platform based application into a JavaWebStart one?
I mean I know how to make a javawebstart application (the process with signing and all those steps is not quite simple), but I don't know
how to bring a NBplatform based to be one and to work without problems under the restricted conditions of the javawebstart.
I saw in your articles hints about how to brand and also very important how to loose weight for a NBplatform application, so I thought maybe you have some ideas/hints about how to make it "webstartable" too.
Thank you,
Demetrios.
Posted by Demetrios Kyriakis on April 12, 2008 at 10:32 AM PDT #
Demetrios, right-click your application, choose "Build JNLP Application" or "Run JNLP Application".
Posted by Geertjan on April 13, 2008 at 12:06 PM PDT #


