Friday Oct 10, 2008

Using the Layer to Set Customer-Specific Properties

Let's say you have one base application for all your customers. However, each customer has some user-specific settings that need to be distributed and installed in some way. Previously, i.e., in your pre NetBeans Platform days, you might have distributed an INI file (or some other config file) which was somehow read into the application to include the customizations.

But now you're working with the NetBeans Platform. Is there specific support for this scenario or should you go on using your INI approach? Here's where the System FileSystem comes in handy. Let's say we have two clients, called 'Red Station' and 'Blue Station'. For each of these, create a new NetBeans module. Don't add any code at all. Simply populate the layer.xml file of the 'Red Station' module with this content (or whatever content your original INI file used to have):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" 
"http://www.netbeans.org/dtds/filesystem-1_1.dtd">

<filesystem>

    <folder name="station">
        <attr name="name" stringvalue="Red Station"/>
        <attr name="welcomeText" stringvalue="Welcome to the Red Station!"/>
        <attr name="isHelpMenuIncluded" boolvalue="false"/>
        <attr name="isToolbarsIncluded" boolvalue="true"/>
    </folder>
   
</filesystem>

Then, in the 'Blue Station' module, populate the layer.xml file with this content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" 
"http://www.netbeans.org/dtds/filesystem-1_1.dtd">

<filesystem>
    
    <folder name="station">
        <attr name="name" stringvalue="Blue Station"/>
        <attr name="welcomeText" stringvalue="Welcome to the Blue Station!"/>
        <attr name="isHelpMenuIncluded" boolvalue="true"/>
        <attr name="isToolbarsIncluded" boolvalue="false"/>
    </folder>
    
</filesystem>

As you can see, we have set various properties—the name of the station, some welcome text, whether the Help menu should be displayed, and whether the toolbars should be displayed. You can set any attribute you like, i.e., those attributes could be anything at all, whatever you need, such as 'isSantaClausReal' or whatever. By the way, notice those attribute types, i.e., 'stringvalue' and 'boolvalue'. Those are fixed, i.e., there is a specific subset of types that can be used. How did I know what was available? First, I used code completion:

Secondly, look at the DTD, which is available on-line.

OK. So, now we've set our properties. They could be a whole range of different things. Then we distribute them to our users. Users at the 'Red Station' would get that particular module, while users at the 'Blue Station' would get the other one. Even though neither module contains any code at all, once the respective users install them, they'd get very different results (look at the title bar, tab text, text area, toolbars, and Help menu in the screenshots below):

How is that possible? In the base application (i.e., the application that all the users have), I have a TopComponent with all of this content in the constructor (though the code could be anywhere else too, but since it mostly relates to the TopComponent, I put all the code there):

private BaseTopComponent() {

    try {

        initComponents();

        //Get the root of the user directory:
        FileObject root = Repository.getDefault().getDefaultFileSystem().getRoot();

        //Get the station element:
        FileObject station = root.getFileObject("station");

        //Get the 'name' string attribute for the station:
        final String name = station.getAttribute("name").toString();

        //Get the 'welcome text' string attribute for the station:
        String welcomeText = station.getAttribute("welcomeText").toString();

        //Get the 'isHelpIncluded' boolean attribute for the station:
        final Boolean isHelpMenuIncluded = (Boolean) station.getAttribute("isHelpMenuIncluded");

        //Get the 'isToolbarsIncluded' boolean attribute for the station:
        final Boolean isToolbarsIncluded = (Boolean) station.getAttribute("isToolbarsIncluded");

        //Dynamically set the main window's title based on the 'name' above:
        WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
            public void run() {
                WindowManager.getDefault().getMainWindow().setTitle(name);
            }
        });

        //Also set the tab of the TopComponent to the 'name' value:
        setName(name);

        //Set the text area's content, using the 'welcome text' above:
        welcomeTextArea.setText(welcomeText.toString());

        //Hide the Help menu, using the boolean above:
        if (!isHelpMenuIncluded) {
            FileObject helpMenu = root.getFileObject("Menu/Help");
            if (helpMenu != null) {
                helpMenu.delete();
            }
        }

        //Hide the toolbars, using the boolean above:
        if (!isToolbarsIncluded) {
            FileObject toolbars = root.getFileObject("Toolbars");
            if (toolbars != null) {
                toolbars.delete();
            }
        }

    } catch (IOException ex) {
        Exceptions.printStackTrace(ex);
    }

}

This solution means that you need to be using the File System API, which provides the very powerful org.openide.filesystems.FileObject class that you see in action above. In effect, this API lets you very easily parse the layer.xml file, finding its elements and attributes and then converting them to strings, booleans, and so on. Another approach would be to use the NbPreferences class. However, in that case you'd be using properties files. That's less powerful than an XML file, because you simply have key/value pairs, instead of the hierarchical folder/file and element/attribute structure that the layer.xml file implies. I will blog about this second approach soon, at which point the disadvantages will become very clear, especially when compared to the above.

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
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today