Package org.itsnat.impl.core.req.attachcli

Source Code of org.itsnat.impl.core.req.attachcli.RequestAttachedClientLoadDocImpl

/*
  ItsNat Java Web Application Framework
  Copyright (C) 2007-2011 Jose Maria Arranz Santamaria, Spanish citizen

  This software is free software; you can redistribute it and/or modify it
  under the terms of the GNU Lesser General Public License as
  published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
  This software is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details. You should have received
  a copy of the GNU Lesser General Public License along with this program.
  If not, see <http://www.gnu.org/licenses/>.
*/

package org.itsnat.impl.core.req.attachcli;

import org.itsnat.impl.core.servlet.ItsNatServletRequestImpl;
import org.itsnat.impl.core.servlet.ItsNatServletContextImpl;
import org.itsnat.impl.core.servlet.ItsNatSessionImpl;
import org.itsnat.core.ItsNatException;
import org.itsnat.core.CommMode;
import org.itsnat.core.event.ItsNatAttachedClientEvent;
import org.itsnat.impl.core.browser.Browser;
import org.itsnat.impl.core.clientdoc.ClientDocumentAttachedClientCometImpl;
import org.itsnat.impl.core.clientdoc.ClientDocumentAttachedClientImpl;
import org.itsnat.impl.core.clientdoc.ClientDocumentAttachedClientErrorImpl;
import org.itsnat.impl.core.clientdoc.ClientDocumentAttachedClientNotRefreshImpl;
import org.itsnat.impl.core.clientdoc.ClientDocumentAttachedClientTimerImpl;
import org.itsnat.impl.core.clientdoc.ClientDocumentImpl;
import org.itsnat.impl.core.clientdoc.ClientDocumentStfulImpl;
import org.itsnat.impl.core.doc.BoundElementDocContainerImpl;
import org.itsnat.impl.core.doc.ItsNatStfulDocumentImpl;
import org.itsnat.impl.core.doc.ItsNatDocSynchronizerImpl;
import org.itsnat.impl.core.event.client.ItsNatAttachedClientEventCometImpl;
import org.itsnat.impl.core.event.client.ItsNatAttachedClientEventImpl;
import org.itsnat.impl.core.event.client.ItsNatAttachedClientEventNotRefreshImpl;
import org.itsnat.impl.core.event.client.ItsNatAttachedClientEventTimerImpl;
import org.itsnat.impl.core.listener.ItsNatAttachedClientEventListenerUtil;
import org.itsnat.impl.core.req.RequestLoadDocImpl;
import org.itsnat.impl.core.req.shared.RequestDelegateLoadDocImpl;
import org.itsnat.impl.core.resp.attachcli.ResponseAttachedClient;
import org.itsnat.impl.core.resp.attachcli.ResponseAttachedClientLoadDocErrorNotDocImpl;
import org.itsnat.impl.core.resp.attachcli.ResponseAttachedClientLoadDocErrorNotDocInContainerImpl;
import org.itsnat.impl.core.resp.attachcli.ResponseAttachedClientLoadDocImpl;
import org.itsnat.impl.core.resp.attachcli.ResponseAttachedClientLoadDocErrorNotSessionImpl;
import org.itsnat.impl.core.resp.attachcli.ResponseAttachedClientLoadDocErrorParentElementNotFoundImpl;
import org.itsnat.impl.core.util.MiscUtil;

/**
*
* @author jmarranz
*/
public class RequestAttachedClientLoadDocImpl extends RequestLoadDocImpl implements RequestAttachedClient
{
    protected RequestDelegateLoadDocImpl delegate;

    /**
     * Creates a new instance of RequestAttachedClientLoadDocImpl
     */
    public RequestAttachedClientLoadDocImpl(ItsNatServletRequestImpl itsNatRequest)
    {
        super(itsNatRequest);

        this.delegate = new RequestDelegateLoadDocImpl(this);
    }

    public static RequestAttachedClientLoadDocImpl createRequestAttachedClientLoadDoc(ItsNatServletRequestImpl itsNatRequest)
    {
        return new RequestAttachedClientLoadDocImpl(itsNatRequest);
    }

