Integrating ZIP Features in a NetBeans Platform Application

Let's say your requirement is that you need to open a ZIP file into an application, modify its content, and then ZIP it all up again.

And you're using the NetBeans Platform. Here's the general approach to take:

  1. Learn from Similar Code. The very first thing to do is to ask yourself: "Does NetBeans IDE or any other NetBeans Platform application do something similar?" The answer in this case is Yes because NetBeans IDE has "File | Import Project | From ZIP". So you can look in the NetBeans source code and get some nice code relating to java.util.zip.ZipInputStream, while FileUtil.copy is also great to use.

  2. Create a NetBeans Platform Application. When you create the application, go to the "ide" cluster in the Project Properties dialog of the application and include the "Image" module, as well as the "XML Text Editor" module, together with all the related modules (simply click the Resolve button) and then you'll have some cool editors immediately available when you open the content of the ZIP file in the application. Also include "User Utilities" so that you have "File | Open File" in your application.

  3. Use CentralLookup. We're going to end up creating a Node hierarchy, i.e., we'll be using classes such as Node, ChildFactory, BeanTreeView, and ExplorerManager. These integrate very well with the Lookup concept. That is, when objects of interest (e.g., a folder that contains the newly unzipped ZIP file) are registered in the Lookup, you will create new Nodes in the Node hierarchy.

    But which Lookup to use? Lookup.getDefault? No. That gives you access to META-INF/services, which is the standard Java 6 extension mechanism. Utilities.actionsGlobalContext? No. That gives you access to the currently selected object. We don't care about selection in this scenario. Whenever a ZIP file is unzipped into a new folder, we need to add that folder to some kind of observable list, i.e., Lookup, to which our Node hierarchy is listening. Therefore, copy CentralLookup into your application and use that. Here it is.

  4. Recognize ZIP Files. Create a new MIME type (i.e., use the New File Type wizard) to recognize files with a ZIP extension as "application/x-zip", remove all the editor related code in the DataObject (because you don't want to open the ZIP file into an editor, instead, you want to open the files within the ZIP file into an editor), and implement Openable.

    When the OpenAction is invoked, which happens automatically when you try to open a file via "File | Open File" (or from the Favorites window), your implementation of Openable will be called. In that Openable implementation, unzip the ZIP file into a new folder and then register that folder as a FileObject in the CentralLookup.

  5. Create a Node Hierarchy. Create a TopComponent in "explorer" mode. Create a ChildFactory that implements LookupListener, listening to CentralLookup for new FileObjects. When a new FileObject is present, wrap it in a FilterNode and refresh the Node hierarchy.

  6. Listen for Changes in the Folder. Use FileObject.addRecursiveListener() to listen for additions/deletions/changes in the folder. That gives you a way to mark the Node hierarchy as being "dirty", in some way, e.g., publish a Savable into the Lookup of the TopComponent or the Node and then the Save action will become enabled to save the Node hierarchy back into a ZIP file. And how to implement that? Well, look at the source code for "File | Export Project | To ZIP" in the NetBeans sources.

I've completed the first 5 steps above (and everything in step 6 is done, too, i.e., the Savable is added to the Node Lookup when appropriate and, when invoked, an "Export to ZIP" dialog is shown, which works as one might expect) and checked in the sources here:

https://java.net/projects/nb-api-samples/sources/api-samples/show/versions/7.3/misc/OpenZIP

Here's what the result looks like after opening a ZIP file, via "File | Open File", e.g., the images that you see will open into the NetBeans image editor automatically when they are double-clicked, because FilterNode is used to wrap the unzipped folder and its children:


Just for fun, I made the feature modular, i.e., the infrastructure for recognizing and parsing ZIP files is in one module, the explorer view is in another module, and a Utils module is included to provide the CentralLookup, which is the communication mechanism between the two modules:

Above you see everything I did to make this work, not very much when you consider the amount of features provided at the end, e.g., an application frame, window system, modular infrastructure, plugin system, menubar, toolbar, image editor, XML editor, ZIP file recognition, ZIP file parsing, rendering of ZIP file content in a Swing JTree (via ExplorerManager and BeanTreeView):

Finally, note that what you see above in the "ZIP Window" are not actually ZIP files. They're FilterNodes on top of folders created from ZIP files, with the display name of the FilterNode (and all its content, i.e., its children) derived from the original node, which is the folder created from unzipping the ZIP file. 

Comments:

Coming from JEE and starting to refresh my Swing knowledge I found your very valuable blog entries.
As just starting to have a look at Netbeans Platform I got every time confused seeing the netbeans-menubar and toolbar in all example applications. This makes me think that all applications implemented with Netbeans Platform must be heavier than they should be (carrying all the unnecessary menu and toolbar stuff...). I (and probably all old school Swing developers) would like to see how easy it is to remove unneccessary menubar and toolbar. And is the end result (JAR file) smaller when removing these stuff?

But nevertheless: thank you again for this impressive example (it also seems to answer my question asked yesterday, if you could provide the sourcecode for the image viewer ;-) )

Posted by guest on June 18, 2013 at 02:19 AM PDT #

guest,

what you will find is that the menu and toolbar gets populated dynamically by the features you add to your app. It will only be as heavy as you want to make it, though if you want features you have to include the associated support for GUI components.

If it is a matter of just not showing these things, you can hide them quite easily. Geertjan has written towards that several times:

https://blogs.oracle.com/geertjan/entry/simplified_usage_of_the_netbeans

for starters. Make sure you check is back-log of entries.

Also be sure to go through the Platform Community page and its tutorials, especially this one:

https://platform.netbeans.org/tutorials/nbm-runtime-container.html

Posted by Sean Phillips on June 19, 2013 at 11:30 AM PDT #

I suffered the broken projects in upgraded Netbeans IDE several times.

The new IDE can not recognize the libraries used in the project, and you have to reconfigure all libraries i nit first, and then resolve the missing lib issue one by one.

How is the "importing project from zip" way help the missing lib problem?

Maybe zipping all lib (of jars) in the zip file and hard code the path in the project?

Posted by Ken on June 19, 2013 at 04:01 PM PDT #

What is "the new IDE", Ken. And what are you talking about, at all? Open the project in NetBeans IDE 7.3.1. If you have problems, provide step by step instructions so I can try and reproduce your problem. Thanks.

Posted by Geertjan on June 20, 2013 at 12:03 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
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
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today