You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Zhong Li <we...@gmail.com> on 2005/10/04 21:39:40 UTC

new thought about saveState

Hi All,

I am trying to find a way to avoid saveState tag on client side, finally I
got an idea, please give me comments regardless my thought wrong or right.
Actually it is way to save server side data/model. We define DataSaveManager
to manage save/remove a data in a session. When code saves data into
session, sametime need set possible pages the data will be used, or create a
data path rules. In phaseListener after RENDER_RESPONSE(6), we check the
data in session, if current viewRoot isn't in possible pages list or data
path rules list, the data will be removed automatically. Of couse, code can
remove any data anytime. If the way works, we may find a way to do it in
config file. We can add possiblePageList in ManageBean defination section
and pageRuleList in Navigation Rules section.

Codes looks like

/**
* @author zli
*
*/
public class MposPhaseListener implements PhaseListener {

/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#afterPhase(
javax.faces.event.PhaseEvent)
*/
public void afterPhase(PhaseEvent arg0) {
//System.out.println("afterPhase:"+arg0.getPhaseId());
String viewId = arg0.getFacesContext().getViewRoot().getViewId();
Map sessionData = DataSaveManager.getSessionDataMap();
Set removeIds = new HashSet();
if( sessionData!=null ){
Iterator itr = sessionData.keySet().iterator();
while( itr.hasNext() ){
String dataId = (String)itr.next();
SaveData saveData = (SaveData)sessionData.get(dataId);
LinkedList possiblePageList = saveData.getPossiblePageList();
//we check if the viewId in possible page
if(possiblePageList!=null && possiblePageList.contains(viewId) ){
//we need keep it;
continue;
}

LinkedList pageRuleList = saveData.getPageRuleList();
if( pageRuleList!=null ){
//we check and consume rules
for( int pi = 0;pi<pageRuleList.size();pi++ ){
//try one rule
LinkedList rulePath = (LinkedList)pageRuleList.get(pi);
if( rulePath.contains(viewId) ){
if( viewId.equals(rulePath.get(0)) ){//cosume it
rulePath.remove(0);//cosumed.
//we need keep it;
continue;
}
}
}
}
//this data is useless, put in removeIds
removeIds.add(dataId);
}
//remove data
itr = removeIds.iterator();
while(itr.hasNext()){
String dataId = (String)itr.next();
sessionData.remove(dataId);
}

}

}

/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#beforePhase(
javax.faces.event.PhaseEvent)
*/
public void beforePhase(PhaseEvent arg0) {
//System.out.println("beforePhase:"+arg0.getPhaseId());
}

/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#getPhaseId()
*/
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
//return PhaseId.ANY_PHASE;
}

}


public class DataSaveManager{
public final static String sessionID="_DATA_SAVE_SESSION_ENTRY";
public static Map getSessionDataMap(){
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext ext = context.getExternalContext();
return (Map)ext.getSessionMap().get(sessionID);
}

/**
*
* @param data
* @param possiblePageList is LinkedList
* @param pageRuleList is LinkedList wrap of LinkedList
*/
public static void saveData(String dataId, Object data, LinkedList
possiblePageList, LinkedList pageRuleList){
getSessionDataMap().put(dataId,new SaveData(dataId,data, possiblePageList,
pageRuleList));
}
public static void removeData(String dataId){
getSessionDataMap().remove(dataId);
}
public static SaveData getSaveData(String dataId){
return (SaveData)getSessionDataMap().get(dataId);
}

}


public class SaveData{
String dataId;
Object data;
LinkedList possiblePageList;
LinkedList pageRuleList;
public SaveData(String dataId, Object data, LinkedList possiblePageList,
LinkedList pageRuleList){
this.dataId = dataId;
this.data = data;
this.possiblePageList = possiblePageList;
this.pageRuleList = pageRuleList;
}
public Object getData(){
return data;
}
public LinkedList getPossiblePageList(){
return possiblePageList;
}
public LinkedList getPageRuleList(){
return pageRuleList;
}
public String getDataId(){
return dataId;
}
}



If this is possible, so we can make it in JSF1.2, it will solve lots
problems.


--
Zhong Li

WebJabber.Net

Re: new thought about saveState

Posted by Zhong Li <we...@gmail.com>.
Hi All,

I did some tests, it works great.

You need added phase-listener in jsf config file.

<lifecycle>
<phase-listener>com.webjabber.net.jsf.datasave
.SaveDataPhaseListener</phase-listener>
</lifecycle>