    public ItsNatStfulDocumentImpl getItsNatStfulDocumentReferrer()
    {
        // El referrer s�lo tiene sentido en tiempo de carga de una p�gina para que tenga acceso a la anterior
        return null;
    }

    public ItsNatStfulDocumentImpl getItsNatStfulDocument()
    {
        return (ItsNatStfulDocumentImpl)getItsNatDocument();
    }

    public ResponseAttachedClient getResponseAttachedClient()
    {
        return (ResponseAttachedClient)response;
    }

    public ResponseAttachedClientLoadDocImpl getResponseAttachedClientLoadDoc()
    {
        return (ResponseAttachedClientLoadDocImpl)response;
    }

    public ClientDocumentAttachedClientImpl getParentClientDocumentAttachedClient()
    {
        ItsNatSessionImpl sessionParent = delegate.getBoundParentItsNatSession();
        if (sessionParent == null) return null;

        String clientParentId = getAttrOrParam("itsnat_client_parent_id");
        if (clientParentId == null) return null; // No tiene padre.
        return sessionParent.getClientDocumentAttachedClientById(clientParentId);
    }

    @Override   
    public void processRequest(ClientDocumentStfulImpl clientDocStateless)
    {
        // Procesamos el request suministrado en un URL

        ItsNatStfulDocumentImpl itsNatDoc = null;
        final ClientDocumentAttachedClientImpl clientDoc;

        // Vemos si este request proviene de un iframe/object/embed/applet
        ClientDocumentAttachedClientImpl parentClientDoc = getParentClientDocumentAttachedClient();
        if (parentClientDoc != null) // S�
        {
            ItsNatStfulDocumentImpl parentItsNatDoc = parentClientDoc.getItsNatStfulDocument();

            BoundElementDocContainerImpl bindInfo = delegate.getBoundElementDocContainer(parentItsNatDoc);
            if (bindInfo == null)
            {
                processParentElementNotFound();
                return;
            }

            // Obtenemos el documento a trav�s del documento padre en un caso de binding a trav�s de iframe/object
            // Si devuelve null es que todav�a no se ha cargado por parte del iframe/object cliente owner.
            itsNatDoc = (ItsNatStfulDocumentImpl)bindInfo.getContentItsNatDocument();

            // El timeout NO es necesario pasarlo como par�metro pues
            // ya lo tenemos aqu�, en el cliente.
            long timeout = parentClientDoc.getWaitDocTimeout();

            if ((itsNatDoc == null)&&(timeout > 0)) // Podr�amos considerar timeout = -1 como espera indefinida pero es peligroso permitir esto como par�metro "libre". Consideramos el valor 0 como "no esperar"
            {
                // Probamos en intervalos de tiempo hasta el timeout, pero no
                // en intervalos regulares sino en intervalos m�s cortos al ppio
                // y m�s largos al final, a partir de un intervalo inicial
                // esperar sucesivamente algo m�s (el doble sucesivamente es demasiado r�pido
                // al ppio y demasiado lento al final pues es una progresi�n geom�trica):
                // t + 2t + 3t + 4t ... = timeout => (1+2+3+4...)t = timeout
                // Si an = a1 + (n ? 1)d (donde a1 = 1, d = 1) la suma
                // de n t�rminos es: n*(a1+an)/2 => n(1+n)/2
                // http://es.wikipedia.org/wiki/Progresi%C3%B3n_aritm%C3%A9tica
                // Podemos considerar n=50 intentos => 50(1+50)/2 = 1275
                // => 1275 * t = timeout => t = timeout / 1275

                long lapse = 0;
                long t = timeout / 1275; // Divisi�n entera
                if (t == 0) t = 1; // 1 ms el m�nimo
                for(int i = 1; i <= 50; i++)
                {
                    try { Thread.sleep(t); } catch(Exception ex) { throw new ItsNatException(ex); }

                    itsNatDoc = (ItsNatStfulDocumentImpl)bindInfo.getContentItsNatDocument();
                    if (itsNatDoc != null) break;

                    lapse = lapse + t;
                    if (lapse >= timeout) break;

                    t = ((i+1) * timeout) / 1275;
                    if (t == 0) t = 1; // 1 ms el m�nimo
                }
            }

            if ((itsNatDoc == null) || itsNatDoc.isInvalid()) // El caso itsNatDoc.isInvalid() devolviendo true es muy raro porque al invalidarse se desregistra de su sesi�n pero puede ocurrir, as� tenemos la seguridad de que la request se realiza sobre un documento v�lido
            {
                processChildDocInDocContainerNotFound();
                return;
            }

            // Las propiedades de attachment las heredamos del cliente padre
            String refreshMethod = parentClientDoc.getRefreshMethod();
            int refreshInterval = -1;
            if (parentClientDoc instanceof ClientDocumentAttachedClientTimerImpl)
                refreshInterval = ((ClientDocumentAttachedClientTimerImpl)parentClientDoc).getRefreshInterval();
            int commMode = parentClientDoc.getCommModeDeclared();
            long eventTimeout = parentClientDoc.getEventTimeout();
            long waitDocTimeout = parentClientDoc.getWaitDocTimeout();
            boolean readOnly = parentClientDoc.isReadOnly();

            clientDoc = requestAuthorization(itsNatDoc,refreshMethod,refreshInterval,commMode,eventTimeout,waitDocTimeout,readOnly);
        }
        else
        {
            // La sesi�n que se quiere monitorizar no tiene porqu� ser la misma del monitorizador
            String targetSessionId = getAttrOrParamExist("itsnat_session_id"); // Debe existir (sino da error)
            ItsNatServletContextImpl context = itsNatRequest.getItsNatServletContext();
            ItsNatSessionImpl targetSession = context.findItsNatSessionByItsNatId(targetSessionId);
            if (targetSession == null)
            {
                processTargetSessionNotFound(targetSessionId);
                return;
            }

            // El documento a monitorizar est� registrado en la sesi�n remota:
            String targetDocId = getAttrOrParamExist("itsnat_doc_id"); // Debe existir (sino da error)
            itsNatDoc = targetSession.getItsNatStfulDocumentById(targetDocId);
            if ((itsNatDoc == null) || itsNatDoc.isInvalid()) // El caso itsNatDoc.isInvalid() devolviendo true es muy raro porque al invalidarse se desregistra de su sesi�n pero puede ocurrir, as� tenemos la seguridad de que la request se realiza sobre un documento v�lido
            {
                processTargetDocumentNotFound(targetSessionId,targetDocId);
                return;
            }

            clientDoc = requestAuthorization(itsNatDoc);
        }

        if (clientDoc == null) return; // Autorizaci�n denegada

        ItsNatDocSynchronizerImpl syncTask = new ItsNatDocSynchronizerImpl()
        {
            protected void syncMethod()
            {
                processThreadSync(clientDoc);
            }
        };
        syncTask.exec(itsNatDoc);
    }

