2012-06-06 4 views
2

Я использую JBoss6.1.Final, JSF 2.0 (Mojarra), Weld CDI, MyFaces CODI 1.0.5 (для просмотра-доступа к области видимости)SFSB удаляется

Я использую что-то вроде шлюза Шаблон от Real World Java EE Patterns Rethinking Best Practices (к сожалению, у меня его нет, поэтому я, возможно, что-то прикрутил). В принципе, приложение позволяет пользователю перейти в «режим редактирования» и отредактировать список людей (создавать, редактировать, удалять), поддерживаемые в фонотеке @ViewAccessScoped с расширенным контекстом персистентности, а затем щелкнуть ссылку «сохранить», которая сбрасывается все их изменения в базе данных. Сначала у меня возникла проблема с ViewExpiredExceptions (если браузер простаивал за период ожидания сеанса, а затем выполнялся дальнейший запрос), но я добавил некоторый jQuery, чтобы сделать запрос на получение сервлета, который поддерживает сеанс (10 секунд до таймаута сессии). Кажется, что это работает, но теперь у меня есть другая проблема: бэк-файл также является SFSB, и после некоторого времени простоя он удаляется, в результате чего записывается следующее сообщение об ошибке (и все данные, обработанные ajax, исчезают) при попытке выполнить больше изменений ...

13: 06: 22,063 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] javax.el.ELException: /index.xhtml @ 27,81 rendered = "# {! talkBean. Editmode} ": javax.ejb.NoSuchEJBException: не удалось найти компонент с учетом состояния: 43h1h2f-9c7qkb-h34t0f34-1-h34teo9p-де

Любые идеи о том, как я мог бы предотвратить удаление SFSB или, по крайней мере, справиться с этим более изящно?

Вот моя поддержка боб:

package com.ray.named; 

import java.io.Serializable; 
import java.util.List; 

import javax.annotation.PostConstruct; 
import javax.ejb.EJBTransactionRolledbackException; 
import javax.ejb.Stateful; 
import javax.ejb.TransactionAttribute; 
import javax.inject.Named; 
import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.persistence.PersistenceContextType; 

import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.ViewAccessScoped; 

import com.ray.model.Person; 

@Named 
@Stateful 
@ViewAccessScoped 
@TransactionAttribute(javax.ejb.TransactionAttributeType.NEVER) 
public class ConversationBean implements Serializable { 
    private static final long serialVersionUID = 1L; 
    //properties 
    private List<Person> people; 
    private String name; 
    private Boolean editMode; 

    @PersistenceContext(type=PersistenceContextType.EXTENDED) 
    private EntityManager em; 

    @PostConstruct 
    public void init() { 
    people = em.createNamedQuery("Person.findAll", Person.class).getResultList(); 
    setEditMode(false); 
    } 

    //event listeners 
    public void beginEdits() { 
    setEditMode(true); 
    } 

    public void addPerson() { 
    Person p = new Person(name); 
    em.persist(p); 
    people.add(p); 
    name = null; 
    } 

    public void removePerson(Person p) { 
    people.remove(people.indexOf(p)); 
    em.remove(p); 
    } 

    //this method flushes the persistence context to the database 
    @TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRES_NEW) 
    public void saveEdits() { 
    setEditMode(false); 
    } 

    //getters/setters 
    public List<Person> getPeople() { 
    return people; 
    } 

    public String getName() { 
    return name; 
    } 

    public void setName(String name) { 
    this.name = name; 
    } 

    public Boolean getEditMode() { 
    return editMode; 
    } 

    public void setEditMode(Boolean editMode) { 
    this.editMode = editMode; 
    } 
} 

Вот Person бин сущности:

package com.ray.model; 

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.NamedQueries; 
import javax.persistence.NamedQuery; 
import javax.persistence.Version; 

@Entity 
@NamedQueries({ 
    @NamedQuery(name="Person.findAll", 
       query="SELECT p FROM Person p") 
}) 
public class Person { 
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Integer id; 
    private String name; 
    @Version 
    private int version; 

    public Person() { } 

    public Person(String name) { 
    setName(name); 
    } 

    public boolean equals(Object o) { 
    if (!(o instanceof Person)) { 
     return false; 
    } 
    return id == ((Person)o).id; 
    } 

    //getters/setters 
    public String getName() { 
    return name; 
    } 
    public void setName(String name) { 
    this.name = name; 
    } 

