// 
//     Licensed to the Apache Software Foundation (ASF) under one
//     or more contributor license agreements.  See the NOTICE file
//     distributed with this work for additional information
//     regarding copyright ownership.  The ASF licenses this file
//     to you under the Apache License, Version 2.0 (the
//     "License"); you may not use this file except in compliance
//     with the License.  You may obtain a copy of the License at
// 
//       http://www.apache.org/licenses/LICENSE-2.0
// 
//     Unless required by applicable law or agreed to in writing,
//     software distributed under the License is distributed on an
//     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//     KIND, either express or implied.  See the License for the
//     specific language governing permissions and limitations
//     under the License.
//

= DevFaqDynamicSystemFilesystem
:jbake-type: wiki
:jbake-tags: wiki, devfaq, needsreview
:jbake-status: published

== Can I dynamically change the contents of the System Filesystem at runtime?

Yes.  This technique is commonly used in platform applications which require the user to log in, to keep menu contents/toolbar actions/keyboard shortcuts/window definitions hidden until the user is authenticated.

There are two ways to do it.  The most obvious way is to programmatically write files to disk at runtime (call `FileUtil.getConfigRoot().createFolder()`, etc.).  This technique is appropriate if you are creating files which should be preserved across restarts (for example, adding folders to the Favorites window).  _It is completely inappropriate in the case of authentication, or any other case where you do not want the added files to be present after restart. You cannot depend on the application always being shut down normally and having a chance to clean such files up - since they are actually written to disk._

=== Using Dynamically Added Layers

The alternative is quite simple:  Write a subclass of `link:http://bits.netbeans.org/dev/javadoc/org-openide-filesystems/org/openide/filesystems/MultiFileSystem.html[MultiFileSystem]`.  Put it in the link:DevFaqLookupDefault.html[default lookup].

At runtime, when you want to add contents to the system filesystem, simply add additional filesystems to your `MultiFileSystem`.  To remove the contents, simply remove those filesystems.

A convenient way to do this is to use XMLFileSystem - this is a filesystem created with exactly the same syntax as normal module XML layer files (see link:DevFaqModulesLayerFile.html[DevFaqModulesLayerFile]). The following code loads an XML filesystem, which is in an XML file in the same package as the class, called `dynamicContent.xml`:

[source,java]
----

@ServiceProvider(service=FileSystem.class)
public class DynamicLayerContent extends MultiFileSystem {
    private static DynamicLayerContent INSTANCE;
    public DynamicLayerContent() {
        // will be created on startup, exactly once
        INSTANCE = this;
        setPropagateMasks(true); // permit *_hidden masks to be used
    }
    static boolean hasContent() {
        return INSTANCE.getDelegates().length &amp;gt; 0;
    }
    static void enable() {
        if (!hasContent()) {
            try {
                INSTANCE.setDelegates(new XMLFileSystem(
                        DynamicLayerContent.class.getResource(
                        "dynamicContent.xml")));
            } catch (SAXException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
    }
    static void disable() {
        INSTANCE.setDelegates();
    }
}
----

In NetBeans 7.2 and later, the above code can be simplified by using `Repository.LayerProvider`. See its Javadoc for a usage example.

If finer grained control of what is added is needed at runtime, there are two possibilities, using this general approach:

* If the new layer contents are fixed and known, but perhaps correspond to user roles which may be overlaid together, split up the functionality for each role into a separate XML file (hint: define an enum of roles, where each role can point to an XML file URL, use `link:http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumSet.html#of%28E,%20E...%29[EnumSet.of()]` and process that to decide what to enable)
* Write contents programmatically, but write folders/files to an in-memory filesystem created using `link:http://bits.netbeans.org/dev/javadoc/org-openide-filesystems/org/openide/filesystems/FileUtil.html#createMemoryFileSystem()[FileUtil.createMemoryFileSystem()]` so the contents disappear on VM exit

link:https://bitbucket.org/jglick/dynamicmenudemo/[https://bitbucket.org/jglick/dynamicmenudemo/] tries to automate this kind of task.

=== Apache Migration Information

The content in this page was kindly donated by Oracle Corp. to the
Apache Software Foundation.

This page was exported from link:http://wiki.netbeans.org/DevFaqDynamicSystemFilesystem[http://wiki.netbeans.org/DevFaqDynamicSystemFilesystem] , 
that was last modified by NetBeans user Jglick 
on 2012-04-10T00:02:19Z.


*NOTE:* This document was automatically converted to the AsciiDoc format on 2018-01-10, and needs to be reviewed.