    public void processThreadSync(ClientDocumentAttachedClientImpl clientDoc)
    {
        ItsNatStfulDocumentImpl itsNatDoc = clientDoc.getItsNatStfulDocument();

        if (itsNatDoc.isInvalid()) // As� tenemos la seguridad completa de que la request se realiza sobre un documento v�lido (pues el doc est� bloqueado y ya no puede invalidarse desde otro hilo)
        {
            String targetSessionId = itsNatDoc.getClientDocumentOwnerImpl().getItsNatSessionImpl().getId();
            String targetDocId = itsNatDoc.getId();
            processTargetDocumentNotFound(targetSessionId,targetDocId);
            return;
        }

        try
        {
            bindClientToRequest(clientDoc);

            clientDoc.setPhase(ItsNatAttachedClientEvent.LOAD);

            try
            {
                this.response = ResponseAttachedClientLoadDocImpl.createResponseAttachedClientLoadDoc(this);
                response.process();

                // Salvo que se lanzara una excepci�n estamos obligados a
                // servir el documento aunque el proceso del evento LOAD
                // haya supuesto la invalidaci�n del documento (=>observador inv�lido)

                // Pero si por alguna rara los listeners han "rechazado" el evento (setAccepted(false))
                // el cliente estar� invalidado, en este caso estamos OBLIGADOS a desregistrar el cliente remoto
                // El resultado es que se sirve la p�gina pero no se refrescar�, el listener tiene la oportunidad de informar al usuario si quiere.
                // Una utilidad de este caso ser�a la de "ver" la p�gina del usuario remoto
                // aunque no se tenga intenci�n de monitorizarla.
                if (clientDoc.isInvalid())
                {
                    clientDoc.setPhase(ItsNatAttachedClientEvent.UNLOAD); // Da igual realmente
                    clientDoc.invalidateAndUnregister(); // Desregistra de la sesi�n (lo que falta)
                }
                else
                    clientDoc.setPhase(ItsNatAttachedClientEvent.REFRESH);
            }
            catch(RuntimeException ex)
            {
                clientDoc.invalidateAndUnregister();

                throw ex; // Para que la p�gina retornada sea la excepci�n
            }
        }
        finally
        {
            unbindRequestFromDocument();
        }
    }

