001: /*
002: ItsNat Java Web Application Framework
003: Copyright (C) 2007 Innowhere Software Services S.L., Spanish Company
004: Author: Jose Maria Arranz Santamaria
005:
006: This program is free software: you can redistribute it and/or modify
007: it under the terms of the GNU Affero General Public License as published by
008: the Free Software Foundation, either version 3 of the License, or
009: (at your option) any later version. See the GNU Affero General Public
010: License for more details. See the copy of the GNU Affero General Public License
011: included in this program. If not, see <http://www.gnu.org/licenses/>.
012: */
013:
014: package org.itsnat.impl.core.listener;
015:
016: import java.util.HashMap;
017: import java.util.Map;
018: import org.itsnat.core.ItsNatException;
019: import org.itsnat.impl.core.ItsNatDocumentImpl;
020: import org.itsnat.impl.core.event.client2serv.*;
021: import org.itsnat.impl.core.js.listener.EventListenerJSRenderImpl;
022: import org.itsnat.impl.core.js.listener.AsyncTaskEventListenerJSRenderImpl;
023:
024: /**
025: *
026: * @author jmarranz
027: */
028: public class AsyncTaskRegistry {
029: protected Map tasks = new HashMap();
030: protected ItsNatDocumentImpl itsNatDoc;
031:
032: /**
033: * Creates a new instance of AsyncTaskRegistry
034: */
035: public AsyncTaskRegistry(ItsNatDocumentImpl itsNatDoc) {
036: this .itsNatDoc = itsNatDoc;
037: }
038:
039: public AsyncTaskEventListenerWrapperImpl createAsyncTaskEventListenerWrapper(
040: AsyncTask taskContainer, long ajaxTimeout) {
041: return new AsyncTaskEventListenerWrapperImpl(
042: (AsyncTask) taskContainer, ajaxTimeout, itsNatDoc);
043: }
044:
045: public EventListenerJSRenderImpl getJSRender() {
046: return AsyncTaskEventListenerJSRenderImpl.SINGLETON;
047: }
048:
049: public void addAsynchronousTask(Runnable task, boolean lockDoc,
050: long maxWait, long ajaxTimeout) {
051: // Usar por ejemplo cuando una tarea
052: // va a ser muy larga pero no es deseable que esté bloqueado durante la tarea (lockDoc = false)
053: // y dicha tarea modifica el documento
054: // por lo que hay que recoger los cambios, dichos cambios se recogerán
055: // a través de un evento generado automáticamente al volver al cliente y asíncrono.
056:
057: AsyncTask taskContainer = new AsyncTask(task, lockDoc, maxWait,
058: itsNatDoc);
059: AsyncTaskEventListenerWrapperImpl listener = createAsyncTaskEventListenerWrapper(
060: taskContainer, ajaxTimeout);
061:
062: EventListenerWrapperImpl evtListener = (EventListenerWrapperImpl) listener;
063:
064: String id = evtListener.getId();
065:
066: tasks.put(id, listener);
067:
068: taskContainer.start();
069:
070: getJSRender().addEventListenerCode(evtListener);
071: }
072:
073: public AsyncTaskEventListenerWrapperImpl removeAsynchronousTask(
074: String id) {
075: // Método no público, es llamado por el framework
076: // En este contexto hay que recordar que el ItsNatDocument está bloqueado
077: // por el hilo actual.
078:
079: AsyncTaskEventListenerWrapperImpl listener = (AsyncTaskEventListenerWrapperImpl) tasks
080: .get(id);
081: if (listener == null)
082: throw new ItsNatException("Asynchronous Task with id " + id
083: + " does not exist");
084:
085: AsyncTask task = listener.getAsyncTask();
086:
087: if (!task.isAlive()) {
088: task.dispose();
089: tasks.remove(id);
090: }
091:
092: // El hilo-tarea está vivo todavía, si locksDocument() es true no debería estar vivo
093: // todavía pues no podríamos llegar aquí si el documento está bloqueado por la tarea
094: // (o bien acaba de salir del synchronized y todavía no se ha marcado el hilo como finalizado)
095: // El problema más bien es cuando locksDocument() devuelve false, en ese caso
096: // la tarea puede ser muy larga y el programador tiene la obligación
097: // de bloquear el ItsNatDocument en el momento que vaya a acceder al mismo (resultados, cambios en el DOM etc),
098: // esto supone que como ahora el ItsNatDocument está bloqueado por el hilo
099: // actual NO podemos esperar al hilo-tarea a que acabe (con un join())
100: // pues éste en *cualquier momento* puede intentar bloquear el ItsNatDocument
101: // por lo que entraríamos en un bloqueo mutuo.
102: // Para resolver el problema hay que obtener el Thread que no ha terminado todavía, esto implica
103: // que se ha de intentar de nuevo pero antes desbloqueando el ItsNatDocument
104: // para que el hilo-tarea pueda bloquear el ItsNatDocument si lo necesita
105: // o bien otros request puedan hacer su trabajo. Con el Thread
106: // podremos hacer un join() fuera del documento sincronizado, de esa manera
107: // el hilo podrá esperar "dormido" hasta que termine el hilo
108:
109: return listener;
110: }
111: }
|