Tomcat wirft keine ViewExpiredException

chrisbad

Mitglied
Hallo zusammen,

aktuell nutze ich Primefaces 3.2 und JSF2´, Mojarra in einem Tomcat 7 Container.

Natürlich habe ich auch das alt bekannte Problem, dass AJAX auf einer geöffneten Seite nicht mehr funktioniert sobald die Session abgelaufen ist.

Also habe ich die Anleitung von Ed Burns umgesetzt.

Das Problem: Es wird gar keine Exception geworfen wenn ich z. B. versuche nach einem SessionTimeout einen bereiets geladenen DataTable weiter zu blättern. Folglich kann der Exceptionhandler auch keinen Redirect machen.

Geprüft habe ich das mit diversen Sysouts - Der Handler wird aufgerufen aber der ExceptionStack ist leer .hasNext() = false.

Was mache ich falsch?
 

chrisbad

Mitglied
klaro

meine web.xml

[XML]<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<description>JSF 2.0 - Hello World</description>

<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<session-config>
<session-timeout>1</session-timeout>
</session-config>

<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>

<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>

<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>true</param-value>
</context-param>

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>Server</param-value>
</context-param>

<security-constraint>
<display-name>Admin</display-name>
<web-resource-collection>
<web-resource-name>admin</web-resource-name>
<description/>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>

