We have a custom JSF2 Exception Handler ...
Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
boolean isUnHandledException = false;
SystemException se = null;
while(i.hasNext()) {
ExceptionQueuedEvent event = (ExceptionQueuedEvent)i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext)event.getSource();
Throwable t = context.getException();
try {
if (apperror)
take to app error page
if (filenotfound)
take to page not found error page
}catch(){
} finally {
i.remove ().....causes problem....in filenot found...
.....
}
The application exception handling works fine ,without any issues.
But the FileNotFound in our custom handler causes the issue. The exception handler catches the FileNotFound ,but while trying to remove the queuedevent i.remove it results in NullPointerException ,if i comment i.remove it works fine...
java.lang.NullPointerException
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:96)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
This isn't entirely the right place to handle a FileNotFoundException coming from Mojarra. There's then no means of a UIViewRoot. Line 96 in RenderResponsePhase tries to do a facesContext.getViewRoot().getViewId(), but that fails then with that NPE.
Better handle it with a servlet filter, or just with an <error-page> if you have a custom 404 error page.
So, either in the filter which is mapped on the FacesServlet:
try {
chain.doFilter(request, response);
}
catch (FileNotFoundException e) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, request.getRequestURI());
}
This will then end up in the server's default HTTP 404 error page, or any custom <error-page> with an <error-code> of 404. OmniFaces has also such a filter.
Or in an <error-page> in web.xml matching <exception-type> of FileNotFoundException.
<error-page>
<exception-type>java.io.FileNotFoundException</exception-type>
<location>/WEB-INF/errorpages/404.xhtml</location>
</error-page>
Related
This is causing me quite a headache. All I find is how to disable the redirect.
I'm trying to do the opposite and can't seem to figure out how!
What I'm trying to achieve is: after a successful logout, redirect the user to another page (be that the login page or a logout success page, whatever).
What happens is: after a successful logout, I stay on the same page, even though I can see the correct response under network the network tab of the developer tools.
Here's what I currently have:
security config:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.anyRequest().authenticated()
.and()
.csrf(c -> c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.oauth2Login()
.loginPage("/login").permitAll()
.and()
.logout()
.logoutSuccessUrl("/logged-out").permitAll()
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
}
controller method:
#GetMapping("logged-out")
public ModelAndView loggedOut(ModelMap model) {
return new ModelAndView("logged-out", model);
}
js script hooked to the button:
let logout = function() {
let request = new XMLHttpRequest();
request.open("POST", "/logout");
request.setRequestHeader("X-XSRF-TOKEN", Cookies.get('XSRF-TOKEN'));
request.setRequestHeader("Accept", "text/html");
request.send();
}
the log events after clicking the button:
DEBUG 15539 --- [nio-8080-exec-9] o.s.web.servlet.DispatcherServlet : GET "/logged-out", parameters={}
DEBUG 15539 --- [nio-8080-exec-9] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.hamargyuri.petprojectjava2021.controller.HomeController#loggedOut(ModelMap)
DEBUG 15539 --- [nio-8080-exec-9] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html]
DEBUG 15539 --- [nio-8080-exec-9] o.s.web.servlet.DispatcherServlet : Completed 200 OK
and here's what I see in the browser
I'm sure there must be some very stupid thing I'm missing here, but I'm at the stage of banging my head to the wall, so I'd appreciate any guidance!
So, it seems like my frontend code was at fault, as it's the one that should do something if the logout call was successful.
I know it's very basic, but this is what I've changed in the js:
let goHome = function() {
window.location.href = "/";
}
let logout = function() {
let request = new XMLHttpRequest();
request.open("POST", "/logout");
request.setRequestHeader("X-XSRF-TOKEN", Cookies.get('XSRF-TOKEN'));
request.onload = goHome;
request.send();
}
I also removed the explicit logoutSuccessUrl, the default is fine, all I need a successful response, then the above function will take me "home".
I have an MVC Web API project that I am working on. I created a controller with an action. I am able to hit the action properly using Postman, but when an external system tries to reach my controller, it gets a 500 error. The owner of the external service cannot give me any details beyond that, they can only retry the request.
Here is one of the log entries of their requests in IIS log
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2017-02-15 20:38:58 192.168.2.34 POST /Route/to/actionName 8002 - 192.168.2.37 Apache-HttpClient/4.5.2+(Java/1.8.0_102) - 500 0 0 146
First I thought may be the action is being hit, so I added an exception handler and added logging.
[Route("actionName")]
[HttpPost]
public IHttpActionResult actionName(MessageModel message)
{
try
{
// code to handle the action
}
catch (Exception e)
{
// Code to log exception in the log file
}
}
Tried above and saw nothing in the log, I have run tests for failed requests to make sure the above exception handler logs and it does.
So the next thing I decided to do was to handle application level errors in Global.asax and log exception there.
protected void Application_Error(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
var request = SomeMethodToReadRequestContentsInString();
var service = new SomeExceptionLoggingService();
var exception = Server.GetLastError();
if (exception == null)
{
exception = new ApplicationException("Unknown error occurred");
}
service.LogException(exception, Request.UserHostAddress, Request.UserAgent, request);
}
}
And to my surprise, nothing in the log file.
So then I decided to log ALL Post requests and see if I register ANYTHING in the log.
protected void Application_EndRequest(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
var request = Helper.ReadStreamUnknownEncoding(Request.InputStream);
var service = new InterfaceTestingService();
var exception = Server.GetLastError();
if (exception == null)
{
exception = new ApplicationException("No Error in this request");
}
service.LogException(exception, Request.UserHostAddress, Request.UserAgent, request);
}
}
And again, nothing!
How do I catch this bug? My goal is to see the Content-Type, and contents.
I tried to add a Custom Field in IIS log settings to include `Content-Type', but the log files still don't have that.
I added a handler for Application_BeginRequest logging everything I did in Application_EndRequest. And it turns out, the content-length was zero, and there was no content. I also restarted IIS Web Server to get it to log custom fields too.
What's strange is that if I send empty content through Postman, I get the action code executed but for some reason when they do it, it doesn't.
I occasionally see the ConcurrentModificationException below in my grails application's log in CI. I think it only happens when the app is under a lot of load (we fire 8 concurrent Geb test shards at the same tomcat instance).
2015-06-14 13:44:16,702 [http-bio-8080-exec-53] ERROR errors.GrailsExceptionResolver - ConcurrentModificationException occurred when processing request: [POST] /myapp/task/getSchedules
Stacktrace follows:
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:394)
at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:413)
at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:412)
at com.myapp.controller.ControllerSearchService.getMostRecentPrefixedParams(ControllerSearchService.groovy:83)
at com.myapp.controller.ControllerSearchService.getMostRecentFilterParams(ControllerSearchService.groovy:65)
at com.myapp.controller.ControllerSearchService.advancedSearch(ControllerSearchService.groovy:239)
at com.myapp.aspect.ServiceMethodTimingAspect.traceServiceMethodCall(ServiceMethodTimingAspect.java:20)
at GrailsMelodyGrailsPlugin$_closure4_closure16_closure17.doCall(GrailsMelodyGrailsPlugin.groovy:184)
at com.myapp.task.TaskController.getSchedules(TaskController.groovy:287)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:150)
at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:285)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:198)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:176)
at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
at com.myapp.organisation.security.RestAuthenticationFilter.doFilter(RestAuthenticationFilter.groovy:160)
at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49)
at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)
at com.odobo.grails.plugin.springsecurity.rest.RestLogoutFilter.doFilter(RestLogoutFilter.groovy:63)
at org.grails.jaxrs.web.JaxrsFilter.doFilterInternal(JaxrsFilter.java:46)
at com.brandseye.cors.CorsFilter.doFilter(CorsFilter.java:82)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
The code in the getMostRecentPrefixedParams method looks like this:
private def getMostRecentPrefixedParams(params, session, prefix, sessionParamName) {
synchronized (params) {
for (String key : params) { // line 83 - exception happens here
if (key.startsWith(prefix)) {
if (session != null) {
clearTags(params)
}
return params
}
}
}
if (session == null) {
return params
}
return session."${sessionParamName}" == null ? params : session."${sessionParamName}"
}
I added the synchronized block in an attempt to stop this from happening, but clearly something else is going on.
The params argument passed into the getMostRecentPrefixedParams method just comes from a controller (the implicit params controller property) - as far as I'm aware, only a single request thread should have access to that map during the entire request/response cycle, but even if that wasn't the case and another thread somehow had access to that map, I would have thought the synchronized block would have prevented the ConcurrentModificationException.
We're using Grails 2.3.7.
How to properly handle a cancelled file download? The file in question is a pretty large zip file that takes a long time to build, so the user has plenty of time to hit the Cancel button on his download dialog window.
When it happens, a nasty Exception occurs (see below), which is expected, since the client broke the pipe. But how to clean it up? Where/What's the proper way to catch the Exception so that the tomcat logs are not littered with them?
Thank you.
The download code itself is pretty standard code from the textbook:
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
def getZipFile(params) {
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setHeader("Content-Disposition", "attachment; filename=\"filename.zip\"");
response.contentType = "application/zip"
def zos = new ZipOutputStream(response.outputStream)
zos = functionThatCreatesTheZipFile(zos, params) // this takes some time
zos.close()
}
Exception:
rfpmgr [2013-05-01 10:14:32.337] ERROR: web.errors.GrailsExceptionResolver IOException occurred when processing request: [GET] /rfpManager/report/downloadZipFile
Stacktrace follows:
java.io.IOException
at java.util.zip.ZipOutputStream.writeBytes(ZipOutputStream.java:617)
at java.util.zip.ZipOutputStream.writeCEN(ZipOutputStream.java:501)
at java.util.zip.ZipOutputStream.finish(ZipOutputStream.java:348)
at java.util.zip.DeflaterOutputStream.close(DeflaterOutputStream.java:238)
at java.util.zip.ZipOutputStream.close(ZipOutputStream.java:360)
at gov.usgs.eventManager.ZipService.getZipFile(ZipService.groovy:32)
at gov.usgs.eventManager.ReportController$_closure18.doCall(ReportController.groovy:738)
at gov.usgs.jdt.josso.spring.JOSSOProcessingFilter.doFilter(JOSSOProcessingFilter.java:144)
at gov.usgs.jdt.josso.agent.GenericServletSSOAgentFilter.doFilter(GenericServletSSOAgentFilter.java:431)
at java.lang.Thread.run(Thread.java:722)
rfpmgr [2013-05-01 10:14:32.354] ERROR: web.errors.GrailsExceptionResolver IllegalStateException occurred when processing request: [GET] /rfpManager/report/downloadZipFile
getOutputStream() has already been called for this response. Stacktrace follows:
org.codehaus.groovy.grails.web.pages.exceptions.GroovyPagesException: Error processing GroovyPageView: getOutputStream() has already been called for this response
at gov.usgs.jdt.josso.spring.JOSSOProcessingFilter.doFilter(JOSSOProcessingFilter.java:144)
at gov.usgs.jdt.josso.agent.GenericServletSSOAgentFilter.doFilter(GenericServletSSOAgentFilter.java:431)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
at gsp_rfpManager_errorserrors_gsp.run(gsp_rfpManager_errorserrors_gsp.groovy:17)
... 3 more
This seems to work just fine:
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import org.apache.catalina.connector.ClientAbortException
def getZipFile(params) {
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setHeader("Content-Disposition", "attachment; filename=\"filename.zip\"");
response.contentType = "application/zip"
try {
def zos = new ZipOutputStream(response.outputStream)
zos = functionThatCreatesTheZipFile(zos, params) // this takes some time
zos.close()
}
catch (ClientAbortException ex) {
println "user aborted download"
}
}
I can see there:
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
This is common for Grails controllers when directly rendering things. Solutions:
render ( file: <InputStream>, contentType: 'image/jpeg')
//or
render ( file: <byte[]>, contentType: 'image/jpeg')
//or
GrailsWebRequest webRequest =
(GrailsWebRequest) RequestContextHolder.currentRequestAttributes()
webRequest.setRenderView(false)
That should help.
On save of the jqgrid, the action catches a constraint violation exception and returns "error". However, the onEditInlineErrorTopics function is not called on the jsp. The exception needs to be translated to a user message saying "Duplicate Records"
The code is as follows:
JSP grid Code
<sjg:grid id="gridtable"
dataType="json"
href="%{remoteurl}"
loadonce="true"
pager="true"
navigator="true"
scroll="true"
navigatorAdd="false"
navigatorEdit="false"
navigatorView="false"
navigatorDelete="true"
navigatorDeleteOptions="{height:220,reloadAfterSubmit:true,url:'%{deleteurl}'}"
gridModel="gridModel"
rowList="10,15,20"
rowNum="15"
navigatorRefresh="false"
navigatorSearch="false"
editurl="%{editurl}"
editinline="true"
navigatorInlineEditButtons="true"
gridview="true"
viewrecords="false"
shrinkToFit="true"
onEditInlineErrorTopics="onediterror">
Tried these tags as well
errorElementId, errorText & onErrorTopics
Action header (annotations)
#ParentPackage(value = "basicstruts2")
#Action(value = "/editDetails",
results = {
#Result(name="success",type="json"),
#Result(name="error",type="json"),
#Result(name="none",type="json"),
#Result(name="input",type="json")
})
Action catch block
catch(Exception e){
addActionError("Duplicate Records. Please enter again.");
return "error";
}
The Json string created is:
{"JSON":"error","field1":"1","field2":3,"oper":"edit","field3":5,"field4":"9","field5":null,"field6":null,"field7":"19","field8":156}
Tried throwing exception in the catch block but it shows the stacktrace in a popup.
Tried the success topic onEditInlineSuccessTopics as mentioned in the showcase here and it works fine.