IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java EE Discussion :

Business methods Transaction Asynchronous


Sujet :

Java EE

  1. #1
    Membre actif
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Septembre 2002
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 74
    Par défaut Business methods Transaction Asynchronous
    Bonjour, je me pose beaucoup de questions autour du terme business methods.
    En effet lors de mes dernières expériences, je constate plusieurs choses qui me laissent perplexe :

    Soit le code suivant simplifié...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    @Stateless
    @LocalBean
    public AClass {
       @EJB
       BClass bclass;
     
       @TransactionAttribute(NOT_SUPPORTED)
       public void aMethod() {
           bMethod();
           cMethod();
           bClass.dMethod();
           bClass.eMethod();
       }
       @TransactionAttribute(REQUIRED_NEW)
       public void bMethod() {
       }
       @Asynchronous
       public void cMethod() {
       }
    }
     
    public BClass {
       @TransactionAttribute(REQUIRED_NEW)
       public void dMethod() {
       }
       @Asynchronous
       public void eMethod() {
       }
    }
    Je constate la chose suivante :
    aMethod comme prévu n'est pas dans une transaction : NOT_SUPPORTED.
    bMethod N'est PAS dans une transaction malgré REQUIRED_NEW
    cMethod N'est PAS Asynchronous malgré Asynchronous
    dMethod est dans une nouvelle transaction quoi qu'il arrive
    eMethod est asynchronous

    Donc si je comprends bien mes lectures et mes constatations : bMethod et cMethod ne sont pas des business method dans ce cas, mais pourrait l’être dans le cas d'un autre appel, les autres oui car elle sont appelées par extérieure de l'EJB.
    Je constate aussi la même chose quand à l'application des Interceptors.

    soit un interceptor :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public AInterceptor {
      @AroundInvoke
      public Object process(InvocationContext ic)  throws Exception {
         return ic.proccess();
      }
    }
    puis sur la class :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    @Interceptors(AInterceptor.class)  
        public class AClass {  ...}
    Seule la methode aMethod (appelé de l'exterieur) sera "décoré" par l'interceptor.

    Déjà à ce stade, je trouve cela bien dommage et surtout pas très clair.

    Maintenant un cas pratique :

    Soit un ejb gérant la persistance d'une Entity
    celui ci permet de persister une entité ou plusieurs entités à la fois comme suit, mais je veux que quoi qui l'arrive chaque persistance soit individuelle. Mais les transactions gérer par le container toujours.

    Naïvement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ...
    @TransactionAttribute(REQUIRED_NEW)
    public void persistOk(MonEntity o) throws NokException(){
    // code de persistence metant en oeuvre plusieurs persitence d'objets
    ... throw new NokException(); // ou pas
    }
     
    @TransactionAttribute(REQUIRED_NEW)
    public void persistNok(MonEntity o) {}
     
    @TransactionAttribute(REQUIRED_NEW)
    public void persistList(Collection<MonEntity> list {
       for(MonEntity  o : list) {
          try {
            persistOk(o); 
          } catch(NokException ne) {
            persistNok(o);
          }
    }
    ...
    on pourrait imaginer que si j'appelle persistList, chaque persistOk et persistNok soit dans leur propre transaction. Il n'en ai rien. seule persistList crée une nouvelle transaction.
    Le code précédent ne marche donc pas.
    En revanche si vous déplacer dans un autre EJB les methodes persistOk et persistNok. tout rentre dans l'ordre.

    Quelque chose m’échappe ? Je réalise une grosse appli, et mes EJBs se compte par dizaines. et certains ont parfois plusieurs dizaines de méthode. Si mes constatation sont justes, il va falloir revoir pas mal de truc.
    Mes EJBs on plutôt tendances à gérer un coté fonctionnel. un EJB pour s'occuper des Users, un, EJB pour les Groups etc... N'est ce pas comme cela qu'il faut faire ???
    J'avoue être très perplexe. J'ai plutôt tendance à essayer de laisser le container gérer le plus de chose. Je sais bien que l'on peut gérer les Transaction en mode BEAN, mais je pense que normalement cela devrait être à utiliser qu'en cas d'impasse avec le container.
    Je lis tout ce qui me tombe sur la main, mais les exemples sont souvent très simplistes.
    Quelqu'un à t'il quelques tuyaux, ouvrages, tutos qui explique les transactions et tout ce qui va autour vraiment en détails ?

    Cordialement

  2. #2
    Membre actif
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Septembre 2002
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 74
    Par défaut Personne ne constate cela ?
    Je remonte le post, je suis étonné que personne n'est son avis la dessus. c'est pourtant primordiale.

  3. #3
    Membre chevronné
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Par défaut
    Citation Envoyé par hhfr Voir le message
    Je remonte le post, je suis étonné que personne n'est son avis la dessus. c'est pourtant primordiale.
    Plein de gens sont, ou reviennent encore de vacances.

    Sinon pour tes questions:
    Citation Envoyé par hhfr Voir le message
    Je constate la chose suivante :
    aMethod comme prévu n'est pas dans une transaction : NOT_SUPPORTED.
    bMethod N'est PAS dans une transaction malgré REQUIRED_NEW
    cMethod N'est PAS Asynchronous malgré Asynchronous
    dMethod est dans une nouvelle transaction quoi qu'il arrive
    eMethod est asynchronous

    Donc si je comprends bien mes lectures et mes constatations : bMethod et cMethod ne sont pas des business method dans ce cas, mais pourrait l’être dans le cas d'un autre appel, les autres oui car elle sont appelées par extérieure de l'EJB.
    Je constate aussi la même chose quand à l'application des Interceptors.

    ...

    Quelque chose m’échappe ?
    La seule chose à savoir pour bien comprendre ce comportement, c'est que le container crée un wrapper (proxy) autour de l'instance de ta classe EJB qui n'est donc pas accessible directement depuis l'extérieur.
    Tous les appels (externes) vers ton ejb sont faits sur cet objet wrapper qui ensuite délègue vers ton instance ejb.
    C'est ce qui permet au container d'intercepter ces appels et d'appliquer les services "cross-cutting" (transactions, interceptors, asynchrone ou autres services AOP) configurés pour l'ejb avant délégation. Tous les containers (ejb, spring...) fonctionnent comme cela.

    Quand tu fais un appel interne (aMethod --> bMethod), le container ne peut pas "voir" ça pour l'intercepter, c'est comme si la méthode bMethod() était déclarée private dans ta classe. L'exécution de bMethod() dans ce cas va se faire dans le contexte de aMethod() et utiliser les attributs de transactions et autres interceptors déclarés pour aMethod().

    En principe c'est rare de faire ce genre d'appels internes, mais si tu veux vraiment faire cet appel de aMethod vers bMethod tout en conservant la sémantique configurée pour bMethod, le mieux à faire c'est d'obtenir une référence vers l'objet wrapper (getBusinessObjet ou getEJBLocalObjet) du bean courant et de faire ensuite l'appel:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    @Stateless
    @LocalBean
    public AClass {
       @EJB
       BClass bclass;
    
       private @Resource SessionContext ctx;
     
       @TransactionAttribute(NOT_SUPPORTED)
       public void aMethod() {
           ctx.getBusinessObject(AClass .class).bMethod();
           ....
       }
    
       @TransactionAttribute(REQUIRED_NEW)
       public void bMethod() {
       }
    
       @Asynchronous
       public void cMethod() {
       }
    }
     
    public BClass {
       @TransactionAttribute(REQUIRED_NEW)
       public void dMethod() {
       }
       @Asynchronous
       public void eMethod() {
       }
    }
    C'est à tester, mais je crois que ça devrait faire l'affaire.

    Bon courage.

  4. #4
    Membre actif
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Septembre 2002
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 74
    Par défaut Interessant
    Intéressant, je vais tester ça. Malgré mes constatations et mes modifications en conséquences, je ne trouvais pas cela très clair ou logique.

    Par contre, tu dis que c'est plutôt rare comme appel, mais, on n’arrête pas de faire des appels de méthodes au sein d'un même EJB. J'ai rien compris d'après toi ?
    L'exemple de la persistance de X entities via une boucle est pourtant pas si rare. Si ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @TransactionAttribute(REQUIRED_NEW)
    public void persistSingle(MonEntity o) throws NokException(){
    ... throw new NokException(); // ou pas
    }
     
    public void persistList(Collection<MonEntity> list {
       for(MonEntity  o : list) {
          try {
            persistSingle(o); 
          } catch(NokException ne) {
            log.error(...);
          }
    }
    Ceci n'est pas un mauvais pattern avec JPA ? Si ?

    En tous cas, ton explication du proxy est intéressante. Ceci dit, la modification à chaud du code aurait été aussi une solution non ? Cela aurait aussi été envisageable et avec une couverture plus large.

    Sinon, au niveau perf, cela n'aura pas d'incidence de faire appel à la business méthode ? Comme tu le suggère ?

  5. #5
    Membre actif
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Septembre 2002
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 74
    Par défaut ca marche
    Effectivement cela marche.

    J'ai pensé aussi à un autre exemple ou cette histoire de proxy n'est pas top, quand tu utilises un interceptor pour logger/bencher par exemple, seule les méthodes business sont "décorées".

    Mais bon, ta solution est quand même plus élégante que de systématiquement découper les ejbs en x morceaux pour profiter des fonctions du container.

    Merci en tous cas.

  6. #6
    Membre actif
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Septembre 2002
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 74
    Par défaut Petite deception
    Après avoir testé cela chez moi et constaté le fonctionnement, teste grandeur réelle sur le projet sur lequel je travaille. Et là surprise, cela ne marche plus.
    la récupération du businessObject via :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ctx.getBusinessObject(AClass.class);
    retourne tout simplement null.

    Différence entre chez moi et au taf, la différence de version de glassfish. 3.01 au boulot, 3.1 at home.

    La migration vers la 3.1 n'étant pas tout a fait à l'ordre du jours (mais prévu), quelqu'un sait il si cela peut venir de la ?

    Merci

  7. #7
    Membre actif
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Septembre 2002
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 74
    Par défaut toujours sur la même histoire
    Encore quelques doutes.

    J'utilise cette fois le pattern et l'EJB Singleton

    Prenons l'exemple suivant un singleton qui sert de cache à une donné issue d'un calcul savant. (C'est pour illustrer mon problème)
    Si la donné à déjà été calculé, parfait, je la retourne, si elle n'a pas encore était calculé, je la calcul et la stocke dans une Map avant de la retourner.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Singleton
    public class ConstantsManager {
      private Map<String, Long> map = null;
      @PostConstruct
      public void init() {
        map = new HashMap();
      }
      @Lock(LockType.READ)
      public Long getConstant(String key) {
        if(!map.contains(key)) return null;
        return map.get(key);
      }
     
      @Lock(LockType.WRITE)
      public void buildConstant(String key) {
        if(!map.contains(key)) {
          Long result = buildComplex(key); // methode complexe et longue
          map.push(key, result);
        }
      }
    }
    Le problème ici est évident, il serait dommage que deux processus demande de faire le même calcul couteux.

    Idéalement ici l'accès à la donné en lecture est totalement concurrente.
    annotée Lock(LockType.READ), la méthode getConstant n'est pas exclusive.
    La map quand à elle est threadsafe.
    Pour l’écriture en revanche. C'est plus complexe, même si ici l'approche est simpliste, car plusieurs demandes de calcul pour des clés différentes devraient s'attendre, l'accès à la méthode buildConstant est quand à elle exclusive. Un processus accédant à cette méthode attendrait son tour. C'est ce que l'on veut (à peut prés). Elle illustre bien mon problème.

    Si un autre EJB exécute le code suivant tout va bien.
    C'est l'EJB suivant qui devra être visible par mes autres services qui voudraient accéder aux constantes.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Stateless
    @LocalBean
    public class ConstantServices {
      @EJB
      ConstantsManager contantsManager;
     
      public Long getConstantByKey(String key) {
         Long result = contantsManager.getConstant(key); // accès concurrentiel
         if(result==null) {
           contantsManager.buildConstant(key); // accès bloquant
           result = contantsManager.getConstant(key); // accès concurrentiel
         }
         return result;
      }
    }
    Maintenant, toujours dans l'idée de ne pas coder 150 classes qui ne font pas grand chose, j'aurais été tenté d'écrire le ConstantsManager comme suit.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Singleton
    public class ConstantsManager {
      private Map<String, Long> map = null;
      @PostConstruct
      public void init() {
        map = new HashMap();
      }
      @Lock(LockType.READ)
      public Long getConstant(String key) {
        if(!map.contains(key)) buildConstant(key); // appel interne bloquant ???
        return map.get(key);
      }
     
      @Lock(LockType.WRITE)
      private void buildConstant(String key) {
        if(!map.contains(key)) {
          Long result = buildComplex(key); // methode complexe et longue
          map.push(key, result);
        }
      }
    }
    Il suffirait donc aux services nécessitant une constante de demander directement au singleton.
    hors après mes constations qui m'ont fait ouvrir ce post, je pense que la deuxième solution n'est pas bonne. Car "buildConstant" n'étant pas une méthode business, le container ne peut gérer les annotations appliquées. Est ce vrai aussi dans ce cas ? Quelqu'un peut il me confirmer mes doutes ?

    Au final, je trouve cela très limitatif. surtout que l'appel via la méthode getBusinessMethod ne fonctionne pas tout le temps.
    Je suis très perplexe, si quelqu'un à des idées ou des lectures à me conseiller.
    Merci d'avance.

Discussions similaires

  1. Business Method sous Net 6
    Par abdoinfo dans le forum NetBeans
    Réponses: 0
    Dernier message: 14/02/2011, 09h15
  2. methodes en asynchrones
    Par micka132 dans le forum Silverlight
    Réponses: 4
    Dernier message: 29/06/2010, 11h36
  3. Réponses: 24
    Dernier message: 13/11/2006, 09h00
  4. Réponses: 1
    Dernier message: 12/06/2006, 19h02
  5. [JSP][EJB]usebean --> utilisation d'une business method
    Par Eric Berger dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 23/05/2006, 09h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo