0
votes

I need to forward/craft request to another servlet from other servlet's service method manually. This servlet which calls another servlet, should extract the data from other servlet's response and send it's own response to client. How to achieve this kind of functionality?

Client <-----> Servlet1 <-----> Servlet2

I know it's bad design, but due the circumstances we have to introduce the functionality of Servlet2 to Servlet1

1
What about response.sendRedirect();.Kartic
Yes you can achieve either by using Request Dispatcher's Forward or Include methods (available with request object) or Send Redirect method(available with response object). ServletContext is also one of the ways to acheive servlet collaboration because it is the one which provides the information of all the servlets.Mihir

1 Answers

1
votes

you need to use HttpServletResponseWrapper and override its getOutputStream Method.

CustomHttpServletResponseWrapper and CustomServletOutputStream are implementation for this.

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class CustomHttpServletResponseWrapper extends HttpServletResponseWrapper {
    private ServletOutputStream outputStream;
    private PrintWriter writer;
    private CustomServletOutputStream os;

    public CustomHttpServletResponseWrapper(HttpServletResponse response) throws IOException {
        super(response);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (writer != null) {
            throw new IllegalStateException("getWriter() has already been called on this response.");
        }

        if (outputStream == null) {
            outputStream = getResponse().getOutputStream();
            os = new CustomServletOutputStream(outputStream);
        }

        return os;
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        if (outputStream != null) {
            throw new IllegalStateException("getOutputStream() has already been called on this response.");
        }

        if (writer == null) {
            os = new CustomServletOutputStream(getResponse().getOutputStream());
            writer = new PrintWriter(new OutputStreamWriter(os, getResponse().getCharacterEncoding()), true);
        }

        return writer;
    }

    @Override
    public void flushBuffer() throws IOException {
        if (writer != null) {
            writer.flush();
        } else if (outputStream != null) {
            os.flush();
        }
    }

    public byte[] getContent() {
        if (os != null) {
            return os.getContent();
        } else {
            return new byte[0];
        }
    }

}

customServletOutputStream.java

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;

public class CustomServletOutputStream extends ServletOutputStream {

      private OutputStream outputStream;
        private ByteArrayOutputStream content;

        public CustomServletOutputStream(OutputStream outputStream) {
            this.outputStream = outputStream;
            this.content = new ByteArrayOutputStream(1024);
        }

        @Override
        public void write(int b) throws IOException {
            outputStream.write(b);
            content.write(b);
        }

        public byte[] getContent() {
            return content.toByteArray();

}

        @Override
        public boolean isReady() {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {
            // TODO Auto-generated method stub

        }
}

your Main class: use RequestDespetcher.include() to redirect request to s2 and pass CustomHttpServletResponseWrapper.

 @ResponseBody
    @RequestMapping("/s1")    
public String s1(HttpServletRequest req, HttpServletResponse res) throws Exception{
         RequestDispatcher rd = req.getRequestDispatcher("/oauth2/s2");
         CustomHttpServletResponseWrapper wrappedResponse = new CustomHttpServletResponseWrapper(res);
         rd.include(req, wrappedResponse);
         wrappedResponse.flushBuffer();
        byte[] result = wrappedResponse.getContent();
        System.out.println("result of servlet 2 "+new String(result));
    // here you got the result of servlet 2. manipulate it as you want. 

        return new String(result);
    }

    @ResponseBody
    @RequestMapping("/s2")
    public String s2(HttpServletRequest req, HttpServletResponse res){
        return "hello from s2";
    }