how to clear contents of a PrintWriter after writing - java

Good evening, i want to know how to clear the data written to a PrintWriter, i.e. is it possible to remove the data from a PrintWriter after printing?
here in this servlet i print some text to the response and at the line denoted by # i want to remove all the previously printed data and print new stuff:
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String uName = request.getParameter("uName");
String uPassword = request.getParameter("uPassword");
if (uName .equals("Islam")) {
out.println("Valid-Name");
if (uPassword !=null) {
if (uPassword .equals("Islam")) {
// # clear the writer from any printed data here
out.println("Valid-password");
} else {
out.println("");
out.println("InValid-password");
}
}
} else {
out.println("InValid-Name");
}
}
Note: i tried out.flush() but the old printed text remains

Create an in-memory PrintWriter using a StringWriter. You can get the underlying buffer from the StringWriter and clear it if you need to.
StringWriter sr = new StringWriter();
PrintWriter w = new PrintWriter(sr);
w.print("Some stuff");
// Flush writer to ensure that it's not buffering anything
w.flush();
// clear stringwriter
sr.getBuffer().setLength(0);
w.print("New stuff");
// write to Servlet out
w.flush();
response.getWriter().print(sr.toString());

HttpServlteResponse.resetBuffer() will clear the buffered content. But yes, if the response is already flushed to the client it will throw IllegalStateException. Because it is illegal to clear after partial response is sent to the client.
resetBuffer........
void resetBuffer()
Clears the content of the underlying buffer in the response without clearing headers or status code. If the response has been committed, this method throws an IllegalStateException.
References:
Cause of Servlet's 'Response Already Committed'

You can't do that with the original PrintWriter you get from the response, as that's backed by the actual OutputStream corresponding to the client connection. What you write there goes right to the browser via the wire (after some buffering), so you can't "take it back".
What you can do is write your message in some StringBuilder and once you know it's good to go, write it to the PrintWriter.
If you want this logic to be applied in multiple places (transparently), you can consider writing a filter that wraps the original response in an HttpServletResponseWrapper which returns a "fake" OutputStream or PrintWriter and performs this check prior to actually sending it over the wire.
public class CensorshipFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
CensorshipResponseWrapper wrapper = new CensorshipResponseWrapper(httpServletResponse);
chain.doFilter(request, wrapper);
String output = wrapper.sw.toString();
if ( output.contains("Some forbidden pattern") ) { // your check goes here
// throw exception or whatever
} else { // write the whole thing
httpServletResponse.getWriter().write(output);
}
}
#Override
public void destroy() {
}
static class CensorshipResponseWrapper extends HttpServletResponseWrapper {
private final StringWriter sw = new StringWriter();
public CensorshipResponseWrapper(HttpServletResponse response) {
super(response);
}
#Override
public ServletOutputStream getOutputStream() throws IOException {
// you may also fake the output stream, if some of your servlets use this method
return super.getOutputStream();
}
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(sw);
}
}
}

What ended up working for me was to change the logic of how I was outputting my data.
This is the data structure I was outputting that stored the results of a search using the text from a html form as input.
private final TreeMap<String, ArrayList<SearchResult>> searchResults;
So I was iterating over the contents of this data structure and printing it out to html.
public void writeSearchResultsToHtml(PrintWriter writer)
{
try
{
JSONTreeWriter. writeSearchResultsToHtml(searchResults, writer);
} catch (ArithmeticException | IllegalArgumentException | IOException | NoSuchElementException e)
{
System.err.println("Unable to write the search results builder to JSON to the file html.");
}
// clear results for next search otherwise
// the next search will contain the previous
// results, store them in history.
searchResults.clear();
}
Clearing the data structure worked great given my servlet setup.
Here was my main serverlet loop logic:
public void startServer()
{
// seed the database for testing
crawler.startCrawl("http://cs.usfca.edu/~cs212/birds/birds.html");
index.toJSON("index.json");
// type of handler that supports sessions
ServletContextHandler servletContext = null;
// turn on sessions and set context
servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContext.setContextPath("/");
servletContext.addServlet(ViewServlet.class, "/");
// default handler for favicon.ico requests
DefaultHandler defaultHandler = new DefaultHandler();
defaultHandler.setServeIcon(true);
ContextHandler defaultContext = new ContextHandler("/favicon.ico");
defaultContext.setHandler(defaultHandler);
// setup handler order
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{defaultContext, servletContext});
openWebBrowser();
// setup jetty server
Server server = new Server(portNumber);
server.setHandler(handlers);
try
{
server.start();
server.join();
} catch (Exception e)
{
e.printStackTrace();
}
}

