Debugging in JBuilder
Christopher M. Judd - Judd Solutions, LLC.
One of Java's many benefits is freedom of choice. Organizations and developers
are not confined by the choice of operating system, application server,
architecture or development tool. Many successful Java projects have been
written using tools like notepad, emacs and even vi. While such tools
are capable and even extremely productive in the right hands, they are
all missing a debugger. Developers often have to revert to displaying
debug messages with
JBuilder's debugger like most Java debuggers uses the Java Platform Debugger Architecture (JPDA), a standard debugging architecture provided by Java Virtual Machines. The JPDA is separated in to the Java Virtual Machine Debugger Interface (JVMDI), Java Debug Interface (JDI) and Java Debug Wire Protocol (JDWP) specifications. The Java Virtual Machine Debugger Interface (JVMDI) defines the service level interface implemented by compliant Java Virtual Machine. The Java Debug Interface (JDI) defines the interfaces used by UI debuggers like JBuilder. Java Debug Wire Protocol defines the communications between the two (see resources).
Figure 1 - Java Platform Debugger Architecture (JPDA)
JBuilder provides features to locate and resolve syntax, logical, runtime and threading errors. Because this paper is intended for an intermediate audience it will not spend a lot of time detailing each debugging menu item or button. Instead it will cover beginner topics I receive the most questions about or find most interesting. The remainder of the paper will cover intermediate debugging techniques for client/server, web J2EE and OpenTool debugging. If you desire a detailed explanation of beginner debugging features please see the JBuilder Documentation links in the resource section.
Syntax errors are caused by introducing incorrect syntax such as forgetting a semicolon at the end of a statement. Syntax errors prevent code from being compile and are typically located at compile time. JBuilder continually compiles the code in the source code editor to provide notification of syntax errors prior to compiling time. This early feedback increases productivity by allowing you to resolve syntax errors while you are in the same vicinity and by reducing the number of compiling attempts. The notification is provided as error nodes in the Structure Pane (figure 2). Double clicking on the node navigates the editor to the offending line. I have also found the SyntaxChecker OpenTool (see resources) valuable in locating syntax errors early. The SyntaxChecker OpenTool adds an icon to the gutter and underlines offending code with a Microsoft Word style squiggly (figure 3). SyntaxChecker also provides the error message as a flyby hint when the cursor hovers over the icon or squiggly. I have heard some developers complain that SyntaxChecker works to well and identifies errors on lines before they are even finished typing it.
Figure 2 - Structure Pane lists errors while JBuilder is passing the code in the background
Figure 3 - The SyntaxChecker OpenTool provides more obvious indications of errors while typing
Question #1 - What is the difference between run () and debug ()?
Run executes the program normally ignoring breakpoints and other debugging indicators. While debug enables debug features such as step into, step over and resume program. Debug also stops on lines that include break points and provides valuable information about threads, call stacks and watches. Under the covers JBuilder includes the following VM parameters when the debug option is chosen:
The -classic parameter turns off hotspot which can cause unusual behavior in the debugger because the native code produced at run time is cache and executed on subsequent executions giving the appearance the debugger did not step though the Java code properly. The rest of the parameters enable debugging. They will be discussed in detail in the J2EE Debugging section where remote debugging is discussed.
Question #2 - Why does the Runtime Properties dialog popup when I try to run my application?
Figure 4 - Runtime Properties dialog
The Runtime Properties dialog pops up because there can be multiple executable classes, classes with a main method, in a project. JBuilder needs to know which one it should run or debug. Use the ... button to choose a class containing a main method. Now the Run and Debug buttons in the speed bar will invoke the main method of that class. This is similar to creating an executable jar by setting the Main-Class property in the manifest file to a specific executable class.
Question #3 - Do I have to change the Main class to run another executable class?
No, as a matter of fact I rarely if ever use the Run and Debug buttons on the speed bar. Most of my projects have multiple executable classes that I might want to run. Instead of changing the Main class, I prefer to run a specific class. The context menu of an executable class (see figure 5) includes the run and debug options for that specific class. The ability to execute specific classes is also advantageous when debugging multiple classes such as in a client/server environment discussed in the Client/Server Debugging section.
Figure 5 - Run and Debug options are available from the Java file node context menu
Question #4 - Why do my changes to the project properties not take effect?
When a program is run or debugged it basically makes a copy of the project properties at the time of invocation. After project properties have been changed, the debug window in the message view should be closed and the executable class should be run or debugged again.
Figure 6 - Message view debugging window
JBuilder supports debugging multiple processes. This is vital for debugging applications that include the writing of a client and server piece. Examples include socket and Java Message Service (JMS) applications. Using a Run Configuration or the executable class context menu, two separate processes can be started. Two separate debug windows will appear in the message view, each having their own debug toolbar.
Figure 7 - Multiple processes appear as multiple tabs in the Message View each with its own debug toolbarresources).
The first step in debugging a web application is to create a web application using the Object Gallery. Then add customized JSP and/or Servlets to the project. After placing break points in strategically located positions, start the debugging process by using the Web Run or Web Debug from the JSP and Servlet context menu (see figure 8). This starts an instance of Tomcat listening on port 8080 by default. If port 8080 is already being used by another process it increments the port by 2 until it finds an available port. The debug tab name indicates the URL available to test the application. The URL can be used by browsers such as Microsoft Internet Explorer to test your application. After the Tomcat process is started, Web View and Web View Source tabs are added to the content pain. The Web View is a web browser that immediately makes a HTTP request to the web component selected for debugging. If break points are encountered, the debugger will perform normal debugging. The Web View Source provides debugging support by displaying the resulting HTML that the Web View renders. The Web View can provide valuable information about how the page was generated.
NOTE: Making some changes to JSPs may require the debug process to be terminated and restarted. JBuilder recompiles the JSPs to determine executable lines.
Figure 8 - JSP and Servlet debugging is started from the context menu of JSP and Servlet nodes
Figure 9 - Instance of Tomcat listening to port 8084
Figure 10 - Web View browsing JSP generated page
This section could also be labeled Remote Debugging, the techniques described here are not specific to J2EE. Remote debugging is the process of debugging a separate running process that may or may not be separated by physical machine boundaries. The example for this section is a Message-Driven bean managed by the open source JBoss application server (see resources). J2EE debugging requires remote debugging because J2EE applications are managed and run within an application server process such as the Borland Application Server or JBoss.
J2EE Debugging requires configuration in JBuilder indicating which process to debug and which protocol to use. In addition, the application server's virtual machine has to be told to enable remote debugging and to use the same protocols that JBuilder was configured for. JBuilder's remote debugging properties are available on the Project | Project Properties... | Debug or the Run | Configuration | Debug tab (see Figure 11). Enable remote debugging with the associated check box. There are two choices for remote debugging. Launch requires the installation of JBuilder's remote debug server so typically I use the Attach option that allows JBuilder's debugger to attach to an already running process. The host name indicates the name of the computer running the application server. Currently there are two choices of Transport (inter-process communications). The dt_socket is a socket based communications mechanism and is available on both Windows and Solaris. dt_shmem on the other hand is a Windows specific mechanism that requires that both the debugger and debuggee are running on the same machine. As mentioned above the difference between running and debugging is JBuilder starts the debuggee process using a dt_shmem transport. Because of dt_shmem's remote debugging limitations this example uses the dt_socket. The address indicates which port the VM process is listening to.
Figure 11 - JBuilder remote debugging options
Telling the application server to listen for remote debugging commands involves passing it the appropriate VM parameters. The following are examples of the VM parameters passed to the JBoss VM:
Debug enables the debugger and noagent disables the old sun.tools.debug agent. Setting java.compiler to NONE disables the JIT compiler. Runjdwp starts the JDWP described in the introduction. JDWP includes options to tell it how to communicate with the JDI. The transport and address must be set to the same values as the JBuilder debug properties. In addition, server tells the VM that it is the process being debugged and suspends tells the VM to start and then wait for the remote debugger to tell tell it to begin.
@echo off @if not "%ECHO%" == "" echo %ECHO% @if "%OS%" == "Windows_NT" setlocal set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;run.jar REM Add all login modules for JAAS-based security REM and all libraries that are used by them here set JBOSS_CLASSPATH=%JBOSS_CLASSPATH% REM Add the XML parser jars and set the JAXP factory names REM Crimson parser JAXP setup(default) set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/crimson.jar set JAXP=-Djavax.xml.parsers.DocumentBuilderFactory=org.apache.crimson.jaxp.DocumentBuilderFactoryImpl set JAXP=%JAXP% -Djavax.xml.parsers.SAXParserFactory=org.apache.crimson.jaxp.SAXParserFactoryImpl set REMOTE_DEBUG=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,address=5000,suspend=y echo JBOSS_CLASSPATH=%JBOSS_CLASSPATH% java %JAXP% %REMOTE_DEBUG% -classpath "%JBOSS_CLASSPATH%" org.jboss.Main %1 %2 %3 %4 %5 %6 %7 %8 %9 pause
Listing 1 - Entire remote debugging enabled JBoss script
OpenTools are extensions to JBuilder. Setting up OpenTool debugging requires configuring some libraries and setting some project properties. Create a library configuration named JBuilder containing the following jars from JBuilder's lib directory: jbuilder.jar, gnuregexp.jar, jbcl.jar lawt.jar, xml4j.jar, xerces.jar, parser.jar, jdom.jar, help.jar. Every jar in JBuilder's lib directory could be added but it is not necessary and just slows down the loading of JBuilder during debugging. If during the debugging process other existing OpenTool are needed, added them from JBuilder's lib/ext directory.
NOTE: Including all the jars in the lib directory will prevent JBuilder 6 and 7 from prompting for a license.
NOTE: If Borland Enterprise Server has been installed and configured the jars referenced in the lib/ext/bes.properties file may be required to be on the classpath.
Debugging an OpenTool involves starting a new JBuilder process from within JBuilder. In the new process the OpenTool is loaded for testing. Enabling OpenTool debugging requires setting the project properties' Main Class and Application Parameters. Select Project | Project Properties... Run tab, set the Main Class to com.borland.jbuilder.JBuilder and the Application Parameters to -verbose -nosplash. Now pressing the Run Project or Debug Project buttons will start another instance of JBuilder. Breakpoints and other debugging techniques work as normal.
NOTE: Notice that JBuilder is nothing more than a collection of OpenTool APIs. Oops, what was that!!! Yes, JBuilder does throw a lot of exceptions during the start up process.
Becoming familiar with JBuilder's debugger can increase productivity and improve application stability.
JBuilder OpenTools (codecentral.borland.com/codecentral/ccweb.exe/prodcat?prodid=3&catid=11)
Copyright © 2002 Judd Solutions LLC