jsf2 spring webflow transition exception handling does not work with exceptions during render phase - spring-mvc

I am not sure either I missed a point in the concept of exception handling in webflow, or this is a bug.
I hope someone can help me to understand it, or I will file a bug in webflow/spring mvc.
Following situation.
JSF2 (2.1.X) with webflow 2.4.0 and spring faces (2.4.0)
A RuntimeException is thrown during render phase. Not nice, but can happen.
Exceptionhandling kicks in, a it tries a make a new tansition to an error site. Works like expected.
ErrorState is resolved, it tries to make a transition to it. Everything is ok so far. Now here is the problem. The transition will never be executed.
org.springframework.webflow.engine.ViewState
protected void doEnter(RequestControlContext context) throws FlowExecutionException {
context.assignFlowExecutionKey();
ExternalContext externalContext = context.getExternalContext();
if (externalContext.isResponseComplete()) {
if (!externalContext.isResponseCompleteFlowExecutionRedirect()) {
clearFlash(context);
}
} else {
if (shouldRedirect(context)) {
context.getExternalContext().requestFlowExecutionRedirect();
if (popup) {
context.getExternalContext().requestRedirectInPopup();
}
} else {
View view = viewFactory.getView(context);
context.setCurrentView(view);
render(context, view);
}
}
}
Transition will only be done if the response is not already completed.
This will never happen for any exception in the render phase, because in
org.springframework.faces.mvc.JsfView in the finally block there will be always a responseComplete.
/**
* Performs the standard duties of the JSF RENDER_RESPONSE phase.
*/
public void render() throws IOException {
FacesContext facesContext = FlowFacesContext.getCurrentInstance();
if (facesContext.getResponseComplete()) {
return;
}
facesContext.setViewRoot(this.viewRoot);
try {
logger.debug("Asking faces lifecycle to render");
this.facesLifecycle.render(facesContext);
} finally {
logger.debug("View rendering complete");
facesContext.responseComplete();
}
}
For me it looks like a bug. How is the webflow exceptionhandling to work with exceptions in the renderphase?
There is no way to change the responseComplete-Flag, in org.springframework.webflow.context.servlet.ServletExternalContext
It is a private field with only the possibility to set it to true via
public void recordResponseComplete() {
responseComplete = true;
}
I changed in the debugger-session the flag to false. Then everything works like expected, and the user sees can see the error page.

Related

Unable to Set Cookie in ASP.NET MVC IExceptionFilter

I've implemented a custom IExceptionFilter to handle an exception some users are experiencing with a third party library our application is consuming. When this particular error state occurs, I need to modify the user's cookies (to clear their session state), but what I am finding is that no cookies seem to make it out of the filter. Not sure what's wrong or even how to debug it.
I've modified the functional bits filter to simplify the intent, but here's the gist of the filter. I've ensured that it is the first filter to run on the controller and tested removing the HandleErrorAttribute filter as well to no avail. After the below code runs, "somecookie" is never set on the client.
public class HandleSessionErrorAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext == null) throw new ArgumentNullException("filterContext");
var exception = filterContext.Exception as HttpException;
if (exception != null && exception.Message.Equals("The session state information is invalid and might be corrupted."))
{
filterContext.HttpContext.Response.Cookies.Add(new HttpCookie("somecookie")
{
Value = DateTime.Now.ToString(),
Expires = DateTime.Now.AddMinutes(5),
});
}
}
}
Okay, figured it out. Two issues were preventing the logic from succeeding:
The HandleErrorAttribute must run before any attribute which modifies the response. Part of the implementation of HandleErrorAttribute is to Clear() the response.
CustomErrors must be On for this to work
The initialization code which worked:
GlobalFilters.Filters.Add(new HandleErrorAttribute() { Order = 0 });
GlobalFilters.Filters.Add(new HandleSessionErrorAttribute() { Order = 1 });

Windows Form TopMost don't work with BackgroundWorker?

