[ 
https://issues.apache.org/jira/browse/ISIS-2119?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Dan Haywood updated ISIS-2119:
------------------------------
    Description: 
On a slow connection, can get occasional exceptions when downloading a blob... 
that the behaviour cannot be found on the entity:
{code}
org.apache.wicket.behavior.InvalidBehaviorIdException
Cannot find behavior with id '2' on component 
'org.apache.isis.viewer.wicket.ui.components.scalars.reference.ReferencePanel:theme:entityPageContainer:entity:rows:1:rowContents:2:col:rows:1:rowContents:1:col:tabGroups:1:panel:tabPanel:rows:1:rowContents:1:col:fieldSets:1:memberGroup:properties:1:property'
 in page '[Page class = 
org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage, id = 10, render count 
= 1]'. Perhaps the behavior did not properly implement getStatelessHint() and 
returned 'true' to indicate that it is stateless instead of returning 'false' 
to indicate that it is stateful.
org.apache.wicket.Behaviors#getBehaviorById(Behaviors.java:316)
org.apache.wicket.Component#getBehaviorById(Component.java:4596)
org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler#invokeListener(ListenerInterfaceRequestHandler.java:247)
org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler#respond(ListenerInterfaceRequestHandler.java:234)
org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor#respond(RequestCycle.java:895)
org.apache.wicket.request.RequestHandlerStack#execute(RequestHandlerStack.java:64)
org.apache.wicket.request.cycle.RequestCycle#execute(RequestCycle.java:265)
org.apache.wicket.request.cycle.RequestCycle#processRequest(RequestCycle.java:222)
org.apache.wicket.request.cycle.RequestCycle#processRequestAndDetach(RequestCycle.java:293)
org.apache.wicket.protocol.http.WicketFilter#processRequestCycle(WicketFilter.java:261)
org.apache.wicket.protocol.http.WicketFilter#processRequest(WicketFilter.java:203)
org.apache.wicket.protocol.http.WicketFilter#doFilter(WicketFilter.java:284)
org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1621)
org.apache.isis.core.webapp.diagnostics.IsisLogOnExceptionFilter#doFilter(IsisLogOnExceptionFilter.java:52)
org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1621)
org.togglz.servlet.TogglzFilter#doFilter(TogglzFilter.java:100)
org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1621)
org.apache.shiro.web.servlet.AbstractShiroFilter#executeChain(AbstractShiroFilter.java:449)
org.apache.shiro.web.servlet.AbstractShiroFilter$1#call(AbstractShiroFilter.java:365)
org.apache.shiro.subject.support.SubjectCallable#doCall(SubjectCallable.java:90)
org.apache.shiro.subject.support.SubjectCallable#call(SubjectCallable.java:83)
org.apache.shiro.subject.support.DelegatingSubject#execute(DelegatingSubject.java:383)
org.apache.shiro.web.servlet.AbstractShiroFilter#doFilterInternal(AbstractShiroFilter.java:362)
org.apache.shiro.web.servlet.OncePerRequestFilter#doFilter(OncePerRequestFilter.java:125)
org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1613)
org.eclipse.jetty.servlet.ServletHandler#doHandle(ServletHandler.java:541)
org.eclipse.jetty.server.handler.ScopedHandler#handle(ScopedHandler.java:143)
org.eclipse.jetty.security.SecurityHandler#handle(SecurityHandler.java:548)
org.eclipse.jetty.server.handler.HandlerWrapper#handle(HandlerWrapper.java:132)
org.eclipse.jetty.server.handler.ScopedHandler#nextHandle(ScopedHandler.java:190)
org.eclipse.jetty.server.session.SessionHandler#doHandle(SessionHandler.java:1593)
org.eclipse.jetty.server.handler.ScopedHandler#nextHandle(ScopedHandler.java:188)
org.eclipse.jetty.server.handler.ContextHandler#doHandle(ContextHandler.java:1239)
org.eclipse.jetty.server.handler.ScopedHandler#nextScope(ScopedHandler.java:168)
org.eclipse.jetty.servlet.ServletHandler#doScope(ServletHandler.java:481)
org.eclipse.jetty.server.session.SessionHandler#doScope(SessionHandler.java:1562)
org.eclipse.jetty.server.handler.ScopedHandler#nextScope(ScopedHandler.java:166)
org.eclipse.jetty.server.handler.ContextHandler#doScope(ContextHandler.java:1141)
org.eclipse.jetty.server.handler.ScopedHandler#handle(ScopedHandler.java:141)
org.eclipse.jetty.server.handler.HandlerWrapper#handle(HandlerWrapper.java:132)
org.eclipse.jetty.server.Server#handle(Server.java:564)
org.eclipse.jetty.server.HttpChannel#handle(HttpChannel.java:320)
org.eclipse.jetty.server.HttpConnection#onFillable(HttpConnection.java:251)
org.eclipse.jetty.io.AbstractConnection$ReadCallback#succeeded(AbstractConnection.java:279)
org.eclipse.jetty.io.FillInterest#fillable(FillInterest.java:110)
org.eclipse.jetty.io.ChannelEndPoint$2#run(ChannelEndPoint.java:124)
org.eclipse.jetty.util.thread.Invocable#invokePreferred(Invocable.java:122)
org.eclipse.jetty.util.thread.strategy.ExecutingExecutionStrategy#invoke(ExecutingExecutionStrategy.java:58)
org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume#produceConsume(ExecuteProduceConsume.java:201)
org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume#run(ExecuteProduceConsume.java:133)
org.eclipse.jetty.util.thread.QueuedThreadPool#runJob(QueuedThreadPool.java:672)
org.eclipse.jetty.util.thread.QueuedThreadPool$2#run(QueuedThreadPool.java:590)
java.lang.Thread#run(Thread.java:748)
{code}

  There's not a lot to go on.