    public ClientDocumentAttachedClientImpl requestAuthorization(ItsNatStfulDocumentImpl itsNatDoc)
    {
        // Evaluamos si est� autorizado para controlar rem�tamente
        // EL DOCUMENTO NO ESTA SINCRONIZADO PARA PODER PREGUNTAR AL USUARIO MONITORIZADO
        int commMode;
        String commModeStr = getAttrOrParam("itsnat_comm_mode")// Opcional
        if (commModeStr != null)
            commMode = Integer.parseInt(commModeStr);
        else
            commMode = itsNatDoc.getCommMode();

        long eventTimeout;
        String eventTimeoutStr = getAttrOrParam("itsnat_event_timeout")// Opcional
        if (eventTimeoutStr != null)
            eventTimeout = Long.parseLong(eventTimeoutStr);
        else
            eventTimeout = itsNatDoc.getEventTimeout();

        long waitDocTimeout;
        String waitDocTimeoutStr = getAttrOrParam("itsnat_wait_doc_timeout")// Opcional
        if (waitDocTimeoutStr != null)
            waitDocTimeout = Long.parseLong(waitDocTimeoutStr);
        else
            waitDocTimeout = 0; // No esperar

        boolean readOnly;
        String readOnlyStr = getAttrOrParam("itsnat_read_only")// Opcional
        if (readOnlyStr != null)
        {
            try{ readOnly = MiscUtil.getBoolean(readOnlyStr); }
            catch(Exception ex) { throw new ItsNatException(ex); }
        }
        else readOnly = true; // Por defecto

        String refreshMethod = getAttrOrParam("itsnat_refresh_method");
        if (refreshMethod == null) refreshMethod = "none";

        int refreshInterval = -1;
        if (refreshMethod.equals("timer"))
            refreshInterval = Integer.parseInt(getAttrOrParamExist("itsnat_refresh_interval"));

        return requestAuthorization(itsNatDoc,refreshMethod,refreshInterval,commMode,eventTimeout,waitDocTimeout,readOnly);
    }


