Tempo fa abbiamo dedicato un articolo all'individuazione degli errori nelle pagine JSP. Oggi cerchiamo di affrontare un discorso analogo per le Servlet utilizzando, per le operazioni di debug, gli strumenti messi a disposizione da Tomcat. Non c'è dubbio che esistano degli ottimi strumenti che possono svolgere egregiamente tale compito ma è sempre buona norma imparare a comprendere certi meccanismi partendo da semplici operazioni manuali.
Utilizzo della Console di Tomcat
Se si sta utilizzando Tomcat in un ambiente di sviluppo di tipo stand-alone è possibile avvalersi della console dello stesso Tomcat per stampare a video eventuali messaggi che diano indicazioni utili al programmatore come, ad esempio, il valore di alcune variabili in un determinato istante di tempo.
Supponiamo di avere un semplice scenario in cui ci sia una pagina HTML che invochi una servlet, passandole un parametro via HTTP POST
.
Listato 1. Pagina HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Inserisci il tuo nome</title>
</head>
<body>
<h1>Inserisci il tuo nome</h1>
<p>Inserisci il tuo nome e premi il pulsante Invia</p>
<form action="DummyServlet" method="post">
<table cellspacing="5" border="0">
<tr>
<td align="right">Nome:</td>
<td><input type="text" name="nome" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Invia"/></td>
</tr>
</table>
</form>
</body>
</html>
Listato 2. Codice della Servlet
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
public class DummyServlet extends javax.servlet.http.HttpServlet
{
public void doPost (HttpServletRequest request,
&nb
sp; HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType( "text/html");
PrintWriter out = response.getWriter();
String nome = request.getParameter("nome");
out.println("<html>");
out.println("<body>");
out.println("Il tuo nome è lungo " + nome.length() + " caratteri");
out.println("</body>");
out.println("</html>");
}
}
Le due pagine web risultanti sono rappresentate nelle figure seguenti.
È banale verificare che la lunghezza del nome inserito sia effettivamente corrispondente a quella del risultato ottenuto ma, in generale, non è detto che sia sempre possibile effettuare simili verifiche direttamente dai dati visualizzati a video. In questi casi, possiamo avvalerci della console di Tomcat per monitorare i valori delle proprietà per le quali abbiamo bisogno di un riscontro sicuro.
Per lanciare la console di Tomcat avviamo il nostro Web Application Server da linea di comando.
A questo punto, apportiamo una semplice modifica al codice della Servlet precedente aggiungendo la seguente riga di codice (evidenziata in rosso).
...
String nome = request.getParameter("nome");
System.out.println(nome); // Stampa il valore sulla console
out.println("<html>");
...
Rieseguiamo la nostra semplice applicazione e notiamo che nella console appare una riga in più, che è proprio il valore del parametro che arriva in input alla servlet.
Scrittura dei dati di debug su un file di log
Se non abbiamo la possibilità di stampare i dati di debug sulla console, possiamo utilizzare un altro metodo: salvarli su un file di log. Sebbene ogni servlet engine (Tomcat è un esempio di Servlet Engine) abbia una procedura di salvataggio dei log leggermente diversa dagli altri server, in generale è possibile utilizzare due metodi di scrittura dei log supportati da tutti i servlet engine, questi metodi appartengono alla classe HttpServlet e sono:
log (String message)
log (String message, Throwable t)
Se si desidera semplicemente scrivere un messaggio su un file di log, sarà sufficiente utilizzare il primo metodo, passandogli in input il messaggio desiderato. Se, invece, si vuole scrivere un messaggio accompagnato da una descrizione dettagliata dello stack trace
relativo ad una certa eccezione verificatasi, dovrà essere utilizzato il secondo metodo.
Lo stack trace, per coloro che non avessero familiarità con tale terminologia, corrisponde ad una serie di messaggi che indicano tutta la serie di chiamate a metodi che precedono quella che ha scatenato un'eccezione.
Tomcat salva i suoi log file nella directory denominata "logs". Al suo interno, vengono conservati svariati file di log, uno per tipologia, suddivisi per data.
Vediamo, allora, un semplice esempio ottenuto aggiungendo tre righe di codice alla servlet:
...
String nome = request.getParameter("nome");
log("Messaggio inserito dalla DummyServlet - START");
log("Valore del parametro 'nome' fornito in input: " + nome);
log("Messaggio inserito dalla DummyServlet - END");
out.println("<html>");
...
Mandiamo nuovamente in esecuzione la servlet (partendo sempre dalla pagina HTML iniziale) ed osserviamo il file di log (nella directory "logs" di Tomcat) con denominazione localhost.[anno]-[mese]-[giorno].log
, con i valori di anno, mese e giorno corrispondenti, naturalmente, a quelli relativi al tempo di esecuzione della servlet (ad esempio localhost.2006-08-20.log
).
È facile riconoscere, nelle righe finali del file di log, i messaggi da noi inviati attraverso l'invocazione del metodo log.
Oltre ai messaggi da noi inseriti, però, sono presenti anche altre informazioni scritte direttamente dal servlet engine, che potrebbero renderlo poco leggibile. Per ovviare al problema, basterà creare una classe personalizzata per la scrittura dei log che generi file con percorsi e nomi a nostro piacimento e, per il resto, metta a disposizione due metodi uguali a quelli della classe HttpServlet.
Listato 3. Classe personalizzata per la gestione dei log
import java.io.*;
public class CustomLog
{
private static String FILE = "../webapps/DummyServlet/WEB-INF/etc/Log.txt";
public static void logToFile(String message)
{
try
{
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(FILE, true)));
out.println(message);
out.close();
}
catch(IOException exc){}
}
public static void logToFile(String message, Throwable t)
{
try
{
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(FILE, true)));
out.print(message);
out.println(t.toString());
out.close();
}
catch(IOException exc){}
}
}
Alla prossima.