I have an init method on my #ViewScoped mananged bean. In the post construct i load data from the db. I have a custom ExceptionHandlerWrapper to catch all excptions and send to an error pages. However when #PostConstuct throws an exception i recieve an IllegalStateException and am not redirected to the error page. I have tried many combinations.....
Ive tried this inside my ExcpetionHandler
externalContext.getRequestMap().put(ERROR_BEAN_ID, ERROR_TEXT);
externalContext.dispatch(ERROR_PAGE);
fc.responseComplete();
This line below is what i originally had. It also doent work
externalContext.getFlash().put(ERROR_BEAN_ID, ERROR_TEXT);
nav.handleNavigation(fc, null, ERROR_PAGE);
fc.renderResponse();
These all cause IllegalStateExceptions. I also called redirect with the same result.
Can you globally catch errors thrown from #PostConstruct?
These all cause IllegalStateExceptions.
With the message "Response already committed", I assume? Well, that's a point of no return. A part of the response has already been sent to the client (the webbrowser). It's not possible to take the already sent bytes back. The server will end up with this exception in the logs and the client will end up with a halfbaked response.
What can you do?
Most straightforward way would be to enlarge the response buffer size to the size of the largest page. For example, 64KB:
<context-param>
<param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
<param-value>65536</param-value>
</context-param>
It defaults to ~2KB depending on the server configuration. You only need to keep in mind that this may be memory hogging when your server has to process relatively a lot of requests/responses. Profile and measure properly.
Another way is to reference the bean before the response is to be rendered/committed so that it's (post)construction is triggered before that point. Perhaps the bean in question is referenced for the first time at the very bottom of the view, long beyond the ~2KB response size border. You could take over the job of #PostConstruct with a <f:event type="preRenderView"> somewhere in the top of the view. E.g.
<f:event type="preRenderView" listener="#{bean.init}" />
with
public void init() {
if (!FacesContext.getCurrentInstance().isPostback()) {
// Do here your original #PostConstruct job.
}
}
Related
I have jetty server, which does some logic, when it is finished, it creates a json string (using jackson) and sends it as a response. If there is an exception during the creation of the json, a JsonProcessingException is thrown. This exception bubbles up to an UncaughtErrorHandler (extends ErrorHandler in Jetty), which logs the exception and returns some failure message and status code 500.
This is just for a backend api.
The endpoint is not idempotent (it is a post endpoint), there are changes to the state of the application (ie database) when endpoint is hit and logic applied.
Now if JsonProcessingException occurs, the user will get failure message and will not know that the process/logic has been done.
How do I handle this?
Here are my thoughts on possible solutions:
Leave existing behaviour, and if user complains then tech support can clarify that the process has gone through. Or error will alert support, and they will check the logs and contact the user to say it has gone through.
Leave the endpoint as idempotent (or similar ie no change in state of the app), so that the user can send the same request (with the same body) and get a response (when it is working ie no JsonProcessingException) which states it has already done it, or cannot do it as it has already done.
Catch the JsonProcessingException when creating the json string, log it with exception message, and create a response without json informing the user that process has been done. Although this means the user will need to handle two different responses, but reduces human interaction in the above (current) solution.
OR convert/wrap it in a runtime exception (or other exception) and throw this in the catch block. But assign a better exception message (ie process was completed). Then in errorHandler, I can display this exception message in the response body, when it finds a specific exception. This way the user will know that the process was complete and not send another resquest. But as above, the user will have to handle to different types of responses.
Do not use Jackson to create the json string, do it manually using String.format() and a json template. This is fine for simple json, but complex json will be a nightmare.
Have some logic which checks if the previous call was done but not confirmed in the response, and then makes a call to the user (via some client ie email/sms) with correct details. Seems a lot of work.
Do you have any other suggestions?
Here is some example code to show where this is happening:
private String createFailedResponseBodyJson(FailedPlaneLandStatus failedPlaneLandStatus) throws JsonProcessingException {
LinkedHashMap<String, String> jsonBody = new LinkedHashMap<>();
jsonBody.put("PlaneId", failedPlaneLandStatus.planeId.value);
jsonBody.put("PlaneStatus", failedPlaneLandStatus.planeStatus.name());
jsonBody.put("AirportStatus", failedPlaneLandStatus.airportStatus.name());
jsonBody.put("LandFailureReason", failedPlaneLandStatus.failureMessage.toString());
return new ObjectMapper().setDefaultPrettyPrinter(new DefaultPrettyPrinter())
.writerWithDefaultPrettyPrinter().writeValueAsString(jsonBody);
}
It is the writeValueAsString() method which throws the JsonProcessingException
I think I am happy with the existing behaviour (First bullet point). But I just want to know if the other solutions (other bullet points) are viable, or if there is another solution?
Thanks
I'm sending a request with form data to ProcessorActionBean for processing. An error occurs, but the ProcessorActionBean does not have a JSP view - it is just for processing form data - so I catch the errors by implementing a ValidationErrorHandler on the ProcessorActionBean, and from within handleValidationErrors(), I redirect it to DisplayerActionBean.
The problem is that the error that caused the method to be run disappears after the redirect. I can put non-error messages in the context, and they'll be shown in the DisplayerActionBean's page, but error messages appear to go to /dev/null.
How do I get the errors to display, too?
The solution turned out to be to:
a) in the handleValidationErrors() method, use a FlashScope to put the validation errors somewhere they'll survive until the next request:
FlashScope scope = FlashScope.getCurrent(getRequest(), true);
scope.put("your_key",listOfValidationErrors);
b) in an Interceptor (I've used a modified ErrorMessageInterceptor), where if you find some errors under your_key, you put them in context's validation errors:
ValidationErrors errors = ctx.getActionBeanContext().getValidationErrors();
errors.add(someError.getFieldName(), someError);
(The salient difference to the ErrorMessageInterceptor is that you put each error you get out of the list (which you put in there in the validation error handler) in the regular validation errors, not global errors. This allows them to retain the field they are related to.)
I am trying to implement a process consisting of several webservice-calls, initiated by a JMS-message read by Spring-integration. Since there are no transactions across these WS-calls, I would like to keep track of how far my process has gone, so that steps that are already carried out are skipped when retrying message processing.
Example steps:
Retrieve A (get A.id)
Create new B for A (using A.id, getting B.id)
Create new C for B (using B.id, getting C.id)
Now, if the first attempt fails in step 3, I already have a created a B, and know it's id. So if I want to retry the message, it will skip the second step, and not leave me with an incomplete B.
So, to the question: Is it possible to decorate a JMS-message read by Spring-integration with additional header properties upon message processing failures? If so, how could I do this?
The way it works at the moment:
Message is read
Some exception is thrown
Message processing halts, and ActiveMQ places the message on DLQ
How I would like it to work:
Message is read
Some exception is thrown
The exception is handled, with the result of this handling being an extra header property added to the original message
ActiveMQ places the message on DLQ
One thing that might achieve this is the following:
Read the message
Start processing, wrapped in try-catch
On exception, get the extra information from the exception, create a new message based on the original one, add extra info to header and send it directly to the DLQ
Swallow the exception so the original message dissappears
This feels kinda hackish though, hopefully there is a more elegant solution.
It's hard to generalize without more information about your flow(s) but you could consider adding a custom request handler advice to decorate and/or re-route failed messages. See Adding Behavior to Endpoints.
As the other answer says, you can't modify the message but you can build a new one from it.
EDIT:
So, to the question: Is it possible to decorate a JMS-message read by Spring-integration with additional header properties upon message processing failures? If so, how could I do this?
Ahhh... now I think I know what you are asking; no, you can't "decorate" the existing message; you can republish it with additional headers instead of throwing an exception.
You can republish in the advice, or in the error flow.
It might seem like a "hack" to you, but the JMS API provides no mechanism to do what you want.
From the spring forum:
To place new header to the MessageHeaders you should use
MessageBuilder, because not only headers, but entire Message is
immutable.
return MessageBuilder.fromMessage(message).setHeader(updateflag, message.getHeaders().get("Lgg_Rid") == "ACK" ? "CONF" : "FAIL").build();
In an asynchronous context, errors will go to an error channel - either one you configure yourself and indicate in the message headers with errorChannel, or a global error channel if none is specified. See for more details here.
I've already looked for the answer for this question, and I've found the following suggestions:
If you are always expecting to find a value then throw the exception if it is missing. The exception would mean that there was a problem. If the value can be missing or present and both are valid for the application logic then return a null.
Only throw an exception if it is truly an error. If it is expected behavior for the object to not exist, return the null.
But how should I interpret them in my (so casual) case:
My web app controller is receiving request to show details for a user with a certain id. Controller asks the service layer to get the user, and then the service returns the object, if it's found. If not, a redirect to 'default' location is issued.
What should I do when someone passes invalid user id inside the request URL? Should I consider it as "expected behaviour" and return null to the controller, or perhaps should I call it a "problem or unexpected behaviour" and thus throw an exception inside the service method and catch in inside the controller?
Technically it's not a big difference after all, but I'd like to do it the right way by following standard convetions. Thanks in advance for any suggestions.
EDIT:
I assume, that the URLs generated by the app are valid and existing - when clicked by user, the user with a certaing id should be found. I want to know how to handle a situation, when user tries to access URL with wrong (not existing) user id, by manually typing the URL into browser's address bar.
If I understand you correctly, the request containing the user ID is coming from a client (out of your control). Applying the rules of thumb you quoted: invalid user input is an entirely expectable case, which would not require an exception, rather handle the null value gracefully by returning an appropriate error message to the client.
(OTOH if the user id in the request were automatically generated by another app / coming from DB etc, an invalid user ID would be unexpected, thus an exception would be appropriate.)
My personal suggestion would be to log the error details (IP address, the invalid user ID) and re-direct the user to an error page which says that some error has occurred and the administrators have been notified. Click on so-n-so link to go back to your home page etc.
Point being, whether you throw exception or return null, just make sure that the outermost filter or handler "logs" the details before the response is returned to the user.
What should I do when someone passes invalid user id inside the request URL?
You have two choices: show the 'default' page you mentioned or return a "Not found" / 404.
Regarding null, it depends. If you consider null unacceptable for a reference, then annotate it with #NotNull and the annotation shall take care of doing the correct thing upon getting a null reference: that is, throwing an (unchecked) exception (of course you need to work with the amazing #NotNull annotation for this to work).
What your do higher up the chain is up to you: to me returning a 404 to someone trying to fake user IDs sounds really close to optimal.
What is the reason for encountering this Exception:
org.apache.commons.fileupload.FileUploadException:
Processing of multipart/form-data request failed. Stream ended unexpectedly
The main reason is that the underlying socket was closed or reset. The most common reason is that the user closed the browser before the file was fully uploaded. Or the Internet was interrupted during the upload. In any case, the server side code should be able to handle this exception gracefully.
Its been about a year since I dealt with that library, but if I remember correctly, if someone tries to upload a file, then changes the browser URL (clicks a link, opens a bookmark, etc) then you could get that exception.
You could possibly get this exception if you're using FileUpload to receive an upload from flash.
At least as of version 8, Flash contains a known bug: The multipart stream it produces is broken, because the final boundary doesn't contain the suffix "--", which ought to indicate, that no more items are following. Consequently, FileUpload waits for the next item (which it doesn't get) and throws an exception.
There is a workaround suggests to use the streaming API and catch the exception.
catch (MalformedStreamException e) {
// Ignore this
}
For more details, please refer to https://commons.apache.org/proper/commons-fileupload/faq.html#missing-boundary-terminator