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
Well, Let’s see
ok. As said by Seam in Action book
And
Each conversation can have its own Timeout period, which defaults to the global Timeout setting
Or page-specific
Its value is specified in milliseconds. But it must exceed session Timeout defined in web.xml
Maybe it explains why you get your exception.
But if you really want to know whether you have long-running conversation, Seam stores a built-in conversation-scoped component named conversation. So inside your Managed bean, do as follows to know whether you have a long-running conversation
If you see true, someway you have started a long-running conversation. You can even see inside your page
I hope it can be useful to you.