Thursday, October 6, 2016

Porting my Nb 6.5 RCP app to Nb 8.2

Over the years I have tried to port my Nb 6.5 based  Platform application to an updated NetBeans version. It usually stopped with some major showstopper which was too hard to figure out on my own or which nobody in the great NetBeans community had heard of or could reproduce.This was the case trying Nb 6.7, 6.8, 6.9, 7.0 or 7.2. Over the years I took notes of problems other porters have had and kept those in a list as I knew I would use them one day.

NB 8.2 was released on Oct 3rd, 2016  and I did already work on the 8.2RC which was released about two weeks before. Below I will simply list the issues I run into and which solutions made them go away.

In short:  NB 8.2. was the one release causing minimum of porting needed and I succeeded with the port (42 modules) under a week of work. Some of this time was due to issues with 3rd party products like Derby. (10.12.1.1 had issues with numerous triggers on the same table, which I fixed together with Bryan see https://issues.apache.org/jira/browse/DERBY-6726)

Update (Nov 2016): This fix is now part of the latest Derby 10.13.1.1 release.

1) Upgrade local build to Ant 1.9.7

No big deal really. Nb 8.2 has Ant 1.9.7 build into the distro but I also did have build scripts who could build the system outside NetBeans in batch. Upgrade was done just to have the same version as NetBeans.

2) Upgrade all modules Implementation versions 

Use Project --> properties.  This was done to make sure no old update Center could trigger an update suggestion on the newly upgraded system.

3)  Find which dependencies from NetBeans were needed

This was the first bigger puzzle game. Major split of API's were done in 8.0, like the Lookup was now it its own library. Also splits between Swing and non-swing code were done, like Progress API and Progress API - Swing. The idea was to take out as much as possible and with try and error see what dependencies need each other.

The main one to remove was under "platform" : Swing Layout Extension integration as it is deprecated.Which had implications on numerous TopComponents.  From the suite's project properties I only needed 3. "ide", "nb" and "platform".




To reduce carrying too much not-to-be-used jar files around, below I list the modules in each of those 3 nodes which I excluded and which did not trigger dependency warnings when removing.

"ide":  Bugzilla, CSS Preprocessors, CVS Installer, Database, Database Drivers, Docker*, Git*, Hudson*, ini4j, Issue Tracking*, Java DB Database Support,  Lexer to NetBeans Bridge, Local*, Mercurial, Mylyn Support Utilities, Navigate to Test, org.eclipse*, Resource Bundle Syntax Coloring, Schema-to-Beans Library, Selenium*, Smack API, Subversion*, Team Commons, Versioning*, XML WSDL API

Note: The Database, Database Drivers and Java DB Database Support were removed as I have my own Derby setup.

"netbeans": Bugzilla-Exception Reporter Bridge, Exception Detector, IDE Branding, Update Centers, Upgrade, Welcome Screen.

Note: My app is using the update center code but the Update Centers module is not needed.

"platform": Compatibility APIs, Old Enumeration API, Swing Layout Extension integration, UI Gestures Collector Infradtructure, UI Handler Library,

Note: The first 3 are deprecated modules and having written code in Nb 6.5 did have some swing layout using the Swing Layout Extension integration. (more below about that)

4) Add dependencies to your modules were compile errors happen due to missing classes

a) JUnit 4:   Add JUnit 4 to your Unit Test Packages if not there, possibly also Hamcrest
b) org.openide.util.ImageUtilities: Moved to module org-openide-util-ui, i.e. add Utilities API to your module
c) Lookup API:  The lookup code has its own module, hence all your code using this need to depend on this
d) org.netbeans.api.progress.ProgressHandleFactory : You will need to include Progress API and often as well Progress API - Swing dependencies.
e) org.openide.util.Utilities, util.HelpCtx, util.actions.CallableSystemAction: Add Utilities API
f) Module using  <...>.lookup(XyzProject.class) :  Triggers a class file for

org.netbeans.api.project.Project error. Also here - add the Project API as dependency

5) "The type of DialogDescriptor is erroneous” - kind of error
  
      This one did confuse me for a while. Compilation in Java ok, but NetBeans rejected to compile this. It turned out that adding a dependency on the Utilities API did solve this problem. Nasty part here is that you have no way of knowing this. No info why this is happening. See http://forums.netbeans.org/viewtopic.php?t=66899 for more details.
   
     6) javax.crypto not found

     Proguard 5.2.1 trouble shoot page explains that you shall add  jce.jar


-libraryjars 'C:\Program Files\Java\jre6\lib\jce.jar'

     7) Non-Singleton TopComponents NPE's when exiting the application

     A few of my TopComponents are non-singleton and I had to remove the files xyzSettings.xml and xyzWstcref.xml and all references in the layer.xml as well as any action possible left in there. Though removing the layer.xml entirely was a bad idea. For now I left a nearly empty layer.xml like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
<folder name="Windows2">
</folder>
</filesystem>


      8)  VisualLibrary Widget Background default changed from white to gray
    
       Add in each module   this.setBackground(Color.white);   where this extends GraphScene. See http://forums.netbeans.org/viewtopic.php?t=66919 for more details and info
 

