Importing a 3rd Party Project as a NetBeans Free-Form Project

Note. This document is for reference purposes only. The version of the PMD project that is used in this document is no longer available and some of the UI of the IDE that is described has changed. However, many of the principles and steps for importing a project are still applicable in the current version of the IDE.

This document shows you how to import a real 3rd party project built with the Ant tool into NetBeans IDE as a free-form project. The project that has been selected to demonstrate free-form project functionality is the PMD tool. This tutorial will show not only how to import the project but also how to change the build script to better utilize what NetBeans project infrastructure can offer. This tutorial uses information available in Advanced Free-Form Project Configuration and if you are familiar with this document it will be easier for you to finish the tutorial.

Prerequisites

This tutorial assumes you have some basic knowledge of Ant and XML, and that you know basics about how projects in NetBeans IDE work.

Software Needed for the Tutorial

Before you begin, you need to install the following software on your computer:

  • NetBeans IDE 5.5 (download).
  • Java Standard Development Kit (JDK™) version 5.0 (download).

Tutorial Exercises

The following topics are covered in this document:


Getting the PMD Project

PMD is a handy tool for programmers that detects potential problems in Java source code. You can download PMD from pmd.sourceforge.net as a Zip source distribution or check it out from anonymous CVS. This tutorial assumes that you are using zipped sources distribution of PMD 3.5. If you want to use sources checked out from PMD source repository then follow instructions on sourceforge.net to get the PMD sources.

It's really easy using CVS support in NetBeans 5.0. Described instructions can be used for 3.5 sources and for trunk sources as well. This tutorial uses the 3.5 version because there were compilation errors and execution errors in trunk sources at the time the tutorial was written.

Creating a Java Application with an Existing Ant Script

The goal of this exercise is to perform the initial import of the project's build script to the IDE and set up all required settings for basic IDE operations.

Importing the Project Using the Wizard

  1. Open the New Project wizard by selecting New Java Project with Existing Ant Script, click Next.
  2. Specify the location of the pmd folder where you extracted the PMD sources. Click Browse button next to the Build Script field and find build.xml file under pmd/bin folder. Then click Next.
  3. The Build and Run Actions page contains mapping of targets found in the build script to IDE actions based on simple heuristics. So far we don't know if those targets are correct, so leave is as it is for now. Of course if you already know which targets map to which action you can select the correct targets now. Click Next.
  4. On this wizard page you can point the IDE to the folders that contain the project sources and test sources. Click Add Folder next to the Source Package Folders table and select pmd/src. Then click Browse next to the Test Package Folders table and select the pmd/regress/test folder. The Source Level for the project can be also changed here - it won't change the actual compilation task setting but it will provide correct hints for error annotations in the editor. We will leave it as it is, it can be changed anytime. Click Next.
  5. On this wizard page you can setup classpath for source roots, but to do this you need some knowledge of the build script, hence we will do it later. Click Finish.

Now that you have created the project, let's examine it.

imported project in Projects and Files windows

The project node contains both source roots and also the build script. The names of the nodes are a little strange - src and regress/test. We should change them to something nicer. Open Project Properties from project's contextual menu. You will see two tables with source roots location and labels. You can change the label to whatever you want. Double click the label and change src to Source Packages and regress/test to Test Packages.

Setting Up the Classpath

To set the classpath correctly we will need to look what is in the build script - by basic observation we find out that compilation is done with following classpath definition:

  <property name="dir.lib" value="lib\"/>
  ...
  <path id="dependencies.path">
      <pathelement location="${dir.build}"/>
      <fileset dir="${dir.lib}">
          <include name="jaxen-1.1-beta-7.jar" />
          <include name="jakarta-oro-2.0.8.jar" />
          <include name="xercesImpl-2.6.2.jar" />
          <include name="xmlParserAPIs-2.6.2.jar" />
      </fileset>
  </path>

The same classpath is used for compilation of tests, because everything is compiled together.

  1. Open Project Properties dialog and select Java Sources Classpath - the panel on the right allows you to set up the classpath for all source roots.
  2. Select Source Packages [src] in the drop-down, click Add JAR/Folder and browse to the pmd/lib folder. Select all of the JAR files that are included in the above mentioned fileset.
  3. Fix order of classpath elements to be the same as in build script by Move Up and Move Down buttons.
  4. Select Test Packages [regress/test] in the drop-down, click Add JAR/Folder and select the same JAR files as in previous steps, fix the order of files as well.

The classpath set up in this step is used for IDE features such as code completion and by no means affects the classpath used for compilation of the project.

Configuring IDE Actions

When examining the project build script you will actually realize that some targets that you mapped to IDE actions when creating the project are not correct. The Build action target is not compile but in fact jar. The Clean action should not be mapped to the clean target but delete. And the Run Project target is in fact called pmd. This can be easily fixed:

  1. Open Project Properties and select Build and Run.
  2. Select the following targets for IDE actions in the drop-downs:
    Action    Target   
    Build Project jar
      Clean Project   delete
    Run Project pmd
  3. Close Project Properties dialog.