<security-constraint>
<display-name>Manager</display-name>
<web-resource-collection>
<web-resource-name>/manager/*</web-resource-name>
<description/>
<url-pattern>/manager/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>admin</role-name>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>

<security-constraint>
<display-name>User</display-name>
<web-resource-collection>
<web-resource-name>/user/*</web-resource-name>
<description/>
<url-pattern>/user/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>admin</role-name>
<role-name>manager</role-name>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>

<login-config>
<auth-method>FORM</auth-method>
<realm-name>MemoryRealm</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/login-error.xhtml</form-error-page>
</form-login-config>
</login-config>

<security-role>
<description/>
<role-name>admin</role-name>
</security-role>

<security-role>
<description/>
<role-name>manager</role-name>
</security-role>

<security-role>
<description/>
<role-name>user</role-name>
</security-role>

<listener>
<listener-class>
de.firma.onlineshop.filter.JdbcRegisterListener
</listener-class>
</listener>

</web-app>
[/XML]

faces.config

[XML]<?xml version='1.0' encoding='UTF-8'?>

<!-- =========== FULL CONFIGURATION FILE ================================== -->

<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">

<factory>
<exception-handler-factory>de.firma.onlineshop.filter.ViewExpiredExceptionExceptionHandlerFactory</exception-handler-factory>
</factory>

<!--
<lifecycle>
<phase-listener>de.firma.onlineshop.filter.MyPhaseListener</phase-listener>
</lifecycle>
-->

</faces-config>[/XML]

ExceptionHandlerFactory

Java:
package de.firma.onlineshop.filter;

import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;

public class ViewExpiredExceptionExceptionHandlerFactory extends ExceptionHandlerFactory {

    private ExceptionHandlerFactory parent;

    public ViewExpiredExceptionExceptionHandlerFactory(ExceptionHandlerFactory parent) {
        this.parent = parent;
    }

    @Override
    public ExceptionHandler getExceptionHandler() {
        ExceptionHandler result = parent.getExceptionHandler();
        result = new ViewExpiredExceptionExceptionHandler(result);

        return result;
    }


}

ExceptionHandler

Java:
package de.firma.onlineshop.filter;

import java.util.Iterator;
import java.util.Map;
import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;

public class ViewExpiredExceptionExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    public ViewExpiredExceptionExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return this.wrapped;
    }

    @Override
    public void handle() throws FacesException {
        System.out.println("Listener is called...");

        for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
            Throwable t = context.getException();
            if (t instanceof ViewExpiredException) {
                ViewExpiredException vee = (ViewExpiredException) t;
                FacesContext fc = FacesContext.getCurrentInstance();
                Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
                NavigationHandler nav =
                        fc.getApplication().getNavigationHandler();
                try {
                    // Push some useful stuff to the request scope for
                    // use in the page
                    requestMap.put("currentViewId", vee.getViewId());

                    nav.handleNavigation(fc, null, "viewExpired");
                    fc.renderResponse();

                } finally {
                    i.remove();
                }
            }
        }
        // At this point, the queue will not contain any ViewExpiredEvents.
        // Therefore, let the parent handle them.
        getWrapped().handle();

    }
}

Weder auf der Console, im Log oder im ExceptionStack eine Exception wenn die Session in den TimeOut geht...
 

JimPanse

Bekanntes Mitglied
Hi,

auf anhieb finde ich jetzt nichts außer das der Eintrag fehlt wohin deine App navigieren soll bei dem Kommando 'viewExpired'. Die Frage ist wird die Session jemals erstellt? Ich denke du hast testweise den session timeout auf 1 gestellt. Welche Sicherheitsimpl. verwendest du denn? JAAS? Vielleicht fängt der Filter die Exception vorher ab.

+ du mappst das FacesServlet auf *.xhtml -> besser wäre *.jsf oder /faces/*.

Testweise kannst du noch eine Session listener rauf setzen um zu sehen wann die session genau abläuft.

Java:
@WebListener
public class SessionContextListener implements HttpSessionListener {


	@Override
	public void sessionCreated(HttpSessionEvent arg0) {
		System.out.println("Web-Session created");
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent arg0) {
		System.out.println("Web-Session destroyed");
	}
}

Greetz
 
Zuletzt bearbeitet:

chrisbad

Mitglied
Haha, genau das hab ich jetzt auch probiert bevor ich hier rein geschaut habe ,-)

Funktioniert aber leider nicht (ganz).

Die Lösung des Problems bestand erstmal darin, dass der Tomcat gar keine ViewExpiredException werfen kann, da es sich um Ajax-Requests aus Primefaces handelt. In meinem Szenario war die Lösung die Folgende:

Alles was nicht Ajax ist, kann ich getrost aussen vor lassen, da sich die User bei mir anmelden müssen.
Inhalte von Seiten die loggedout aufgerufen werden können sind egal. In den gesicherten Bereichen wird man bei einem HttpRequest sowieso wieder zur Login-Seite geleitet wenn die Session abgelaufen ist.

Das Problem waren nur die Ajax-Requests. Da bleibt Primefaces dann einfach stehen.
Ich habe probiert @WebListener und @WebFilter. Bei ersterem ist das redirecten sehr schwer, letzteres hört auf zu funktionieren wenn die Session abgelaufen ist.

Die Lösung war ein PhaseListener mit entsprechendem Eintrag in der faces-config-xml.
Zuerst wird überprüft ob es sich um einen Ajax-Request handelt und dann ob die Session noch valid ist.
Falls nicht wird über FacesContext.getCurr[...]redirect("/index.jsf") umgeleitet. Und das funktioniert jetzt wunderbar.
Dadurch kommt auch auf den Seiten auf denen man nicht eingeloggt ist nur ein Redirect zu stande, wenn ein Ajax-Request ausgeführt wird.

Das war's für mich gewesen, danke dir trotzdem...
 

Fant

Bekanntes Mitglied
Die Lösung war ein PhaseListener mit entsprechendem Eintrag in der faces-config-xml.
Zuerst wird überprüft ob es sich um einen Ajax-Request handelt und dann ob die Session noch valid ist.
Falls nicht wird über FacesContext.getCurr[...]redirect("/index.jsf") umgeleitet. Und das funktioniert jetzt wunderbar.
Dadurch kommt auch auf den Seiten auf denen man nicht eingeloggt ist nur ein Redirect zu stande, wenn ein Ajax-Request ausgeführt wird.

Kannst du das vielleicht noch etwas genauer ausführen? Das klingt nämlich genau nach dem, was ich momentan suche ... ich weiß nur trotzdem noch nicht so wirklich, wie ich das nun umzusetzen hätte.

Gruß Fant
 

chrisbad

Mitglied
Java:
public class SessionTimeoutPhaseListener implements PhaseListener {

    @Override
    public void afterPhase(PhaseEvent pe) {
    }

    @Override
    public void beforePhase(PhaseEvent pe) {
        ExternalContext ctx = pe.getFacesContext().getExternalContext();
        HttpServletRequest request = (HttpServletRequest) ctx.getRequest();
        HttpSession session = request.getSession(false);

        if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
            if (!request.isRequestedSessionIdValid() || session == null) {
                try {
                    ctx.redirect(ctx.getRequestContextPath() + "/session-expired.xhtml");
                } catch (IOException ex) {
                    Logger.getLogger(SessionTimeoutPhaseListener.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RENDER_RESPONSE;
    }
}

Soweit bin ich jetzt - der Phaselistener muss in der faces-config.xml konfiguriert werden.
Allerdings funktioniert der jetzt "nicht mehr" (hatte ich aber schon mal) auf der Startseite. In einem gesicherten Bereich funktioniert er super.

Das Problem ist, dass beim ersten Aufruf der App noch keine Session existiert.
if session == null funktioniert dann leider nicht. isRequestedSessionIdValid funktioniert dann natürlich auch nicht. Hier muss ich noch rausfinden welchen Wert die jeweiligen Vars zu den relevanten Zeitpunkten haben.

Ein Filter hat nicht funktioniert, weil der bei mir nicht mehr funktionierte sobald die Session abgelaufen war. Ein Weblistener mit Annotations hat auch nicht mehr funktioniert sobald die Session weg war.

Falls du das Problem mit dem ersten Aufruf gelöst bekommst wäre ich für einen Tip auch dankbar...

de Chris
 

JimPanse

Bekanntes Mitglied
Fast richtig aber

Java:
public class SecurityPhaseListener implements PhaseListener, Serializable {
	@Override
	public void afterPhase(PhaseEvent arg0) {
			final FacesContext facescontext = arg0.getFacesContext();
		
		// not exist yet (non-faces-request) 
		if (facescontext.getViewRoot() == null) {
			facescontext.getApplication().getNavigationHandler().handleNavigation(facescontext, null, "index");
			// ignore other phases
			facescontext.renderResponse();
		} else {

			// current view identifier
			final String viewId = facescontext.getViewRoot().getViewId();

			final boolean loginPage = viewId.lastIndexOf("index") > -1;
//  JAAS
			final boolean login = facescontext.getExternalContext().getRemoteUser() != null;
// or (facescontext.getExternalContext().getSessionMap().get("security-token") != null);
			
			// not login page and user is not login - redirect to login page
			if (!loginPage && !login) {

				facescontext.getApplication().getNavigationHandler().handleNavigation(facescontext, null, "index");
				// ignore other phases
				facescontext.renderResponse();

				// login page and user is login - redirect to start page
			} else if (loginPage && login) {
				facescontext.getApplication().getNavigationHandler().handleNavigation(facescontext, null, "start");
				// ignore other phases
				facescontext.renderResponse();
			}
		}
// go on
	}

	/**
	 * @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
	 */
	@Override
	public void beforePhase(PhaseEvent arg0) {
		// nothing to do -> view will be restore or new created
	}

	/**
	 * @see javax.faces.event.PhaseListener#getPhaseId()
	 */
	@Override
	public PhaseId getPhaseId() {
		// before the view will be created
		return PhaseId.RESTORE_VIEW;
	}

}