9) FileUtil.preventFileChooserSymlinkTraversal deprecated in JDK 8

Just remove the line using this. 

10) ProgressHandleFactory.createHandle deprecated

Just use ProgressHandle.createString()

11)  The module org.jdesktop.layout has been deprecated

 Use javax.swing.GroupLayout instead. If most of your code was generated in NetBeans, set to Design mode, select the "From xyzTopComponent" in the Navigator and then in the "Form xyzTopComponent - Properties" window there is a pulldown menu for the "Layout Generation Style" where you can select "Standard Java 6 code" - this will change all your code.

 

12)  DropDownButtonFactory needs small change in usage pattern

I have been using the DropDownButtonFactory as described in https://blogs.oracle.com/geertjan/entry/org_openide_awt_dropdownbuttonfactory1 and combined with ContextAware like in http://wiki.netbeans.org/DevFaqDropdownMenuAddToolbarEnabled

The dropdownbutton is now just showing the gray box until the ContextAware action is enabling it. To fix this the code only needed to insert the icon directly as in

The code used in Nb 6.5:
dropDownButton = DropDownButtonFactory.createDropDownButton(
new ImageIcon(
new BufferedImage(32, 32, BufferedImage.TYPE_BYTE_GRAY)),
popup);

dropDownButton.setIcon(icon);

Fix for 8.2:
dropDownButton = DropDownButtonFactory.createDropDownButton(
icon,
popup);

i.e. do not call the .setIcon() method on the JButton.  


13)  JVM arguments -J-XX:PermSize are not needed in JDK 8 anymore

14)  Numerous of new NetBeans IDE specific menu points to be removed

Use the IDE via the "Important Files" -- XML layer --  this layer in context    to accomplish most of this task. (looove this tool !)

15) Java 8 source level gives "RELEASE_7" warnings.

Currently I simply ignore this. No idea what is happening, something with the Annotation system.

16) Compatibility injections

Got warnings like 

warning: had to upgrade dependencies for module com.effi.vin.model: added = [module org.netbeans.api.progress.compat8 > 1.40, module org.openide.filesystems.nb, module org.openide.filesystems.compat8] removed = []; details: [Separation of desktop and cleanup, Swing dependencies split away]

Not sure what they do but it looks like it works so far. Looks like the system is so smart to make sure the new module splits applied inject in runtime jars usually needed for binary backwards compatibility. Though I could not find code in my module using older code.  Anyone out there who can explain if this just simply happens to all modules or what I can look for triggering this ?


Update (Dec, 2016): After removing all warnings in NetBeans and adding new library dependencies, the compiler still said MyModule: added = [module org.openide.filesystems.compat8] removed = []; details: [Separation of desktop and cleanup] - even though there were no deprecated or older function calls left. FIX: For this I removed the dependency on "File System API" and added it again. - Voila, compiler warning gone, no more injections of the compat8.jar.


17) Branding update

Since Nb 6.9 (? or 7.0) you have to add "--branding  your_branding_token" into the myapp.conf file to make sure your splash, about screen, icons etc are picked up.

18) org.openide.filesystems.Repository.getDefault().getDefaultFileSystem()  deprecated

Replace with FileUtil.getConfigRoot()

19)  Remove default UpdateCenters made available to the user

LOL, after having build my app it suddenly informed me that the FileSystem module needs to be updated. For sure I had not this in my UpdateCenter. It turns out that 3 update centers are enabled by default and need to be hidden when you only want your users to get updates for your app via your UpdateCenter and to make sure that the NetBeans under the hood is not updated and causing non-tested possible problems with your deployed app.

Like in point 14) you can remove those via the  Important Files- XML Layer - this layer in context - Services - AutoupdateType.  In there, delete the "certified update provider", "distribution update provider" and the "pluginportal update provider" - in case you do not want to give users access to update from those straight into your RCP app.

20Refactor from SaveCookie to the Savable

Inspired by Geertjan's link (Geertjan bye SaveCookie)  you remove your dummy Node created to enable the SaveCookie and create your Savable. Now, in my situation the class triggering a Save is a non-TopComponent and hence a little differnt. But in general what you need to do is:
a) Remove the "Save" action via the Important Files - XML Layer -  this layer in context - Toolbars - File, but keep the SaveAll Icon
b) In the class controlling if anything needs saving add
    private InstanceContent content = new InstanceContent();
    private final Lookup myLookup = new AbstractLookup(content);
 

c) Now create like Geertjan is showing a private class MySavable and in the handleSave() you do
    content.remove();
    unregister();

d) The controlling class activates the SaveAll icon by adding a MySavable extends AbstractSavable to the lookup vis something like
        if (myLookup.lookup(MySavable.class) == null) {
            content.add(new MySavable(this));
        }
 


e) Now, other classes might see if there is some Savable and the current best way I found was using code like:
  Collection objCol = Savable.REGISTRY.lookupAll(Savable.class);

and simply check if the Collection is empty or not.  

 

That was it really. Not so bad, thinking the time period from 6.5 to 8.2. 
 

1 comment: