2 votes

Suppression du SFSB

J'utilise JBoss6.1.Final, JSF 2.0 (Mojarra), Weld CDI, MyFaces CODI 1.0.5 (pour view-access-scoped).

J'utilise quelque chose comme le modèle de passerelle de Real World Java EE Patterns Repenser les meilleures pratiques (malheureusement, je ne l'ai pas avec moi, donc je peux avoir fait une erreur ici). En gros, l'application permet à un utilisateur de passer en "mode édition" et de modifier une liste de personnes (créer, modifier, supprimer) maintenue dans un bean de soutien @ViewAccessScoped avec un contexte de persistance étendu, puis de cliquer sur un lien de commande "enregistrer" qui efface toutes les modifications dans la base de données. Au début, j'ai eu un problème avec les exceptions ViewExpiredExceptions (si le navigateur était inactif après la période d'expiration de la session et que d'autres requêtes étaient effectuées), mais j'ai ajouté un peu de jQuery pour faire une requête get à une servlet qui maintient la session en vie (appelée 10 secondes avant l'expiration de la session). Cela semble fonctionner mais maintenant j'ai un autre problème, le backing bean est également un SFSB et après un certain temps d'inactivité, il est supprimé, ce qui entraîne l'enregistrement du message d'erreur suivant (et toutes les données rendues par ajax disparaissent) lorsque je tente d'effectuer d'autres modifications ...

13:06:22,063 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] javax.el.ELException : /index.xhtml @27,81 rendered="#{!conversationBean.editMode}" : javax.ejb.NoSuchEJBException : Could not find stateful bean : 43h1h2f-9c7qkb-h34t0f34-1-h34teo9p-de

Avez-vous une idée de la façon dont je pourrais empêcher la suppression de la SFSB ou du moins la gérer de façon plus élégante ?

Voici mon haricot de soutien :

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;
  }
}

Voici le bean d'entité Personne :

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;
  }
}

Voici la vue :

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

Voici une servlet utilisée pour maintenir la session en vie (appelée par la requête jQuery ajax get 10 secondes avant l'expiration de la session) :

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() {
  }
}

1voto

jan groth Points 5071

Avez-vous des idées sur la façon dont je pourrais empêcher la suppression de SFSB ou au moins la gérer ? plus gracieusement ?

Pour aller plus loin, je vous recommande de jeter un coup d'œil aux crochets du cycle de vie des EJB pour les éléments suivants passivation et ajoutez-y une sortie de débogage.

Si c'est la source du problème, vous pourrez configurer/désactiver la passivation, mais l'évolutivité pourrait poser problème.

Honnêtement, ce scénario me semble assez peu fréquent. En général, je m'attends à ce que les demandes, les conversations et les sessions fonctionnent plus ou moins dans les limites par défaut. Si vous vous retrouvez à écrire du code qui contourne cela, est-il possible que vous soyez mieux loti avec une approche RESTful / stateless ?

Veuillez mettre à jour la question avec des informations supplémentaires si elles sont disponibles.

0voto

luigib Points 1

Je suppose que vous avez déjà résolu votre problème. Sinon, cette page du wiki JBoss devrait être utile (également pour les futurs lecteurs...).

https://community.jboss.org/wiki/Ejb3DisableSfsbPassivation

A la vôtre, Luigi

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X