I'm trying to show window when user need to be notify about some work to do. Every think work fine, but i want to show form absolute topmost. I set form property TopMost = true but it does not work, window still show behind other forms.
I figure out that TopMost = true don't work only with BackgroundWorker, when i use Timer class it work fine. I'm wonder why? Anybody can explain me this?
Here is simple example what i want to do.
static void Main(string[] args)
{
try
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync();
Application.Run(new Form());
}
catch (Exception exp)
{
Console.WriteLine(exp);
}
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
System.Threading.Thread.Sleep(1000);
if (NeedNotify())
{
NotifyForm myNotifyForm = new NotifyForm();
myNotifyForm.TopMost = true;
myNotifyForm.ShowDialog(); // NotifyForm still show behind others windows
}
}
}
private static bool NeedNotify()
{
return true;
}
}
Creating the form within the background worker causes the form to be created on a different thread. Instead, create and show the form in your main thread before calling RunWorkerAsync.
Another problem may arise from the fact that you're creating the "notification" before the application's main loop is even started. You may consider reorganizing your code so that the background worker is started from the main form's OnLoad event.

Failing to redirect from JSF phaselistener

My problem is similar to the one here but doesn't involve PrimeFaces in any way. Also, I couldn't find a real solution there.
I'm basically trying to get the phaselistener to redirect to login page in case there is no JSF session (When, for example, session has timed out)
I'm trying to redirect from within a JSF 2 Phaselistener. To sum up, what I'm doing is this:
public void beforePhase(PhaseEvent event) {
PhaseId id = event.getPhaseId();
if(id.equals(PhaseId.RESTORE_VIEW)){
FacesContext context = event.getFacesContext();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
if(sessionMap==null || sessionMap.isEmpty()){
// No Session, Redirect to login
try {
context.getExternalContext().redirect("/login");
} catch (Exception e) {
...
}
}
}
}
When the redirect code runs I get this exception:
java.lang.NullPointerException
at org.apache.myfaces.context.servlet.PartialViewContextImpl.getPartialResponseWriter(PartialViewContextImpl.java:301)
at org.apache.myfaces.context.servlet.ServletExternalContextImpl.redirect(ServletExternalContextImpl.java:452)
at com.AuthenticationPhaseListener.userIsNotLogedIn
What could be causing this? Am I doing this wrong?
Thanks!
This seem to be happening during an ajax request. I'm not sure about the exact cause, the stacktrace at least indicates a possible bug in MyFaces implementation.
At least, the overall design approach is poor. This kind of HTTP request/response modifications should preferably not take place in a PhaseListener. There it is not intended for. You want to do this kind of job in a normal servlet Filter instead.
Well I had the same problem like you but I did not solve in in such a complicated way as you are doing.My steps
1) create a class that implements the PhaseListener
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
/**
*
* #author fakumawah #date 09.03.2012
*/
public class LoggedInCheck extends BackingBean implements PhaseListener
{
#Override`enter code here`
public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}
#Override
public void beforePhase(PhaseEvent event)
{
}
#Override
public void afterPhase(PhaseEvent event)
{
FacesContext fc = event.getFacesContext();
boolean loginPage = fc.getViewRoot().getViewId().lastIndexOf("login") > -1 ? true : false;
if (!loginPage && !loggedIn())
{
NavigationHandler nh = fc.getApplication().getNavigationHandler();
nh.handleNavigation(fc, null, "gotologin");
}
}
private boolean loggedIn()
{
return getSessionWrapper().isLoggedInAgain();
}
}
Sorry for the uncommented code but I guess the code is really easy to understand. Most important thing to note is the afterPhase(..) which checks if I am in the logged in or if I have a session already. If I donĀ“t it creates a navigator and navigates me to the login page
2) Your isLoggedInAgain() should look something like this:
/**
* A method to check if Username is already logged in
* #param username
* #return
*/
public boolean isLoggedInAgain()
{
if (session != null) // Check if session is not null
{
if (session.isConnected()) // Check if session is connected
{
return true;
//destroyIfsLibrarySession(); // Session is available -> destroy session
}
else // session is not available
{
logger.log(Level.SEVERE, "Already logged out");
return false;
}
}
return false;
}
Since I am dealing with LibrarySessions from Oracle CMSDK that is why my test for the session looks like this. Most important is to check your session somehow and give out true or false, depending on if session exist or not.
3) Configure the Listener in faces-config.xml
<!-- Phase-Listener to check if user is logged in or not -->
<lifecycle>
<phase-listener>com.mycompany.mypackagename.webapp.LoggedInCheck</phase-listener>
</lifecycle>
4) Lastly define a navigation rule for the "gotologin"
<!-- Navigation Rule for sending user to login page from an expired session -->
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>gotologin</from-outcome>
<to-view-id>/login.em</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
And that is it, whenever you do not have a session on any page and are not on the login page, you will be carried to the login page.
Enjoy