    public ClientDocumentAttachedClientImpl requestAuthorization(ItsNatStfulDocumentImpl itsNatDoc,String refreshMethod,int refreshInterval,int commMode,long eventTimeout,long waitDocTimeout,boolean readOnly)
    {
        // Evaluamos si est� autorizado para controlar rem�tamente
        // EL DOCUMENTO NO ESTA SINCRONIZADO PARA PODER PREGUNTAR AL USUARIO MONITORIZADO
        Browser browser = itsNatDoc.getItsNatStfulDocumentTemplateVersion().getBrowser(itsNatRequest); // No hay problema de sincronizaci�n (multihilo) en estas llamadas

        ItsNatSessionImpl itsNatSession = itsNatRequest.getItsNatSessionImpl();

        // Phase ItsNatAttachedClientEvent.REQUEST;
        ClientDocumentAttachedClientImpl clientDoc = null;

        if (refreshMethod.equals("timer"))
        {
            clientDoc = new ClientDocumentAttachedClientTimerImpl(readOnly,refreshInterval,commMode,eventTimeout,waitDocTimeout,browser,itsNatSession,itsNatDoc);
        }
        else if (refreshMethod.equals("comet"))
        {
            clientDoc = new ClientDocumentAttachedClientCometImpl(readOnly,commMode,eventTimeout,waitDocTimeout,browser,itsNatSession,itsNatDoc);
        }
        else if (refreshMethod.equals("none"))
        {
            clientDoc = new ClientDocumentAttachedClientNotRefreshImpl(readOnly,commMode,eventTimeout,waitDocTimeout,browser,itsNatSession,itsNatDoc);
        }
        else throw new ItsNatException("Unrecognized refresh method: \"" + refreshMethod + "\"",itsNatRequest);

        bindClientToRequest(clientDoc,false);

        ItsNatAttachedClientEventImpl requestEvent = createItsNatAttachedClientEvent(clientDoc);

        // clientDoc por defecto est� en modo REQUEST y acepted = false

        boolean wasProcessed = ItsNatAttachedClientEventListenerUtil.handleEventIncludingGlobalListeners(requestEvent);
        if (!requestEvent.isAccepted())
        {
            if (wasProcessed) return null; // El c�digo del usuario tuvo oportunidad para hacer lo que sea
            else throw new ItsNatException("Request to remote control the document/page \"" + itsNatDoc.getItsNatDocumentTemplateImpl().getName() + "\" is not accepted",itsNatRequest);
        }

        commMode = clientDoc.getCommModeDeclared();
        if (!clientDoc.isReadOnly() && (clientDoc instanceof ClientDocumentAttachedClientCometImpl) &&
            ((commMode == CommMode.XHR_ASYNC_HOLD) || (commMode == CommMode.XHR_SYNC) ||
             (commMode == CommMode.SCRIPT_HOLD)) )
        {
            // No podemos permitir que el evento Comet al volver deje bloqueado el cliente pues dicho
            // request puede quedarse indefinidamente en el servidor, impidiendo los eventos normales del usuario en el cliente remoto.
            // No pasa nada por lanzar una excepci�n, el programador tuvo la oportunidad de detectar esto y esta situaci�n
            // se detectar� siempre en tiempo de desarrollo.
            throw new ItsNatException("Sync modes ASYNC_HOLD and SYNC and SCRIPT_HOLD are not valid in full remote control and Comet");
        }

        return clientDoc;
    }

    public void processTargetSessionNotFound(String targetSessionId)
    {
        prepareErrorResponse();

        this.response = new ResponseAttachedClientLoadDocErrorNotSessionImpl(targetSessionId,this);
        response.process();
    }

    public void processTargetDocumentNotFound(String targetSessionId,String targetDocId)
    {
        prepareErrorResponse();

        this.response = new ResponseAttachedClientLoadDocErrorNotDocImpl(targetSessionId,targetDocId,this);
        response.process();
    }

    public void processChildDocInDocContainerNotFound()
    {
        prepareErrorResponse();

        this.response = new ResponseAttachedClientLoadDocErrorNotDocInContainerImpl(this);
        response.process();
    }

    public void processParentElementNotFound()
    {
        prepareErrorResponse();

        this.response = new ResponseAttachedClientLoadDocErrorParentElementNotFoundImpl(this);
        response.process();
    }

    public void prepareErrorResponse()
    {
        ItsNatSessionImpl session = getItsNatSession();
        ClientDocumentAttachedClientErrorImpl clientDoc = new ClientDocumentAttachedClientErrorImpl(session);
        clientDoc.setPhase(ItsNatAttachedClientEvent.REQUEST);

        bindClientToRequest(clientDoc,false)// El documento es nulo, no se vincula por tanto
    }

    public ItsNatAttachedClientEventImpl createItsNatAttachedClientEvent(ClientDocumentAttachedClientImpl clientDoc)
    {
        if (clientDoc instanceof ClientDocumentAttachedClientTimerImpl)
            return new ItsNatAttachedClientEventTimerImpl(this);
        else if (clientDoc instanceof ClientDocumentAttachedClientCometImpl)
            return new ItsNatAttachedClientEventCometImpl(this);
        else if (clientDoc instanceof ClientDocumentAttachedClientNotRefreshImpl)
            return new ItsNatAttachedClientEventNotRefreshImpl(this);
        return null; // ERROR
    }
   
    protected boolean isMustNotifyEndOfRequestToSession()
    {
        return true;
    }   
}
TOP

Related Classes of org.itsnat.impl.core.req.attachcli.RequestAttachedClientLoadDocImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.