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.

Comments:

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 06:33 AM PDT #

Ah! Good point Tom, thanks!

Posted by Geertjan on April 11, 2008 at 06:38 AM 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 03:32 AM PDT #

Demetrios, right-click your application, choose "Build JNLP Application" or "Run JNLP Application".

Posted by Geertjan on April 13, 2008 at 05:06 AM PDT #

Gj,

I think it has huge scope! Login application is good to start with, however there could be many more things that can be achieved with this!

For instance, Features-on-Demand, I think this could make good use of the above functionality, you stated. Correct me, if I'm wrong!

Thanks!

Posted by Varun on June 27, 2008 at 03:01 AM PDT #

You're 100% right, Varun. This is exactly the functionality on which Feature on demand is based.

Posted by Geertjan on June 27, 2008 at 03:04 AM PDT #

Awesome, looking forward to it!

Posted by Varun on June 27, 2008 at 03:05 AM PDT #

Thanks for explanation!

can I also do this not durring the startup of the module?
if so, how can i refresh the table?

Posted by Tom schroeder on August 11, 2008 at 12:04 AM PDT #

Hi, I try it and I could make a new menu injecting a new layer.
Now I want to hide a menu item or menu folder declared by other module wich was loaded before.
I try to put into the layer the menu item name plus "_hidden" but I fail.

layer.xml in one module declares
<folder name="Menu">
<folder name="MyMenuFolder"/>
</folder>

custom layer injected after declares
<folder name="Menu>
<folder name="MyMenuFolder_hidden"/>
</folder>

wat's wrong in my logic?
I hide system menu folders like File and Edit by this mechanism (concatenate "_hidden") but can't hide folders declared by other modules

Posted by Jimena on January 23, 2009 at 02:04 AM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today