Tuesday Jun 24, 2014

Injecting the NetBeans Platform into a Maven Application

Here we have a simple application in Maven.

It has a GUI that uses ServiceLoader.load to process a text, using two SPI implementations, one for converting the input to uppercase, the other to lowercase. The GUI module has a Main class that prints output to System.out. The Maven modules are contained in a Maven reactor module named "WordProcessor".

Here is a ZIP containing the above app.

Our task is to migrate this application to the NetBeans Platform. The nice thing about applications that use Maven is that a concept of modularity already exists. This is, of course, compile-time modularity, while the NetBeans Platform offers run-time modularity, which is one of the reasons we might have for wanting to migrate this application to the NetBeans Platform in the first place.

The most immediate approach one can think of when migrating this application is to create a new Maven-based NetBeans Platform application and copy and paste the content of our modules into the new modules in our new application. But, since both applications are Maven based, maybe we should explore (1) reconfiguring the reactor module to use the NetBeans Maven plugin, (2) adding a new Maven module that will provide the NetBeans Platform application archetype, (3) changing the POM files of the existing Maven projects to make them NetBeans modules, and (4) adding another Maven module to provide the NetBeans Platform branding module.

This approach I call "injecting the NetBeans Platform", versus the standard approach which is "migrating to the NetBeans Platform". The injection approach might make sense in large Maven applications, since you don't want to spend weeks copying and pasting classes, etc, from a non-NetBeans Maven module into a NetBeans Maven module. Instead, you'd simply like to Mavenize your existing application by adding a few new Maven artifacts here and there, changing some POM files, and basically sugaring your existing Maven application with NetBeans Platform content. (It's comparable to the mountain coming to Mohammed, instead of Mohammed going to the mountain; where the mountain is the NetBeans Platform and Mohammed is your application. Yes, a true miracle.)

Note: I am not recommending this approach, I am not advising against it either. I am simply providing it as one approach to consider when porting a Maven based application to the NetBeans Platform.

Here's how to do it.

Part 1: Reconfiguring the Reactor POM

Open the POM of the reactor, i.e., the WordProcessor main project application, i.e., the one that contains the other Maven modules. Add the Maven repo that contains the Maven NetBeans Platform modules:

<repositories>
    <!--
    Repository hosting NetBeans modules, especially APIs.
    Versions are based on IDE releases, e.g.: RELEASE691
    To create your own repository, use: nbm:populate-repository
    -->
    <repository>
        <id>netbeans</id>
        <name>NetBeans</name>
        <url>http://bits.netbeans.org/nexus/content/groups/netbeans/</url>
    </repository>
</repositories>

Next, add this build section:

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>nbm-maven-plugin</artifactId>
                <version>3.13</version>
                <extensions>true</extensions>
                <configuration>
                    <brandingToken>${brandingToken}</brandingToken>
                    <cluster>${brandingToken}</cluster>
                </configuration>
            </plugin>
            <plugin>
                <!-- NetBeans 6.9+ requires JDK 6, starting NetBeans 7.4 source 1.7 is required -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
        </plugin>
        </plugins>
    </pluginManagement>
</build>

Finally, change the properties of the reactor's POM to include netbeans.version and brandingToken:

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <netbeans.version>RELEASE80</netbeans.version>
        <brandingToken>wordprocessor</brandingToken>
</properties>

Part 2: Injecting the NetBeans Platform Application

Next, we're going to create a special NetBeans Maven module, one that has goals for running and debugging the NetBeans Platform application. We'll start by creating just an ordinary Maven NetBeans module and we'll then change its POM to use the 'nbm-application' packaging type, instead of 'nbm'. Start like this, to make sure the Maven module will end up being part of the reactor:

Next, choose "NetBeans Module" in the Maven category:

Name the Maven module "Application", or anything else you like, but to me "Application" is clearest. You could, for example, instead, name it "NetBeans", to indicate that it represents the NetBeans Platform in your Maven application.

When you finish the wizard above, you should now see a new Maven module named "Application", with a purple icon. There's also a warning badge that tells you you need to associate a NetBeans Platform with the project. Right-click the Application module, choose "Resolve Project Problems", click Resolve, and then click "Define Property". Now a 'settings.xml' file is added to the "Project Files" node of the reactor. You might now need to close and open the whole project, just to refresh it, you might also need to build it, but in the end the warning icon should be gone as shown here:

Now let's change the POM of the Application module so that the Application module gets an orange icon in the Projects window, instead of a purple one, indicating that it is a NetBeans Platform application module, instead of a NetBeans module.

In the POM, change the packaging type from "nbm" to "nbm-application". And immediately the icon changes from purple to orange.

Change the dependencies section to the following:

<dependencies>
   <dependency>
      <groupId>org.netbeans.cluster</groupId>
      <artifactId>platform</artifactId>
      <version>${netbeans.version}</version>
      <type>pom</type>
   </dependency>
</dependencies>

Change the build section to this:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>nbm-maven-plugin</artifactId>
        </plugin>
        <!-- Permits NbModuleSuite to be run in integration-test phase: -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.12.2</version>
            <configuration>
                <systemPropertyVariables>
                    <all.clusters>${all.clusters}</all.clusters>
                    <branding.token>${brandingToken}</branding.token>
                </systemPropertyVariables>
            </configuration>
        </plugin>
    </plugins>
</build>

Add this profiles section:

<profiles>
    <profile>
        <id>deployment</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>nbm-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>extra</id>
                            <goals>
                                <goal>autoupdate</goal>
                                <goal>webstart-app</goal>
                                <goal>build-installers</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Finally, add this properties section:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <all.clusters>${project.build.directory}/${brandingToken}</all.clusters>
</properties>

Build the reactor and everything should be good:

Here is a ZIP containing the above app.

Right-click the Application and choose Run. The NetBeans Platform starts up. However, the four Maven modules with which we started are not loaded into the application. That's because we need to make them Maven NetBeans modules and add them as dependencies to the Application. That's the focus of the next step.

Part 3: Converting Maven Modules to NetBeans Maven Modules

Open the POM of the "GUI" module. Change its packaging from "jar" to "nbm". The icon should now become purple, indicating that it is a Maven NetBeans module.

Next, add this build section:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>nbm-maven-plugin</artifactId>
            <extensions>true</extensions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <useDefaultManifestFile>true</useDefaultManifestFile>
            </configuration>
        </plugin>
    </plugins>
</build>

Now we need to make sure that the GUI module will be loaded into the NetBeans Platform application when you run the Application module. Open the GUI module in the Projects window. Right-click on the Dependencies node in the Application project, choose Add Dependency, then in the Open Projects tab you should see the GUI project, with its purple icon, select it and choose Add. It is now added as a dependency of the Application project, while the three other Maven modules (which are not yet NetBeans Maven modules) are shown as transitive dependencies, i.e., greyed out.

Switch to the Files window. Below the 'main' folder, on the same level as 'java', create a folder named 'nbm', containing a manifest.mf file with this content:

Manifest-Version: 1.0

Clean and build the reactor. Use the New Window Component wizard to create a new TopComponent with any name and any location, etc, i.e., anywhere at all. You should not encounter any problems. Run the application and you should see your window.

Add this to the end of the TopComponent constructor, to prove that your original code, i.e., the code that's in the Main class in the GUI module, still works, i.e., the ServiceLoader loads your SPI implementations correctly:

JTextArea ta = new JTextArea();
ServiceLoader<Processor> sl = ServiceLoader.load(Processor.class);
for (Processor p : sl) {
    ta.append(p.process("input to be processed"));
}
setLayout(new BorderLayout());
add(ta, BorderLayout.CENTER);

You should see the output from your processors appear in the text area in the TopComponent you created. In other words, right now, we have only moved one Maven module to a NetBeans Maven module. The other Maven modules could stay the way they are, i.e., you don't have to move them to NetBeans modules. On the other hand, if you want to integrate them more closely into the NetBeans module system, e.g., to have support for hiding classes from other modules and to provide support the NetBeans versioning features, you could move those modules to the NetBeans modules, too. But, as you can see, you have a choice. The only Maven modules you have no choice about are those that need to integrate with the NetBeans Platform in some way, e.g., the window system or menubar, etc.

Part 4: Integrating the NetBeans Branding Module

Our final step is to add another NetBeans Maven module, as described in detail in part 2. Name it, for example, "Branding". Once the module has been created, go to the Files window, and go to src/main/java. There, create a new folder, i.e., on the same level as 'nbm', named 'nbm-branding'. Now go back to the Projects window and you should be able to right-click on the Branding module and choose a menu item right near the end, above 'Properties', named 'Branding', where you can set splash screen, icons, etc. Add the Branding module as a dependency to the Application module, as done for the GUI module in the previous section.

Here is a ZIP containing the above app.

Hurray, your Maven application has now been injected with the NetBeans Platform. At this point you're not completely finished, there's probably other things to do, but at least you now have a starting point. Continue from this point onwards to code against the NetBeans APIs, etc. Interested to know what readers out there think about this approach.

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
« June 2014 »
SunMonTueWedThuFriSat
14
15
19
28
29
     
       
Today