This is my codes for using it, data saved in the Constructor.
private List unitList;
public UnitList(){
SaveData saveData = DataSaveManager.getSaveData("_UNIT_LIST_DATA");
if( saveData!=null ){
System.out.println("Saved list");
unitList = (List)saveData.getData();
}else{
System.out.println("New list");
unitList = getDataFromDB("UnitList");

LinkedList possiblePageList = new LinkedList();
possiblePageList.add("/unitadmin/unitList..jsp");
possiblePageList.add("/unitadmin/unitEdit.jsp");
DataSaveManager.saveData("_UNIT_LIST_DATA",unitList,possiblePageList,null);
}
}


--
Zhong Li

WebJabber.Net

Files, This mail list doesn't allow attach file, so have to post here
-------------------------------------------
DataSaveManager.java-------------------------------------------------------
/*
* Created on Oct 4, 2005
*
*/
package com.webjabber.net.jsf.datasave;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;


/**
* @author zli
*
*/
public class DataSaveManager {
public final static String sessionID="_DATA_SAVE_SESSION_ENTRY";
public static Map getSessionDataMap(){
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext ext = context.getExternalContext();
Map sessionData = (Map)ext.getSessionMap().get(sessionID);
if( sessionData ==null ){
sessionData = new HashMap();
ext.getSessionMap().put(sessionID,sessionData);
}
return sessionData;
}

/**
*
* @param data
* @param possiblePageList is LinkedList
* @param pageRuleList is LinkedList wrap of LinkedList
*/
public static void saveData(String dataId, Object data, LinkedList
possiblePageList, LinkedList pageRuleList){
getSessionDataMap().put(dataId,new SaveData(dataId,data, possiblePageList,
pageRuleList));
}
public static void removeData(String dataId){
getSessionDataMap().remove(dataId);
}
public static SaveData getSaveData(String dataId){
return (SaveData)getSessionDataMap().get(dataId);
}

}


-------------------------------------------
SaveData.java------------------------------------------------------

/*
* Created on Oct 4, 2005
*
*/
package com.webjabber.net.jsf.datasave;

import java.util.LinkedList;

/**
* @author zli
*
*/
public class SaveData {
String dataId;
Object data;
LinkedList possiblePageList;
LinkedList pageRuleList;
public SaveData(String dataId, Object data, LinkedList possiblePageList,
LinkedList pageRuleList){
this.dataId = dataId;
this.data = data;
this.possiblePageList = possiblePageList;
this.pageRuleList = pageRuleList;
}
public Object getData(){
return data;
}
public LinkedList getPossiblePageList(){
return possiblePageList;
}
public LinkedList getPageRuleList(){
return pageRuleList;
}
public String getDataId(){
return dataId;
}

}

---------------------------------------------
SaveDataPhaseListener.java---------------------------------------------------------
/*
* Created on Oct 4, 2005
*
*/
package com.webjabber.net.jsf.datasave;

import java.util.LinkedList;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;


import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

/**
* @author zli
*
*/
public class SaveDataPhaseListener implements PhaseListener{
/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#afterPhase(
javax.faces.event.PhaseEvent)
*/
public void afterPhase(PhaseEvent arg0) {
System.out.println("afterPhase:"+arg0.getPhaseId());
String viewId = arg0.getFacesContext().getViewRoot().getViewId();
Map sessionData = DataSaveManager.getSessionDataMap();
Set removeIds = new HashSet();
if( sessionData!=null ){
Iterator itr = sessionData.keySet().iterator();
while( itr.hasNext() ){
String dataId = (String)itr.next();
SaveData saveData = (SaveData)sessionData.get(dataId);
LinkedList possiblePageList = saveData.getPossiblePageList();
//we check if the viewId in possible page
if(possiblePageList!=null && possiblePageList.contains(viewId) ){
//we need keep it;
continue;
}

LinkedList pageRuleList = saveData.getPageRuleList();
if( pageRuleList!=null ){
//we check and consume rules
boolean isInRule = false;
for( int pi = 0;pi<pageRuleList.size();pi++ ){//consume all rules
//try one rule
LinkedList rulePath = (LinkedList)pageRuleList.get(pi);
if( rulePath.contains(viewId) ){
if( viewId.equals(rulePath.get(0)) ){//cosume it
rulePath.remove(0);//cosumed.
//we need keep it;
isInRule = true;

}
}
}
if( isInRule )continue;

}
//this data is useless, put in removeIds
removeIds.add(dataId);
}
//remove data
itr = removeIds.iterator();
while(itr.hasNext()){
String dataId = (String)itr.next();
sessionData.remove(dataId);
System.out.println("clean:"+dataId);
}

}

}