Now you should be able to run all project actions. Well, except Run Project. The pmd target contains a taskdef without an explicit classpath attribute, meaning that it counts on having the correct JAR file on the classpath implicitly. How do we fix this? One way is by adding classpathref="dependencies.path" attribute to taskdef for the pmd task, so the taskdef will look like this:

  <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="dependencies.path"/>

Another method is to add pmd-3.5.jar to the additional classpath entries for Ant. Choose Tools > Options, then select Miscellaneous > Ant, click the Manage Classpath button, and add pmd/lib/pmd-3.5.jar. The JAR file is only available after the project is built, of course.

The better method is to use explicit classpath when defining the task, because then the build script is more portable. And in this particular case it's also better because if you add pmd-3.5.jar to Ant classpath on Windows then it's not possible to run Clean Project since the JAR file is be locked by the OS.

But there is still one minor problem with Run Project action. The build script points to the absolute location of some not existing source file in the bin folder. A simple fix is to replace the absolute path in pmd task with bin. The fileset inside the pmd task then should look like this:

  <fileset dir="bin">
      <include name="Foo.java"/>
  </fileset>

And you also need to create missing class in pmd/bin folder:

  public class Foo {
      private static int FOO = 2; // Unused
      private int i = 5; // Unused
      private int j = 6;
      public int addOne() {
          return j++;
      }
      public void doSomething() {
          int i = 5; // Unused
      }
      private void foo() {} // unused
      private void bar(String howdy) {
          // howdy is not used
      }
  }

Note: The Foo class is based on comments in rulesets/unusedcode.xml.

Usually, it's useful to make the run target depend on the build target. It's not the case in PMD's build script, so if you want run target to be executable even when project is not built, add depends="jar" to the pmd target definition.

Now you can finally run the project and you will get the pmd-3.5/rpt.html file in the project folder showing problematic parts of the Foo class:

PMD Report

Now your project is set up and you can execute all basic project related actions: Build Project, Clean Project, Generate Javadoc for Project, Run Project, Test Project and Clean and Build Project.

Setting Project Outputs

Having correctly set up project outputs is a very important part of free-form project configuration. It's important for debugging tasks, for fast background classpath scanning, and for using project products as libraries for other projects.

Each source root should have its own build product(s), either a folder or JAR file. From observation of the compile and jar targets in the PMD build script you can find out that the Source Packages are built into the build folder along with test classes and the final JAR file is lib/pmd-3.5.jar. In order to view Javadoc in projects that depends on the PMD free-form project you also need to set the Javadoc output. PMD build script produces Javadoc documentation into folder docs/apidocs - according to the javadoc target.

  1. Open Project Properties, select Output node under Categories.
  2. Select Source Packages [src] in Source Package Folder.
  3. Click Add JAR/Folder button and specify both the build folder and lib/pmd-3.5.jar. Click the Browse button next to Javadoc Output text field and select the docs/apidocs folder.
  4. Select Test Packages [regress/test] in Source Package Folder.
  5. Click Add JAR/Folder button and locate the build folder, then close the Properties dialog.

Now the project is set up and ready to be used in IDE. In following chapters I will show how to get even more from the IDE.


Configuring JUnit Output

Each good project should have tests and the PMD project has a number of tests that can be executed with the Test Project command. But if you run this command you will see that output doesn't look as nice as it looks when running standard NetBeans projects.

This can be fixed too. First, you need to modify target names to comply with simple convention - the name must start with test, which can be followed by a dash or period and then anything you want (e.g. test-server or test.server). Alternatively, you can name the target run-tests. The other thing is that JUnit tasks use various formatters to print various types of output and the NetBeans JUnit module requires a particular combination of formatters to show nice output. The JUnit tasks in PMD build script use the following formatter:

  <formatter type="plain"/>
but if you want to have nice output, you have to replace the previous formatter with the following two in all JUnit tasks:
  <formatter type="xml"/>
  <formatter type="brief" usefile="false"/>

And you will get very nice display of JUnit test execution that updates itself when tests are running, as in the following image:

PMD Junit Output Window

Mapping Non-Standard Targets to IDE Actions

3rd party projects have also special targets that are project-specific and there can be no mapping to standard IDE commands. But that's not a problem for a free-form project - you can map any target to a command which is then available in project context menu.

The PMD project contains a couple of such targets that might be candidates for adding them to the context menu, for example targets for uploading build products to a web server or targets for running partial test suites.

  1. Open Project Properties and select Build and Run.
  2. Click the Add button next to the Custom Menu Items table. A new row appears.
  3. Double click the empty cell in the Ant Target column and select the target you want to map to a command, (e.g. the tomserver target,) and press Enter. Double click the cell in the Label column and enter a command name, e.g. Upload Project. Repeat the same for any additional targets.

The context menu for the PMD free-form project then might look like this:

PMD Project context menu

Note: Upload actions are just an example, they require external executable files and appropriate write access.


Special NetBeans Actions