    public Integer getId() { 
    return id; 
    } 

    public int getVersion() { 
    return version; 
    } 

    public void setVersion(int version) { 
    this.version = version; 
    } 
} 

Вот мнение:

<?xml version="1.0" encoding="UTF-8"?> 
<!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:h="http://java.sun.com/jsf/html" 
     xmlns:f="http://java.sun.com/jsf/core" 
     xmlns:ui="http://java.sun.com/jsf/facelets"> 
<h:head> 
    <script src="http://code.jquery.com/jquery-latest.min.js"></script> 
    <script> 
    $(document).ready(function() { 
    setInterval(function() { 
     $.get("#{request.contextPath}/poll"); 
    }, #{(session.maxInactiveInterval - 10) * 1000}); 
    }); 
    </script> 
    <title>Conversation Test</title> 
</h:head> 
<h:body> 
    <h:form> 
    <h:commandLink value="Begin Edits" rendered="#{!conversationBean.editMode}"> 
     <f:ajax render="@form" listener="#{conversationBean.beginEdits}"/> 
    </h:commandLink> 
    <h:commandLink value="Save" rendered="#{conversationBean.editMode}"> 
     <f:ajax render="@form" listener="#{conversationBean.saveEdits}"/> 
    </h:commandLink> 
    <h:dataTable id="peopleTable" value="#{conversationBean.people}" var="person"> 
     <h:column> 
     <f:facet name="header">Name</f:facet> 
     <h:panelGroup> 
      <h:inputText value="#{person.name}" disabled="#{!conversationBean.editMode}"> 
      <f:ajax/> 
      </h:inputText> 
      <h:commandLink value="X" disabled="#{!conversationBean.editMode}"> 
      <f:ajax render="@form" listener="#{conversationBean.removePerson(person)}"/> 
      </h:commandLink> 
     </h:panelGroup> 
     </h:column> 
    </h:dataTable> 
    <h:panelGrid columns="2"> 
     <h:outputLabel for="name">Name:</h:outputLabel> 
     <h:inputText id="name" value="#{conversationBean.name}" disabled="#{!conversationBean.editMode}"/> 
    </h:panelGrid> 
    <h:commandButton value="Add" disabled="#{!conversationBean.editMode}"> 
     <f:ajax execute="@form" render="@form" listener="#{conversationBean.addPerson}"/> 
    </h:commandButton> 
    </h:form> 
</h:body> 
</html> 

Вот сервлет используется для поддержания сеанса в живых (вызванный jQuery ajax получить запрос за 10 секунд до окончания сессии):

package com.ray.web; 

import java.io.IOException; 

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

public class PollServlet extends HttpServlet { 
    private static final long serialVersionUID = 1L; 

    public void init() throws ServletException { 
    } 

    public String getServletInfo() { 
    return null; 
    } 

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { 
    request.getSession(); //Keep session alive 
    } 

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { 
    } 

    public void destroy() { 
    } 
} 

ответ

1

Любые идеи о том, как я мог бы предотвратить удаление SFSB или, по крайней мере, справиться с этим более изящно?

Для дальнейшего исследования я бы рекомендовал смотреть на этапах жизненного цикла крючков EJB для пассивации и добавить вывод отладки там.

Должно ли быть источником проблемы, вы сможете настроить/деактивировать пассивацию, но масштабируемость может возникнуть как проблема.

Честно говоря, этот сценарий для меня довольно необычен. В общем, я ожидал бы, что запросы/беседы/сессии будут работать более или менее в границах по умолчанию. Должны ли вы найти код, который обходит это, может быть, вам лучше с помощью подхода RESTful/stateeless ...?

Пожалуйста, уточните вопрос с дополнительной информацией, если таковой имеется.

+0

Спасибо еще раз января Просто любопытно, видите ли вы что-нибудь недостатки с моим примером кода? Есть ли что-то, что бы вы сделали по-другому? – JasonI

+0

Я добавил аннотированный метод @PrePassivate и мог видеть, что компонент бэканга/сеанса действительно пассивировался. Я экспериментирую с RichFaces a4j: poll с интервалом в 10 секунд меньше, чем session.maxInactiveInterval, и это, похоже, делает трюк. Сеанс остается в живых до тех пор, пока открыто окно браузера. – JasonI

+0

@Jasonl (# 1) Нет, в коде нет ничего плохого. Я не могу выразить себя лучше, как я уже сделал в ответ ... –