Question

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?

Was it helpful?

Solution 3

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.

OTHER TIPS

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.

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.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top