Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 3307238
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 17, 20262026-05-17T21:22:57+00:00 2026-05-17T21:22:57+00:00

I am using the Dojo ProgressBar to show a long running process in Struts2

  • 0

I am using the Dojo ProgressBar to show a long running process in Struts2 using the execAndWait interceptor. The execAndWait interceptor puts the action on the value stack for each call that returns the wait result. However, when the result type is JSON, the action only has the default values of the action.

Here is my struts action config
(I tried to wild card the result names, but that didn’t work)
NOTE: I have to wrap my JSON in a textarea because Dojo’s iframe.send expects it to be wrapped in a textarea.


<action name="upload" class="ProcessFileAction" method="upload">
  <interceptor-ref name="agfStack" />
  <interceptor-ref name="execAndWait">
    <param name="delay">1000</param>
    <param name="delaySleepInterval">500</param>
  </interceptor-ref>
  <result name="wait" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
  <result name="success" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
  <result name="error" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
</action>

Here is my JSP
NOTE: I have to use the iFrame.send action beacuse I am uploading a file. Since my struts result will be the same for the initial wait return as it will for each successive call, I have to use the iframe.send for the AJAX call too (as opposed to xhrGet). That is because iframe.send expects the JSON to be wrapped in a text area, and xhrGet doesn’t.


<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<script type="text/javascript">
dojo.require("dojo.io.iframe");
dojo.require("dijit.ProgressBar");
dojo.require('dojox.timing');
var t = new dojox.timing.Timer(<tiles:getAsString name="refreshTime" />);
t.onTick = function() {
  dojo.io.iframe.send({
    url: '<s:url action="upload" namespace="/" />',
    method: "POST",
    handleAs: "json",
    load: function(response, ioArgs){
    if(response.running) {
      var progressPercent = response.percentComplete + "%";
      var reportText = response.processMessage;
      var uploadProgesssBar = dijit.byId("uploadProgress");
      if(uploadProgesssBar == null) {
        return;
      }
      uploadProgesssBar.update({progress:progressPercent, report:function() {return reportText;}});
    }
    else {
      showById("progressDialogButtonDiv");
      t.stop();
    }
  },
  error: function(response, ioArgs) {
    t.stop();
    var progressPercent = response.percentComplete + "%";
    var reportText = response.processMessage;
    var uploadProgesssBar = dijit.byId("uploadProgress");
    if(uploadProgesssBar == null) {
      return;
    }
    uploadProgesssBar.update({progress:progressPercent, report:function() {return reportText;}});
    showById("progressOkButton");
  }
});
};
function showProgressBar() {
  hideById("uploadForm");
  showById("progressBar");
}
function hideProgressBar() {
  hideById("progressBar");
  showById("uploadForm");
}
function submitAndShowProgress(submitForm) {
  dojo.io.iframe.send({
    form: submitForm,
    handleAs: "json",
    load: function(response, ioArgs) {
      submitForm.reset();
      var progressPercent = response.percentComplete + "%";
      var reportText = response.processMessage;
      if(response.running) {
        showProgressBar();
        var uploadProgesssBar = dijit.byId("uploadProgress");
        if(uploadProgesssBar == null) {
          return;
        }
        uploadProgesssBar.update({progress:progressPercent, report:function() {return reportText;}});
        t.start();
      }
      else {
        createAndShowAlertDialog(reportText, "");
      }
      return response;
    },
    error: function(response, ioArgs) {
      t.stop();
      hideProgressBar();
      createAndShowAlertDialog(response.processMessage, "An Error Occurred");
      return response;  
    }
  });
  return false;
}
</script>

<div id="progressBar" class="hidden loading">
<div dojoType="dijit.ProgressBar" style="width:400px" jsId="uploadProgress" id="uploadProgress" annotate="true"></div>
<div class="hidden actionButtons" id="progressOkButton">
<button style="position: relative; left: 42px;" dojoType="dijit.form.Button" onClick="hideProgressBar(); return false;">Ok</button>
</div>
</div>
<s:form action="upload" namespace="/" enctype="multipart/form-data" id="uploadForm" method="post" onsubmit="return submitAndShowProgress(this);">
<s:file name="file" id="file" label="File" />
<s:submit id="submit" name="submit">Upload</s:submit>
</s:form>

Here is my action:
(trimmed)


