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.Iterator;
017: import java.util.LinkedList;
018: import org.itsnat.impl.core.ItsNatDocumentImpl;
019: import org.itsnat.impl.core.listener.DOMBasedEventTargetListenerList.Pair;
020: import org.itsnat.impl.core.util.WeakMapPluggable;
021: import org.w3c.dom.events.EventListener;
022: import org.w3c.dom.events.EventTarget;
023:
024: public abstract class DOMBasedEventListenerRegistryByTargetTooImpl
025: extends DOMBasedEventListenerRegistryImpl implements
026: WeakMapPluggable.ExpungeListener {
027: protected WeakMapPluggable remoteListenersByTarget = new WeakMapPluggable(
028: this );
029:
030: // Evitamos "sujetar" los nodos DOM porque un listener sólo tiene
031: // sentido (por lo menos en ItsNat) si el nodo está vinculado al Document
032: // por lo que si está en el Document ya está sujeto, si no está en el Document
033: // (y nadie más lo sujeta) evitamos así memory leaks en programadores descuidados
034: // que no liberan listeners por ejemplo antes nodos que ser pierden
035: // al eliminarse su fragmento. Esto funciona incluso con el AutoCleanEventListeners desactivado.
036: // Esto no es suficiente con componentes que son listeners sí mismos en donde olvidemos hacer dispose(),
037: // estos necesitan el AutoCleanEventListeners también activado para que pueda actuar el Garbage Collector,
038: // porque el registro sujeta a los componentes con referencias normales por ejemplo en remoteListenersById
039: // y el propio componente tiene una referencia normal al nodo, la simple
040: // eliminación del nodo del documento no libera al nodo para el GC pues hay más referencias.
041:
042: /** Creates a new instance of DOMBasedEventListenerRegistryByTargetTooImpl */
043: public DOMBasedEventListenerRegistryByTargetTooImpl(
044: ItsNatDocumentImpl itsNatDoc) {
045: super (itsNatDoc);
046: }
047:
048: public void addDOMBasedEventListener(
049: DOMBasedEventListenerWrapperImpl listenerWrapper) {
050: super .addDOMBasedEventListener(listenerWrapper);
051:
052: EventTarget target = listenerWrapper.getEventTarget();
053:
054: DOMBasedEventTargetListenerList targetList = (DOMBasedEventTargetListenerList) remoteListenersByTarget
055: .get(target);
056: if (targetList == null) {
057: targetList = newDOMBasedEventTargetListenerList(false);
058: remoteListenersByTarget.put(target, targetList);
059: }
060:
061: String id = listenerWrapper.getId();
062: String type = listenerWrapper.getType();
063: boolean useCapture = listenerWrapper.getUseCapture();
064: EventListener listener = listenerWrapper.getEventListener();
065: targetList.addEventListener(type, useCapture, listener, id);
066: }
067:
068: public void removeAllDOMBasedEventListeners(EventTarget target,
069: boolean updateClient) {
070: if (!isValidEventTarget(target, false))
071: return; // No pudo registrarse, nos ahorramos una búsqueda inútil
072:
073: DOMBasedEventTargetListenerList targetList = (DOMBasedEventTargetListenerList) remoteListenersByTarget
074: .get(target);
075: if (targetList == null)
076: return;
077:
078: LinkedList listeners = targetList.getAllEventListeners();
079: if (listeners == null)
080: return;
081:
082: for (Iterator it = listeners.iterator(); it.hasNext();) {
083: Pair pair = (Pair) it.next();
084: String id = pair.getId();
085:
086: removeDOMBasedEventListenerByIdOnly(id, updateClient);
087: }
088:
089: targetList.removeAllEventListeners();
090:
091: remoteListenersByTarget.remove(target);
092: }
093:
094: public DOMBasedEventListenerWrapperImpl removeDOMBasedEventListener(
095: EventTarget target, String type, boolean useCapture,
096: EventListener listener, boolean updateClient) {
097: if (!isValidEventTarget(target, false))
098: return null; // No pudo registrarse, nos ahorramos una búsqueda inútil
099:
100: DOMBasedEventTargetListenerList targetList = (DOMBasedEventTargetListenerList) remoteListenersByTarget
101: .get(target);
102: if (targetList == null)
103: return null;
104:
105: String id = targetList.removeEventListener(type, useCapture,
106: listener);
107:
108: if (targetList.isEmpty())
109: remoteListenersByTarget.remove(target);
110:
111: return removeDOMBasedEventListenerByIdOnly(id, updateClient);
112: }
113:
114: public EventListener[] getDOMBasedEventListeners(
115: EventTarget target, String type, boolean useCapture) {
116: if (!isValidEventTarget(target, false))
117: return null; // Nos ahorramos la búsqueda
118:
119: DOMBasedEventTargetListenerList targetList = (DOMBasedEventTargetListenerList) remoteListenersByTarget
120: .get(target);
121: if (targetList == null)
122: return null;
123: return targetList.getEventListenersAsArray(type, useCapture);
124: }
125:
126: public void processExpunged(Object value) {
127: DOMBasedEventTargetListenerList targetList = (DOMBasedEventTargetListenerList) value;
128:
129: LinkedList listeners = targetList.getAllEventListeners();
130: if (listeners == null)
131: return;
132:
133: for (Iterator it = listeners.iterator(); it.hasNext();) {
134: Pair pair = (Pair) it.next();
135: String id = pair.getId();
136: removeDOMBasedEventListenerByIdOnly(id, false);
137:
138: // Pasamos updateClient = false para evitar llamar getJSRender().removeEventListenerCode(listenerWrapper);
139: // precisamente porque este método se llama cuando nadie sujeta el nodo
140: // y por tanto no pertenece al Document.
141: // Al menos evitamos que haya memory leaks en el servidor
142: // aunque podrá haber en el cliente, para evitarlo han de desregistrarse
143: // explícitamente los listeners cuando no se necesitan o el nodo DOM se va a perder
144: }
145: }
146:
147: public abstract DOMBasedEventTargetListenerList newDOMBasedEventTargetListenerList(
148: boolean concurrentAllowed);
149: }
|