Examining the Source Code of the NetBeans Google Protocol Buffer Plugin
By Geertjan on Feb 10, 2009
Now.. let's examine the code itself. Here's the trunk folder, showing that Piotr created a set of 4 modules within a suite, which is a container for modules:
The above modular approach makes a lot of sense. The Configuration module contains the Options window, the Editor module contains the editor, the code generator is in the Generator module, and the templates are in the Templates module. As a result, (1) if you don't want the templates, for example, you simply don't need to install that module and (2) if someone provides a better/different editor for the same syntax, then the user can exchange Piotr's editor for the other editor.
Hurray, we have a very logical division of code across modules. Also, clearly, modularity is a HELP and not a HINDRANCE at all. It simply makes sense and gives the end user more choice, while giving the developer the possibility of neatly dividing code into logical containers.
Now let's look inside each of the modules in turn. First, the Configuration module:
We can see that the Matisse GUI Builder was used to create the Options window extension. That's good. It's a very simple form, one that is unlikely to change very much, you're unlikely to be working with lots of colleagues using various IDEs on this module, so the Matisse GUI Builder makes sense. Looking inside the source file, we can see that localization is handled via the org.openide.util.NbBundle class, while the standard JDK Preferences class is used to store settings to disk. Better would be to use the org.openide.util.NbPreferences class, as described in the NetBeans Options Window Module Tutorial, because that way the settings would be stored inside the NetBeans IDE user directory (which is the read/writable part of the NetBeans System Filesystem) rather than in the default JDK location, which is where the Preferences class puts it.
Second, the Editor module:
We can see, from the "nbs" file extension, that Schliemann is used to define the syntax and business rules of the Google Protocol Buffers. That's fine, especially since it is quite a small language. Click here to browse through the Schliemann file to see all the features provided by this file, all done declaratively.
However, the tide is turning against Schliemann. See http://blogtrader.net/, where one can read how Scala support is being migrated from Schliemann to the new Parsing API. Soon I want to take the notes from that blog and write some kind of migration guide from Schliemann to the new approach, but that is something that will need to be done for the Google Protocol Buffers plugin too, sometime. Maybe I will use this NBS file as my example in the tutorial.
Finally, the module includes an implementation of the code completion SPIs in the NetBeans IDE's APIs. It makes for a good example. Start by looking in the layer file and notice that the completion provider is registered there. Then look in the completion provider, where a new completion query is created (note especially how Schliemann is hooked into the code completion, via a call to the activated node in the "getCurrentRootNode" method), and finally examine the completion item, which represents the actual items in the code completion box.
Then, the generator module:
The first thing I notice here is the ProtobufOutputListener, one of the most fun NetBeans API classes, letting you create hyperlinks in the Output window. Here also LineCookie is used to jump back into the editor for any errors that result from processing the content of the editor. An error annotation is also defined, with its description, as is to be expected, in an XML file that is registered in the layer file.
The integration of the Protoc executable, which is set in the Options window, is done via the org.openide.util.RequestProcessor class. An action in the editor and toolbar (thanks to registration in the layer file) instantiates a new RequestProcessor and posts the ProtobufGeneratorRunnable to it. That's the class that hooks everything together: the setting in the Options window, the OutputListener, the error annotation, and information about the current file and project are obtained as well. That definitely is the most interesting class in the whole plugin, in my opinion.
The main thing I am missing in this particular module is... extendability. This particular plugin lets one generate Java files from the Google Protocol Buffers. However, let's say I am someone who wants to add my own extensions to this plugin so that, for example, Python code can be generated instead? I believe this module should be extendable: the menu item and toolbar button should be read from the layer file, from within their own distinct developer-created folder, to which I would add my Python implementation, for example. That would be a very cool enhancement so that external contributors could insert their own code generators to this plugin.
Finally, the templates module:
There's nothing special here. A single file template is registered so that the user has a starting point for creating new Google Protocol Buffers. How to register file templates? Look here inside the layer file of that module.
In short, this is a very good plugin that illustrates the usage of many of the common approaches to creating new editors on the NetBeans Platform. However, already it could be extended to make the code generator pluggable. Also, a few steps could be taken to investigate the alternative to Schliemann that will be used in 7.0 and try and convert the Schliemann approach to the new approach. As stated above, I should have a tutorial about that in the coming period.
Finally, of course, Piotr Tabor is a "NetBeans Platform Certified Engineer" and will receive a certificate that says exactly that!