faces-config.xml

[XML]
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
Java EE : XML Schemas for Java EE Deployment Descriptors
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
<lifecycle>
<phase-listener>de.my.package.SecurityPhaseListener</phase-listener>
</lifecycle>
<navigation-rule>
<from-view-id>/*</from-view-id>
<navigation-case>
<from-outcome>index</from-outcome>
<to-view-id>/index.xhtml</to-view-id>
<redirect />
</navigation-case>
<navigation-case>
<from-outcome>start</from-outcome>
<to-view-id>/public/start.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
</faces-config>

[/XML]

Grüße
 

chrisbad

Mitglied
Howdy,

sorry war ne Zeit lang geschäftlich unterwegs.

Im Prinzip macht dein Code genau das was er soll, ich war auf einem leicht anderen Weg auch schon soweit, aber das Problem ist, dass das nur funktioniert wenn man in einem gesicherten Bereich unterwegs ist.

Wenn ich die ganz normale Startseite aufrufe, und dort z. B. einen DataTable mit Ajax habe funktioniert der auch nur, so lange die Session existiert. Läuft die Session ab, funktioniert auch der DataTable nicht mehr (z. B. Blättern).

Dafür suche ich eine Lösung, habe aber noch keine gefunden.
Eine Möglichkeit wäre natürlich die Beans RequestScoped zu machen, oder? Aber ich hätte halt schon gerne, das z. B. Filtereinstellungen erhalten bleiben solange die Session läuft.
Die User können bei mir die App teilweise schon benutzen ohne sich anmelden zu müssen, müssten sich alle automatisch anmelden würde deine Lösung super funktionieren...

LG Chris
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
A Beispiel wirft Fehler. JSF 2.0 / Tomcat / Eclipse Web Tier 2
ruutaiokwu Servlet Tomcat Versionsproblem? Web Tier 4
I JSF JSF, Tomcat, Server Faces und maven Web Tier 3
feinperligekohlensaeure JSF JSF + Tomcat 9 | HTTP Status 404 |(com.sun.faces.config.ConfigureListener?) Web Tier 1
R Tomcat - java.lang.OutOfMemoryError: PermGen space Web Tier 0
puba mit JDev entwickelter WS auf Tomcat deployen Web Tier 2
R JSF Tomcat 7 & JSF - UnsupportedOperationException Web Tier 1
G Probleme mit Java + Tomcat | Cannot switch on a value of type String for source level below 1.7 Web Tier 8
S Tomcat 8.0.9 logging Web Tier 0
S Servlet Tomcat 8.0.9 logging Web Tier 13
D JSP Anfängerfrage - Ändern von JSP / Tomcat Web Tier 4
R Tomcat 7 und SSL Web Tier 3
J JSP Web Applikation auf virtuellem Tomcat Server Web Tier 1
T JSF in Eclipse mit Tomcat Web Tier 0
S JSF Tomcat in Eclipse einbinden (JSF) Web Tier 0
G Magnolia CMS - jedes mal Tomcat restart Web Tier 7
A Wartezeit nach Tomcat start wegen Servlets zu hoch Web Tier 2
M tomcat anwendungsabhängige konfigdateien Web Tier 6
H JSP, Eclipse, Tomcat - Java Klasse wird nicht gefunden Web Tier 8
C Tomcat + Eclipselink = NotSerializable Exception? Web Tier 2
M JSP Problem beim deployen auf Tomcat Web Tier 2
A Servlet File Upload funktioniert nur lokal auf Entwicklungsrechner, nicht in Tomcat Web Tier 5
T Tomcat mit Servlets Problem Web Tier 7
B JSF JSF1.1 @Tomcat 5.5 für ein neues Projekt Web Tier 18
P JSF Umgebungsvariablen bei Tomcat-Start setzen Web Tier 4
D Tomcat/Struts2 Benutzer bestimmt Name der URL Web Tier 2
T Tomcat: Packete dynamisch auslesen und Klassen erzeugen Web Tier 3
S Servlet Problem mit Tomcat Web Tier 3
M Classpath für JPA in Tomcat Webapp: Wie konfigurieren? Web Tier 4
reibi Tomcat : Änderbare Config-Files Web Tier 5
reibi Servlet Tomcat : Display name und version setzen Web Tier 3
JCODA Tomcat ohne Fenster starten Web Tier 5
P Eclipse zeigt Errors an, die auf Tomcat nicht auftreten Web Tier 2
B Tomcat 6 ergibt Fehler - java.net.SocketException Web Tier 2
L Services in Tomcat einbinden? Web Tier 2
B JSF Tomcat Windows Linux equals Problem Web Tier 3
N JSP org.apache.tomcat cannot be resolved to a type InstanceManager cannot be resolved to a type Web Tier 4
S Tomcat 7, Struts, JPA baut keine Verbindung auf Web Tier 13
M Geschwindigkeit von Tomcat / JavaWebanwendungen Web Tier 3
D Probleme mit Tomcat Web Tier 3
M Tomcat 6 Umlaut Probleme Web Tier 2
F No Factories configured for this Application - Myfaces mit Tomcat Web Tier 1
T jsf Tobago in Tomcat classpath aufnehmen Web Tier 2
J Tomcat-Server mit JSF auf Eclipse einrichten Web Tier 7
F umzug von tomcat 4 auf tomcat 6 Web Tier 2
J tomcat webapp restarten Web Tier 2
ruutaiokwu tomcat autodeploy Web Tier 7
I Tomcat aktualisiert CSS - Datei nur ab und zu Web Tier 4
T Tomcat-Projektverzeichnis Web Tier 13
E JSF Applikation läuft nicht über Tomcat Web Tier 3
F JApplet in Tomcat-Umgebung funktioniert mal wieder nicht ... Web Tier 8
T Tomcat, JSP, UTF-8 und URL-Codierung Web Tier 4
A Hat Tomcat einen Cache? Web Tier 5
S Tomcat Heap Memory erhoehen..? Web Tier 4
I Rich Faces nur mit JBoss oder auch Tomcat? Web Tier 7
S Tomcat / Eclipse Probleme Web Tier 2
T Tomcat Projekt ohne Eclipse starten Web Tier 11
A Tomcat - JSP läuft nicht Web Tier 2
reibi access.log in Tomcat ... ist das möglich? Web Tier 2
R Fehler 1053 beim Beenden von Tomcat Web Tier 25
A Tomcat - JSP ausführen Web Tier 8
M Tomcat - Mehrere Verzeichnisse für die jsp Web Tier 12
thE_29 Tomcat - Applications(Context) bekommen Web Tier 19
A Tomcat: beim Start des Servers einmalige Aktion aufrufen (Problem gelöst) Web Tier 2
T Hibernate, Debuggingparameter Tomcat Web Tier 3
A JDBC in Tomcat einbinden Web Tier 3
P Tomcat funktioniert nicht so wie er sollte Web Tier 11
C Tomcat total memory Web Tier 11
C Apache-Tomcat Web Tier 13
F ssl, tomcat und jsp anwendungen Web Tier 5
G Tomcat 4.1 Experimente 8) Web Tier 3
S Tomcat JSP context.xml - Standartpfad einstellen Web Tier 3
J Fehler Tomcat/JSP findet Methode nich Web Tier 3
jann Tomcat und Kompression Web Tier 9
Q tomcat konfiguration - rewrite Web Tier 3
A TomCat will nicht - Wieso? Web Tier 5
Q Auth. per Tomcat Web Tier 4
O kurze Frage zur Tomcat Installation Web Tier 2
G Probleme mit Tomcat Web Tier 14
G Tomcat findet angeblich die Datei nicht. Web Tier 8
J Tomcat - web.xml und package . Web Tier 4
L JSP Tomcat Login Web Tier 6
G SCHWERWIEGEND: NullPointerException bei Tomcat Web Tier 4
U Java Application auf Tomcat Web Tier 5
Y JSF - Exception bei Tomcat Start Web Tier 4
O Source-Code vom Tomcat kompilieren lassen Web Tier 6
H Applet wirft AccessControlException bei File von Servlet Web Tier 3
W RichFaces converter in orderingList wirft exception Web Tier 5
R rich:datatabele : kennt Keine events ? Web Tier 1
S JSF CommandButton soll keine Request starten! Web Tier 2
R URL Rewrite hängt keine sessionid an Web Tier 6
V JSF keine Ränder bei PanelGrid Web Tier 5
A Logback erzeugt keine Lockdateien Web Tier 3
S Keine Verbindung zur MySQL-DB Web Tier 4
remus outputText keine 0 anzeigen Web Tier 3
J JSF - CommandButton keine Action Web Tier 14

Ähnliche Java Themen

Neue Themen


Oben