Geertjan is a DZone Zone Leader and has posted 459 posts at DZone. You can read more from them at their website. View Full User Profile

Video: Part 4 of an Introduction to the NetBeans APIs

11.06.2008
| 16248 views |
  • submit to reddit

Welcome to part 4 of the 'Top 10 NetBeans APIs' screencast series. Assuming you've watched the previous three parts, you'll have sufficient background to watch this one:

Download for off-line viewing here.

 

Rough Transcript

The screencast begins by talking about what a filesystem is generically and then in the context of the NetBeans Platform. Once it is clear why you might want to use it, we look at how to incorporate it into your own NetBeans Platform application. Next, we look at how the filesystem can be changed and how the changes can be accessed and used. We also look at the tools that you can use in this context and we finish off with several concrete examples of things you might want to store in a NetBeans Platform application's filesystem.

What is a filesystem, generally?

A file system, generically, is a place where you can store, organize, and retrieve folders, files, and data. For example, filesystems are an integral part of operating systems. Whenever you install an application, the application's installer puts the application's launcher in a particular folder, with the related libraries being put somewhere else, and so on. Managing the applications installed on your computer is fairly trivial with a filesystem that presents a hierarchical view on top of everything that's available to you.

How does that apply to NetBeans Platform?

Now imagine an application that itself has a filesystem. That would make sense if the application were to be modular. In the same was as installing an application on your computer results in folders and files being created in your operating system's filesystem, so installing a module into your modular applications results in folders and files being created in your application's filesystem.

Modules do not have to install something to the filesystem: they only do so when it makes sense to do so. And the reasons why it might make sense to do so varies. For example, if you want your module to contribute new menu items to the application's menu bar, you'll need your module to add files to a folder called 'Menu', which is defined by the NetBeans Platform module that constructs the menu bar. That module picks up whatever is in the 'Menu' folder and adds it to the menu bar. In other words, the filesystem provides a mechanism in which modules can communicate with each other.

But you can do a lot more with your application's filesystem, as you'll find out during the rest of this screencast.

How do you include the filesystem in your own application?

Now that you have a general flavor of how a filesystem might be useful to your application, let's look at how to get started with it. In other words, what do you need to do to include a filesystem into your application? The answer is: Nothing. Remember the 'runtime container', which is the collective name for the 5 mandatory modules that every NetBeans Platform application must have? Well, as you can see, one of the 5 mandatory modules is the FileSystem API. Hence, every single NetBeans Platform application is able to make use of the NetBeans Platform's filesystem.

How do you contribute to the filesystem?

So, at this point we're aware that a NetBeans Platform application has a filesystem and that modules can contribute folders and files to it. So, the next question is, how does it do that? It does that by means of a small XML file that each module can have. Modules do not HAVE to have this file, but they can't have more than one of these. This file goes by various names. Its physical name is 'layer.xml' file. Some people refer to it as 'the layer file', others as 'the layer', and still others as 'the module configuration file'.

How do you create one of these layer files?

The next question is: How do you create one of these layer files? Well, whenever you create a new module, the Module Project template prompts you to create the layer file.

DEMO

If you choose not to create it, then it will be created when you use one of the file templates that generates stubs for an API that requires usage of the layer. So, for example, when you use the New Action wizard to create a new menu item, the wizard will create a layer file if it doesn't already exist, because the New Action wizard needs to add new folders and files to it in order to register the menu item.

DEMO

Finally, note that if you use the Groovy script to create the module, the layer file is automatically created.

DEMO

How do the contributions find their way into the filesystem?

So, potentially, you'll end up with an application containing many modules, several (or all) of them including a layer file. How do these layer files end up contributing to the filesystem? Well, when the NetBeans Platform starts up, the runtime container assembles the modules that make up the application and finds all the layer files in each of these modules. It then merges all these layer files together. The application then opens, with the results of the merge being made available to the application. So, for example, all files registered within the Menu folder are resolved into the menu bar.

In addition, the runtime container writes a user directory to disk, allowing the user to customize what the modules have made available via their layer files. For example, one module will have provided the default colors for syntax in the NetBeans IDE's Java editor. When the user goes to the Options window and changes the default colors, those changes are saved in the user directory and restored when the application restarts, overriding the colors provided by the layer of the module that defines the relevant syntax colors.

