Todos los m�todos de servicio de un servlet deber�an estar terminados cuando se elimina el servlet. El servidor intenta asegurarse llamando al m�todo destroy s�lo despu�s de que todas las peticiones de servicio hayan retornado, o despu�s del periodo de tiempo de gracia espec�fico del servido, lo que ocurra primero. Si nuestro servlet tiene operaciones que tardan mucho tiempo en ejecutarse (esto es, operaciones que tardan m�s que el tiempo concedido por el servidor), estas operaciones podr�an estar ejecut�ndose cuando se llame al m�todo destroy. Debemos asegurarnos de que cualquier thread que maneje peticiones de cliente se hayan completado; el resto de est� p�gina describe una t�cnica para hacer esto.
Si nuestro servlet tiene peticiones de servicio potencialmente largas, debemos utilizar las t�cnicas de esta lecci�n para.
- Seguir la pista de cuantos threads est�n ejecutando el m�todo service actualmente.
- Proporcionar una limpieza de desconexi�n haciendo que el m�todo destroy notifique a los threads la desconexi�n y espere a que ellos se hayan completado.
- Haciendo que todos los m�todos de larga duraci�n comprueben peri�dicamente la desconexi�n y, si es necesario, paren su trabajo, limpien y retornen.
�Peticiones de Seguimiento de Servicio
Para seguir la pista a una petici�n de servicio, incluimos un campo en nuestra clase servlet que cuente el n�mero de m�todos de servicio que se est�n ejecutando. El campo deber� tener acceso a m�todos para incrementar, decrementar y devolver su valor. Por ejemplo.
public ShutdownExample extends HttpServlet {
private int serviceCounter = 0;
...
//Access methods for serviceCounter
protected synchronized void enteringServiceMethod() {
serviceCounter++;
}
protected synchronized void leavingServiceMethod() {
serviceCounter--;
}
protected synchronized int numServices() {
return serviceCounter;
}
}
El m�todo service deber�a incrementar el contador de servicios cada vez que se entre en �l y decrementarlo cada vez que se salga de �l. Esta es una de las pocas veces que al subclasificar la clase HttpServlet debamos sobreescribir el m�todo service. El nuevo m�todo deber�a llamar al super.service para preservar la funcionalidad del m�todo HttpServlet.service original.
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
enteringServiceMethod();
try {
super.service(req, resp);
} finally {
leavingServiceMethod();
}
}
�Proporcionar Limpieza a la Desconexi�n
Para proporcionar esta limpieza, nuestro m�todo destroy no deber�a destruir ning�n recurso compartido hasta que todas las peticiones de servicio se hayan completado. Una parte de esto es chequear el contador de servicos. Otra parte es notificar a los m�todos de larga duraci�n que es la hora de la desconexi�n. Para esto, se necesita otro campo con sus m�todos de acceso normales. Por ejemplo.
public ShutdownExample extends HttpServlet {
private Boolean shuttingDown;
...
//Access methods for shuttingDown
protected setShuttingDown(Boolean flag) {
shuttingDown = flag;
}
protected Boolean isShuttingDown() {
return shuttingDown;
}
}
Abajo podemos ver un m�todo destroy que utiliza estos campos para proporcionar una limpieza de desconexi�n.
public void destroy() {
/* Check to see whether there are still service methods running,
* and if there are, tell them to stop. */
if (numServices() > 0) {
setShuttingDown(true);
}
/* Wait for the service methods to stop. */
while(numServices() > 0) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
}
}
}
�Crear M�todos de Larga Duraci�n Educados
El paso final para proporcionar una limpieza de desconexi�n es crear m�todos de larga duraci�n que sean educados. Estos m�todos deber�an comprobar el valor del campo que notifica las desconexiones, e interrumpir su trabajo si es necesario. Por ejemplo.
public void doPost(...) {
...
for(i = 0; ((i < lotsOfStuffToDo) && !isShuttingDown()); i++) {
try {
partOfLongRunningOperation(i);
} catch (InterruptedException e) {
}
}
}