Inspecting the returned payload though, I discovered at the end:

{code}
<evaluate><![CDATA[(function(){setTimeout("window.location.href='./orders.Order:7975?24-1.IBehaviorListener.0-'",
 10);})();]]></evaluate>
{code}

which gave me the clue.  The relevant code is in 
ActionResultResponseHandlingStrategy:

{code}
    SCHEDULE_HANDLER {
        @Override
        public void handleResults(
                final ActionResultResponse resultResponse,
                final IsisSessionFactory isisSessionFactory) {
            final RequestCycle requestCycle = RequestCycle.get();
            AjaxRequestTarget target = 
requestCycle.find(AjaxRequestTarget.class);

            if (target == null) {
                // non-Ajax request => just stream the Lob to the browser
                // or if this is a no-arg action, there also will be no parent 
for the component
                
requestCycle.scheduleRequestHandlerAfterCurrent(resultResponse.getHandler());
            } else {
                // otherwise,
                // Ajax request => respond with a redirect to be able to stream 
the Lob to the client
                ResourceStreamRequestHandler scheduledHandler = 
(ResourceStreamRequestHandler) resultResponse.getHandler();
                StreamAfterAjaxResponseBehavior streamingBehavior = new 
StreamAfterAjaxResponseBehavior(scheduledHandler);
                final Page page = target.getPage();
                page.add(streamingBehavior);
                String callbackUrl = 
streamingBehavior.getCallbackUrl().toString();
                target.appendJavaScript("setTimeout(\"window.location.href='" + 
callbackUrl + "'\", 10);");
            }

        }
    },
{code}

What's happening here is that response from the ajax call to invoke the button 
is the fragments to rebuild the page ... it's not possible to also return the 
BLOB.  So the Ajax instead sets a timeout to download that Blob as a separate 
web call.

Experimenting with this code, if the behaviour is stripped off (everything 
after the "?") then the download doesn't occur; so this is needed.

Since I've seen the problem mostly with large docs and on a slow connection, my 
guess is that this is some sort of race condition.  Since we can wait a bit 
more than 10ms, my suggestion is to increase the timeout to 250ms.


  was:
On a slow connection, can get occasional exceptions when downloading a blob... 
that the behaviour cannot be found on the entity.  There's not a lot to go on.

Inspecting the returned payload though, I discovered at the end:

{code}
<evaluate><![CDATA[(function(){setTimeout("window.location.href='./orders.Order:7975?24-1.IBehaviorListener.0-'",
 10);})();]]></evaluate>
{code}

which gave me the clue.  The relevant code is in 
ActionResultResponseHandlingStrategy:

{code}
    SCHEDULE_HANDLER {
        @Override
        public void handleResults(
                final ActionResultResponse resultResponse,
                final IsisSessionFactory isisSessionFactory) {
            final RequestCycle requestCycle = RequestCycle.get();
            AjaxRequestTarget target = 
requestCycle.find(AjaxRequestTarget.class);

            if (target == null) {
                // non-Ajax request => just stream the Lob to the browser
                // or if this is a no-arg action, there also will be no parent 
for the component
                
requestCycle.scheduleRequestHandlerAfterCurrent(resultResponse.getHandler());
            } else {
                // otherwise,
                // Ajax request => respond with a redirect to be able to stream 
the Lob to the client
                ResourceStreamRequestHandler scheduledHandler = 
(ResourceStreamRequestHandler) resultResponse.getHandler();
                StreamAfterAjaxResponseBehavior streamingBehavior = new 
StreamAfterAjaxResponseBehavior(scheduledHandler);
                final Page page = target.getPage();
                page.add(streamingBehavior);
                String callbackUrl = 
streamingBehavior.getCallbackUrl().toString();
                target.appendJavaScript("setTimeout(\"window.location.href='" + 
callbackUrl + "'\", 10);");
            }

        }
    },
{code}