DEMO

What tools are available to help me with all of this?

Firstly, as pointed out earlier, a module's layer file can be created automatically for you. You will never actually need to create it yourself manually.

Secondly, whenever you use one of the file wizards that relate to module development, if the code that the wizard generates is required to be registered in the layer file, the wizard will do this for you automatically. So, for most of the common APIs that you implement, such as the TopComponent class, and the Action classes, you won't need to create folders and files yourself manually -- because the file template will do this for you.

Thirdly, you can expand the layer file inside the module in the IDE, and then you can see everything within it, as well as everything provided by all the layer files in all the other modules that are part of your application. Then you have menu items on these nodes, which help you to localize the text, add an icon, or delete the item. So in your own module you can delete a menu item provided by another module.

Finally, you can learn from other folders that you want to contribute to, and you can even copy bits from other layers into your own. For example, let's say we want to add a menu item to the right-click contextual menu of Properties files. One way of learning how to do that is to investigate inside the layer file. You can expand the layer file, find the folders that declare how a Properties file is loaded and then open that layer file, in read-only mode, and look at the declarations of the other files that have been contributed to the right-click contextual menu of Properties files. Let's do that now.

DEMO

Let's quickly recap on one point. When we expand the layer.xml file and see the folder 'this layer in context', we are able to see all the folders and files contributed by all the other modules that are part of the application that this module is also part of. But a question to ask is: What determines the names and contents of these folders? You can see there is no standard content. There's an 'Actions' folder and a 'Menu' folder and a 'Loaders' folder and so on. Again, what determines these folders? The answer to this question is: The implementation of whatever API that is applicable. So, for example, the Menu folder, and its content, is prescribed by the implementation of the API that you'd like to extend in order to contribute to the menubar. That API's implementation defines a folder called 'Menu' and, again within that implementation, determines what happens to the files that are registered within that Menu folder.

So, then the question becomes, how on earth are you meant to figure out which folders to use in a particular case, since each particular case is different? Well, firstly, when you use a file template for the most common APIs, such as those relating to the window system and the actions system, then the file template takes care of this for you and you do not need to even think about the content of the layer file. Secondly, however, the Javadoc (and tutorials) explain the required layer entries necessary for complying with a particular API. So when you want to contribute to the menubar, you'd read the relevant tutorial and Javadoc, where you'd be informed about what needs to be entered into the layer file.

Next, once something is in the filesystem, is there a way of accessing things in a generic programmatic way?

Yes. You can use the FileSystem API if you want to interact programmatically with your application's filesystem.

DEMO

FileObject root = Repository.getDefault().getDefaultFileSystem().getRoot();

FileObject dir = root.getFileObject("Menu");

FileObject[] kids = dir.getChildren();

for (int i = 0; i < kids.length; i++) {
    FileObject fileObject = kids[i];
    String name = fileObject.getName();
    JOptionPane.showMessageDialog(null, name);
}

What's a FileObject?

FileObjects are NetBeans wrappers around java.io.File. When you use the NetBeans Platform, you will rarely use java.io.File directly. And you won't want to either since FileObjects are much more powerful, providing far greater functionality than java.io.File.

DEMO
public void fileObjectTest() {
    try {
        //Easy to convert to/from:
        FileObject fo = FileUtil.toFileObject(new File("myfile.txt"));
        //FileObjects have an input & outputstream:
        InputStream inStream = fo.getInputStream();
        //FileObjects have a MIME type:
        String mimeType = fo.getMIMEType();
        //You can get an attribute:
        Object attr = fo.getAttribute("bla");
        //Can delete them too:
        fo.delete();
    } catch (IOException ex) {
        Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
    }
}
DEMO
fo.addFileChangeListener(new FileChangeListener() {

    public void fileFolderCreated(FileEvent arg0) {
    }

    public void fileDataCreated(FileEvent arg0) {
    }

    public void fileChanged(FileEvent arg0) {
    }

    public void fileDeleted(FileEvent arg0) {
    }

    public void fileRenamed(FileRenameEvent arg0) {
    }

    public void fileAttributeChanged(FileAttributeEvent arg0) {
    }
});


So, what did this demo show you? It showed you that one module can register folders and files in the layer file that another module can use, such as, in this simple case, to set the title in the title bar.

