views:

1286

answers:

4

I've got a struts2 action that responds to an AJAX request by taking some request parameters, calling a remote service that returns XML data, then transforming the data via XSL and returning the resulting XHTML via a Stream Result. The response is different depending on the given parameters.

Here is the action class with a bunch of stuff taken out:

public class ServiceHandler extends ActionSupport {
    private ByteArrayInputStream inputStream;

    public String execute(){

        String response = "";

        // Get request parameters
        // Make a request to a remote server via an http connection
        // Transform result via XSL

        //uses dom4j for XML/XSL stuff
        //this should never be empty
        response = resultDoc.asXML();

        inputStream = new ByteArrayInputStream(response.getBytes()); 
        return "success";
    }

    public ByteArrayInputStream getInputStream(){
        return inputStream;
    }
}

And here are the important struts.xml bits:

<action name="sh" class="ServiceHandler">
    <result name="success" type="stream">
        <param name="contentType">text/html</param>
        <param name="contentDisposition">inline;filename="response.html"</param>
        <param name="bufferSize">1024</param>
        <param name="allowCaching">false</param>
    </result>
</action>

My problem is that when I have multiple requests going at the same time, all calling the ServiceHandler action, sometimes the response is totally blank (should never happen), sometimes the response is cut off at the beginning or end by some random amount, and sometimes the responses are switched, so that the wrong response is received by a an AJAX requestor.

I know this is an issue of thread safety, and I've moved all important variable definitions into the execute() method so that they are not instance variables (and hence shared by all). The only interesting variable that is an instance variable is the inputStream, and I'm looking at that as the cause of my problems.

Is there a way to make the inputStream variable thread-safe? Or is there another solution I'm not seeing?

A: 

I'm familiar with Struts 1 only but take a look into DonwloadAction. Or just use a plain struts Action, write the result directly to the response object and return null as forward.

GClaramunt
A: 

I'm not into Struts 2 at all, but if you really have to return the "success" result and have no way to write to the output directly, this looks like a good place to use a ThreadLocal to keep your stream local to the current thread. (Also see the Wikipedia article on thread-local storage for more information on the pattern.)

Henning
I don't need to return "success" and am only constrained by struts2 as far as what I can and can't do. If I can find a way to output directly without having to using an instance variable then I will do that.
Adam Plumb
Found a way to do this, and writing directly appears to have fixed my problem.
Adam Plumb
A: 

Thanks for Henning for leading me in the right direction. I hadn't thought of writing directly to the response output stream, as it isn't mentioned anywhere in struts2 documentation.

The benefit of writing the response directly to the output stream is that you don't need to create an instance object for inputStream. This keeps all data in the execute() method, which is safe from other threads.

Here is a modified action class that writes directly to the output stream and returns a null result.

import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;

public class ServiceHandler extends ActionSupport {
    public String execute(){

        String response = "";

        // Get request parameters
        // Make a request to a remote server via an http connection
        // Transform result via XSL

        //uses dom4j for XML/XSL stuff
        //this should never be empty
        response = resultDoc.asXML();

        HttpServletResponse httpResponse = ServletActionContext.getResponse();
        try{
            httpResponse.getOutputStream().print(response);
        }
        catch(IOException e){
            return "failure";
        }

        return null;
    }
}

This appears to have fixed the issues I was having.

Adam Plumb
A: 

I have to write html conetents directly to the page. using struts 2.0 tags.. mine code is working properly gor normal html tags, but i not getting output with tags.

Code is pasted below ++++++++++++++++++++++++++++++++++++++++

Action class

String countryName = request.getParameter("countryName"); System.out.println(countryName); countryCodeList = comDB.getCountryCodes(countryName); System.out.println(countryCodeList); //html=""; //html=""; html=""; //html=""; inputStream = new StringBufferInputStream(html); System.out.println(html); return "success";

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

JSP file

function retrieveURL1(url,form) {

alert(url);
if (window.XMLHttpRequest) { // Non-IE browsers
req = new XMLHttpRequest();
req.onreadystatechange = processStateChange1;
try {       
     req.open("GET", url, true);
       } catch (e) {
     alert(e);
    }
    req.send(null);
  } else if (window.ActiveXObject) { // IE
    req = new ActiveXObject("Microsoft.XMLHTTP");
    if (req) {
      req.onreadystatechange = processStateChange1;
      req.open("GET", url, true);

      req.send();
    }
  }
}

function processStateChange1() { //alert("processStateChange1 called"); if (req.readyState == 4) { // Complete if (req.status == 200) { // OK response

      document.getElementById("character").innerHTML = req.responseText;

    } else {
      alert("Problem: " + req.statusText);
    }
  }
}
mystery_girl