public class ProcessFileAction implements LongRunning {
  String processMessage = "Uploading...";
  Integer percentComplete = 0;
  Boolean running = true;

  private FileProcessor fileProcessor;
  private File file;
  private String fileContentType;
  private String fileFileName;

  public String upload() throws Exception {
    setProcessMessage("Processing File...");
    setPercentComplete(10);
    try {
      if(!getFile().exists()) {
        getFile().createNewFile();
      }
      File processedFile = getFileProcessor().process(getFile(), this);
    } catch(Exception e) {
      e.printStackTrace();
      setProcessMessage("An error occurred while processing your file.");
      setPercentComplete(100);
      setRunning(false);
      return ERROR;
    }
    setProcessMessage("Process Complete!");
    setPercentComplete(100);
    setRunning(false);
    return SUCCESS;
  }
...
}
public interface LongRunning {
    public void setProcessMessage(String processMessage);
    public String getProcessMessage();
    public void setPercentComplete(Integer percentComplete);
    public Integer getPercentComplete();
    public void setRunning(boolean running);
    public boolean isRunning();
}

I am going to look at the code for the JSON result type and ExecAndWait interceptor for more clues.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-17T21:22:57+00:00Added an answer on May 17, 2026 at 9:22 pm

    After looking at JSONResult, I found the problem.

    When you set a ‘root’ object on the JSON, it looks for the values on the value stack. If not, it looks at the ActionInvocations action (which is not used with the ExecAndWait Intercepror).

    
    public void execute(ActionInvocation invocation) throws Exception {
    ...
        String json;
        Object rootObject;
        if (this.enableSMD) {
          // generate SMD
          rootObject = this.writeSMD(invocation);
        } else {
          // generate JSON
          if (this.root != null) {
            ValueStack stack = invocation.getStack();
            rootObject = stack.findValue(this.root);
          } else {
            rootObject = invocation.getAction();
          }
        }
    ...
    }
    

    So, I created a LongRunningImpl class to hold the LongRunning information

    
    public class LongRunningImpl implements LongRunning {
      private Integer percentComplete = 0;
      private String processMessage = "Uploading file...";
      private boolean running = true;
    ...
    }
    

    I used that object in my action:

    
    public class ProcessFileAction {
      LongRunning longRunning;
    
      private FileProcessor fileProcessor;
      private File file;
      private String fileContentType;
      private String fileFileName;
    
      public String upload() throws Exception {
        getLongRunning().setProcessMessage("Processing File...");
        getLongRunning().setPercentComplete(10);
        try {
          if(!getFile().exists()) {
            getFile().createNewFile();
          }
          File processedFile = getFileProcessor().process(getFile(), getLongRunning());
        } catch(Exception e) {
          e.printStackTrace();
          getLongRunning().setProcessMessage("An error occurred while processing your file.");
          getLongRunning().setPercentComplete(100);
          getLongRunning().setRunning(false);
          return ERROR;
        }
        getLongRunning().setProcessMessage("Process Complete!");
        getLongRunning().setPercentComplete(100);
        getLongRunning().setRunning(false);
        return SUCCESS;
      }
    ...
    }
    

    And then set a root object on my results:

    
    <action name="upload" class="ProcessFileAction" method="upload">
      <interceptor-ref name="agfStack" />
      <interceptor-ref name="execAndWait">
        <param name="delay">1000</param>
        <param name="delaySleepInterval">500</param>
      </interceptor-ref>
      <result name="wait" type="json">
        <param name="noCache">true</param>
        <param name="contentType">text/html</param>
        <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
        <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
        <param name="root">longRunning</param>
        <param name="includeProperties">percentComplete,processMessage,running</param>
      </result>
      <result name="success" type="json">
        <param name="noCache">true</param>
        <param name="contentType">text/html</param>
        <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
        <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
        <param name="root">longRunning</param>
        <param name="includeProperties">percentComplete,processMessage,running</param>
      </result>
      <result name="error" type="json">
        <param name="noCache">true</param>
        <param name="contentType">text/html</param>
        <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
        <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
        <param name="root">longRunning</param>
        <param name="includeProperties">percentComplete,processMessage,running</param>
      </result>
    </action>
    

    Now everything works! I might list this as a defect for Struts2, but I am not sure how it’ll be received. I think the JSON Result object should check for the action on the value stack before defaulting back to the action on the ActionInvocation.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

No related questions found

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.