Error Rendering View: java.lang.IllegalStateException: getOutputStream() has already been called for this response - jsf

I am creating a project in JSF and spring whose main only purpose is to generate PDF file in the browser. Everything seems fine and pdf generated too but on console i am getting this exception.Anyone have idea about this? I have searched and found that many peoples had that problem but i didn't find any solution for mine one.
SEVERE: Error Rendering View[/WebPages/SearchPages/index.xhtml]
java.lang.IllegalStateException: PWC3991: getOutputStream() has already been called for this response
I am getting this error while creating my outputstream object
HTTPServletResponse response = (HTTPServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
ServletOutputStream out = response.getOutputStream();
Is there any problem while my creation or anyother reason? Any help would be greatly appreciable

You need to tell JSF that you've already completed the HTTP response yourself, otherwise JSF will still continue doing the default RENDER_RESPONSE job after the action method is finished, which would result in exactly this exception, because the response is already committed.
You can do that by calling FacesContext#responseComplete() in the action method.
responseComplete
public abstract void responseComplete()
Signal the JavaServer Faces implementation that the HTTP response for this request has already been generated (such as an HTTP redirect), and that the request processing lifecycle should be terminated as soon as the current phase is completed.
See also:
How to provide a file download from a JSF backing bean?

Related

SignalR Core 1.0 intermittently changes the case of http method for non signalR POST, need fix (AKA Random 404 Errors)

I'm always reluctant to claim that a bug that I'm seeing is actually a .Net Core bug, but after spending 8+ hours investigating the following bug, it looks like a .Net Core SignalR bug to me. I need techniques for tracking this down further and for fixing it.
The first rule of honing in on a bug is to try to create a minimal amount of code that can consistently repro the bug. While I can't reproduce it in a small stand along project, I have worked hard try to zero in on what's happening.
I have a controller with the following action method
[HttpPost]
[Route("/hack/ajax/start")]
public JsonResult AjaxStart([FromBody] JObject data) {
//A call to some method that does some work
return Json(new {
started = true
});
}
Calling this code via a jquery ajax call or Postman works flawlessly every time if I do not have any SignalR Core 1.0 hubs registered in the startup.cs method. However, when I register the following in the startup.cs file I have intermittent issues.
namespace App.Site.Home {
public class HackHub : Hub {
public async Task SendMessage(string status, string progress) {
await Clients.All.SendAsync("serverMsg", status, progress);
}
}
}
Startup.cs ConfigureServices contains
services.AddSignalR();
Startup.cs Configure contains
app.UseSignalR(routes => {
routes.MapHub<App.Site.Home.HackHub>("/hub/hack");
});
If I were to comment out the one line above routes.MapHub<App.Site.Home.HackHub>("/hub/hack"); everything works fine every time. However with this line present, (I.e. some SignalR hub registered) then that's when the fun starts for me, even if I have no code executing on the client or server that makes use of the hub!
The issue is that sometimes when a HTTP POST request is made for the action method above, something in .Net Core (SignalR??) is converting the POST method to Post, and then because Post is not a valid HTTP Method it converts it to a blank method. And since My action method requires an HTTP POST a 404 status code is returned. Many of the HTTP POSTS for that endpoint work fine, but often the issue I just described occurres.
To ensure that my client code was not part of the problem, I was able to reproduce my issue using Postman to make the requests. Further to ensure that POST was actually being sent and not Post, I used Fiddler to watch what was going over the wire. All this is documented below.
Here is the first request (which always works) done via Postman:
Here is the second (identical!) request done via Postman, this one resulted in a 404:
Here is what the first request (the one that worked properly) looked like in fiddler:
Here is what the second request looked like in fiddler:
As you can see, the requests are identical. But the response certainly is not.
So to get a better idea what the server was seeing, I added the following code to the beginning of the startup.cs Configure method. Due to it's placement, for the request this code gets to run before any other application code or middleware.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
//for debugging
app.Use(async (context, next) => {
if(context.Request.Method == "") {
string method = context.Request.Method;
string path = context.Request.Path;
IHttpRequestFeature requestFeature = context.Features.Get<IHttpRequestFeature>();
string kestralHttpMethod = requestFeature.Method;
string stop = path;
}
await next();
});
//more code here...
}
For the first request, the request.Method was POST as one would expect:
But for the second request request.Method was blank!!
To investigate this further, I accessed the requestFeature and checked the Http Method Method there. This is where things get really interesting. If I just hover over the property in the debuggger, it's blank too.
But, If I expand the requestFeature object and look at the Method property there, is it Post!!!
That alone seems like craziness. How can two views of the SAME property in the debugger have different values???! It would seem that some code converted the POST to Post, and at some level the system knows that Post is not a valid http method so in some views of that variable it's converted to a blank string. But that is so weird!
Also, we clearly saw via Postman and Fiddler that POST was sent, so how did it get changed to Post? What code did that? I'd like to claim that it can't be my code since I'm checking the value of the RequestFeature before any of my other code related to the request gets a chance to run. Also, if I comment out the one line of code that registers that SignalR hub, then POST is never converted to Post and I never get a 404. But with that SignalR hub registered I periodically get this behavior.
Are there any SignalR or other .net Core switches I can turn on to get better trace or logging info to see when the POST is getting changed to Post? Is there a way to fix this?
This question was looked into via this GitHub issue https://github.com/aspnet/KestrelHttpServer/issues/2591 which was originally opened up when someone else also observed random 404 errors
I want to especially thank #ben-adams for his help in understanding what was going on.
Let me start by saying that this did not turn out to be a bug in the framework. It was a bug in my code. How can that be given what I was observing?
Well, it's like this...
In some parts of the HttpRequest the method is a string, but it in other parts it's an enum. The enum value for POST is Post. So that's why the case conversion was happening.
The reason that one part of the request was saying Post while the other part showed a Method value of a blank string was because the request object was gummed up because I had accessed it at a time when it was in between requests.
How did I do THAT? you may wonder. Well let me tell you, because the plot thickens...
I turns out that I have some logging code that that gathers context information when it's called and one of the pieces of context info it gathers is the current request.Method. When this logging code is called from a main thread, there is no issue.
However, my system does have some code that runs on background threads that are either started via a Timer or via a ThreadPool.QueueUserWorkItem. If this code hits an exception it will call the same logger code.
When my logger code, running on a background thread, checks for the current httpContext via IHttpContextAccessor I fully expected it to receive null. And certainly this same code in the same situation when accessing the current HttpContext via HttpContext.Current in a non .Net Core website does receive null. But as it turns out, under .Net core, it wasn't receiving null, it was receiving an object. But that object was for a request that had already finished and who's request object had already been reset!!!
Starting in .Net Core 2.0 the HttpContext, and it's child objects like request, gets reset after the connection for a request closes. So the HttpContext object (and it's request object) the logger code was getting when running on a background thread was an object that had been reset. It's request.Path for example was null.
It turns out that a request in this state does not expects it's request.Method property to be accessed. And doing so gums up the works for the next request that comes in. Ultimately this is the source of why the next request that came in ended up returning a 404 error.
So how do we fix this? Why does IHttpContextAccessor return an object rather than null in this out of context situation especially given that the object may very possibly be between requests? The answer is that when I was used Timer or ThreadPool.QueueUserWorkItem to create a background task, the Execution Context was being flowed to the new thread. This is just what happens by default when you use these API methods. But, internally the IHttpContextAccessor uses an AsyncLocal to keep track of the current HttpContext and since my new thread received Execution Context from the main thread it had access to the same AsyncLocal. And so IHttpContextAccessor provided an object rather than the null I was expecting when called from a background thread.
The fix? (Thank you #Ben-Adams!) Instead of calling ThreadPool.QueueUserWorkItem I needed to call ThreadPool.UnsafeQueueUserWorkItem instead. This method DOES NOT flow the current Execution Context to the new thread, and therefore the new thread won't have access to those AsyncLocals from the main thread. Once I did this, IHttpContextAccessor then returned null when called from the background thread instead of returning a object that was in between requests and untouchable. Yea!
When creating a `Timer' I also needed to change my code to do it in a way that would not flow Execution Context. Here is the code I use (which was inspired by some #Ben-Adams suggested):
public static Timer GetNewTimer(TimerCallback callback, object state, int dueTime, int interval) {
bool didSuppress = false;
try {
if (!ExecutionContext.IsFlowSuppressed()) {
//We need to suppress the flow of the execution context so that it does not flow to our
//new asynchronous thread. This is important so that AsyncLocals (like the one used by
//IHttpaccessor) do not flow to the new thread we are pushing our work to. By not flowing the
//execution context, IHttpAccessor wil return null rather than bogusly returning a context for
//a request that is in between requests.
//Related info: https://github.com/aspnet/KestrelHttpServer/issues/2591#issuecomment-399978206
//Info on Execution Context: https://blogs.msdn.microsoft.com/pfxteam/2012/06/15/executioncontext-vs-synchronizationcontext/
ExecutionContext.SuppressFlow();
didSuppress = true;
}
return new Timer(callback, state, dueTime, interval);
} finally {
// Restore the current ExecutionContext
if (didSuppress) {
ExecutionContext.RestoreFlow();
}
}
}
This only leaves one remaining question unanswered. My original question noted that registering a SignalR hub was causing the system to exhibit this random 404 behavior but the system did not exhibit this behavior when no SignalR hub was registered (or so I thought). Why was this? I truly don't know. Perhaps it was putting more resource pressure on some part of the system and thus causing the issue to show up more easily. Not sure. All I know is that the root issue was that I was flowing Execution Context to my background threads without realizing it and that was causing the IHttpContextAccessor's AsyncLocal to be in scope. Not flowing the Execution Context to the background threads fixes that issue.

WKWebView delegate method error message

I am using WKWebView to load and display the content of a web site. After the app was launched and running, the delegate method -webView:didFailNavigation:withError:got called. Following is the error description (error.description) extracted from this delegate method using Xcode debugger:
Error Domain=NSURLErrorDomain Code=-999 "(null)" UserInfo={NSErrorFailingURLStringKey=, NSErrorFailingURLKey=, _WKRecoveryAttempterErrorKey=}
I did some Google search and found that Code=-999 is caused by ErrorCancelled, meaning another request is made before the previous request is completed. So how should I fix this issue in my app? Thanks a lot in advance.

Execute Javascript function between two Backing bean methods

I'm writing a JSF web application who follow the next steps:
Read a number from an input text
Look for the number in a legacy system
Generate a message and send It to a websocket
Get the response from the websocket
Store the result in a database
All of these steps must be executed in a single event, all of these tasks are executed in a backing bean, the problem is to execute the javascript to call the websocket and use this result to save it in the database.
I tried to use the RequestContext.getCurrentInstance().execute("function();"); method, but this function "Executes script after ajax request completes or on page load" and I need to get the result to store it into the database and execute other operations.
The question is, How and where can I handle these calls?
NOTE:
I can see the following options, but I'm not sure how to implement them:
Handle the calls using Javascript instead of backing bean, following the next tasks:
from Javascript call a backing bean method to look the number and get the response.
from Javascript get the result of the backing bean and send it to the websocket.
from javascript receive the response from the websocket and call another backing bean to store the result into the database.
Found a way to call a javascript function from the backing bean before the ajax request completes.
Call the WebSocket in the Backing bean instead of using Javascript.
I hope you can help me, Thanks.
----EDIT-----
The websocket is running in localhost, in this way the web page handle a device in a local machine, so it must be executed in the Javascript side and the 3rd option is not possible.
an option could be the following:
your xhtml should have 3 forms:
"User inputText/number form"
"websocket-Request Form" (hidden form/input)
"websocket response Data Form" (hidden form)
now you follow these steps:
A user submits input to your Bean (via ajax or commandActions ...etc)
bean-methode reads/validates that submitted data, then update value in form#2
Javascript/Jquery should listen on form#2/inputhidden value changed( then sends a wensocket request)
after recieving websocket response, update value inside form#3 and do autosubmit. now submitting this form calls an action methode in your bean which saves data to DB.

Liferay Portlet Response: how to set status code?

I have a simple method accepting PortletResponse and PortletRequest in my liferay portlet
public void remove(PortletResponse response, PortletRequest request) {
}
I want to set response status to 404, like I can do with HttpServletResponse by httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST)
Can you tell me how I can do it?
What does Portlet Specification 2.0 have to say - you can set the response status only when handling resource request:
If the portlet want to set a response status code it should do this
via setProperty with the key ResourceResponse.HTTP_STATUS_CODE.
That means, you can set the response status code this way when serving resources:
resourceResponse.setProperty(ResourceResponse.HTTP_STATUS_CODE,
Integer.toString(HttpServletResponse.SC_BAD_REQUEST));
With Liferay, you can get instance of the underlying HttpServletResponse and set status code there. The portal will return it to the client. This way, you can set the response status for any portal request, not only resource request.
HttpServletResponse httpServletResponse = PortalUtil.getHttpServletResponse(portletResponse);
httpServletResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
However, such practice is strongly discouraged as well explained in Olaf Kock's answer. See it to get the bigger picture.
In addition to Tomas Pinos' answer (please accept his answer): Note that a portlet is never delivered directly by an HttpServletRequest - it's embedded in a page which is generated by the portal. Thus the HTTP response codes don't have any meaning (for portlets) in the portal world: The page might still be there, just contain or not contain the portlet in question - it's the business of the portal to show whatever it likes then.
The only exception to this rule is what Tomas describes correctly: When handling a resource request, you're serving exclusive content - thus you have the option to do more to the request than just piping HTML that would otherwise be embedded in a page generated by someone else (the portal, together with other unknown portlets)

Writing plain HTML in a JSF based web application

I have this use case in a JSF application.
Supposed in a JSF web application, I have a button that calls an external service that returns a complete HTML response then how can I show that HTML response to my users browsers?
The sequence of events are like this.
In user browser, my application is displayed. A button is there that user can click.
Clicking the button will call an external service. The external service will return information about a certain HTML tags. The HTML is complete with both head/body and with javascript. Currently the service can be implemented thru REST service or a plain DB call then
How can I display that HTML tag in my user browser?
Is this possible to write non-JSF output in a JSF web application?
Just to add, I think my problem is how to write an HTML in my backing bean and write it back to the users browser.
Just write it outright to the HTTP response body whereafter you instruct JSF that the response is manually completed. The principle is not much different from How to provide a file download from a JSF backing bean?, except that you need to set content disposition to inline (which is already the default anyway).
public void writeHtmlResponse() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.setResponseContentType("text/html;charset=UTF-8");
ec.setResponseCharacterEncoding("UTF-8");
ec.getResponseOutputStream().write(html.getBytes("UTF-8"));
fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}

Resources