Related

How to test a controller with streamed content with MockMvc?

I'd like to test a Spring controller, without Spring context, with MockMvc.
This controller streams the content by writing it in the OutputStream of the response.
Here is the controller code:
#RequestMapping(method = GET, value = "/file")
public void getFile(HttpServletResponse response) throws IOException {
response.setHeader("Content-Disposition", "attachment; filename=file.json");
ObjectWriter objectWriter = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL).writer();
Item item = new Item();
List<Item> items = new ArrayList<>();
items.add(item);
try (Writer bufferedWriter = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()))) {
objectWriter.writeValue(bufferedWriter, items);
bufferedWriter.flush();
}
}
Here is the test:
#Test
public void getFile_ok() throws Exception {
mockMvc.perform(get(END_POINT + "/file").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
This controller works well, but the unit test fails with an IOException:
java.io.IOException: Stream closed
at java.io.BufferedWriter.ensureOpen(BufferedWriter.java:116)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:126)
at java.io.BufferedWriter.flush(BufferedWriter.java:253)
Actually the objectWriter.writeValue(bufferedWriter, items); tries to close the stream.
Javadoc:
Note: method does not close the underlying stream explicitly here;
however, JsonFactory this mapper uses may choose to close the stream
depending on its settings (by default, it will try to close it when
JsonGenerator we construct is closed).
In runtime, it doesn't close it but in my tests, it does, and the next line bufferedWriter.flush(); just sends the IOEception.
So to fix it I added a try/catch this way:
try {
writer.flush();
} catch (IOException e) {
logger.info("Stream closed in writeValue()", e);
}

Servlet mixes header and content and writing twice same in output?

I have implemented servlet which behaves not stable, sometimes it mixes header in content and writing same twice.
and sometimes it is returning file which contains response header mixed by content like this:
Server: Apache-Coyote/1.1
: W/"43-1353687036000"
DatCCoonntenntt--DDiissppoosittiioonn: : atatatacehnmte;n tf;i lfenlaemnea=m20=12201112211127325421_4W1_Wirnkgi_nSgc_Seern.xnlsx
sx
Content-Typ-eT: ype: applaipcatciaoti/on/toctestt-rstare
am
ConCtoententy-pTeype: appalicatcion/oon/octet-setarm
m
CCoonntent-Lnegtht h: 4199
Date: te: FriF,r i2,3 2No vNo2v0 120162: 215:25 :G4M2T
....
File content bytes ...
And again same header and content
UPDATE
*This situation happens on Tomcat7*
I have tested also on Tomcat6 and Jetty, in both cases there is no injection of HTTP-Header to response content but HTTP-Header is wrong and returns wrong file name, the file content is correct file. I have noticed that wrong return from servlet happens when
returns transfer-encoding is chunked.
When I am removing header stuff, and second part of bytes, it is valid file.
Is it possible that is synchronization issue ?
UPDATE
Here is full source of servlet :
public class ExcelDownloadServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger
.getLogger (ExcelDownloadServlet.class);
#Override
protected void doGet (HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
try
{
TransactionId transactionId = getTransactionId (request);
String fileName =
request.getParameter (GlobalConstants.EXCEL_FILE);
ExcelDownloadType downloadType =
ExcelDownloadType
.valueOf (request
.getParameter (GlobalConstants.EXCEL_DOWNLOAD_TYPE));
ActionContextFactory actionContextFactory =
ApplicationContext.getContext ()
.getActionContextFactory ();
//suppress warning. HttpServletRequest.getLocales does not support generics
#SuppressWarnings("unchecked")
ActionContext actionContext =
actionContextFactory.create (request.getSession ()
.getId (), Collections.<Locale> list (request
.getLocales ()));
GetExcelDataResponse dataResponse =
new GetExcelData (transactionId, fileName, downloadType)
.execute (actionContext);
writeToResponse (response, dataResponse.getFileName (),
dataResponse.getData ());
}
catch (InvalidSessionException e)
{
LOG.error ("Invalid session in Excel download", e);
throw new ServletException (e);
}
catch (ActionException e)
{
LOG.error ("Could not download into excel.", e);
throw new ServletException (e);
}
}
protected TransactionId getTransactionId (HttpServletRequest request)
{
return RequestParameterDeserializer.<TransactionId> deserialize (
request, GlobalConstants.TRANSACTION_ID);
}
protected void writeToResponse (HttpServletResponse response,
String rawFileName, byte[] data) throws IOException
{
ServletOutputStream sout = null;
try
{
response.setContentType ("application/octet-stream");
response.setContentLength (data.length);
// removing blanks from the file name, since FF cuts file names
// otherwise.
String fileNameWithTime = rawFileName.replaceAll (" ", "_");
response.setHeader ("Content-Disposition", "attachment; filename="
+ fileNameWithTime);
sout = response.getOutputStream ();
sout.write (data, 0, data.length);
}
finally
{
if (sout != null)
{
sout.close ();
}
}
}
UPDATE
*The call comes from GWT application when is generating the URL of servlet with required parameters and sets in IFrame, then servlet calls and file is downloading. Are there any suggestions ?*
I had a similar issue a long time ago.
It turned out that closing the ServletOutputStream triggered an unexpected behaviour on the request flow.
Servlets are not supposed to close the container provided OutputStream.
Another issue could be manually setting the content length, it is responsibility of the container producing the correct value.
To summarize, try removing out.close() and response.setContentLength()

Need help with creating custom HttpServletResponse

Suddenly stuck on generating custom servlet response. I want to replace servlet response with predefined one:
public class MyCustomResponse extends HttpServletResponseWrapper {
private String customOutput;
public MyCustomResponse(String customOutput, HttpServletResponse response) {
super(response);
// PrintWriter and Outputstream should stream this variable as output
this.customOutput = customOutput;
}
//
// Below I need to override something
//
}
and filter code snipped as follows:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//
//
MyCustomResponse customResponse = new MyCustomResponse("Hello world!", (HttpServletResponse) response);
chain.doFilter(request, customResponse);
}
Shame on me, but i'm really stuck on coding this simple task :(
Any help would be appreciated.
UPDATE:
All I want is to implement custom response wrapper which, once it's put into filter chain, would always respond with some predefined text. I know how to write custom data from within doFilter() method, but I want MyCustomResponse to be responsible for that - just instantiate and put in chain. Any well-reasoned responses "You cant do that because..." are also welcome.
As quoted in one of your comments :
"I want my custom response to return a
string in response to getWriter or
getOutputStream method invocation"
For that, you have to provide your own implementation for getWriter() & getOutputStream() by overriding them.
//---
private PrintWriter printWriter = null;
private ServletOutputStream outputStream = null;
public PrintWriter getWriter( ) throws IOException {
if (this.outputStream != null) {
throw new IllegalStateException(
"Cannot call getWriter( ) after getOutputStream( )");
}
if (this.printWriter == null) {
// initialize printWriter
}
return this.printWriter;
}
public ServletOutputStream getOutputStream( ) throws IOException {
if (this.printWriter != null) {
throw new IllegalStateException(
"Cannot call getOutputStream( ) after getWriter( )");
}
if (this.outputStream == null) {
// initialize outputStream
}
return this.outputStream;
}
//---
I am sorry, but
it is not clear what is your
problem. You code is written, so? It
does not work? what exactly does not work?
Why do you want to do this? The "right" solution is to pass information as session attribute.
I do not believe this can work. Really, you do not call directly the next filter in chain. You are kindly asking the app. server to do this. And you are not expected to replace the servlet request/response by your own. Use method explained above (#2)
Your response wrapper is useless as is, since it only stores a string in the Java object used to model the actual HTTP response.
The actual HTTP response that the client receives is the stream of bytes (resp. characters) sent via the output stream (resp. writer) of the HttpServletResponse object (and the headers, cookies, etc. stored in the HttpServletResponse object).
If you want to send a custom output string to the client, just use response.getWriter().print("Hello worlds!").
Passing the response to the rest of the filter chain is questionable, since the rest of the chain will probably want to add its own data to the response stream.
If you want to hard-code the response to send to the client to your custom output, but be able to still pass the response to the chain and ignore whatever the rest of the chain puts in the response, you could try to add the following to your wrapper :
private ServletOutputStream fakeOutputStream =
new ServletOutputStream() {
#Override
public void write(int b) throws IOException {
// do nothing. Everything written to this stream is ignored
}
}
private PrintWriter fakeWriter = new PrintWriter(fakeOutputStream);
public MyCustomResponse(String customOutput, HttpServletResponse response) {
super(response);
response.getWriter().print(customOutput);
}
#Override
public ServletOutputStream getOutputStream() {
return fakeOutputStream;
}
#Override
public PrintWriter getWriter() {
return fakeWriter;
}
I don't see the reason of what you want to do, but if you want to use your wrapper, my suggestion would be:
Create your own servlet that uses your wrapper and register it in web.xml, in something like this:
Extend javax.servlet.GenericServlet and override the service(ServletRequest, ServletResponse) method. Then you use the Template Method pattern to create a service(ServletRequest, ServletResponseWrapper). OR
Extend javax.servlet.HttpServlet and override service(HttpServletRequest, HttpServletResponse) method. Use the Template Method pattern to create a service(HttpServletRequest, HttpServletResponseWrapper). This will require that you don't use the doGet, doPost, doPut, doTrace methods already provided by HttpServlet but, instead create your own that uses your wrapper.
Hope this helps.

Why download popup window in browser not showing up when using JAX-RS v.s. standard servlet?

When I try using standard servlet approach, in my browser the popup window shows up asking me whether to open .xls file or save it.
I tried the exactly same code via JAX-RS and the browser popup won't show up somehow. Has anyone encounter this?
JAX-RS way that won't display popup:
#Path("excellaTest")
public class ExcellaTestResource {
#Context
private UriInfo context;
#Context
private HttpServletResponse response;
#Context
private HttpServletRequest request;
public ExcellaTestResource() {
}
#Path("horizontalProcess")
#GET
//#Produces("application/vnd.ms-excel")
#Produces("application/vnd.ms-excel")
public void getProcessHorizontally() {
try {
URL templateFileUrl = this.getClass().getResource("myExcelTemplate.xls");
String templateFilePath = URLDecoder.decode(templateFileUrl.getPath(), "UTF-8");
String outputFileDir = "MasatoExcelHorizontalOutput";
ReportProcessor reportProcessor = new ReportProcessor();
ReportBook outputBook = new ReportBook(templateFilePath, outputFileDir, ExcelExporter.FORMAT_TYPE);
ReportSheet outputSheet = new ReportSheet("myExcelSheet");
outputBook.addReportSheet(outputSheet);
reportProcessor.addReportBookExporter(new OutputStreamExporter(response));
reportProcessor.process(outputBook);
System.out.println("done!!");
}
catch(Exception e) {
System.out.println(e);
}
return;
}
}//end class
class OutputStreamExporter extends ReportBookExporter {
private HttpServletResponse response;
public OutputStreamExporter(HttpServletResponse response) {
this.response = response;
}
//ReportProcessor output()
//This method is call when ReportProcessor process() is invoked.
//The Workbook from POI API can be used to write to stream
#Override
public void output(Workbook book, BookData bookdata, ConvertConfiguration configuration) throws ExportException {
//TODO write to stream
try {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=masatoExample.xls");
book.write(response.getOutputStream());
response.getOutputStream().close();
System.out.println("booya!!");
}
catch(Exception e) {
System.out.println(e);
}
}
}//end class
What JAX-RS framework are you using?
My guess is that your code doesn't work, because you are returning void. The framework you are using probably recognizes void as HTTP 204 No Content. This causes browser to skip the actual response body and to ignore conntent-disposition header.
As I already wrote you in a parallel thread: try to returning Response object. You can put either OutputStream or byte[] as entity as set the content-disposition header.
I have never used class level injection for a jax-rs service. I suggest one of 2 solutions.
1) Try injecting the request and response as method arguments.
2) Output your file to a byte array output stream and return a byte array from your method instead of void.

