public static NodeLocationWithParentImpl getNodeLocationWithParentUsingCache(
      Node node, String id, boolean cacheIfPossible, NodeCacheRegistryImpl nodeCache) {
    // nodeCache NO puede ser nulo

    // Se supone que el nodo no ha sido cacheado en el cliente todavía  aunque tenga
    // un id asignado en el servidor (este id puede ser null si no ha sido cacheado en el servidor)
    // por lo que hay que obtener un path, absoluto o relativo respecto a un padre cacheado.

    // Buscamos un nodo padre que esté cacheado para evitar formar un path
    // absoluto que lleva tiempo.

    String parentId = null;
    Node parent = node;

    do {
      parent = parent.getParentNode();
      parentId = nodeCache.getId(parent); // si cachedParent es null devuelve null
    } while ((parentId == null) && (parent != null));

    ClientDocumentStfulDelegateImpl clientDoc = nodeCache.getClientDocumentStfulDelegate();
    String path =
        clientDoc.getStringPathFromNode(
            node,
            parent); // Si cachedParent es null (cachedParentId es null) devuelve un path absoluto

    return new NodeLocationWithParentImpl(
        node, id, path, parent, parentId, cacheIfPossible, clientDoc);
  }
  private NodeLocationWithParentImpl(
      Node node,
      String id,
      String path,
      Node cachedParent,
      String cachedParentId,
      boolean cacheIfPossible,
      ClientDocumentStfulDelegateImpl clientDoc) {
    super(clientDoc);

    if (node == null) throw new ItsNatException("INTERNAL ERROR");

    this.nodeLocationDeleg = getNodeLocationNotParent(node, id, path, clientDoc);

    this.cachedParent = cachedParent;
    this.cachedParentId = cachedParentId;

    NodeCacheRegistryImpl nodeCache = clientDoc.getNodeCacheRegistry();
    if ((nodeCache != null)
        && cacheIfPossible) // Aunque esté cacheado el nodo principal aprovechamos para cachear los
    // padres.
    {
      // Cacheamos unos cuantos padres inmediatos para que los nodos "adyacentes" (de la zona en
      // general)
      // puedan encontrarse más rápidamente, sobre todo si el cachedParent no se encontró o está muy
      // arriba.

      int maxParents =
          3; // Un valor razonable para evitar cachear en exceso nodos padre (y enviar demasiado
      // JavaScript)
      // que a lo mejor no se usan nunca ni para el cálculo de paths
      Node currParent = node.getParentNode();
      for (int i = 0;
          (currParent != null) && (currParent != cachedParent) && (i < maxParents);
          i++) {
        String parentId = nodeCache.getId(currParent);
        if (parentId == null) // No cacheado
        {
          parentId = nodeCache.addNode(currParent);
          if (parentId != null) {
            // Hemos cacheado un nuevo nodo, DEBEMOS LLAMAR toJSArray y enviar al cliente
            // de otra manera el cliente NO se enterará de este cacheado.
            if (newCachedParentIds == null)
              this.newCachedParentIds = new ArrayList<String>(maxParents);
            newCachedParentIds.add(parentId);
            currParent = currParent.getParentNode();
            i++;
          } else currParent = null; // No se puede cachear, paramos
        } else currParent = null; // Ya cacheado, paramos
      }
    }

    if ((nodeLocationDeleg instanceof NodeLocationAlreadyCachedNotParentImpl)
        && !isNull(cachedParentId)) throw new ItsNatException("INTERNAL ERROR");
  }
  public static NodeLocationWithParentImpl getNodeLocationWithParent(
      Node node, boolean cacheIfPossible, ClientDocumentStfulDelegateImpl clientDoc) {
    // Si cacheIfPossible es true y se cachea el nodo, el location DEBE enviarse al cliente y
    // resolverse para cachear en el cliente

    NodeCacheRegistryImpl nodeCache = clientDoc.getNodeCacheRegistry();
    if (nodeCache != null) {
      String id = nodeCache.getId(node);
      if (id != null) {
        return new NodeLocationWithParentImpl(
            node,
            id,
            null,
            cacheIfPossible,
            clientDoc); // Sólo se necesita el id del nodo, cuando está en la caché no necesitamos
        // el string path que es una tarea que consume mucho tiempo tanto en el
        // servidor como en el cliente
      } else // No cacheado
      {
        if (cacheIfPossible) {
          id =
              nodeCache.addNode(
                  node); // Si el nodo no es cacheable o la caché está bloqueada (sólo lectural)
          // devuelve null, no pasa nada por no poder cachear
          return getNodeLocationWithParentUsingCache(node, id, true, nodeCache);
        } else {
          String path = clientDoc.getStringPathFromNode(node);
          return new NodeLocationWithParentImpl(
              node, null, path, false, clientDoc); // cacheIfPossible es false
        }
      }
    } else // El documento tiene el cache desactivado
    {
      String path = clientDoc.getStringPathFromNode(node);
      return new NodeLocationWithParentImpl(node, null, path, cacheIfPossible, clientDoc);
    }
  }