Kaliyug Antagonist
Kaliyug Antagonist

Reputation: 3612

Spring exhausting inputstream of the request

I am trying to pass a String array from a Web Service to a Spring web application.

The Web Service code is :

/**
 * 
 */
package lnt.remote.ws;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;

import javax.jws.WebMethod;
import javax.jws.WebService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author 298790
 * 
 *         This class is a JAX-WS end-point implementation and contains
 *         method(s) to fire batch jobs pertaining to reports
 */
@WebService
public class BatchJobWS {

    private static String remoteAppURL;
    private static Logger log = LoggerFactory.getLogger(Constants.WS_LOGGER);

    static {
        try {

            Properties props = new Properties();
            props.load(BatchJobWS.class.getResourceAsStream("/url.properties"));

            remoteAppURL = props.getProperty(Constants.REMOTE_APP_URL);

            log.info("In BatchJobWS , remote app. url is {}", remoteAppURL);

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            log.error("FileNotFoundException in static block of BatchJobWS", e);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            log.error("IOException in static block of BatchJobWS", e);
        }

    }

    @WebMethod
    public String[] generateReportBatchJob(String... params) {

        HttpURLConnection httpConn;
        URL remotePayrollUrl = null;
        ObjectOutputStream oos = null;
        String[] returnValues = null;

        log.info("In BatchJobWS.generateReportBatchJob(...),params = {}",
                params);

        if (params == null || params.length == 0) {
            return null;
        }

        try {
            remotePayrollUrl = new URL(remoteAppURL);
        } catch (MalformedURLException e1) {
            // TODO Auto-generated catch block
            // e1.printStackTrace();
            log.error(
                    "MalformedURLException in BatchJobWS.generateReportBatchJob(...)",
                    e1);
        }

        /*
         * Give some thought to which exception(s) be handled and which must be
         * thrown
         */
        try {
            httpConn = (HttpURLConnection) remotePayrollUrl.openConnection();
            httpConn.setDoOutput(true);
            httpConn.setUseCaches(false);

            oos = new ObjectOutputStream(httpConn.getOutputStream());

            log.info("Writing params to the outputstream");

            oos.writeObject(params);

            oos.flush();
            oos.close();

            ObjectInputStream ois = new ObjectInputStream(
                    httpConn.getInputStream());

            Object returnParams = ois.readObject();

            log.info("Reading params from the inputstream");

            if (returnParams.getClass().isArray()) {
                returnValues = (String[]) returnParams;
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            log.error("IOException in BatchJobWS.generateReportBatchJob(...)",
                    e);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            log.error(
                    "ClassNotFoundException in BatchJobWS.generateReportBatchJob(...)",
                    e);
        }

        log.info(
                "Returning from BatchJobWS.generateReportBatchJob(...),returnValues = {}",
                returnValues);

        return returnValues;
    }

}

Initially, on the web application side, I had written a plain-old servlet as shown below :

package lnt.remote;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lnt.service.ReportService;
import lnt.utilities.BatchJobService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Servlet implementation class RemoteCallInterceptor
 */
  public class RemoteCallInterceptor extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private static Logger log = LoggerFactory
            .getLogger(RemoteCallInterceptor.class);


    /**
     * @see HttpServlet#HttpServlet()
     */
    public RemoteCallInterceptor() {
        // super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        log.info("In Target Payroll. RemoteCallInterceptor.doGet()");
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        log.info(
                "In Target Payroll. RemoteCallInterceptor.doPost(),reportService = {}",
                reportService);

        BatchJobService BatchJobService = new BatchJobService();
        BatchJobService.runBatchJob(request, response);

    }
}

I wrote a new class BatchJobService that calls a few existing Spring beans which , in turn, have multiple Spring beans injected using @Autowire. Hence, the code in BatchJobService(which is not a Spring-managed component) was failing with NullPointerException(asthe beans were not getting injected). Hence, to ‘inject’ BatchJobService(thereby, injecting the beans needed in BatchJobService ) in RemoteCallInterceptor, I made the latter a Spring Controller(using @Controller) and modified the doPost(…) as shown :

package lnt.remote;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lnt.service.ReportService;
import lnt.utilities.BatchJobService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Servlet implementation class RemoteCallInterceptor
 */
@Controller
public class RemoteCallInterceptor extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private static Logger log = LoggerFactory
            .getLogger(RemoteCallInterceptor.class);

    @Autowired
    @Qualifier("ReportService")
    ReportService reportService;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public RemoteCallInterceptor() {
        // super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        log.info("In Target Payroll. RemoteCallInterceptor.doGet()");
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    @RequestMapping(value = "/RemoteCallInterceptor.do", method = RequestMethod.POST)
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        log.info(
                "In Target Payroll. RemoteCallInterceptor.doPost(),reportService = {}",
                reportService);

        BatchJobService BatchJobService = new BatchJobService();
        BatchJobService.runBatchJob(request, response);

    }
}

But now the issue is that the code in BatchJobService that reads the object(String array written by the Web Service) from the input stream gets an EOFException.

I suppose the @RequestMapping thing caused the input stream to be consumed - is my assumption correct ? If not, how should I retrieve the String [] params – which is neither a parameter nor an attribute, in web application? If yes, what can be the work-around?

Upvotes: 1

Views: 948

Answers (1)

skaffman
skaffman

Reputation: 403441

I suspect that it's broken because the Spring MVC application is broken, and that your WS client is being sent an error response. Your BatchJobWS isn't checking the HTTP response code, and is just assuming everything's fine. It's not surprising that it gets an exception.

You need to do two things. Firstly, add an explicit response status check to BatchJobWS, e.g.

HttpURLConnection httpConn;
...
oos.writeObject(params);
oos.flush();
oos.close();

if (httpConn.getResponseCode() != 200) {
   // error - throw an exception, or whatever
}

Secondly, there's no point in annotating an HttpServlet with @Controller - use one or the other, not both. Remove the extends HttpServlet and make doPost public. The protected may be what's causing the error.

Upvotes: 1

Related Questions