When developing a larger project you might want to be able to run compilation only for a selected file or group of files, execute a single file, or debug a project or even a single file. All this is possible, although it requires some Ant knowledge. The PMD project is not a good example to show all of the commands that I just mentioned but I can show how to set up at least some of them.

There is support in the IDE for generating additional build scripts the for Compile File action and for the Debug Project action. All details about setting up NetBeans-specific actions are in the document Advanced Free-Form Project Configuration.

Compile File

  1. Select a single Java source file under Source Packages source root
  2. Right-click the file and choose Compile File from file's context menu. You are asked whether you want to generate special target. Click Generate. The newly generated Ant build script along with the project.xml file are opened in editor.

The target in the generated build script is called when you invoke the Compile File command on one or more files from a single source root folder. If you have already correctly setup everything the script does not require any modifications. Just to check - the compilation target should look like this:

  <target name="compile-selected-files-in-src">
      <fail unless="files">Must set property 'files'</fail>
      <mkdir dir="build"/>
      <javac destdir="build" includes="${files}" source="1.5" srcdir="src">
          <classpath path="lib/jakarta-oro-2.0.8.jar;lib/jaxen-1.1-beta-7.jar;lib/xercesImpl-2.6.2.jar;lib/xmlParserAPIs-2.6.2.jar"/>
      </javac>
  </target>

The destination build directory must be created in case the target is called after a clean. The source dir must point to the src folder, the includes attribute of the javac task must contain the property ${files}, and the classpath must be the same as the classpath for compilation in main build script.

The other file that has been modified and is opened in the editor is project.xml. It contains the actual mapping of the Compile File action to the appropriate Ant target.

Run File

There is no support for generating an Ant target for the Run File command. It must be created by hand.

  1. Open pmd/nbproject/project.xml, find the action element whose name attribute has a value of compile.single and paste the following XML snippet after the element:
      <action name="run.single">
          <script>nbproject/ide-file-targets.xml</script>
          <target>run-selected-file</target>
          <context>
              <property>runclass</property>
              <folder>src</folder>
              <pattern>\.java$</pattern>
              <format>java-name</format>
              <arity>
                  <one-file-only/>
              </arity>
          </context>
      </action>
    
  2. Open file pmd/nbproject/ide-file-targets.xml and add following XML code snippet to the project:
      <target name="run-selected-file" depends="jar">
          <fail unless="runclass">Must set property 'runclass'</fail>
          <java classname="${runclass}" classpathref="dependencies.path" fork="true"/>
      </target>
    
  3. Add following import task to the top of the file nbproject/ide-file-targets.xml, right after the property definition:
      <import file="../${ant.script}"/>
    
    The import is required because the Run single file target must depend on the jar target from the main build script. Save both files.

The Run File command is now enabled on any file under the Source Packages folder. Of course, it makes sense to run this command only on classes with a main method.

Debug File

The Debug Project command is normally pre-generated when invoked for first time, but it requires a correctly configured run target in the main script using the java task. This is not the case in the PMD project. Hence, we have to create a Debug File action that is enabled on single files and not on the project itself.

  1. Open pmd/nbproject/project.xml and insert following XML snippet after the action element inserted in previous step:
      <action name="debug.single">
          <script>nbproject/ide-file-targets.xml</script>
          <target>debug-selected-file</target>
          <context>
              <property>debugclass</property>
              <folder>src</folder>
              <pattern>\.java$</pattern>
              <format>java-name</format>
              <arity>
                  <one-file-only/>
              </arity>
          </context>
      </action>
    
  2. Open file pmd/nbproject/ide-file-targets.xml and add following XML code snippet to the project:
    <target name="debug-selected-file" depends="jar" if="netbeans.home">
          <fail unless="debugclass">Must set property 'debugclass'</fail>
          <nbjpdastart name="debugclass" addressproperty="jpda.address" transport="dt_socket">
              <classpath refid="dependencies.path"/>
          </nbjpdastart>
          <java classname="${debugclass}" fork="true">
              <jvmarg value="-Xdebug"/>
              <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
              <classpath refid="dependencies.path"/>
          </java>
      </target>
    
    Save both files.

The Debug File command is also enabled on all files under the Source Packages folder and it makes sense to invoke it only on executable classes.

Conclusion

The PMD project is now fully integrated in IDE and the user can utilize almost all actions that are available for NetBeans native projects.

There are some general rules and good practices that, if followed, make it easier to integrate 3rd party projects into the IDE as free-form projects:

  • Compilation of sources should be separate from compilation of tests
  • Each compilation unit should have its own compilation classpath and destination folder
  • Execution should be achieved with a forked java task
  • Libraries should be packaged with the project, if possible of course
  • Separate targets for all parts of the build process should be provided
  • A clean target for all build products should be provided
  • taskdefs should have explicit relative classpaths
  • Relative paths should be used for referring to parts of the project
  • Each source root should be in its own folder

Next Steps

To send comments and suggestions, get support, and keep informed on the latest developments on the NetBeans IDE J2EE development features, join the mailing list.

Bookmark this page

del.icio.us furl slashdot technorati digg
get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo