Migrating an Existing Extension to JDeveloper 11gR2 -- Part Two
By John 'JB' Brock on Jun 15, 2011
We covered the basics of how to migrate an extension that does not use the Addin.initialize() method, in Part One of this topic. If you haven't taken a look at that yet, I strongly recommend that you do.
With the release of JDeveloper 11g R2, the extension framework is now based on OSGi. Because of this, we no longer load all of the extensions at the same time, at the startup of the IDE. We now use something called Lazy Loading which only loads extensions when they are needed. Because Addin.initialize() is no longer called at IDE startup, you have to think a little more carefully about of how your extension integrates into the IDE. You can't just dump everything out there and have it ready to go.
I'm going to use the Extension SDK sample project, "OpenNodes" for this migration example.
A different point of view
The first thing we need to think about, is what user interface element can be used to trigger the loading of the rest of the extension. When we open the OpenNodesAddin class, which extends Addin, we see that there are two different things going on in the initialize() method.
A new factory object is being created and a call to a method called installViewMenu, which does exactly that. It installs a menu item into the View menu. This is exactly what we are looking for.
If we move the functionality of this method to be done declaratively in the extension.xml file's trigger-hooks section, we will be able to show the menu item in the View menu, without actually loading any of the other code in the extension. It will not get completely initialized until the menu item is selected. Go ahead and comment out the call to the installViewMenu() method and save the file.
The existing extension.xml file also contains an action element which will need to be migrated. You can refer back to Part One for information on how to modify the action element and add the now required controller element as well.
We'll focus on the installViewMenu() method and how we will migrate it's functionality over to a menu element in the extension.xml file. Here is what the existing method looks like
This is a pretty simple method that adds a menu item to the View menu on the IDE main menubar. It calls the only action that we have in the extension.xml file already. It doesn't have anything in the method that defines where the menu item is supposed to be placed within the View menu itself. We can just do the same thing and let the IDE place the menu item in the default location if we like.
Let's move over to the extension.xml file now and add our menu element to the triggers section of the file. For this example, I have already gone ahead and done the migration of the action element, as well as the changes to the reuired-bundles element.
I'm going to go ahead and add the <menu-hook> element to the bottom of the <triggers> element, right after the new <controllers> element that we added.
The <menu-hook> element has one required argument of "xmlns". We'll set this to "http://jcp.org/jsr/198/extension-manifest"
Once you have the menu-hook element started, you can use the xml schema tool in the Structure window, just as we described in Part One of this topic. We will need to add the following elements to finish the menu-hook section.
If you are not sure what values to use for the <menubar> id and <menu> id, you can refer back to a blog post I did early in 2011 about how to work with declarative menus in jdeveloper extensions.
The new trigger-hooks section is going to look like this when it's done.
We should be able to test the new version of the extension now, by doing the steps of:
-- Deploy to target platform
-- Run Extension
The "Deploy to Target Platform" step is required in 11gR2 before you try the "Run Extension" feature. This builds the OSGi bundle so that it can be deployed properly.
Cleaning things up
Once you run the new version, you should come across two things.
1) There is a warning telling you that "registerDockableFactory" has been deprecated, after you do the compile (I'm doing a rebuild when I see this)
2) When you actually run the extension, a Warning will be thrown telling you that the <feature> hook doesn't have a corresponding <feature-member>.
While everything will run fine with these warnings in place, lets go ahead and clean things up.
To get rid of the runtime warning, let's add a <feature-member> element just before we start the <trigger-hooks> section.
The registerDockableFactory() method is being replaced with a trigger-hook. You can add this to the triggers element using the schema editor in the Structures window. The class name and id will be required.
The result will look like this.
The last thing to do, is go into the OpenNodesDockableFactory class and comment out the method that does the existing registration. Leave the ID variable declaration though. That's needed by other parts of the code.
Now if we rebuild, deploy, and run the extension, everything should work without any warnings or errors.
By moving the GUI elements out of the Addin.initialize() method, we can display the connections that our extension requires for the user to enable the full functionality and start usng the extension. Once the trigger is hit, the IDE will call the Addin.initialize() method and do the rest of the loading of the extension.
There may still be cases where an extension needs to load, but doesn't have a GUI element to use as a trigger. In those cases, there is usually something else that is being added to the IDE by the extension, that can be used as a trigger. Take a look at the Trigger Hooks Wiki for a list of trigger-hooks provided by the IDE, and some more information about each of them.
As usual... Comments, Comments, Comments. Toss out your experiences and questions for others to learn from. All are welcome.