How do i improve the legacy code implementation, Response.Redirect?

Some scenarios to ponder. There is a legacy code which has following implementation Example1 and Example2. If we try to implement MSDN recommendation then the legacy code fails.
Here is a Legacy code example:
Example 1:
void Page_Load() {
.... some code
if(condition) {
/// some condition
} else {
RedirectPage(url);
}
// another code block
// some other conditions.
}
Example 2:
a. File1.ascx
void Page_Load() {
try {
.. some code
base.CheckPreference();
RedirectPage(defaultPage);
}
catch(Exception ex) {
ExceptionHandling.GetErrorMessage(ex);
}
}
b. BaseClass.cs // this is the base class
void CheckPreference() {
try {
if(condition) {
RedirectPage(url1);
} else if(condition2) {
RedirectPage(url2);
} else {
// update session
}
}
catch(Exception ex) {
ExceptionHandling.GetErrorMessage(ex);
throw;
}
}
void RedirectPage(string url) {
Response.Redirect(url);
}
One possible way is to add a boolean field in the class e.g endExecution, set the field to true whenever RedirectPage is called.
We have to update RedirectPage code see code snippet below:
// Updated code - MSDN recommendation.
void RedirectPage(url) {
Response.Redirect(url, false);
this.Context.ApplicationInstance.CompleteRequest();
endExecution = true;
}
Please suggest some other better ways to improve the legacy code implementation.
Probably the most unintuitive thing for folks issuing a redirect is that in our minds we've already returned from the method what we call Respond.Redirect (or whatever the equivilent is in your language/platform of the day. All we've done is call a method.
Bottom line is that you have to stop processing the request to avoid trying to commit to responses for the same request. That would throw an exception on just about any platform I've worked with.
ASP.NET MVC improved this with the ActionResponse so that you are returning from the method (and terminating the remainder of request processing) with code that looks like this:
return Redirect(url);
Bottom line is that you need to get in the habit of returning from your event right after you perform your redirect. Any deviation from that habit needs to be documented in the code why. This will help make the application perform the way you expect.
The approach that you've taken is perfectly reasonable.

SEAM: Component "disinjected" "too soon" in interceptor?

Let's say I have the following interceptor in a SEAM app:
public class MyInterceptor {
#In
private Monitor myMonitor;
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
}
}
}
myMonitor.a() works (so Monitor is correctly injected), myMonitor.b() fails because Monitor is already null. Seam Doc says: "Injected values are disinjected (i.e., set to null) immediately after method completion and outjection."
Is that what is happening? Can I do something to tell SEAM to "not yet" "disinject" the component? I can of course also do something like XContext.get(..), but I'm wondering whether this is a bug or a mistake from my side. thanks!
Try this one instead
Object response = null;
try {
myMonitor.a();
response = ctx.proceed();
} finally {
myMonitor.b();
}
return response;
regards,
Avoid using injection.
Try working around this problem. I see you have some sort of monitoring going on. Look at this interceptor that captures the amount of time a method is executed in Seam components. Try modifying your code to match that.
It works great!
Here is the link
Seam is working as advertised.
You could just ignore the disinjection:
public class MyInterceptor {
private Monitor myMonitor;
#In
private void setMonitor(Monitor aMonitor) {
if (aMonitor != null) {
myMonitor = aMonitor;
}
}
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
myMonitor = null; //perform disinjection yourself
}
}
}
The caveat here is that Seam is disinjecting the reference for a reason. Seam wants to control the lifecycle and identity of "myMonitor" and by keeping a reference to it, you are not abiding by your contract with Seam. This could lead to unexpected behavior.
For instance, if myMonitor were for some reason in the Stateless scope, Seam might destroy it before ctx.proceed() returns, leaving you with a reference to a broken proxy. Best advice is to know the scope and lifecycle of what you are retaining since you are "living on the edge."

Resources