JBoss Seam:在ScopeType.PAGE中我得到:java.lang.IllegalStateException:没有激活对话上下文

时间:2010-03-15 14:02:22

标签: java jsf seam

我有一个页面范围的组件,它有一个带有数据的实例变量List,我在数据表中显示。该数据表具有分页,排序和过滤功能。

第一次进入页面时,我会在网址中附加此内容:?conversationId = 97 。页面正常工作,当我更改数据表页面时,现在没有创建组件。

一两分钟后,在随机的随机时间,我得到一个例外,说没有上下文。我没有在我的代码或导航文件中使用@Create。

所以,我有两个问题:

  • 为什么我的URL中会出现此后缀?为什么会话开始?
  • 为什么例外?该组件的范围是PAGE。如果我收到例外,则不应与会话相关。对?或者,例外的对话是指临时对话?

干杯!

更新I:

该项目是一个耳朵。

这是页面:

<!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>

这是支持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;
}
}

这是页面文件(请注意,只要我不离开页面就不会创建对话):

<?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>

更新II:

stacktrace是here

2 个答案:

答案 0 :(得分:4)

好吧,让我们看看

  

第一次进入页面时,我会在网址中附加此内容:?conversationId = 97

确定。如Seam in Action书中所述

  

默认情况下,Seam会创建一个临时对话来为当前请求提供服务。在呈现响应之后,在恢复视图阶段之后紧接着初始化 被销毁相。

  

一两分钟后,在随机的随机时间,我得到一个例外,说没有上下文。

每个会话都有自己的超时期限,默认为全局超时设置

/WEB-INF/components.xml

<core:manager conversation-timeout="1000000"/>

或特定于页面的

<page view-id="/app.xhtml" timeout="1000000"/>

其值以毫秒为单位。但必须超过在web.xml中定义的会话超时

/WEB-INF/web.xml

<!--specified in minutes-->
<session-config>
    <session-timeout>30</session-timeout>
</session-config>

也许它解释了为什么你会得到你的例外。

但是如果你真的想知道你是否有长时间的对话,Seam会存储一个名为对话的内置对话范围组件。所以在您的托管bean 中,执行以下操作以了解您是否有长时间运行的对话

org.jboss.seam.core.Conversation conversation = (Conversation) Component.getInstance("conversation");

System.out.println(conversation.isLongRunning());

如果您看到 true ,那么您已开始长时间对话。您甚至可以在页面内看到

#{conversation.longRunning}

我希望它对你有用。

答案 1 :(得分:0)

尝试制作组件范围的对话而不是页面。听起来你想做的事情比页面范围更大,它只保留一个请求的上下文。

我不确定你为什么把这个conversationId参数附加到你的网址上。然而,接缝中的所有通信都发生在对话中。如果其页面作用域,则会话是临时会话。要将对话提升为长时间运行的对话,您需要开始注释或在pages.xml中启动对话。

我认为seamBooking示例应用程序有一些示例代码应该与您尝试的类似。