Chapter 26: Debugging Java Server Applications
Download
Report
Transcript Chapter 26: Debugging Java Server Applications
Debugging Java Server
Applications
Yingzi Jin
4/16/01
1
Debugging Java Server
Applications
Differences of Java Server Programming
Debugging Tools and Techniques
2
What’s the differences?
Java is used as the programming language
The application runs mainly on the server
Processes often run for a very long time.
The applications should:
Be stable and robust
Run in a multi-user/multi-threaded/multi-server environment
Be able to handle heavy loads with reasonable performance
3
The Java Language
Create small, clear components and follow the guidelines
for creating beans
Java Debugger(JDB)
http://java.sun.com/products/jdk/1.2/docs/tooldocs/win32/
jdb.html
4
The Application Runs on the Server
Server applications generally run in a non-visual
environment.
– Exceptions are ignored using an empty catch clauses
Try{
// Problematic code
}catch(Exception e){ }
5
Long Running Processes
Problems: running out of system memory
resources(memory leak).
–
Garbage collector can do something.
–
Loiterers
Jprobe and Optimizeit
–
6
Long Running Processes(‘cont)
Memory- or resources-related bugs: they only show up after
a certain time .
Try{
FileInputStream in = new FileInputStream
// Do something that can throw an IOException
In.close();
}catch(IOException e){//We don’t have a handle here to the InputStream
}
7
Long Running Processes(‘cont)
try{
Connection conn=//Get a connection from the pool
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(“SELECT COLUMNS FROM TABLE”);
// Get the values
// or update the database
rs.close();
stmt.close();
return conn to the pool();
}catch(SQLException e){System.out.println(e.getMessage());}
8
Long Running Processes(‘cont)
The correct code:
Connection conn=null;
Statement stmt=null;
ResusltSet rs=null;
Try{
conn=get connection form the pool
conn.setAutoCommit(false);
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(“SELECT COLUMNS FROM TABLE”);
// Get the values
// or update the database
conn.commit();
}
9
Long Running Processes(‘cont)
catch(SQLException e){
System.out.println(e.getMessage());
While ((e=e.getNextException())!=null){
System.out.println(“next”+e.getMessage());
}
}finally{
try{
if(rs!=null){rs.close();}
if(stmt!=null){stmt.close();}
if(conn!=null){conn.rollback(); return the conn to the pool}
}catch(SQLException e){
System.out.println(e.getMessage());
while((e=e.getNextException())!=null){
System.out.println(“ next”+e.getMessage());
}
}
}
10
nested exception
Public class NestedException extends Exception{
private Exception nested;
public NestedException(){}
public NestedException(String msg){super(msg);}
public NestedException(String msg, Exception
nested){super(msg);this.nested=nested;}
Public Exception getNestedException(){return nested;}
}
11
nested exception(‘cont)
To throw the higher-level exceptions and catch the lowerlevel ones:
Public boolean login(String userid, String password) throws
LoginException {
try{}catch(SQLException e){
//Log the error
throw new LoginException(“Could not validate login”, e);
//Constructor type 3 from NestedException
}
}
12
Robustness and Stability(‘cont)
Override the getMessage() method to recursively get all the information
from a NestedException
Public String getMessage(){
StringBuffer msg = new StringBuffer(super.getMessage());
if(nested !=null){
msg.append(“\r\n”);// or<BR /> for display in browser
msg.append(nested.getMessage());
}
return msg.toString();
}
13
Multi-User/Multi-Thread
Import java.io.*;
Import javax.servlet.*;
Import javax.servlet.http.*;
Public calss HitCounter extends HttpServlet{
int hits=0;
public void doGet(HttpServletRequest req, httpServletResponse res) throws ServletException,
IOException{
PrintWriter out = res.getWriter();
res.setContentType(“text/html”);
hits++;
out.println(“<html><head><titile>Run command</titile></head>”);
out.println(“<body><h1>You are visitor # ” );
out.println(hits);
out.println(“</h1></body></html>”);
}
}
14
Multi-User/Multi-Thread(‘cont)
public void doGet(HttpServletRequest req, httpServletResponse res) throws
ServletException, IOException{
PrintWriter out = res.getWriter();
res.setContentType(“text/html”);
out.println(“<html><head><titile>Run command</titile></head>”);
out.println(“<body><h1>Number of hits: ” );
synchronized(this){
hits++;
out.println(hits);
}
out.println(“</h1></body></html>”);
}
15
Multi-User/Multi-Thread(‘cont)
Synchronizing can have a serious impact on
execution speed.
Need to decide “What to synchronize”
Synchronizing too much can cause deadlock
problems
16
What to synchronize?
Where can we expect concurrency problems?
Servlet member variable
There’s normally only one instance of a servlet and every request uses that same
servlet instance, every method that changes member variables should use
synchronized blocks.
Objects stored in the ServletContext( the JSP application scope).
Objects stored in a session.(multiple threads originate from a single user)
Use a cache mechanism
Singleton patterns and static methods that access static variables.
RMI remote objects member variables
17
Performance
Using a StringBuffer instead of concatenating Strings
Change the code like:
out.print(“Hey, ”+username+” <p>”);
out.print(“you chose item # “+ itemNr + “ <BR>”);
Into:
out.print(“Hey, ”);
out.print(userName);
out.print(“<P>”);
out.print(“you chose item #”);
out.print(“ <BR>”);
18
Performance(‘cont)
Or:
StringBuffer responseLine = new
StringBuffer();
responseLine.append(“Hey, ”);
responseLine.append(userName);
responseLine.append(“<P> ”);
responseLine.append(“you chose item # ”);
responseLine.append(itemNr);
responseLine.append(“ <BR>”);
Out.println(responseLine.toString());
19
Debugging Tools and Techniques
Integrated Debuggers
–
VisualAge, Jbuilder
Do-It-Yourself, the JDB
20
Integrated Debuggers
Many problems (like concurrency bugs) cannot be caught by
integrated debuggers.
Remote debugging.
The VM’s on the different servers has different debug mode.
The debugger is often linked to a specific application server
and even to a certain platform.
Debugging a server-side application will never be easy.
Some of these tools aren’t bug free themselves.
These tools can be rather expensive.
21
Do-It-Yourself, the JDB
JDB allows remote debugging.
Windows:set CLASSPATH=lib\jsdk.jar;examples;%classpath%
$ jdb sun.servlet.http.HttpServer
Initializing jdb…
0xee2fa2f8:class(sun.servlet.http.HttpServer)
> stop in SnoopServlet.doGet
Breakpoint set in SnoopServlet.doGet
> run
run sun.servlet.http.HttpServer
running ...
main[1] servletrunner starting with settings:
port = 8080
backlog = 50
max handlers = 100
timeout = 5000
servlet dir = ./examples
document dir = ./examples
servlet propfile = ./examples/servlet.properties
http://yourmachine:8080/servlet/SnoopServlet
22
A Broader View
Eyeballing
System.out.println()
Unit Testing
Self-Made Monitoring Tools
23
Eyeballing
In order to enhance the visual inspection:
Keep methods small and clear
Try to make the code self-explanatory. Use intuitive variable and
method names
Use proper indentation. Whatever style we use for aligning braces, be
consistent.
Use a good code editor
24
System.out.println()
It can be used everywhere without the need to install any
extra classes.
It doesn’t interfere much with the normal execution flow of
the application, which makes it very valuable when timing
is crucial.
Reduce debugging overhead by not use string
concatenation
25
Unit Testing
A unit test’s purpose is to determine whether the unit
works as designed.
We can design how to write applications that don’t have
any bugs in the first place by employing unit testing.
A unit almost always corresponds to a class.
The tool for unit testing is Junit.
Testing by itself doesn’t directly help us find bugs, but
makes it easier to detect whether there are problems or not.
26
Self-Made Monitoring Tools
Sessions
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import javax.servlet.*;
import javax.servlet.http.*;
// SDK version 2.0 !!!
public class SessionMonitor extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
HttpSession session = req.getSession(true);
out.println("<html><head><title>session monitor</title></HEAD>");
out.println("<body><h1>SessionMonitor</h1>");
out.println("This form allows us to add new string values to the current session to check out this servlet<br />");
out.println("<form>add string key <input type=\"text\" name=\"key\"><br/>");
out.println("add string value<input type=\"text\" name=\"value\"><br/>");
out.println("<input type=\"submit\"></form><p>");
27
Self-Made Monitoring Tools
testInit(req,session);
String beanName = req.getParameter("name");
if (beanName == null) {
showBeanList(req, session, out);
} else {
showSingleInstance(beanName, session, out);
}
out.println("</body></html>");
}
private void testInit(HttpServletRequest req, HttpSession session) {
String newKey = req.getParameter("key");
String newValue = req.getParameter("value");
if ((newKey !=null) && (newValue != null)){
TestBean test= new TestBean();
test.setValue1(newValue);
test.setValue2("fixed text");
test.setValue3(newKey+"-->"+newValue);
session.putValue(newKey, test);
// for servlet API < 2.2 use setValue instead of setAttribute
}
}
28
Self-Made Monitoring Tools(‘cond)
testInit(req,session);
String beanName = req.getParameter("name");
if (beanName == null) {
showBeanList(req, session, out);
} else {
showSingleInstance(beanName, session, out);
}
out.println("</body></html>");
}
private void testInit(HttpServletRequest req, HttpSession session) {
String newKey = req.getParameter("key");
String newValue = req.getParameter("value");
if ((newKey !=null) && (newValue != null)){
TestBean test= new TestBean();
test.setValue1(newValue);
test.setValue2("fixed text");
test.setValue3(newKey+"-->"+newValue);
session.putValue(newKey, test);
// for servlet API < 2.2 use setValue instead of setAttribute
}
}
29
Self-Made Monitoring Tools(‘cont)
private void showBeanList(HttpServletRequest req, HttpSession session, PrintWriter out) {
String URI = req.getRequestURI();
String[] names = session.getValueNames();
// for servlet API < 2.2 use getValueNames instead of getAttributeNames
for (int i=0;i<names.length;i++){
String attributeName= names[i];
out.print("<A HREF=");
out.print(URI);
out.print("?name=");
out.print(attributeName);
out.print(">");
out.println(attributeName);
out.print("</A><br />");
}
}
private void showSingleInstance(String beanName,
HttpSession session,
PrintWriter out) {
Object check = session.getValue(beanName);
// for servlet API < 2.2 use getValue instead of getAttribute
30
Self-Made Monitoring Tools(‘cond)
private class TestBean {
public String value1;
public String value2;
public String value3;
public String getValue1() {
return value1;
}
public void setValue1(String value) {
value1 = value;
}
public String getValue2() {
return value2;
}
public void setValue2(String value) {
value2 = value;
}
public String getValue3() {
return value3;
}
public void setValue3(String value) {
value3 = value;
}
}
}
31
Self-Made Monitoring Tools(‘cond)
32
Self-Made Monitoring Tools(‘cond)
33
Self-Made Monitoring Tools(‘cond)
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class FileViewer extends HttpServlet{
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String fileName = (req.getParameter("fileName"));
if (fileName != null) {
doView(req,res,fileName);
} else {
PrintWriter out = res.getWriter();
out.println("<html><head><title> File viewer</title></head><body>");
out.println("<form> filename<input type=text name=fileName size=50><br />");
out.println(" skip first <input type=text name=first size=4> and show ");
out.println(" <input type=text name=size size=4 /> bytes<br />");
out.println("Or Show last <input type=text name=last size=4 /> bytes<p>");
out.println("<input type=submit /></form> </body></html>");
}
}
34
Self-Made Monitoring Tools(‘cond)
public void doView(HttpServletRequest req, HttpServletResponse res, String fileName) throws ServletException,
IOException {
PrintWriter out = res.getWriter();
out.println("<html><head><title>View file</title></head><body bgcolor=silver>");
out.println("<p><pre>");
if (fileName != null) {
RandomAccessFile in = null;
try {
in = new RandomAccessFile (fileName,"r");
int len = 0;
try {
len = Integer.parseInt(req.getParameter("last"));
in.seek(in.length() - len);
} catch (NumberFormatException e){}
try{
len = Integer.parseInt(req.getParameter("first"));
in.seek(len);
} catch (NumberFormatException e){}
int size = 0;
try{
size = Integer.parseInt(req.getParameter("size"));
} catch (NumberFormatException e){}
String line = null;
int runningSize = 0;
35
Self-Made Monitoring Tools(‘cond)
while ((line=in.readLine()) != null){
out.print(line);
runningSize += line.length();
if (size>0 && runningSize > size){
break;
}
out.println("</pre><br />");
}
} catch (IOException e){
out.println(e.getMessage());
}
finally{
if (in != null){
in.close ();
}
}
}
out.println("<p>");
out.println("</body></html>");
}
}
36
Self-Made Monitoring Tools(‘cond)
37
Self-Made Monitoring Tools(‘cond)
38
Self-Made Monitoring Tools(‘cond)
Commands
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RunBatch extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
String command = req.getParameter("command");
if (command == null) {
PrintWriter out = res.getWriter();
res.setContentType("text/html");
out.println("<html><head><title>Run command</title></head>");
out.println("<body><form><input type=text size=80 name=command><input
type=submit>");
out.println("</form></body></html>");
}
39
Self-Made Monitoring Tools(‘cond)
else {
Process proc = Runtime.getRuntime().exec(command);
InputStream procOut = proc.getInputStream();
byte[] buf = new byte[4096];
int bytesRead;
OutputStream out = res.getOutputStream();
res.setContentType("text/html");
out.write("<html><head><title>Run
command</title></head><BODY><PRE>".getBytes());
while((bytesRead=procOut.read(buf)) != -1) {
out.write(buf,0,bytesRead);
}
procOut.close();
out.write("</PRE></BODY></HTML>".getBytes());
}
}
}
40
Self-Made Monitoring Tools(‘cond)
41
Self-Made Monitoring Tools(‘cond)
42
summary
First we looked at what’s typical in Java server
programming
Then java server applications should be stable and robust,
in a multi-user/multi-threaded environment.
Know how to make best use of ‘old style’ debugging.
At the end, how to create servlets to monitor what’s
happening in the different components.
43