【问题标题】:JBoss Seam: In ScopeType.PAGE I get: java.lang.IllegalStateException: No conversation context activeJBoss Seam:在 ScopeType.PAGE 中我得到:java.lang.IllegalStateException:没有对话上下文处于活动状态
【发布时间】:2010-03-15 14:02:21
【问题描述】:

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

第一次进入页面时,我在我的 URL 中附加了这个:?conversationId=97。该页面工作正常,当我更改数据表页面时,不会创建任何组件。

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

所以,我有两个问题:

  • 为什么我的 URL 中有这个后缀?为什么开始对话?
  • 为什么会出现异常?该组件的范围为 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>

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

更新二:

堆栈跟踪是here

【问题讨论】:

  • @Markos Fragkakis 你能展示你的Seam组件和你的页面吗?耳朵还是战争?
  • @Arthur Ronald F D Garcia 我添加了代码。请再看一看。
  • 添加你的bean超类的代码(至少是相关部分)
  • @Markos Fragkakis 你最好提供我要求的相关代码:)
  • @Bozho 基于 StackTrace,我认为它与 Ajax4j 有关。看看

标签: java jsf seam


【解决方案1】:

好吧,让我们看看

第一次进入页面时,我在我的 URL 中附加了这个:?conversationId=97

好的。正如 Seam in Action 书中所说

Seam 默认创建一个临时对话来服务当前请求。一个临时对话在 JSF 生命周期的restore view 阶段之后立即被初始化,并在呈现响应之后被销毁阶段。

一两分钟后,在非常随机的时间,我收到一个异常,说没有上下文。

每个对话都可以有自己的超时时间,默认为全局超时设置

/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 会存储一个名为 conversation 的内置对话范围组件。所以在您的托管 bean 中,执行以下操作以了解您是否进行了长时间的对话

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

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

如果您看到 true,则说明您已经开始了长时间的对话。你甚至可以看到你的页面内部

#{conversation.longRunning}

希望对你有用。

【讨论】:

  • 感谢您的回答 (+1)。我还认为 conversationId 表明开始了长时间的对话,尽管我不明白为什么。由于我还没有设法让调试页面显示,我在我的应用程序中包含了工作区切换器,它不显示任何对话。不过,我也会试试这个系统,看看它显示了什么。
  • 我在 Seam - JSF(a4j &Co.) 和这类错误方面的经验是 == 花费更多时间来弄清楚到底发生了什么,而不是在我自己的代码中修复错误。我认为所有这些注释、xml 和 jsf 组件只是隐藏和外化了太多……很高兴我不必再使用这些工具了。
  • @fraido 该错误似乎与 Weblogic 服务器有关。但是学习 基于服务器端的组件模型 像 JSF、Vaadin、Wicket 的关键是理解它的核心概念 以便充分利用它并避免很多头痛。因此,我认为基于服务器端的组件模型可以很好地在 Web 开发中发挥作用。
【解决方案2】:

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

我不知道为什么你的 url 上附加了这个 conversationId 参数。然而,接缝中的所有通信都发生在对话内部。如果它的页面有范围,则对话是临时对话。要将对话提升为长时间运行的对话,您需要开始注释或在 pages.xml 中启动对话。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    • 2021-03-19
    • 2019-09-16
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多