How to output a binary document based on a HTML document using filters in Java

This may be a little confusing but I having some trouble. My goal is to take an input HTML document and then process that document and use the HTML data to output a image document. For example, a user will request a URL, with some action=png in the querystring and then the filter will get invoked for the URL and output image document.
I have tried everything but in my environment (Websphere), I am only able to output of one type. If the input type is text/html then I can only output a text document, I can't seem to output a binary document. Why? Because I get an illegal state exception each time.
[1/29/09 17:59:57:576 EST] 00000020 SystemErr R java.lang.IllegalStateException: SRVE0209E: Writer already obtained
[1/29/09 17:59:57:576 EST] 00000020 SystemErr R at com.ibm.ws.webcontainer.srt.SRTServletResponse.getOutputStream(SRTServletResponse.java:505)
I am using pseudo code not to reveal all of my code:
<filter>
<filter-name>TestFilter</filter-name>
<filter-class>
com.util.TestFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>TestFilter</filter-name>
<url-pattern>/index_test2.html</url-pattern>
</filter-mapping>
The Wrapper Class code is essentially this:
public class ContentCaptureServletResponse extends HttpServletResponseWrapper {
private ByteArrayOutputStream contentBuffer;
private PrintWriter writer;
public PrintWriter getWriter() throws IOException {
if (writer == null) {
contentBuffer = new ByteArrayOutputStream();
writer = new PrintWriter(contentBuffer);
}
return writer;
}
public String getContent(){
try {
writer = getWriter();
} catch (IOException e) {
e.printStackTrace();
}
writer.flush();
String xhtmlContent = new String(contentBuffer.toByteArray());
System.out.println(xhtmlContent);
return xhtmlContent;
}
}
And the filter code is this:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
final String renderType = request.getParameter("R");
final String renderClassName = request.getParameter("C");
if ((renderType != null) && (renderClassName != null)) {
try {
this.setFilterChain(filterChain);
response.setContentType("image/png");
PrintWriter out = response.getWriter();
// I call getWriter but not BOTH!
//response.getOutputStream();
response.getWriter();
// Build up the HTML document into a string.
CaptureResponse capContent = new CaptureResponse(response);
this.mainFilterChain.doFilter(req, );
String myString = capHtmlContent.getContent();
// What I really want to do here is output an output stream
// so I can write a binary image
processStr(myString);
response.getOutputStream();
response.write(binaryimage)
} catch (Exception e) {
e.printStackTrace();
}
// No data will be output to the user.
} else {
filterChain.doFilter(request, response);
} // End of if-else
} // End of the method.
The code works if I want to take some input html text document. I am assuming because of the open printwriter stream. But I am having trouble going to a different format. Basically, because I can't call response.getOutputStream()
The issue does appear to be that you are opening the response Writer prior to wrapping the response.
It looks like you should be able to do:
this.setFilterChain(filterChain);
CaptureContent capContent = new CaptureResponse(response);
doFilter()
process();
response.setContentType("image/png");
response.getOutputStream().write(imagedata);
You definitely cannot safely open both the Writer and the OutputStream
I have no experience with Websphere, but one common problem is that you try to manipulate the HTTP header after you already committed to sending the body -- once the webserver started to deliver the content, you cannot update the headers any more since they've already been sent.
Maybe you need to review your documentation and examples. For example, I don't see why you call response.get*() without actually looking at the result. Are you sure this is necessary or is this because you trimmed your code?
Cheers,
Volker

Categories

Resources