/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#beforePhase(
javax.faces.event.PhaseEvent)
*/
public void beforePhase(PhaseEvent arg0) {
//System.out.println("beforePhase:"+arg0.getPhaseId());
}

/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#getPhaseId()
*/
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
//return PhaseId.ANY_PHASE;
}
}

Re: new thought about saveState

Posted by Craig McClanahan <cr...@apache.org>.
On 10/4/05, Werner Punz <we...@gmx.at> wrote:
>
> Good point, to my knowledge, something similar to Shale Dialog was
> supposed
> to make it in. What is the status on this one Craig?


Nothing like this is in JSF 1.2 (there, the primary focus was on the new
unified expression language, plus cleaning up some JSF/JSP interoperability
problems). I wouldn't be surprised to see something in this functionality
area on the table for JSF 2.0, but that won't be for a while yet.

In the mean time, technologies built on top of standards, and which are
portable across implementations, can still be a pretty safe bet. Otherwise,
things like Struts or Spring would have never achieved the popularity they
have.

Werner



Craig

Zhong Li wrote:
> > Ofcouse we can have many ways to deal it. But if it can be written in
> > JSF specification, we don't worry about the Vendor. Myfaces is greate,
> > but in real world, I need to deal with ohter companies and other
> > developers. I need standards.
> >
>
>

Re: new thought about saveState

Posted by Werner Punz <we...@gmx.at>.
Good point, to my knowledge, something similar to Shale Dialog was supposed
to make it in. What is the status on this one Craig?

Werner


Zhong Li wrote:
> Ofcouse we can have many ways to deal it. But if it can be written in
> JSF specification, we don't worry about the Vendor. Myfaces is greate,
> but in real world, I need to deal with ohter companies and other
> developers. I need standards.
> 


Re: new thought about saveState

Posted by Zhong Li <we...@gmail.com>.
Ofcouse we can have many ways to deal it. But if it can be written in JSF
specification, we don't worry about the Vendor. Myfaces is greate, but in
real world, I need to deal with ohter companies and other developers. I need
standards.

On 10/4/05, Werner Punz <we...@gmx.at> wrote:
>
> Zhong Li wrote:
> > Hi All,
> >
> > I am trying to find a way to avoid saveState tag on client side, finally
> > I got an idea, please give me comments regardless my thought wrong or
> > right. Actually it is way to save server side data/model. We define
> > DataSaveManager to manage save/remove a data in a session. When code
> > saves data into session, sametime need set possible pages the data will
> > be used, or create a data path rules. In phaseListener after
> > RENDER_RESPONSE(6), we check the data in session, if current viewRoot
> > isn't in possible pages list or data path rules list, the data will be
> > removed automatically. Of couse, code can remove any data anytime. If
> > the way works, we may find a way to do it in config file. We can add
> > possiblePageList in ManageBean defination section and pageRuleList in
> > Navigation Rules section.
>
>
> All I can say is do not spend too much work into this issue,
> others have solved
> the problem for you
> check out Shale Dialog
> and Seam, if you do not like x:saveState.
>
>


--
Zhong Li

WebJabber.Net

Re: new thought about saveState

Posted by Werner Punz <we...@gmx.at>.
Zhong Li wrote:
> Hi All,
> 
> I am trying to find a way to avoid saveState tag on client side, finally
> I got an idea, please give me comments regardless my thought wrong or
> right. Actually it is way to save server side data/model. We define
> DataSaveManager to manage save/remove a data in a session. When code
> saves data into session, sametime need set possible pages the data will
> be used, or create a data path rules. In phaseListener after
> RENDER_RESPONSE(6), we check the data in session, if current viewRoot
> isn't in possible pages list or data path rules list, the data will be
> removed automatically. Of couse, code can remove any data anytime. If
> the way works, we may find a way to do it in config file. We can add
> possiblePageList in ManageBean defination section and pageRuleList in
> Navigation Rules section.


All I can say is do not spend too much work into this issue,
others have solved
the problem for you
check out Shale Dialog
and Seam, if you do not like x:saveState.


Re: new thought about saveState

Posted by Zhong Li <we...@gmail.com>.
Thank you all for comments.

