Geertjan's Blog

Using the Layer to Set Customer-Specific Properties

Geertjan Wielenga
Product Manager
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"
<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"/>

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"
<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"/>

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() {
});//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) {
}//Hide the toolbars, using the boolean above:
if (!isToolbarsIncluded) {
FileObject toolbars = root.getFileObject("Toolbars");
if (toolbars != null) {
} catch (IOException 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.

Join the discussion

Comments ( 4 )
  • guest Friday, October 10, 2008


    thanks a lot.

  • Vincent Cantin Monday, October 13, 2008

    Really useful to know.

    Thank you.

  • Matthew Thursday, October 16, 2008

    thank u r information

    it very useful

  • Daniel Felix Ferber Monday, July 13, 2015

    Interesting. But I would like to hear how you passed the proper layer.xml to the application. Bundling the layer.xml into the application requires one compilation for each client. I documented on my blog how to pass an external layer.xml as parameter to the application.

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.