What's happening here is that response from the ajax call to invoke the button 
is the fragments to rebuild the page ... it's not possible to also return the 
BLOB.  So the Ajax instead sets a timeout to download that Blob as a separate 
web call.

Experimenting with this code, if the behaviour is stripped off (everything 
after the "?") then the download doesn't occur; so this is needed.

Since I've seen the problem mostly with large docs and on a slow connection, my 
guess is that this is some sort of race condition.  Since we can wait a bit 
more than 10ms, my suggestion is to increase the timeout to 250ms.



> Increase timeout to avoid occasional exceptions when download Blobs
> -------------------------------------------------------------------
>
>                 Key: ISIS-2119
>                 URL: https://issues.apache.org/jira/browse/ISIS-2119
>             Project: Isis
>          Issue Type: Bug
>    Affects Versions: 1.17.0
>            Reporter: Dan Haywood
>            Assignee: Dan Haywood
>            Priority: Minor
>             Fix For: 1.18.0
>
>
> On a slow connection, can get occasional exceptions when downloading a 
> blob... that the behaviour cannot be found on the entity:
> {code}
> org.apache.wicket.behavior.InvalidBehaviorIdException
> Cannot find behavior with id '2' on component 
> 'org.apache.isis.viewer.wicket.ui.components.scalars.reference.ReferencePanel:theme:entityPageContainer:entity:rows:1:rowContents:2:col:rows:1:rowContents:1:col:tabGroups:1:panel:tabPanel:rows:1:rowContents:1:col:fieldSets:1:memberGroup:properties:1:property'
>  in page '[Page class = 
> org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage, id = 10, render 
> count = 1]'. Perhaps the behavior did not properly implement 
> getStatelessHint() and returned 'true' to indicate that it is stateless 
> instead of returning 'false' to indicate that it is stateful.
> org.apache.wicket.Behaviors#getBehaviorById(Behaviors.java:316)
> org.apache.wicket.Component#getBehaviorById(Component.java:4596)
> org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler#invokeListener(ListenerInterfaceRequestHandler.java:247)
> org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler#respond(ListenerInterfaceRequestHandler.java:234)
> org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor#respond(RequestCycle.java:895)
> org.apache.wicket.request.RequestHandlerStack#execute(RequestHandlerStack.java:64)
> org.apache.wicket.request.cycle.RequestCycle#execute(RequestCycle.java:265)
> org.apache.wicket.request.cycle.RequestCycle#processRequest(RequestCycle.java:222)
> org.apache.wicket.request.cycle.RequestCycle#processRequestAndDetach(RequestCycle.java:293)
> org.apache.wicket.protocol.http.WicketFilter#processRequestCycle(WicketFilter.java:261)
> org.apache.wicket.protocol.http.WicketFilter#processRequest(WicketFilter.java:203)
> org.apache.wicket.protocol.http.WicketFilter#doFilter(WicketFilter.java:284)
> org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1621)
> org.apache.isis.core.webapp.diagnostics.IsisLogOnExceptionFilter#doFilter(IsisLogOnExceptionFilter.java:52)
> org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1621)
> org.togglz.servlet.TogglzFilter#doFilter(TogglzFilter.java:100)
> org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1621)
> org.apache.shiro.web.servlet.AbstractShiroFilter#executeChain(AbstractShiroFilter.java:449)
> org.apache.shiro.web.servlet.AbstractShiroFilter$1#call(AbstractShiroFilter.java:365)
> org.apache.shiro.subject.support.SubjectCallable#doCall(SubjectCallable.java:90)
> org.apache.shiro.subject.support.SubjectCallable#call(SubjectCallable.java:83)
> org.apache.shiro.subject.support.DelegatingSubject#execute(DelegatingSubject.java:383)
> org.apache.shiro.web.servlet.AbstractShiroFilter#doFilterInternal(AbstractShiroFilter.java:362)
> org.apache.shiro.web.servlet.OncePerRequestFilter#doFilter(OncePerRequestFilter.java:125)
> org.eclipse.jetty.servlet.ServletHandler$CachedChain#doFilter(ServletHandler.java:1613)
> org.eclipse.jetty.servlet.ServletHandler#doHandle(ServletHandler.java:541)
> org.eclipse.jetty.server.handler.ScopedHandler#handle(ScopedHandler.java:143)
> org.eclipse.jetty.security.SecurityHandler#handle(SecurityHandler.java:548)
> org.eclipse.jetty.server.handler.HandlerWrapper#handle(HandlerWrapper.java:132)
> org.eclipse.jetty.server.handler.ScopedHandler#nextHandle(ScopedHandler.java:190)
> org.eclipse.jetty.server.session.SessionHandler#doHandle(SessionHandler.java:1593)
> org.eclipse.jetty.server.handler.ScopedHandler#nextHandle(ScopedHandler.java:188)
> org.eclipse.jetty.server.handler.ContextHandler#doHandle(ContextHandler.java:1239)
> org.eclipse.jetty.server.handler.ScopedHandler#nextScope(ScopedHandler.java:168)
> org.eclipse.jetty.servlet.ServletHandler#doScope(ServletHandler.java:481)
> org.eclipse.jetty.server.session.SessionHandler#doScope(SessionHandler.java:1562)
> org.eclipse.jetty.server.handler.ScopedHandler#nextScope(ScopedHandler.java:166)
> org.eclipse.jetty.server.handler.ContextHandler#doScope(ContextHandler.java:1141)
> org.eclipse.jetty.server.handler.ScopedHandler#handle(ScopedHandler.java:141)
> org.eclipse.jetty.server.handler.HandlerWrapper#handle(HandlerWrapper.java:132)
> org.eclipse.jetty.server.Server#handle(Server.java:564)
> org.eclipse.jetty.server.HttpChannel#handle(HttpChannel.java:320)
> org.eclipse.jetty.server.HttpConnection#onFillable(HttpConnection.java:251)
> org.eclipse.jetty.io.AbstractConnection$ReadCallback#succeeded(AbstractConnection.java:279)
> org.eclipse.jetty.io.FillInterest#fillable(FillInterest.java:110)
> org.eclipse.jetty.io.ChannelEndPoint$2#run(ChannelEndPoint.java:124)
> org.eclipse.jetty.util.thread.Invocable#invokePreferred(Invocable.java:122)
> org.eclipse.jetty.util.thread.strategy.ExecutingExecutionStrategy#invoke(ExecutingExecutionStrategy.java:58)
> org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume#produceConsume(ExecuteProduceConsume.java:201)
> org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume#run(ExecuteProduceConsume.java:133)
> org.eclipse.jetty.util.thread.QueuedThreadPool#runJob(QueuedThreadPool.java:672)
> org.eclipse.jetty.util.thread.QueuedThreadPool$2#run(QueuedThreadPool.java:590)
> java.lang.Thread#run(Thread.java:748)
> {code}
>   There's not a lot to go on.
> Inspecting the returned payload though, I discovered at the end:
> {code}
> <evaluate><![CDATA[(function(){setTimeout("window.location.href='./orders.Order:7975?24-1.IBehaviorListener.0-'",
>  10);})();]]></evaluate>
> {code}
> which gave me the clue.  The relevant code is in 
> ActionResultResponseHandlingStrategy:
> {code}
>     SCHEDULE_HANDLER {
>         @Override
>         public void handleResults(
>                 final ActionResultResponse resultResponse,
>                 final IsisSessionFactory isisSessionFactory) {
>             final RequestCycle requestCycle = RequestCycle.get();
>             AjaxRequestTarget target = 
> requestCycle.find(AjaxRequestTarget.class);
>             if (target == null) {
>                 // non-Ajax request => just stream the Lob to the browser
>                 // or if this is a no-arg action, there also will be no 
> parent for the component
>                 
> requestCycle.scheduleRequestHandlerAfterCurrent(resultResponse.getHandler());
>             } else {
>                 // otherwise,
>                 // Ajax request => respond with a redirect to be able to 
> stream the Lob to the client
>                 ResourceStreamRequestHandler scheduledHandler = 
> (ResourceStreamRequestHandler) resultResponse.getHandler();
>                 StreamAfterAjaxResponseBehavior streamingBehavior = new 
> StreamAfterAjaxResponseBehavior(scheduledHandler);
>                 final Page page = target.getPage();
>                 page.add(streamingBehavior);
>                 String callbackUrl = 
> streamingBehavior.getCallbackUrl().toString();
>                 target.appendJavaScript("setTimeout(\"window.location.href='" 
> + callbackUrl + "'\", 10);");
>             }
>         }
>     },
> {code}
> What's happening here is that response from the ajax call to invoke the 
> button is the fragments to rebuild the page ... it's not possible to also 
> return the BLOB.  So the Ajax instead sets a timeout to download that Blob as 
> a separate web call.
> Experimenting with this code, if the behaviour is stripped off (everything 
> after the "?") then the download doesn't occur; so this is needed.
> Since I've seen the problem mostly with large docs and on a slow connection, 
> my guess is that this is some sort of race condition.  Since we can wait a 
> bit more than 10ms, my suggestion is to increase the timeout to 250ms.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to