protected String doIntercept()

in core/src/main/java/org/apache/struts2/interceptor/ExecuteAndWaitInterceptor.java [233:328]


    protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
        ActionProxy proxy = actionInvocation.getProxy();
        String name = getBackgroundProcessName(proxy);
        ActionContext context = actionInvocation.getInvocationContext();
        Map<String, Object> session = context.getSession();
        HttpSession httpSession = ServletActionContext.getRequest().getSession(true);

        //sync on the real HttpSession as the session from the context is a wrap that is created
        //on every request
        synchronized (httpSession) {
            // State flag processing moved within the synchronization block, to ensure consistency.
            Boolean secondTime = true;
            if (executeAfterValidationPass) {
                secondTime = (Boolean) context.get(KEY);
                if (secondTime == null) {
                    context.put(KEY, true);
                    secondTime = false;
                } else {
                    secondTime = true;
                    context.put(KEY, null);
                }
            }

            final String bp_SessionKey = KEY + name;
            BackgroundProcess bp = (BackgroundProcess) session.get(bp_SessionKey);

            LOG.debug("Intercepting invocation for BackgroundProcess - session key: {}, value: {}", bp_SessionKey, bp);

            //WW-4900 Checks if from a de-serialized session? so background thread missed, let's start a new one.
            if (bp != null && bp.getInvocation() == null) {
                LOG.trace("BackgroundProcess invocation is null (remove key, clear instance)");
                session.remove(bp_SessionKey);
                bp = null;
            }

            if ((!executeAfterValidationPass || secondTime) && bp == null) {
                LOG.trace("BackgroundProcess instance is null (create new instance) - executeAfterValidationPass: {}, secondTime: {}.", executeAfterValidationPass, secondTime);
                bp = getNewBackgroundProcess(name, actionInvocation, threadPriority).prepare();
                session.put(bp_SessionKey, bp);
                if (executor == null || executor.isShutdown()) {
                    LOG.warn("Executor is shutting down (or null), cannot execute a new process, invoke next ActionInvocation step and return.");
                    return actionInvocation.invoke();
                }
                executor.execute(bp);
                performInitialDelay(bp); // first time let some time pass before showing wait page
                secondTime = false;
            }

            if ((!executeAfterValidationPass || !secondTime) && bp != null && !bp.isDone()) {
                LOG.trace("BackgroundProcess instance is not done (wait processing) - executeAfterValidationPass: {}, secondTime: {}.", executeAfterValidationPass, secondTime);
                actionInvocation.getStack().push(bp.getAction());

                final String token = TokenHelper.getToken();
                if (token != null) {
                    TokenHelper.setSessionToken(TokenHelper.getTokenName(), token);
                }

                Map<String, ResultConfig> results = proxy.getConfig().getResults();
                if (!results.containsKey(WAIT)) {
                    LOG.warn("ExecuteAndWait interceptor has detected that no result named 'wait' is available. " +
                        "Defaulting to a plain built-in wait page. It is highly recommend you " +
                        "provide an action-specific or global result named '{}'.", WAIT);
                    // no wait result? hmm -- let's try to do dynamically put it in for you!

                    //we used to add a fake "wait" result here, since the configuration is unmodifiable, that is no longer
                    //an option, see WW-3068
                    FreemarkerResult waitResult = new FreemarkerResult();
                    container.inject(waitResult);
                    waitResult.setLocation("/org/apache/struts2/interceptor/wait.ftl");
                    waitResult.execute(actionInvocation);

                    return Action.NONE;
                }

                return WAIT;
            } else if ((!executeAfterValidationPass || !secondTime) && bp != null && bp.isDone()) {
                LOG.trace("BackgroundProcess instance is done (remove key, return result) - executeAfterValidationPass: {}, secondTime: {}.", executeAfterValidationPass, secondTime);
                session.remove(bp_SessionKey);
                actionInvocation.getStack().push(bp.getAction());

                // if an exception occurred during action execution, throw it here
                if (bp.getException() != null) {
                    throw bp.getException();
                }

                return bp.getResult();
            } else {
                LOG.trace("BackgroundProcess state fall-through (first instance, pass through), invoke next ActionInvocation step and return - executeAfterValidationPass: {}, secondTime: {}.", executeAfterValidationPass, secondTime);
                // this is the first instance of the interceptor and there is no existing action
                // already run in the background, so let's just let this pass through. We assume
                // the action invocation will be run in the background on the subsequent pass through
                // this interceptor
                return actionInvocation.invoke();
            }
        }
    }