A map of the lands where the Trobadors flourished.
"France 1154-en" by Reigen - Own work.
Licensed under CC BY-SA 4.0 via Wikimedia Commons.
|
Introduction
There are a number ofSystemEvent
s supported by JSF 2.x. A question that comes up frequently is how to implement them. In a number of cases on stackoverflow, it is implemented using a PhaseListener
. I was looking for a way to cleanup the view map, or just get values from it before it was destroyed. I decided that the simplest way to do so was to implement a ViewMapListener
. I also noticed that there were very few posts on how to implement it using the faces-config.xml
so I decided to use that approach since it was instructive and more clear to me.Implementation
The basic implementation requires that you add our listener implementation to thefaces-config.xml
. The example I have here is designed to get called on a PreDestroyViewMapEvent
which is called on a normal navigation. We can force it though by adding a @PreDestroy
annotation to a method to invoke before being destroyed. Inside the method we would need to get the UIViewroot
view map, and call clear()
. This would cause our listener to be invoked too. It would be a good cleanup mechanism for cleaning up resources on session expiration too, but at the moment this does not work on JSF 2.1. The @PreDestroy
is not called on session timeout on JSF 2.1. This is expected to be an enhancement in JSF 2.2+.The code for the project can be downloaded from Bitbuket here: viewmaplistener-example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.bluelotussoftware; | |
import com.sun.faces.application.view.ViewScopeManager; | |
import java.util.Collections; | |
import java.util.Map; | |
import javax.faces.component.TransientStateHelper; | |
import javax.faces.component.UIViewRoot; | |
import javax.faces.context.ExternalContext; | |
import javax.faces.context.FacesContext; | |
import javax.faces.event.AbortProcessingException; | |
import javax.faces.event.PreDestroyViewMapEvent; | |
import javax.faces.event.SystemEvent; | |
import javax.faces.event.ViewMapListener; | |
/** | |
* This class is an implementation of {@link ViewMapListener} which listens for | |
* {@link SystemEvent} on the {@link UIViewRoot}. If the event is a | |
* {@link PreDestroyViewMapEvent}, the listener will clear the session map of | |
* the {@link ViewScopeManager#VIEW_MAP_ID} associated with the current view. | |
* | |
* @author John Yeary <jyeary@bluelotussoftware.com> | |
* @version 1.0 | |
* @see ExternalContext#getSessionMap() | |
* @see ViewScopeManager#ACTIVE_VIEW_MAPS | |
* @see ViewScopeManager#VIEW_MAP_ID | |
* @see TransientStateHelper#getTransient(java.lang.Object) | |
*/ | |
public class ViewMapListenerImpl implements ViewMapListener { | |
/** | |
* {@inheritDoc} | |
*/ | |
@Override | |
public void processEvent(SystemEvent event) throws AbortProcessingException { | |
if (event instanceof PreDestroyViewMapEvent) { | |
PreDestroyViewMapEvent pdvme = (PreDestroyViewMapEvent) event; | |
UIViewRoot root = (UIViewRoot) pdvme.getComponent(); | |
FacesContext fctx = FacesContext.getCurrentInstance(); | |
String key = (String) root.getTransientStateHelper().getTransient(ViewScopeManager.VIEW_MAP_ID); | |
System.out.println("Found " + ViewScopeManager.VIEW_MAP_ID + ": " + key); | |
Map<String, Object> viewMaps = (Map<String, Object>) fctx.getExternalContext().getSessionMap().get(ViewScopeManager.ACTIVE_VIEW_MAPS); | |
Map<String, Object> map = Collections.synchronizedMap(viewMaps); | |
synchronized (map) { | |
System.out.println("Views in session map: " + map.keySet().toString()); | |
map.remove(key); | |
System.out.println("View removed from " + ViewScopeManager.ACTIVE_VIEW_MAPS); | |
System.out.println("The remaining views are: " + map.keySet().toString()); | |
} | |
} | |
} | |
/** | |
* {@inheritDoc} | |
* | |
*/ | |
@Override | |
public boolean isListenerForSource(Object source) { | |
return source instanceof UIViewRoot; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"> | |
<application> | |
<system-event-listener> | |
<system-event-listener-class>com.bluelotussoftware.ViewMapListenerImpl</system-event-listener-class> | |
<system-event-class>javax.faces.event.PreDestroyViewMapEvent</system-event-class> | |
<source-class>javax.faces.component.UIViewRoot</source-class> | |
</system-event-listener> | |
</application> | |
</faces-config> |