I go deeper for the path, I added DataSaveListener for it, you can use
DataSaveListener to process DataSaveEvent . Also added another Contructor
for SaveData with addtional parameters isLocked and isAutoRemovable.

"isLocked" means pages have to have consume at least one rule in
pageRuleList, example, we have one rules {page1,page2,page3}. if you set
isLocked=true; you have to go through from page1 to page3 all steps. So this
will avoid data cleaned when user open another page unexpected. Also give a
clear path for processing back tracking(I will think about next step).

"isAutoRemovable" means, PhaseListener can't remove it, code has to remove
it, so you can keep data in session as long as you like.


------------- listener interface -----
public interface DataSaveListener extends EventListener, Serializable {
public String getDataId();
public void beforeSave(DataSaveEvent e);
public void afterSave(DataSaveEvent e);
public void beforeRemove(DataSaveEvent e);
public void afterRemove(DataSaveEvent e);
}


public class DataSaveEvent extends EventObject {
private SaveData saveData;

public DataSaveEvent(SaveData saveData){
super(saveData);
if (saveData == null) throw new NullPointerException("saveData");
this.saveData = saveData;
}

/**
* @return Returns the saveData.
*/
public SaveData getSaveData() {
return saveData;
}
}

---------- isRemovable method added in SaveData class-----
public boolean isRemovable(){
if( !isAutoRemovable ) return false;
boolean removable = true;
if( isLocked ){
if( pageRuleList!=null && pageRuleList.size()>0 ){
removable = false;//we check if one of rules all consumed
for( int pi = 0;pi<pageRuleList.size();pi++ ){//consume all rules
LinkedList rulePath = (LinkedList)pageRuleList.get(pi);
if( rulePath.size()==0 ){
removable = true;
break;
}
}

}

}
return removable;
}

--
Zhong Li

WebJabber.Net

Re: new thought about saveState

Posted by Werner Punz <we...@gmx.at>.
I think there might be an ajax way as well...
having the page trigger an identifier ajax
request from time to time
having a certain token on page load.

That way you can track if a double page was opened by
having two ajax requests from the same page,
different tokens.

That even should be integratable cleanly in any jsf version
because the rendering part is not affected by this,
the controller which handles the scopes probably
can be done via a simple servlet.

Probably an interesting idea to add such a mechanism to saveState, which
curently cannot deal with this issue. Some kind of ajaxScope which can deal
with those double page issues by simply not omitting the data until the
last axjaxed saveState on the backend bean has been closed.

This however probably also would mean the entire saveStating mechanism of
x:saveState might have to be rewritten.


Werner



Mike Kienenberger wrote:
> My currently project works best as a pure client-side solution.   For
> that t:saveState is sufficient.
> 
> My last project was a pure server-side struts project, and what worked
> best for it was to create a "page-scoped" state manager.
> 
> As I mentioned earlier, I had it configurable to allow either a
> maximum number of pages, and/or a maximum timeout value for the pages
> in the session scope.   In practice I never really hit these limits
> due to the low-volume nature of the application.
> 
> I don't think it's practical to try to determine when a page-scoped
> item goes out of scope using any other criteria, both due to multiple
> opened windows or backtracking/refreshing.  It's too hard to "know"
> that an end-user won't request the page again.
> 
> Unless, of course, you're just going to disallow all such operations. 
>  (That can be handled as a specific case of the above strategy --
> either set the maximum number of pages in the example above to one or
> set the timeout to immediate).
> 
> This is the same strategy set used by WebObjects, which is where I
> first encountered the idea.
> 
> On 10/4/05, Werner Punz <we...@gmx.at> wrote:
> 
>>Mike Kienenberger wrote:
>>
>>>You'd need to address backtracking and page refreshing issues as well.
>>>
>>
>>Well there is also the problem of having to deal with double opened windows...
>>Which means you run the system into a state where the object
>>has to be garbage collected while the other window still is within
>>the scope, thus you force a garbage collection of the object
>>way to early.
>>(Btw. a problem which also should exist in x:saveState)
>>
>>
>>I had a very similar mechanism in my last Struts based project, because Struts dialogs
>>did not do it for me (I found out it did not garbage collect the scoped objects
>>until the session ran out), using a servlet filter.
>>
>>I gracefully omitted the problem yet, because I could not entirely figure
>>out how to deal with it.
>>
>>What is the general consensous on solving this issue.
>>
>>I really have to look into spring dialog, and seam sources they probably have
>>had solved this issue.
>>
>>
> 
> 