What kind of things can be stored in the filesystem?

There are many other things you can do with the filesystem. For example, instead of using META-INF/services to register your serviceprovider, you can register it in the layer file. Secondly, as pointed out, many contributions to the user interface of a NetBeans Platform application are registered via the layer file, based on the requirements of the API in question, as specified in the Javadoc. Thirdly, many supporting artifacts, such as images, JavaHelp, URLs, and PDF documents can also be registered there very simply and effectively.

Here is an overview of some things you can do with it:

  • User interface contributions
  • Images
  • JavaHelp documentation

But what if I don't like working with XML files?

Then you're not alone because I don't always like working with XML files either. In the 7.0 release of the NetBeans Platform, you can expect to see annotations being used as an alternative to (parts of) the layer.xml file. During development time, you will use annotations. When the module is compiled, a layer file will be generated from those annotations. One example that you can already play with is the ServiceProvider annotation, which is an annotation that you can use instead of the META-INF/services registration mechanism and also instead of the layer.xml registration mechanism for service providers.

Are there other implementations of the filesystem?

Yes, you can use a memory filesystem. When you do this, you're writing folders and files to memory instead of to disk.

FileSystem fs = FileUtil.createMemoryFileSystem();
FileObject fob = fs.getRoot().createData("demo","txt");

Above, we have created a file in memory. Later, you might want to save it to disk, but for the moment you have a file available that you can get back from the MemoryFileSystem.

But what about the Lookup API? Didn't you say last time that that's how modules communicate?

Yes. The Lookup API lets one module add objects to the context of another module, or another module's window component, or to other NetBeans-specific components, such as Nodes and DataObjects, (of which the latter two we haven't dealt with yet in this screencast series). The Lookup API can also be used to add folders and files to the context of these components, by means of "Lookups.forPath", like this (where 'MessageProviders' is the folder within the filesystem tags where the service providers are registered):

Lookup lkp = Lookups.forPath("MessageProviders");

for (MessageInterface it : lkp.lookupAll(MessageInterface.class)) {
jTextArea1.append(it.getMessage());
}

So, the NetBeans Platform offers you two ways to provide communication between modules. Which one you choose is up to you, you can use one approach in one case and another in another. Also, the type of communication is different. When you're using the filesystem, you can simply register items that are then used by another module in some way, whereas the Lookup approach is usually concerned with 'selection management' or 'context sensitivity', i.e., the enabling and disabling of ui elements.

Summary

You can place a wide range of items in your application's filesystem. The extent to which you make use of this NetBeans Platform feature is up to you. You will probably find some use for it, since it is clearly pretty versatile and relatively intuitive. Experimentation with it, using some of the approaches outlined above, is likely the best approach to discovering its usefulness in your particular context.

Published at DZone with permission of its author, Geertjan Wielenga.
Tags:

Comments

smith hou replied on Sat, 2009/09/19 - 9:32am

Normal 0 7.8 磅 0 2 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

Good,I like this.

Nobody can ignore the existence of <a href="http://www.christianlouboutins.de">Christian Louboutin</a> shoes in the fashion world. And what makes <a href="http://www.christianlouboutins.de">Christian Louboutin boots</a> so remarkable? Its exquisite quality, fine craftsmanship, sexy high heels, quirky designs and of course the red outsole known as the symbol of <a href="http://www.christianlouboutins.de">Christian Louboutin boots</a>.
<a href="http://www.christianlouboutins.de">Louboutin</a>

Scott Palmer replied on Thu, 2011/05/05 - 12:06pm

Repository.getDefault().getDefaultFileSystem()  is marked as deprecated.  What replaces it?

Gale Chandler replied on Fri, 2013/08/09 - 7:06am

 Ouch, that's some nasty programming you've got there, Geertjan. I like how thew video's done, I watched it offline and was thrilled I can have it on my computer. Did you even consider starting a digital career? You could be one of the most prolific San Francisco videographers I had the change to hear about!

Commonwealth Towers replied on Mon, 2014/04/07 - 9:11pm

Each feasible proposal will be given a grant capped at $10,000 to help with the cost of developing and test-bedding the prototypes. Awardees will have to match dollar for dollar, the grant received from HD residential project

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.