Seam component life cycle
asookazian Jul 9, 2009 8:29 PMSeam 2.0.2
So I have a @DataModel and @Factory method combo to populate a rich:dataTable. I'm noticing that I have to explicitly set the @DataModel List to null in order for the @Factory method to re-fire after I submit the form (and thus @End the conversation).
Even if I use @End(beforeRedirect=true). Why does this happen? I even added a @Destroy method to my JavaBean to see when the Seam container is destroying the instance of the class. So I'd expect that if the LRC is demoted to temp conversation by @End, and then the component is destroyed by the Seam container, then after or upon redirect to the same JSF page, an instance would be re-instantiated by JSF's managed bean facility (or perhaps Seam handles that now?) and the @Factory method would fire.
so what's up here? am I doing anything wrong?
xhtml:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" xmlns:s="http://jboss.com/products/seam/taglib" template="/templates/normal.xhtml"> <ui:define name="body"> <h:form> <rich:dataTable id="table1" value="#{apmdList_main}" var="row"> <rich:column> <f:facet name="header"><h:outputText value="delete"/></f:facet> <h:selectBooleanCheckbox value="false"> <a4j:support event="onclick" action="#{myTest1.deleteRow(apmdList_main.getRowIndex())}"/> </h:selectBooleanCheckbox> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="ID"/></f:facet> <h:outputText value="#{row.applicationMetaDataId}"/> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="BuildNumber"/></f:facet> <h:inputText value="#{row.buildNumber}"/> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="applicationName"/></f:facet> <h:outputText value="#{row.applicationName}"/> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Added By UserID"/></f:facet> <h:outputText value="#{row.addedByUserId}"/> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Added Date"/></f:facet> <h:outputText value="#{row.addedDate}"/> </rich:column> <!-- <rich:column> <f:facet name="header"><h:outputText value="Delete Row"/></f:facet> <h:commandButton value="delete" action="#{myTest1.deleteRow(apmdList_main.getRowIndex())}"/> </rich:column> --> </rich:dataTable> <rich:spacer height="20"/> <h:panelGrid columns="2"> <h:commandButton value="Add" action="#{myTest1.addRow}"/> <h:commandButton value="Save" action="#{myTest1.save}"/> </h:panelGrid> </h:form> <rich:spacer height="20"/> <h:form> <rich:dataTable id="table2" value="#{apmdList_addRow}" var="row" rendered="#{apmdList_addRow.getRowCount() gt 0}"> <rich:column> <f:facet name="header"><h:outputText value="BuildNumber"/></f:facet> <h:inputText value="#{row.buildNumber}"/> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Application Name"/></f:facet> <h:inputText value="#{row.applicationName}"/> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Application Short Name"/></f:facet> <h:inputText value="#{row.applicationShortName}"/> </rich:column> </rich:dataTable> <h:commandButton value="Save" action="#{myTest1.saveAddedRow}" rendered="#{apmdList_addRow.getRowCount() gt 0}"/> </h:form> </ui:define> </ui:composition>
backing bean:
@Name("myTest1") @Scope(ScopeType.CONVERSATION) public class TestApplicationMetaDataAction { @In //inject our Seam-managed Persistence Context (which is conversation-scoped and not tx or component-scoped like EJB3-managed PC) private EntityManager entityManager; @Logger private Log log; @DataModel private List<ApplicationMetaData> apmdList_main; @DataModelSelection("apmdList_main") private ApplicationMetaData selectedApplicationMetaData; @DataModel private List<ApplicationMetaData> apmdList_addRow; private List<Integer> deleteList; /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^BEGIN BUSINESS METHODS^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ public void addRow(){ //showAddRow = true; ApplicationMetaData amd = new ApplicationMetaData(); apmdList_addRow = new ArrayList<ApplicationMetaData>(); apmdList_addRow.add(amd); } @Begin(join=true, flushMode=FlushModeType.MANUAL) @Factory("apmdList_main") public void getDataTable(){ if (apmdList_addRow != null && apmdList_addRow.size() > 0) apmdList_addRow.clear(); apmdList_main = entityManager.createQuery("from ApplicationMetaData").getResultList(); } @End public void save(){ //check deleteList first for removed entities... for (Integer i : deleteList){ ApplicationMetaData amd = apmdList_main.get(i); entityManager.remove(amd); } //persist updates and deletes to db... entityManager.flush(); apmdList_main = null; } @End public void saveAddedRow(){ ApplicationMetaData amd = null; if (apmdList_addRow != null && apmdList_addRow.size() > 0) amd = apmdList_addRow.get(0); amd.setAddedByUserId(0); amd.setUpdatedByUserId(0); amd.setAddedDate(new Date()); amd.setUpdatedDate(new Date()); entityManager.persist(amd); entityManager.flush(); apmdList_main = null; } /*@End public void deleteRow(){ entityManager.remove(selectedApplicationMetaData); //you could flush here if you wanted to, but you should probly prompt user first! //remember that if user has made any changes to the HtmlInputText fields, then those changes will be sync'd with table as well! //when you flush the SMPC, you flush *all* queued changes, whether they're inserts, updates or deletes! entityManager.flush(); apmdList_main = null; }*/ public void deleteRow(Integer row){ if (deleteList == null) deleteList = new ArrayList<Integer>(); deleteList.add(row); } @Destroy public void destroy(){ log.info("myTest1 component destroyed."); } /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^BEGIN GETTER/SETTER METHODS^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ }