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.request;
015:
016: import org.itsnat.core.ItsNatException;
017: import org.itsnat.core.event.RemoteControlEvent;
018: import org.itsnat.impl.core.*;
019: import org.itsnat.impl.core.client.ClientDocumentInvitedRemoteCtrlCometImpl;
020: import org.itsnat.impl.core.client.ClientDocumentInvitedRemoteCtrlImpl;
021: import org.itsnat.impl.core.client.ClientDocumentInvitedRemoteCtrlTimerImpl;
022: import org.itsnat.impl.core.listener.CometTask;
023: import org.itsnat.impl.core.listener.GenericTask;
024: import org.itsnat.impl.core.event.client2serv.RemoteControlCometTaskEventImpl;
025: import org.itsnat.impl.core.listener.RemoteControlCometTaskEventListenerWrapperImpl;
026: import org.itsnat.impl.core.event.client2serv.RemoteControlEventImpl;
027: import org.itsnat.impl.core.event.client2serv.RemoteControlTimerEventImpl;
028: import org.itsnat.impl.core.listener.RemoteControlTimerEventListenerWrapperImpl;
029: import org.itsnat.impl.core.response.ResponseRemoteControlEventImpl;
030:
031: /**
032: *
033: * @author jmarranz
034: */
035: public class RequestRemoteControlEventImpl extends
036: RequestRemoteControlImpl {
037: protected String observerId;
038:
039: /**
040: * Creates a new instance of RequestRemoteControlEventImpl
041: */
042: public RequestRemoteControlEventImpl(String observerId,
043: ItsNatServletRequestImpl itsNatRequest) {
044: super (itsNatRequest);
045:
046: this .observerId = observerId;
047: }
048:
049: public boolean isUnloadRequest() {
050: String unloadParam = itsNatRequest
051: .getParameterOrAttribute("itsnat_unload");
052: return ((unloadParam != null) && unloadParam.equals("true"));
053: }
054:
055: public void process() {
056: ItsNatSessionImpl session = itsNatRequest
057: .getItsNatSessionImpl();
058: ClientDocumentInvitedRemoteCtrlImpl observer = session
059: .getClientDocumentInvitedRemoteCtrl(observerId);
060: if (observer == null) {
061: // Evitamos enviar a toda costa una excepción cuando *se está cerrando una ventana*
062: // pues MSIE no cierra la conexión de dicho request "fallido" y total
063: // no nos vamos a enterar del error pues la ventana se cierra y ni siquiera
064: // se procesa el XMLHttpRequest "fallido".
065: // Este caso puede darse ante un rechazo
066: if (isUnloadRequest())
067: return;
068: throw new ItsNatException(
069: "Remote observer does not exist with session/document id: "
070: + session.getId() + "/" + observerId);
071: }
072:
073: ItsNatDocumentImpl itsNatDoc = observer.getItsNatDocumentImpl();
074: if (itsNatDoc != null) {
075: GenericTask taskPendingToFinish = null;
076:
077: do {
078: synchronized (itsNatDoc) // Sólo un hilo puede acceder al mismo documento
079: {
080: itsNatRequest.setItsNatDocument(itsNatDoc);
081: itsNatRequest.setClientDocument(observer);
082:
083: try {
084: ItsNatServletResponseImpl itsNatResponse = itsNatRequest
085: .getItsNatServletResponseImpl();
086:
087: ResponseRemoteControlEventImpl response = null;
088:
089: if (isUnloadRequest()) {
090: observer
091: .setPhase(RemoteControlEvent.UNLOAD);
092:
093: RemoteControlEventImpl requestEvent = null;
094: if (observer instanceof ClientDocumentInvitedRemoteCtrlTimerImpl) {
095: ClientDocumentInvitedRemoteCtrlTimerImpl observerTimer = (ClientDocumentInvitedRemoteCtrlTimerImpl) observer;
096: RemoteControlTimerEventListenerWrapperImpl listener = observerTimer
097: .getRemoteControlTimerEventListenerWrapper();
098: requestEvent = new RemoteControlTimerEventImpl(
099: listener, itsNatRequest);
100: } else if (observer instanceof ClientDocumentInvitedRemoteCtrlCometImpl) {
101: ClientDocumentInvitedRemoteCtrlCometImpl observerComet = (ClientDocumentInvitedRemoteCtrlCometImpl) observer;
102: RemoteControlCometTaskEventListenerWrapperImpl listener = new RemoteControlCometTaskEventListenerWrapperImpl(
103: null, observerComet);
104: requestEvent = new RemoteControlCometTaskEventImpl(
105: listener, itsNatRequest);
106: }
107: response = new ResponseRemoteControlEventImpl(
108: requestEvent, itsNatResponse);
109: } else if (observer.getPhase() == RemoteControlEvent.REFRESH) {
110: // Es un evento de refresco pero mientras se enviaba es posible
111: // que el observado (el propietario) se haya destruido aunque no haya sido garbage collected dentro del objeto observer, así podemos notificar al usuario
112: if (itsNatDoc.isInvalid())
113: observer
114: .setPhase(RemoteControlEvent.OBSERVED_INVALID);
115:
116: if (observer instanceof ClientDocumentInvitedRemoteCtrlTimerImpl) {
117: ClientDocumentInvitedRemoteCtrlTimerImpl observerTimer = (ClientDocumentInvitedRemoteCtrlTimerImpl) observer;
118: RemoteControlTimerEventListenerWrapperImpl listener = observerTimer
119: .getRemoteControlTimerEventListenerWrapper();
120: RemoteControlTimerEventImpl requestEvent = new RemoteControlTimerEventImpl(
121: listener, itsNatRequest);
122: response = new ResponseRemoteControlEventImpl(
123: requestEvent, itsNatResponse);
124: } else if (observer instanceof ClientDocumentInvitedRemoteCtrlCometImpl) {
125: String listenerId = getParameter("itsnat_listener_id");
126:
127: ClientDocumentInvitedRemoteCtrlCometImpl observerComet = (ClientDocumentInvitedRemoteCtrlCometImpl) observer;
128: RemoteControlCometTaskEventListenerWrapperImpl listener = (RemoteControlCometTaskEventListenerWrapperImpl) observerComet
129: .removeCometTask(listenerId);
130: CometTask task = listener
131: .getCometTask();
132: if (task.isDisposed()) // Procesar
133: {
134: RemoteControlCometTaskEventImpl requestEvent = new RemoteControlCometTaskEventImpl(
135: listener, itsNatRequest);
136: response = new ResponseRemoteControlEventImpl(
137: requestEvent,
138: itsNatResponse);
139: taskPendingToFinish = null;
140: } else
141: taskPendingToFinish = task;
142: }
143: } else {
144: // Estamos aquí porque había un evento de refresco pendiente de procesar mientras el usuario cerró explícitamente la ventana del observador (UNLOAD) o se cerró el documento padre (OBSERVED_INVALID), por tanto el evento ya ha sido procesado, evitamos procesar este evento pendiente pues es "post unload"
145: // además con total seguridad el observador es invalid
146: if (observer instanceof ClientDocumentInvitedRemoteCtrlCometImpl) {
147: String listenerId = getParameter("itsnat_listener_id");
148:
149: ClientDocumentInvitedRemoteCtrlCometImpl observerComet = (ClientDocumentInvitedRemoteCtrlCometImpl) observer;
150: observerComet
151: .removeCometTask(listenerId);
152: }
153:
154: taskPendingToFinish = null;
155: }
156:
157: if (response != null) {
158: response.process();
159: }
160: } finally {
161: int phase = observer.getPhase();
162: if (phase == RemoteControlEvent.UNLOAD) {
163: // Sólo cuando se cierra la ventana observadora cerramos el ciclo, cerrar la principal no es suficiente
164: // pues cuando se cierre la ventana se enviará un evento que procesaremos pues no es bueno responder con una excepción en ese caso
165: // pues el MSIE no cierra la conexión de un request tipo XMLHttpRequest síncrono que retorna una excepción
166: // cuando la ventana se está cerrando (unload)
167: session
168: .removeClientDocumentInvitedRemoteCtrl(observer);
169: itsNatDoc
170: .removeClientDocumentInvitedRemoteCtrl(observer); // El documento no lo retiene pero así se quita explícitamente
171: }
172:
173: itsNatRequest.unsetItsNatDocument();
174: itsNatRequest.setClientDocument(null);
175: }
176: }
177:
178: if (taskPendingToFinish != null) {
179: taskPendingToFinish.waitToFinish();
180: }
181: } while (taskPendingToFinish != null);
182: } else // itsNatDoc es null debido a que la session del documento observado ha caducado
183: {
184: session.removeClientDocumentInvitedRemoteCtrl(observer);
185:
186: throw new ItsNatException(
187: "Observed document "
188: + observer.getObservedItsNatSessionId()
189: + "/"
190: + observer.getItsNatDocumentId()
191: + " does not exist (closed by the user or session lost)");
192: }
193: }
194: }
|