How to save and get an idea when you need it
My goal is to keep the session size as small as possible. (Why? .. that's another topic). I have a phase listener declared in faces-config.xml
<lifecycle>
<phase-listener>mypackage.listener.PhaseListener</phase-listener>
</lifecycle>
I want to store all other views except the last one (maximum two) in some memcache. Getting the session map:
Map<String, Object> sessionMap = event.getFacesContext().getExternalContext().getSessionMap();
the beforePhase (PhaseEvent) method gives me access to all views. So here I can store all views in memcache and remove them from the session. The question is where in jsf these views, which are still loaded in the browser, are requested so that I can populate that view if needed. Is it even possible? Thank.
source to share
To solve the crux of your question, follow ViewHandler
where you can take control RESTORE_VIEW
and RENDER_RESPONSE
phases / processes. You will save the view during RENDER_RESPONSE
and selectively restore during the phase RESTORE_VIEW
. Your view handler might look something like this:
public class CustomViewHandlerImpl extends ViewHandlerWrapper{
@Inject ViewStore viewStore; //hypothetical storage for the views. Could be anything, like a ConcurrentHashMap
ViewHandler wrapped;
public CustomViewHandlerImpl(ViewHandler toWrap){
this.wrapped = toWrap;
}
public UIViewRoot restoreView(FacesContext context, String viewId) throws IOException{
//this assumes you've previously saved the view, using the viewId
UIViewRoot theView = viewStore.get(viewId);
if(theView == null){
theView = getWrapped().restoreView(context, viewId);
}
return theView;
}
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException{
viewStore.put(viewToRender.getId(),viewToRender);
getWrapped().renderView(context, viewToRender);
}
}
Just connect your custom viewer using
<view-handler>com.you.customs.CustomViewHandlerImpl</view-handler>
Of course, you probably don't want this to appeal to all your views; you can add any conditions to the logic above to implement conditional save and restore.
You should also consider other options. It looks like you are running into problems here. If your true concern is limited to the overhead associated with processing views, you should consider
-
Statuses without statuses , new with JSF-2.2. The stateless view option allows you to exclude specific pages from the JSF prediction persistence engine simply by pointing
transient="true"
tof:view
. Much cleaner than scoldingUIViewRoot
by hand. Caveat here is that the representation without the state can not be supported by the areas that depend on the state of economy, that is@ViewScoped
. In a stateless view, the@ViewScoped
bean will be recreated for every postback. Ajax functionality suffers in this scenario as well, since state persistence is at the heart of ajax operations. -
Selectively set label components as
transient
Transient property is available to everyoneUIComponents
, which means that for each view, you can mark specific components withtransient="true"
, effectively giving you the same benefits as 1), but on a much smaller scale. No Reverse ViewScoped
EDIT . UIViewRoot#getViewId()
Doesn't return the name of the current view for some reason (this might be an error). Alternatively, you can use
ExternalContext extCtxt = FacesContext.getCurrentInstance().getExternalContext();
String viewName = ((HttpServletRequest)extCtxt.getRequest()).getRequestURI(); //use this id as the key to store your views instead
source to share