Re: new thought about saveState

Posted by Mike Kienenberger <mk...@gmail.com>.
My currently project works best as a pure client-side solution.   For
that t:saveState is sufficient.

My last project was a pure server-side struts project, and what worked
best for it was to create a "page-scoped" state manager.

As I mentioned earlier, I had it configurable to allow either a
maximum number of pages, and/or a maximum timeout value for the pages
in the session scope.   In practice I never really hit these limits
due to the low-volume nature of the application.

I don't think it's practical to try to determine when a page-scoped
item goes out of scope using any other criteria, both due to multiple
opened windows or backtracking/refreshing.  It's too hard to "know"
that an end-user won't request the page again.

Unless, of course, you're just going to disallow all such operations. 
 (That can be handled as a specific case of the above strategy --
either set the maximum number of pages in the example above to one or
set the timeout to immediate).

This is the same strategy set used by WebObjects, which is where I
first encountered the idea.

On 10/4/05, Werner Punz <we...@gmx.at> wrote:
> Mike Kienenberger wrote:
> > You'd need to address backtracking and page refreshing issues as well.
> >
> Well there is also the problem of having to deal with double opened windows...
> Which means you run the system into a state where the object
> has to be garbage collected while the other window still is within
> the scope, thus you force a garbage collection of the object
> way to early.
> (Btw. a problem which also should exist in x:saveState)
>
>
> I had a very similar mechanism in my last Struts based project, because Struts dialogs
> did not do it for me (I found out it did not garbage collect the scoped objects
> until the session ran out), using a servlet filter.
>
> I gracefully omitted the problem yet, because I could not entirely figure
> out how to deal with it.
>
> What is the general consensous on solving this issue.
>
> I really have to look into spring dialog, and seam sources they probably have
> had solved this issue.
>
>

Re: new thought about saveState

Posted by Werner Punz <we...@gmx.at>.
Mike Kienenberger wrote:
> You'd need to address backtracking and page refreshing issues as well.
> 
Well there is also the problem of having to deal with double opened windows...
Which means you run the system into a state where the object
has to be garbage collected while the other window still is within
the scope, thus you force a garbage collection of the object
way to early.
(Btw. a problem which also should exist in x:saveState)


I had a very similar mechanism in my last Struts based project, because Struts dialogs
did not do it for me (I found out it did not garbage collect the scoped objects
until the session ran out), using a servlet filter.

I gracefully omitted the problem yet, because I could not entirely figure
out how to deal with it.

What is the general consensous on solving this issue.

I really have to look into spring dialog, and seam sources they probably have
had solved this issue.


Re: new thought about saveState

Posted by Mike Kienenberger <mk...@gmail.com>.
Two ways traditionally to handle this are a maximum lifetime interval
(pages expire after a set period of time elapses) and a maximum number
of pages (oldest page expires after a set number of pages are added).

On 10/4/05, Zhong Li <we...@gmail.com> wrote:
> Yeah, it is problem we need deal with. I think "backtracking and page
> refreshing" should in a "safe" scope, I means something like transaction. We
> can't go back forever. We need find a way to define "transaction". It is
> something different with dataSave issue.
>
>
>
> --
> Zhong Li
>
> WebJabber.Net

Re: new thought about saveState

Posted by Zhong Li <we...@gmail.com>.
Yeah, it is problem we need deal with. I think "backtracking and page
refreshing" should in a "safe" scope, I means something like transaction. We
can't go back forever. We need find a way to define "transaction". It is
something different with dataSave issue.



--
Zhong Li

WebJabber.Net

Re: new thought about saveState

Posted by Mike Kienenberger <mk...@gmail.com>.
You'd need to address backtracking and page refreshing issues as well.

