Hi all,
I have a page-scoped component, which has an instance variable List with data, which I display in a datatable. This datatable has pagination, sorting and filtering.
The first time gate into the page, I get this appended in my URL: ?conversationId=97. The page works correctly, and when I change datatable pages no now component is created.
After a minute or two, and at seamingly random time, I get an exception saying that there is no context. I have not used @Create in my code or my navigation files.
So, I have two questions:
- Why do I get this suffix in my URL? Why did a conversation start?
- Why the exception? The component is scoped to PAGE. If I received an exception, it should not be related to a conversation. Right? Or is the conversation the exception is referring a temporary conversation?
Cheers!
UPDATE I:
The project is an Ear.
This is the page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 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">
<body>
<ui:composition template="/WEB-INF/facelets/templates/template.xhtml">
<ui:define name="content">
<!-- This method returns focus on the filter -->
<script type="text/javascript">
function submitByEnter(event){
if (event.keyCode == 13) {
if (event.preventDefault) {
// Firefox
event.preventDefault();
} else {
// IE
event.returnValue = false;
}
document.getElementById("refreshButton").click();
}
}
</script>
<h:form prependId="false">
<h:commandButton action="Back" value="Back to home page" />
<br />
<p><h:outputText
value="Applicants and Products (experimentation page)"
class="page_title" /></p>
<h:commandButton
action="#{applicantProductListBean.showCreateApplicant}"
value="Create Applicant" id="createApplicantButton">
</h:commandButton>
<a4j:commandButton value="Refresh" id="refreshButton"
action="#{applicantProductListBean.refreshData}"
image="/images/icons/refresh48x48.gif"
reRender="compositeTable, compositeScroller">
<!-- <f:setPropertyActionListener-->
<!-- target="# {pageScrollerBean.applicantProductListPage}" value="1" />-->
</a4j:commandButton>
<rich:toolTip for="createApplicantButton" value="Create Applicant" />
<rich:dataTable styleClass="composite2DataTable" id="compositeTable"
rows="1" columnClasses="col"
value="#{applicantProductListBean.dataModel}" var="pageAppList">
<f:facet name="header">
<rich:columnGroup>
<rich:column colspan="3">
<h:outputText styleClass="headerText" value="Applicants" />
</rich:column>
<rich:column colspan="3">
<h:outputText styleClass="headerText" value="Products" />
</rich:column>
<rich:column breakBefore="true">
<h:outputText styleClass="headerText" value="Applicant Name" />
<a4j:commandButton id="sortingApplicantNameButton"
action="#{applicantProductListBean.toggleSorting('applicantName')}"
image="/images/icons/sorting/#{sortingFilteringBean.applicantProductListSorting.sortingValues['applicantName']}.gif"
reRender="sortingApplicantNameButton, sortingApplicantEmailButton, compositeTable, compositeScroller">
<!-- <f:setPropertyActionListener-->
<!-- target="#{pageScrollerBean.applicantProductListPage}" value="1" />-->
</a4j:commandButton>
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['applicantName']}"
id="applicantNameFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Applicant Email" />
<a4j:commandButton id="sortingApplicantEmailButton"
action="#{applicantProductListBean.toggleSorting('applicantEmail')}"
image="/images/icons/sorting/#{sortingFilteringBean.applicantProductListSorting.sortingValues['applicantEmail']}.gif"
reRender="sortingApplicantNameButton, sortingApplicantEmailButton, compositeTable, compositeScroller">
<!-- <f:setPropertyActionListener-->
<!-- target="#{pageScrollerBean.applicantProductListPage}" value="1" />-->
</a4j:commandButton>
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['applicantEmail']}"
id="applicantEmailFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Applicant Actions" />
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Product Name" />
<a4j:commandButton id="sortingProductNameButton"
action="#{applicantProductListBean.toggleSorting('productName')}"
immediate="true"
image="/images/icons/sorting/#{sortingFilteringBean.applicantProductListSorting.sortingValues['productName']}.gif"
reRender="sortingProductNameButton, compositeTable, compositeScroller">
</a4j:commandButton>
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['productName']}"
id="productNameFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Product Email" />
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['productEmail']}"
id="productEmailFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Product Actions" />
</rich:column>
</rich:columnGroup>
</f:facet>
<rich:subTable rowClasses="odd_applicant_row, even_applicant_row"
value="#{pageAppList}" var="app">
<rich:column
styleClass=" internal_cell
composite2TextContainingColumn"
valign="top">
<h:outputText value="#{app.name}" />
</rich:column>
<rich:column
styleClass="internal_cell composite2TextContainingColumn"
valign="top">
<h:outputText value="#{app.receiptEmail}" />
</rich:column>
<rich:column valign="top" styleClass="buttonsColumn">
<h:commandButton
action="#{applicantProductListBean.showUpdateApplicant(app)}"
image="/images/icons/edit.jpg">
</h:commandButton>
<!-- <rich:toolTip for="editApplicantButton" value="Edit Applicant" />-->
<h:commandButton
action="#{applicantProductListBean.showDeleteApplicant(app)}"
image="/images/icons/delete.png">
</h:commandButton>
<!-- <rich:toolTip for="deleteApplicantButton" value="Delete Applicant" />-->
</rich:column>
<rich:column colspan="3">
<table class="productsTableTable">
<tbody>
<tr>
<td class="createProductButtonTableCell"><h:commandButton
action="#{applicantProductListBean.showCreateProduct(app)}"
value="Create Product">
</h:commandButton>
<!-- <rich:toolTip for="createProductButton" value="Create Product" />-->
</td>
</tr>
<tr>
<td><rich:dataTable value="#{app.products}" var="prod"
rowClasses="odd_product_row, even_product_row">
<rich:column
styleClass="internal_cell composite2TextContainingColumn">
<h:outputText value="#{prod.inventedName}" />
</rich:column>
<rich:column
styleClass="internal_cell composite2TextContainingColumn">
<h:outputText value="#{prod.receiptEmail}" />
</rich:column>
<rich:column styleClass="buttonsColumn">
<h:commandButton
action="#{applicantProductListBean.showUpdateProduct(prod)}"
image="/images/icons/edit.jpg">
</h:commandButton>
<!-- <rich:toolTip for="editProductButton" value="Edit Product" />-->
<h:commandButton
action="#{applicantProductListBean.showDeleteProduct(prod)}"
image="/images/icons/delete.png">
<f:setPropertyActionListener target="#{productBean.product}"
value="#{prod}" />
</h:commandButton>
<!-- <rich:toolTip for="deleteProductButton" value="Delete Product" />-->
</rich:column>
</rich:dataTable></td>
</tr>
</tbody>
</table>
</rich:column>
</rich:subTable>
<f:facet name="footer">
<h:panelGrid columns="1" styleClass="applicantProductListFooter">
<h:outputText value="#{msgs.no_results}" rendered="#{(empty applicantProductListBean.dataModel) || (applicantProductListBean.dataModel.rowCount==0)}"/>
<rich:datascroller align="center" for="compositeTable"
page="#{pageScrollerBean.applicantProductListPage}"
id="compositeScroller" reRender="compositeTable"
renderIfSinglePage="false" fastControls="hide">
<f:facet name="first">
<h:outputText value="#{msgs.first}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="first_disabled">
<h:outputText value="#{msgs.first}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="last">
<h:outputText value="#{msgs.last}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="last_disabled">
<h:outputText value="#{msgs.last}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="next">
<h:outputText value="#{msgs.next}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="next_disabled">
<h:outputText value="#{msgs.next}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="previous">
<h:outputText value="#{msgs.previous}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="previous_disabled">
<h:outputText value="#{msgs.previous}" styleClass="scrollerCell" />
</f:facet>
</rich:datascroller>
</h:panelGrid>
</f:facet>
</rich:dataTable>
</h:form>
</ui:define>
This is the backing bean:
@Name("applicantProductListBean")
@Scope(ScopeType.PAGE)
public class ApplicantProductListBean extends
BasePagedSortableFilterableListBean {
/**
* Public field for ad-hoc injection to work.
*/
@EJB(name = "FacadeService")
public ApplicantFacadeService applicantFacadeService;
@Logger
private static Log logger;
private final int pageSize = 10;
@Out(scope = ScopeType.CONVERSATION, required = false)
Applicant currentApplicant;
@Out(scope = ScopeType.CONVERSATION, required = false)
Product product;
@Create
public void onCreate() {
System.out.println("Create");
}
@Override
protected DataModel initDataModel(int pageSize) {
// get filtering and sorting from session
sorting = getSorting();
filtering = getFiltering();
// System.out.println("Initializing a Composite3DataModel");
// System.out.println("Pagesize: " + pageSize);
// System.out.println("Filtering: " + filtering.getFilteringValues());
// System.out.println("Sorting: " + sorting.getSortingValues());
return new Composite3DataModel(1, sorting, filtering);
}
// Navigation methods
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Create Applicant" button
*
* @return the action to be taken
*/
public Navigation.ApplicantProductList showCreateApplicant() {
return Navigation.ApplicantProductList.SHOW_CREATE_APPLICANT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Edit Applicant" button
*
* @return the action to be taken
*/
public Navigation.ApplicantProductList showUpdateApplicant(
Applicant applicant) {
this.currentApplicant = applicant;
return Navigation.ApplicantProductList.SHOW_UPDATE_APPLICANT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Delete Applicant" button
*
* @return the action to be taken
*/
public Navigation.ApplicantProductList showDeleteApplicant(
Applicant applicant) {
this.currentApplicant = applicant;
return Navigation.ApplicantProductList.SHOW_DELETE_APPLICANT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Create Product" button
*
* @return the action to be taken
*/
public Navigation.ApplicantProductList showCreateProduct(Applicant app) {
this.product = new Product();
this.product.setApplicant(app);
return Navigation.ApplicantProductList.SHOW_CREATE_PRODUCT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Edit Product" button
*
* @return the action to be taken
*/
public Navigation.ApplicantProductList showUpdateProduct(Product prod) {
this.product = prod;
return Navigation.ApplicantProductList.SHOW_UPDATE_PRODUCT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Delete Product" button
*
* @return the action to be taken
*/
public Navigation.ApplicantProductList showDeleteProduct(Product prod) {
this.product = prod;
return Navigation.ApplicantProductList.SHOW_DELETE_PRODUCT;
}
/**
* */
@Override
public Sorting getSorting() {
if (sorting == null) {
return (getSortingFilteringBeanFromSession()
.getApplicantProductListSorting());
}
return sorting;
}
/**
*
*/
@Override
public void setSorting(Sorting sorting) {
getSortingFilteringBeanFromSession().setApplicantProductListSorting(
sorting);
}
/**
*
*/
@Override
public Filtering getFiltering() {
if (filtering == null) {
return (getSortingFilteringBeanFromSession()
.getApplicantProductListFiltering());
}
return filtering;
}
/**
*
*/
@Override
public void setFiltering(Filtering filtering) {
getSortingFilteringBeanFromSession().setApplicantProductListFiltering(
filtering);
}
/**
* @return the currentApplicant
*/
public Applicant getCurrentApplicant() {
return currentApplicant;
}
/**
* @param currentApplicant
* the currentApplicant to set
*/
public void setCurrentApplicant(Applicant applicant) {
this.currentApplicant = applicant;
}
/**
* The model for this page
*
*/
private class Composite3DataModel extends
PagedSortableFilterableDataModel<List<Applicant>> {
public Composite3DataModel(int pageSize, Sorting sorting,
Filtering filtering) {
super(pageSize, sorting, filtering);
}
@Override
protected DataPage<List<Applicant>> fetchPage(int fakeStartRow,
int fakePageSize) {
// if (logger.isTraceEnabled()) {
System.out.println("Getting page with fakeStartRow: " + fakeStartRow
+ " and fakePageSize " + fakePageSize);
// }
// to find the page size multiply the startRow and the fakePageSize
// (which is 1) to the actual page size
int startRow = fakeStartRow
* ApplicantProductListBean.this.pageSize;
int pageSize = fakePageSize
* ApplicantProductListBean.this.pageSize;
// if (logger.isTraceEnabled()) {
System.out.println("Getting page with startRow: " + startRow
+ " and pageSize " + pageSize);
// }
List<Applicant> pageApplicants = applicantFacadeService
.findPagedWithCriteria(startRow, pageSize, filtering,
sorting);
// List<Applicant> pageApplicants = applicantFacadeService
// .findPagedWithDynamicQuery(startRow, pageSize, filtering,
// sorting, true);
// if (logger.isTraceEnabled()) {
System.out.println("Set of applicants: " + pageApplicants.size());
// }
List<List<Applicant>> pageApplicantsListContainer = new ArrayList<List<Applicant>>();
pageApplicantsListContainer.add(pageApplicants);
DataPage<List<Applicant>> dataPage = new DataPage<List<Applicant>>(
this.getRowCount(), fakeStartRow,
pageApplicantsListContainer);
return dataPage;
}
@Override
protected int getDatasetSize() {
// int size = getServiceFacade().countWithCriteria(filtering,
// sorting);
// int size =
// applicantFacadeService.countWithDynamicQuery(filtering, sorting,
// false);
int size = (int) Math.ceil((double) applicantFacadeService
.countWithCriteria(filtering, sorting, false)
/ pageSize);
if (logger.isTraceEnabled()) {
logger.trace("Got Dataset Size: " + size);
}
return size;
}
}
/**
* @return the product
*/
public Product getProduct() {
return product;
}
/**
* @param product
* the product to set
*/
public void setProduct(Product product) {
this.product = product;
}
}
And this is the page file (Notice that as long as I don't leave the page no conversation is created):
<?xml version="1.0" encoding="UTF-8"?>
<page>
<navigation>
<rule if-outcome="Back">
<redirect view-id="/index.xhtml" />
</rule>
<rule if-outcome="SHOW_CREATE_PRODUCT">
<begin-conversation join="true" />
<redirect view-id="/pages/product/createProduct.xhtml" />
</rule>
<rule if-outcome="SHOW_UPDATE_PRODUCT">
<begin-conversation join="true" />
<redirect view-id="/pages/product/editProduct.xhtml" />
</rule>
<rule if-outcome="SHOW_DELETE_PRODUCT">
<begin-conversation join="true" />
<redirect view-id="/pages/product/deleteProduct.xhtml" />
</rule>
<rule if-outcome="SHOW_CREATE_APPLICANT">
<begin-conversation join="true" />
<redirect view-id="/pages/applicant/createApplicant.xhtml" />
</rule>
<rule if-outcome="SHOW_UPDATE_APPLICANT">
<begin-conversation join="true" />
<redirect view-id="/pages/applicant/editApplicant.xhtml" />
</rule>
<rule if-outcome="SHOW_DELETE_APPLICANT">
<begin-conversation join="true" />
<redirect view-id="/pages/applicant/deleteApplicant.xhtml" />
</rule>
</navigation>
</page>
UPDATE II:
the stacktrace is here