How many times trying to fix a server-side Java problem appeared trivial, but getting to
the source of the problem took all the time? A debugger attached to a remote Java application
can shorten the defect-discovery times significantly and make the process more enjoyable.
The Java Debugger
The Java Debugger (jdb) is a dynamic, controlled, assignment-based debugging tool.
It helps find and fix bugs in the Java language programs both locally and on the server.
To use jdb in a J2EE application server you must first launch it with debugging enabled and
attach to the server from the debugger through a JPDA port (Default port is 1044).
The default JPDA options for J2EE servers are as follows:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
The jdb parameters specify the way debugger will operate. For instance
transport=dt_socket instructs the JVM that the debugger connections
will be made through a socket while the address=1044 parameter informs it that the port number
will be 1044. Similarly, if you substitute suspend=y, the JVM starts in suspended mode
and stays suspended until a debugger is attached to it. This may be helpful if you want to start
debugging as soon as the JVM starts.
Here is a table with descriptions of the jdb parameters:
Debugger Launch Parameters
Launch Parameter | Description |
-Xdebug | Enables the application to be debugged. |
-Xnoagent | Disables the sun.tools.debug agent so that the JPDA debugger can properly attach its own agent. |
-Djava.compiler=NONE | Disables the JIT (Just-In-Time) compiler. |
-Xrunjdwp | Loads the reference implementation of the Java Debug Wire Protocol, which enables remote debugging. |
transport | Name of the transport to be used when debugging the application. The value can be dt_shmem (for a shared memory connection) or dt_socket (for a socket connection). Shared memory connections are available only on Windows machines. |
server | If this value equals n, the application attempts to attach to the debugger at the address specified in the address subparameter. If this value equals y, the application listens for a connection at this address. |
address | For socket connections, specifies a port number used for communi-cation between the debugger and the application. For
shared memory connections, specifies a name that refers to the shared
memory to be used. This name can consist of any combination of
characters that are valid in filenames on a Windows machine except the
backslash. You use this name in the Name field of the Attach dialog box
when you attach the debugger to the running application. |
suspend | If the value is n, the application starts immediately. If the value is y, the application waits until a debugger has attached to it before executing. |
Debugging WebLogic
Debugging WebLogic is no different than debugging any other Java remote application.
You need to make sure to launch it with the required debugging arguments and attach a debugger.
In the case of WebLogic 8.1, you need to add these arguments to the startup script. WebLogic
comes with several launch scripts (*.sh and *.cmd) under BEA_HOME/weblogic81/server/bin.
- Locate startWSL.cmd and add the following variable DEBUG_OPTS:
set DEBUG_OPTS = -Xdebug -Xrunjdwp:transport= dt_socket,address=1044,server=y,suspend=n
- Next,
insert the new variable to the WebLogic startup command, after
"%JAVA_HOME%\bin\java" and preferably before the other options.
- Your startup script should look like:
"%JAVA_HOME%\bin\java" %DEBUG_OPTS% %JAVA_VM% %MEM_ARGS%
%JAVA_OPTIONS%-Dweblogic.Name=%SERVER_NAME%
-Dweblogic.management.username=
%WLS_USER%-Dweblogic.management.password= %WLS_PW%
-Dweblogic.management.server=
%ADMIN_URL%-Dweblogic.ProductionModeEnabled=
%PRODUCTION_MODE%-Djava.security.policy=
"%WL_HOME%\server\lib\weblogic.policy" weblogic.Server
Debugging IBM WebSphere 5.x/6.x
(Thanks to Michael Murphy)
- Open WebSphere 5.X/6.X Console
- Navigate to Servers | Application Servers | [SERVERNAME] | Process Definition | Java Virtual Machine
- Check off Debug Mode
- Arguments can be edited in the field called Debug arguments. You can paste
this line and use the same port 1044 to debug from Eclipse:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
Debugging JBoss
Same as WebLogic, except that you need to change run.bat/run.sh located under JBOSS_HOME/bin.
Linux users should see something similar to this:
$ cd /var/jboss4/bin
$ sh ./run.sh
=========================================================================
JBoss Bootstrap Environment
JBOSS_HOME: /var/jboss4
JAVA: /usr/java/j2sdk1.4.2_06/bin/java
JAVA_OPTS: -server -Xms128m -Xmx128m -Dprogram.name=run.sh
DEBUG_OPTS = -Xdebug -Xrunjdwp:transport= dt_socket,address=1044,server=y,suspend=n
CLASSPATH: /var/jboss4/bin/run.jar:/usr/java/j2sdk1.4.2_06/lib/tools.jar
=========================================================================
Hot Swapping Code in JBoss
Let's assume your JBoss is rooted in C:\JBoss and the application classpath
is C:\classes\myapp. You can tell Eclipse to compile your application classes to
this folder by setting it as the project
output folder. This should generally work, but there is a small catch.
If you are like me and use Ant scripts to build-clean from time to time you may want to ensure
that the contents of the output folder are not accidentally cleaned by Eclipse. Since Eclipse has
a Clean function for projects it is easy to swipe the entire folder and get only the
class files. So, to keep the Ant-generated files alongside with the *.class files that
Eclipse will generate you must tell Eclipse to be a little less harsh to your output folder.
- Begin by setting your Java project's output folder. Assuming JBoss' application classpath
is outside your Eclipse workspace, it may be a good idea to create a linked folder.
- Navigate to File | New | Folder.
- Enter classes as folder name. Click Advanced and point the new folder
to C:\classes\myapp.
- In the Project Properties page page, change the output folder to the newly created
classes folder. Click Project | Properties | Java Build Path. Fill the
Default output foder with the following:
- You are almost there. Navigate to Window | Preferences... | General | Workspace and
check Build automatically.
- Lastly, tell Eclipse not to erase other files in the
output folder every time it builds the project. While still in Preferences navigate to
Java | Compiler | Building and uncheckScrub
output folders when cleaning projects. That's it. Now every time you save a Java
file, Eclipse will recompile it and JBoss will reload it.
Debugging Tomcat
Debugging Tomcat is very much similar to WebLogic and JBoss, except that you need to change catalina.bat/catalina.sh
located under TOMCAT_HOME/bin.
Tomcat is a special case in the sense that there are couple of strategies you can employ to dubug and
achieve hot code replacement.
Using Sysdeo Tomcat Plugin for Eclipse
Sysdeo are the creators of a small and powerful Tomcat plugin for Eclipse. Among other things using
Sysdeo will allow you to debug Tomcat and reload contexts.
- Begin by
downloading the plugin from Sysdeo's website.
- Unzip the archive to ECLIPSE_HOME/plugins folder.
- Launch Eclipse. Navigate to Window | Preferences... | Tomcat.
- In the Plugin Preferences page, specify Tomcat version and home. There are two ways to declare
contexts in Tomcat. The new way is to create context files under TOMCAT_HOME/conf/Localhost.
In Preferences | Tomcat | Context declaration mode select Context files and the
contexts folder should be automatically selected (Tomcat 5.5.12).
- Close Preferences. Open any perspective. You should see three cat buttons on the toolbar.
To launch Tomcat, click the first icon. This will create a new server process and the Eclipse
debugger will be attached automatically. The debug mode is a preference which can be modified
from the Preferences page.
- You can also add projects to Tomcat's source and classpath lookup path, which you'll need if
you plan to step through the code. One thing you'll notice is that the plugin will redirect
Tomcat's output to Eclipse's console. Another important thing is the ability to append or
prepend JARs to the classpath or just pass JVM arguments to the launcher. You can set all these
in the plugin preferences page.
Configuring Reloadable Tomcat Context
Let's say that for whatever reason you do not want to use Sysdeo. You can still debug Tomcat easily:
- First create a new Tomcat context for your application.
Navigate to TOMCAT_HOME\conf\Catalina\localhost and create a new file, say, myapp.xml.
This will become part of your url, so to access your app you'll have to type
http://localhost:8080/myapp.
- Enter the following in myapp.xml:
<Context docBase="c:/eclipse_workspace/myapp/WebRoot" path="/HelloWorld"/>
This assumes you have a web application containing WEB-INF in c:/eclipse_workspace/myapp/WebRoot
- Create two environment variables:
C:\>set JDPA_ADDRESS=1044
C:\>set JDPA_TRANSPORT=dt_socket
- Now, you can launch Tomcat with these debug options:
C:\Tomcat-5.5.12\bin\>catalina jdpa start
- Use Eclipse to connect to Tomcat through port 1044
Hot Swap Code and Automatic Context Reloading with Tomcat
Debugging will in some cases involve changing the class and you'll naturally want the debugger
to pick the latest changes and reload them seamlessly. Well, that's normally the case, but not always.
To guarantee reloading of the context, you can define the context as reloadable.
Open myapp.xml and change it to:
<Context docBase="c:/eclipse_workspace/myapp/WebRoot" path="/HelloWorld" reloadable="true"/>
Now the context should relaod every time you make a change to any Java file. Note that it may take a few
moments to load, especially if the application is large. Similarly, if you have heavy bootstrap servlet
you may want to disable automatic reload because even the smallest change will cause the entire context
to reload.
Debugging JSP Pages
Debugging JSP in Eclipse can be done in several ways. The easy way is to get one of several commercial
plugins available with built-in support for JSP debugging. One such plugin is MyEclipse and another is
NitroX. In addition to JSP debugging these commercial plugins
come with tons of other features such as Database Explorer, XML editing, UML and ERD diagrams and more.
One side effect of this feature bonanza though is that the environment becomes "fatter" and less
responsive. In my experience, both plugins caused Eclipse to slow down considerably and at times the
environment became very unstable. Similarly, these memory-hungry plugins were the cause of frequent
Out of Memory Exceptions and subsequent environment crashes. Long story short, I finally bit
the bullet I decided to return to the basics. That's when I realized that debugging JSPs can be achieved
without any plugins. The process is a little more time consuming to set up, but the reward is a fast and stable environment.
Debugging JSPs becomes easier after knowing that they are converted into Java files. This takes place at
runtime, just before they are compiled by javac. In this example I am going to set JBoss, however
you can use a similar technique to set other servers. Since JBoss uses jasper and javac for
Java generation and compilation, it makes sense to begin by creating a Java project with the source folder
pointing to JBoss' JSP output folder. This project will be a regular java project with one notable
difference: the size of its source folder will change quite frequently as a result of changes made
to the JSPs and runtime recompilation done by JBoss.
Follow the following steps to set Eclipse for JSP debugging:
- Begin by launching JBoss.
- Locate where JBoss places compiled JSPs. Depending on whether you deploy WARs
and your actual server configuration you should find it somewhere similar to:
JBOSS_HOME\server\j2ee\work\jboss.web\localhost\myapp - Launch Eclipse. Navigate to File | New | Other.... Select Java Project and
click Next.
- In the New Java Project page, enter a Project name, for instance my_jsp.
Leave everything in default state and click Finish.
- Create a new linked folder to JBOSS_HOME\server\j2ee\work\jboss.web\localhost\myapp. This
folder will later become the project's source folder.
- Make src a source folder. Navigate to File | New | Source Folder
- Click Browse and select src. Click Finish. Agree with the
dialog that follows.
- While you are in the same dialog, change the Project output folder to src.
- Eclipse will try to compile my_jsp, but you'll see many problems. Two major issues
have to be resolved in order for the project to compile properly. First, the the jasper
libraries have to be added to the project's classpath and second it has to refer to
your Java code project my_java_code(Assuming you have a separate Java project
hosting domain classes and servlets).
- Open Project properties and add the following libraries to the classpath:
- JBOSS_HOME/server/j2ee/deploy/jbossweb-tomcat50.sar/jasper-runtime.jar
- JBOSS_HOME/server/j2ee/lib/javax.servlet.jsp.jar
Also, click the Projects tab and my_java_code to the classpath.
Now the my_jsp projects classpath should look like:
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry excluding="src/" kind="src" path=""/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="C:/jboss-4.0.1sp1/server/j2ee/deploy/jbossweb-tomcat50.sar/jasper-runtime.jar"/>
<classpathentry kind="lib" path="C:/jboss-4.0.1sp1/server/j2ee/lib/javax.servlet.jsp.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/my_java_code"/>
<classpathentry kind="output" path="src"/>
</classpath>
- Navigate to Project | Build Project. This time it should build with no probelms.
- Start JBoss. Use Eclipse debugger to begin a debug session.
- Open a browser and access several pages. Go back to Eclipse, right-click on my_jsp and
select Refresh. You should now have new Java classes that did not exist before.
- Double-click on any new Java class. Open the _jspService method and set a
breakpoint. Go back to the browser and hit Refresh.
- The JSP page should come up and you should be able to step through the code. The interesting
thing is that while the debugger will be stepping through the Java class representing the JSP page
the JSP editor will automatically link the tow and you'll get the impression you're stepping
through the JSP code itself. All variables will be set and after that you can really debug the page
as any other Java class. Now you should be all set!
Debugger Verification
Now you can launch your application in debug mode. Just to make sure that the server is
listening to port 1044 you can run netstat /a. You should see port 1044 in the list of open ports
(See Figure 1: List of open ports: netstat -a).
Figure 1 List of open ports: netstat -a
The Eclipse Connection
After making sure WebLogic is listening for incoming connections on port 1044, what is left is to tell Eclipse to connect to
this port and you are ready to debug.
- In Eclipse, navigate to Run | Debug(See
Figure 2: Create new Remote Java Application configuration in Eclipse).
- Select Remote Java Application, on the left column. Click New, on the bottom of the same column.
- In the Create configuration screen you'll be prompted to enter some values. Start with a meaningful name. In my case that's WebLogic Instance. For Project, select the Java project that contains the source code you want to debug. Leave Connection Type in default, i.e. Standard (Socket Attach). For Host, enter localhost.
If you want to debug a remote server, enter its hostname or IP address. For port, enter 1044 or the port you defined in your
WebLogic startup script.
- Click Apply
- Make sure WebLogic instance is running in debug mode. In the same screen click Debug.
Eclipse should automatically take you to the Debug perspective and you should see a stack trace in the Debug view.
- If you are not automatically taken to the Debug perspective, select Window | Open Perspective | Other and
then click Debug.
Figure 2 Create new Remote Java Application configuration in Eclipse
Figure 3 Breakpoint hit in Eclipse debugger
Eclipse Debug window should automatically pop-up with the stack pointer on your first
breakpoint (See Figure 3: Breakpoint hit in Eclipse's debugger).
After that, you can use all the various functions that the debugger has
to offer, namely variable assignments, step-into, drop to frame, etc.
References
System Information
- Windows XP Professional
- JDK 1.4.2_07
- Eclipse 3.2
- BEA WebLogic 8.1
- JBoss 4.0.2
- Tomcat 5.5.12
About the Author
Levent
Gurses is a Washington, DC-based technology consultant. He is also one
of the co-founders of Jacoozi,
an integrated solutions provider based in Alexandria, VA. In his
professional life Levent helps clients overcome their J2EE challenges
and develop leaner and meaner software development practices. Most of
his free time goes in reading and motorcycle racing.
( 2005年12月29日, 05:35:52 下午 EST )PermalinkPrint