NodeCache.java :  » Ajax » ItsNat » org » itsnat » impl » core » Java Open Source

Java Open Source » Ajax » ItsNat 
ItsNat » org » itsnat » impl » core » NodeCache.java
/*
  ItsNat Java Web Application Framework
  Copyright (C) 2007 Innowhere Software Services S.L., Spanish Company
  Author: Jose Maria Arranz Santamaria

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version. See the GNU Affero General Public 
  License for more details. See the copy of the GNU Affero General Public License
  included in this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.itsnat.impl.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import org.itsnat.core.ItsNatException;
import org.w3c.dom.Node;

/**
 * Recuerda los nodos cacheados usando un id nico que no puede ser reutilizado
 * aunque el nodo se quite.
 * Los nodos cacheados deben pertenecer al rbol DOM, es decir estn dentro del Document. * 
 *
 * No usamos la coleccin con WeakReferences porque cuando el nodo (subrbol) se quita del rbol
 * es detectado automticamente con un mutation listener que elimina dicho nodo
 * de la cach (si estuviera) as como todos los hijos del subrbol y por tanto 
 * deja de referenciarse y puede recogerse el nodo por el garbage collector. 
 *
 * @author jmarranz
 */
public class NodeCache
{
    protected ItsNatDocumentImpl itsNatDoc; // No se usa pero para que quede claro que es "por documento"
    protected Map nodeMap = new HashMap();    
    protected Map idMap = new HashMap();
     
    /** Creates a new instance of NodeCache */
    public NodeCache(ItsNatDocumentImpl itsNatDoc)
    {
        this.itsNatDoc = itsNatDoc;
    }
    
    public Iterator iterator()
    {
        return nodeMap.entrySet().iterator();
    }
    
    public boolean isCacheableNode(Node node)
    {
        // Cacheamos cualquier nodo excepto el propio Document, la vista, DocumentType
        // pues es absurdo cachearlos pues son "singleton",
        // y nodos de texto, pues los nodos de texto no admiten asociar una propiedad (el id)
        // en el MSIE y adems fcilmente son filtrados por los browsers etc
        
        int type = node.getNodeType();
        if (type == Node.ELEMENT_NODE)
            return true; // El caso tpico, para acelerar
        else if (type == Node.TEXT_NODE)
            return false; // Otro caso tpico, para acelerar        
        else if (type == Node.DOCUMENT_NODE)
            return false;
        else if (type == AbstractViewImpl.ABSTRACT_VIEW)
            return false;        
        else if (type == Node.DOCUMENT_TYPE_NODE)
            return false;               
        
        return true; // Comentarios etc
    }     
    
    public String removeNode(Node node)
    {
        if (!isCacheableNode(node))
            return null; // Nos ahorramos tiempo en buscar
        
        String id = (String)nodeMap.remove(node);
        if (id == null)
            return null;
        
        idMap.remove(id);   
        
        return id;
    }    
    
    public String getId(Node node)
    {
        if (node == null) return null;
        
        if (!isCacheableNode(node))
            return null; // Nos ahorramos tiempo de bsqueda
        
        return (String)nodeMap.get(node);
    }
    
    public Node getNodeById(String id)
    {
        return (Node)idMap.get(id);
    }    
    
    public String addNode(Node node)
    {
        // El id debe ser nico y vinculado al nodo unvoca e inequvocamente
        // (no debera existir el mismo id para otro nodo) y no debera 
        // reutilizarse un id que ya fue usado por otro nodo aunque ya no exista
       
        if (node == null) throw new ItsNatException("Null node is not supported");
        
        if (!isCacheableNode(node))
            return null; // No se puede cachear      
        
        /* Evitamos cachear cuando alguno de los clientes (propietario u observadores)
         * no pueda recibir cdigo de respuesta, porque el objetivo de este nuevo id es que
         * viaje a todos los clientes, propietario y observadores, para aadirse
         * en la cache del cliente, si uno de los clientes no aade el nodo a su cach
         * entonces cuando reciba el id no encontrar el nodo.
         * Ya existir otra oportunidad de cachear el nodo, la cache no es imprescindible simplemente acelera.
         */
        if (!itsNatDoc.allClientDocumentWillReceiveCodeSended())
            return null;
        
        String id = itsNatDoc.generateUniqueId();        
        
        nodeMap.put(node,id);
        idMap.put(id,node);
        
        return id;
    }
    
    public boolean isEmpty()
    {
        boolean res = idMap.isEmpty();
        if (res != nodeMap.isEmpty()) 
            throw new ItsNatException("INTERNAL ERROR");
        return res;
    }

    public ArrayList getOrderedByHeight()
    {
        /* Este mtodo es usado por el control remoto, se debe a que
         * los nodos no estn ordenados de ninguna forma en la cach
         * y al replicar la cach en el browser remoto necesitamos
         * enviar todos los nodos con su id y calculando su path, usando paths absolutos
         * no hay problema pero es un proceso muy lento, si utilizamos paths
         * relativos no sabemos si el padre que hemos encontrado en la cach
         * lo hemos enviado antes al browser y est ya cacheado all.
         * Por ello una tcnica es ordenar los nodos por alturas tal que
         * si se envan primero los ms altos los ms bajos encontrarn ya
         * en el browser el padre cacheado (si existe) pues este es ms alto.
         * Entre nodos de la misma altura no hay problema de orden pues ninguno
         * es padre del otro, no hay dependencias a la hora de calcular el path.
         * El ArrayList devuelto procesar pero no memorizar pues contiene los Map.Entry
         * de este cach.
         * Puede haber alturas en donde no haya ningn nodo (lo normal).
         */
        
        ArrayList cacheCopy = new ArrayList();
        for(Iterator it = iterator(); it.hasNext(); )
        {
            Map.Entry entry = (Map.Entry)it.next(); 
            Node node = (Node)entry.getKey();            
            int h = getNodeDeep(node);
            // Aseguramos que cacheCopy contiene la posicin h
            if (cacheCopy.size() <= h)
            {
                int currSize = cacheCopy.size();
                for(int i = 1; i <= h - currSize + 1; i++)
                    cacheCopy.add(null);
            }
            LinkedList sameH = (LinkedList)cacheCopy.get(h);
            if (sameH == null)
            {
                sameH = new LinkedList();
                cacheCopy.set(h,sameH);
            }
            sameH.add(entry);
        }
        return cacheCopy;
    }
    
    private static int getNodeDeep(Node node)
    {
        int i = 0;        
        while(node != null)
        {
            i++;            
            node = node.getParentNode();
        }       
        return i;
    }    
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.