On 10/4/05, Zhong Li <we...@gmail.com> wrote:
> Hi All,
>
>  I am trying to find a way to avoid saveState tag on client side, finally I
> got an idea, please give me comments regardless my thought wrong or right.
> Actually it is way to save server side data/model. We define DataSaveManager
> to manage save/remove a data in a session. When code saves data into
> session, sametime need set possible pages the data will be used, or create a
> data path rules. In phaseListener after RENDER_RESPONSE(6), we check the
> data in session, if current viewRoot isn't in possible pages list or data
> path rules list, the data will be removed automatically. Of couse, code can
> remove any data anytime. If the way works, we may find a way to do it in
> config file. We can add possiblePageList in ManageBean defination section
> and pageRuleList in Navigation Rules section.
>
>  Codes looks like
>
>  /**
>   * @author zli
>   *
>  */
>  public class MposPhaseListener implements PhaseListener {
>
>      /* (non-Javadoc)
>       * @see
> javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
>       */
>      public void afterPhase(PhaseEvent arg0) {
>
> //System.out.println("afterPhase:"+arg0.getPhaseId());
>          String viewId = arg0.getFacesContext().getViewRoot().getViewId();
>          Map sessionData =
> DataSaveManager.getSessionDataMap();
>          Set removeIds = new HashSet();
>          if( sessionData!=null ){
>              Iterator itr = sessionData.keySet().iterator();
>              while( itr.hasNext() ){
>                  String dataId = (String)itr.next();
>                  SaveData saveData =
> (SaveData)sessionData.get(dataId);
>                  LinkedList possiblePageList =
> saveData.getPossiblePageList();
>                  //we check if the viewId in possible page
>                  if(possiblePageList!=null &&
> possiblePageList.contains(viewId) ){
>                      //we need keep it;
>                      continue;
>                  }
>
>                  LinkedList pageRuleList =  saveData.getPageRuleList();
>                  if( pageRuleList!=null ){
>                      //we check and consume rules
>                      for( int pi = 0;pi<pageRuleList.size();pi++ ){
>                          //try one rule
>                          LinkedList rulePath =
> (LinkedList)pageRuleList.get(pi);
>                          if( rulePath.contains(viewId) ){
>                              if( viewId.equals(rulePath.get(0)) ){//cosume
> it
>                                  rulePath.remove(0);//cosumed.
>                                  //we need keep it;
>                                  continue;
>                              }
>                          }
>                      }
>                  }
>                  //this data is useless, put in removeIds
>                  removeIds.add(dataId);
>              }
>              //remove data
>              itr = removeIds.iterator();
>              while(itr.hasNext()){
>                  String dataId = (String)itr.next();
>                  sessionData.remove(dataId);
>              }
>
>          }
>
>      }
>
>      /* (non-Javadoc)
>       * @see
> javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
>       */
>      public void beforePhase(PhaseEvent arg0) {
>
> //System.out.println("beforePhase:"+arg0.getPhaseId());
>      }
>
>      /* (non-Javadoc)
>       * @see javax.faces.event.PhaseListener#getPhaseId()
>       */
>      public PhaseId getPhaseId() {
>          return PhaseId.RENDER_RESPONSE;
>          //return PhaseId.ANY_PHASE;
>      }
>
>  }
>
>
>  public class DataSaveManager{
>      public final static String
> sessionID="_DATA_SAVE_SESSION_ENTRY";
>      public static Map getSessionDataMap(){
>          FacesContext context = FacesContext.getCurrentInstance();
>          ExternalContext ext = context.getExternalContext();
>          return (Map)ext.getSessionMap().get(sessionID);
>      }
>
>      /**
>       *
>       * @param data
>       * @param possiblePageList  is LinkedList
>       * @param pageRuleList is LinkedList wrap of LinkedList
>       */
>      public static void saveData(String dataId, Object data, LinkedList
> possiblePageList, LinkedList pageRuleList){
>          getSessionDataMap().put(dataId,new
> SaveData(dataId,data, possiblePageList, pageRuleList));
>      }
>      public static void removeData(String dataId){
>          getSessionDataMap().remove(dataId);
>      }
>      public static SaveData getSaveData(String dataId){
>          return (SaveData)getSessionDataMap().get(dataId);
>      }
>
>  }
>
>
>  public class SaveData{
>      String dataId;
>      Object data;
>      LinkedList possiblePageList;
>      LinkedList pageRuleList;
>      public SaveData(String dataId, Object data, LinkedList
> possiblePageList, LinkedList pageRuleList){
>          this.dataId = dataId;
>          this.data = data;
>          this.possiblePageList = possiblePageList;
>          this.pageRuleList = pageRuleList;
>      }
>      public Object getData(){
>          return data;
>      }
>      public LinkedList getPossiblePageList(){
>          return possiblePageList;
>      }
>      public LinkedList getPageRuleList(){
>          return pageRuleList;
>      }
>      public String getDataId(){
>          return dataId;
>      }
>  }
>
>
>
>  If this is possible, so we can make it in JSF1.2, it will solve lots
> problems.
>
>
> --
> Zhong Li
>
> WebJabber.Net