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;
015:
016: import java.lang.ref.WeakReference;
017: import org.itsnat.core.ItsNatDocument;
018: import org.itsnat.core.ItsNatServletContext;
019: import org.itsnat.core.ItsNatSession;
020: import org.itsnat.impl.core.util.UniqueIdGenerator;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.Map;
024: import org.itsnat.core.ClientDocument;
025: import org.itsnat.core.ItsNatVariableResolver;
026: import org.itsnat.impl.core.client.ClientDocumentInvitedRemoteCtrlImpl;
027:
028: /**
029: *
030: * @author jmarranz
031: */
032: public abstract class ItsNatSessionImpl extends ItsNatUserDataImpl
033: implements ItsNatSession {
034: protected String id;
035: protected ItsNatServletContextImpl context;
036: protected UniqueIdGenerator idGenerator = new UniqueIdGenerator();
037: protected Map docs = new HashMap();
038: protected Map observers = new HashMap(); // Sirve para retener los observers para que no sean garbage collected hasta que la sesión se pierda
039: protected WeakReference referrer;
040:
041: /** Creates a new instance of ItsNatSessionImpl */
042: public ItsNatSessionImpl(ItsNatServletContextImpl context) {
043: super (true);
044:
045: this .context = context;
046: this .id = context.generateUniqueId();
047: }
048:
049: public String getId() {
050: return id;
051: }
052:
053: public abstract Object getOriginalSessionObject();
054:
055: public ItsNatServletContext getItsNatServletContext() {
056: return context;
057: }
058:
059: public ItsNatServletContextImpl getItsNatServletContextImpl() {
060: return context;
061: }
062:
063: public String[] getItsNatDocumentIdList() {
064: // Por ahora no lo hacemos público
065: // Este método es útil para el control remoto pues
066: // así evitamos usar el objeto ItsNatDocument que hay
067: // que tener cuidado con él pues ha de sincronizarse
068: // ante cualquier uso.
069: // No serán muchos (es la sesión de un usuario) por eso devolvemos un array
070: synchronized (docs) {
071: String[] res = new String[docs.size()];
072: int i = 0;
073: for (Iterator it = docs.entrySet().iterator(); it.hasNext();) {
074: Map.Entry entry = (Map.Entry) it.next();
075: ItsNatDocumentImpl doc = (ItsNatDocumentImpl) entry
076: .getValue();
077: res[i] = doc.getId();
078: i++;
079: }
080: return res;
081: }
082: }
083:
084: public ItsNatDocument[] getItsNatDocuments() {
085: // No serán muchos (es la sesión de un usuario) por eso devolvemos un array
086: synchronized (docs) {
087: ItsNatDocument[] res = new ItsNatDocument[docs.size()];
088: int i = 0;
089: for (Iterator it = docs.entrySet().iterator(); it.hasNext();) {
090: Map.Entry entry = (Map.Entry) it.next();
091: res[i] = (ItsNatDocument) entry.getValue();
092: i++;
093: }
094: return res;
095: }
096: }
097:
098: public ItsNatDocument getItsNatDocumentById(String id) {
099: return getItsNatDocumentImplById(id);
100: }
101:
102: public ItsNatDocumentImpl getItsNatDocumentImplById(String id) {
103: synchronized (docs) {
104: return (ItsNatDocumentImpl) docs.get(id);
105: }
106: }
107:
108: public void registerItsNatDocument(ItsNatDocumentImpl itsNatDoc) {
109: synchronized (docs) {
110: docs.put(itsNatDoc.getId(), itsNatDoc);
111: }
112: }
113:
114: public void unregisterItsNatDocument(ItsNatDocumentImpl itsNatDoc) {
115: synchronized (docs) {
116: docs.remove(itsNatDoc.getId());
117: itsNatDoc.setInvalid();
118: }
119:
120: if (itsNatDoc.isReferrerEnabled()) {
121: // Normalmente se llega aquí via unload, la posible nueva página
122: // tuvo la oportunidad de obtener el referrer tras el onbeforeunload de la página origen
123: // ahora que seguramente se está ejecutando el unload ya no.
124: ItsNatDocumentImpl itsNatDocRef = getReferrerDocument();
125: if (itsNatDocRef == itsNatDoc)
126: popReferrerDocument();
127: }
128: }
129:
130: public String generateUniqueId() {
131: return idGenerator.generateUniqueId();
132: }
133:
134: public ItsNatDocumentImpl loadItsNatDocument(
135: DocumentTemplateImpl docTemplate) {
136: DocumentTemplateVersionImpl loader = docTemplate
137: .getDocumentTemplateVersion();
138: return loader.loadItsNatDocument(this );
139: }
140:
141: public synchronized ClientDocumentInvitedRemoteCtrlImpl getClientDocumentInvitedRemoteCtrlByObservedDoc(
142: String sessionId, String docId) {
143: // NO SE USA TODAVÍA
144: // Pero podría usarse para conseguir en control remoto que podamos
145: // enviar eventos al servidor. Faltaría hacer que el propietario se refrescara también
146: // automáticamente.
147:
148: // Buscamos el documento a partir de los observadores (si hay alguno observándolo)
149: // No es probable que haya muchos documentos observados por sesión del usuario
150: synchronized (observers) {
151: if (observers.isEmpty())
152: return null;
153:
154: for (Iterator it = observers.entrySet().iterator(); it
155: .hasNext();) {
156: Map.Entry entry = (Map.Entry) it.next();
157: ClientDocumentInvitedRemoteCtrlImpl observer = (ClientDocumentInvitedRemoteCtrlImpl) entry
158: .getValue();
159: ItsNatDocumentImpl doc = observer
160: .getItsNatDocumentImpl();
161: if (doc != null) {
162: ClientDocument owner = doc.getClientDocumentOwner();
163: if (owner.getId().equals(sessionId)
164: && doc.getId().equals(docId))
165: return observer;
166: } else {
167: // El documento ha sido garbage collected, aprovechamos para quitar el observador
168: it.remove();
169: }
170: }
171: return null;
172: }
173: }
174:
175: public ClientDocumentInvitedRemoteCtrlImpl getClientDocumentInvitedRemoteCtrl(
176: String id) {
177: synchronized (observers) {
178: return (ClientDocumentInvitedRemoteCtrlImpl) observers
179: .get(id);
180: }
181: }
182:
183: public void addClientDocumentInvitedRemoteCtrl(
184: ClientDocumentInvitedRemoteCtrlImpl listener) {
185: synchronized (observers) {
186: observers.put(listener.getId(), listener);
187: }
188: }
189:
190: public void removeClientDocumentInvitedRemoteCtrl(
191: ClientDocumentInvitedRemoteCtrlImpl clientDoc) {
192: synchronized (observers) {
193: observers.remove(clientDoc.getId());
194: }
195: }
196:
197: public int getClientDocumentInvitedRemoteCtrlCount() {
198: synchronized (observers) {
199: return observers.size();
200: }
201: }
202:
203: public ItsNatVariableResolver createItsNatVariableResolver() {
204: return new ItsNatVariableResolverImpl(null, null, null, this ,
205: null);
206: }
207:
208: public synchronized ItsNatDocumentImpl getReferrerDocument() {
209: if (referrer == null)
210: return null;
211: return (ItsNatDocumentImpl) referrer.get();
212: }
213:
214: public synchronized void pushReferrerDocument(
215: ItsNatDocumentImpl itsNatDoc) {
216: /* Nota: se sabe que cuando se pulsa un link o se envía el formulario
217: * que substituiría al documento actual, la nueva página
218: * se accede sin que se ejecute el evento unload de la lanzadora.
219: * Por tanto se ha de usar onbeforeunload para hacer el push para
220: * que se ejecute antes de la carga de la nueva página.
221: * No hay problema con la WeakReference pues durante la carga
222: * de la nueva página, el documento referrer todavía está vivo
223: * con referencias normales pues todavía no se ha ejecutado el unload.
224: * La WeakReference es por si el link o formulario no lleva a una página
225: * ItsNat que recoja el referrer y por si el unload fallara por alguna razón.
226: * Sólo funciona el referrer cuando la página se destruye, es decir
227: * los links y forms usando target (ej. target="_blank") no tienen referrer (null)
228: * En esos casos con window.opener tienen acceso al cliente y con el id del documento
229: * tienen acceso al padre en el servidor.
230: * En Internet Explorer sin embargo se ejecuta el unload antes
231: * de acceder a la nueva página cuando no se usa un link o form
232: * como método de transición (caso de navegación directa con un URL
233: en el navegador o pulsando reload), por tanto el referrer se pierde en estos
234: * casos, esto no ocurre en FireFox. El comportamiento del Explorer
235: * ciertamente está más de acorde con el concepto de "referrer".
236: **/
237:
238: this .referrer = new WeakReference(itsNatDoc);
239: }
240:
241: public synchronized ItsNatDocumentImpl popReferrerDocument() {
242: if (referrer == null)
243: return null;
244: ItsNatDocumentImpl itsNatDoc = (ItsNatDocumentImpl) referrer
245: .get();
246: this .referrer = null;
247: return itsNatDoc;
248: }
249:
250: public Object getVariable(String varName) {
251: Object value = getAttribute(varName);
252: if (value != null)
253: return value;
254:
255: return getItsNatServletContextImpl().getVariable(varName);
256: }
257:
258: public abstract boolean isMSIE(); // No tiene por qué ser público este método
259:
260: public abstract boolean isUserAgentCompatible(String userAgent); // No tiene por qué ser público este método es más bien del mundo Http, lo ponemos en este nivel por razones prácticas
261:
262: public abstract String getUserAgent(); // No lo hacemos público porque es más bien del mundo Http, lo ponemos en este nivel por razones prácticas
263: }
|