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

JavaFX Discussion :

Méthode invoke (interf. InvocationHandler du proxy dyn.) et opération sur composant GraphiQ JAVAFX


Sujet :

JavaFX

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut Méthode invoke (interf. InvocationHandler du proxy dyn.) et opération sur composant GraphiQ JAVAFX
    Bonjour,

    Excusez moi de vous déranger, je suis un peu perdu. Lorsque je passe par un proxy dynamique pour effectuer une opération (ici il s'agit de faire passer un calque de type StackPane contenant un spinner au dessus d'un AnchorPane), celle-ci n'est effectuée qu'à la fin de la méthode invoke. Il semblerait que cette dernière bloque toute opération graphique. Il y aurait il moyen de retirer ce blocage s'il vous plait ? Vous allez surement me dire que cela ne sert à rien mais c'est un exemple que j'ai créé car présenter l'autre version qui nécessite le passage par un proxy aurait été un peu trop long.

    Ci-dessous le code de la classe Calque :

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
    import javafx.geometry.Insets;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.Background;
    import javafx.scene.layout.BackgroundFill;
    import javafx.scene.layout.CornerRadii;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
     
    public class Calque extends StackPane {
     
    	private String urlImg;
    	private ImageView imgV;
        private Image image;
     
     
    	public Calque(){
    		this.urlImg = "application/spinner.gif";
    		this.initImg();
    		this.setStyle("-fx-min-Width:-infinity;"
    				+ "-fx-min-Height:-infinity;"
    				+ "-fx-max-Width:-infinity;"
    				+ "-fx-pref-Width:1024;"
    				+ "-fx-pref-Height:800;"
    				+ "-fx-opacity:0.8;");
     
    		AnchorPane.setLeftAnchor(this, 0.0); 
    		AnchorPane.setRightAnchor(this, 0.0); 
    		AnchorPane.setBottomAnchor(this, 0.0); 
    		AnchorPane.setTopAnchor(this, 0.0); 
     
     
    		this.backgroundProperty().set(new Background(new BackgroundFill(Color.valueOf("#4B4B4B"), CornerRadii.EMPTY, Insets.EMPTY)));
    		this.setVisible(false);
    		this.toBack();
    	}
     
    	private void initImg() {
            imgV = new ImageView();
            imgV.setFitHeight(320);
            imgV.setFitWidth(320);
            image = new Image(urlImg);
            imgV.setImage(image);
            this.getChildren().add(imgV);
            this.setCache(true);
        }
     
     
    	public void show(){
    		this.toFront();
    		this.setVisible(true);
    	}
     
    	public void hide(){
    		this.toBack();
    		this.setVisible(false);
    	}
     
     
    }
    Le bout de code permettant d'initialiser le proxy. Il est écrit au sein controller.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ProxyTest<ClassePrTest> testProxy = new ProxyTest<ClassePrTest>(obj,cl);
    objInter = (InterfPrTest) Proxy.newProxyInstance(ClassePrTest.class.getClassLoader(), obj.getClass().getInterfaces(), testProxy);
    //...
    objInter.method1() // méthode d'appel lancée lors du clique sur le bouton.
    Et la classe ProxyTest :
    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
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    
    public class ProxyTest<T> implements InvocationHandler {
    
        private T cible;
        private Calque calque;
    
        public ProxyTest(T cible, Calque calque) {
            this.cible = cible;
            this.calque = calque;
        }
    
        @Override
        public Object invoke(Object arg0, Method arg1, Object[] arg2) throws IllegalAccessException,
                IllegalArgumentException, InvocationTargetException, InterruptedException {
            calque.show();
            Thread.sleep(5000);
            Object val = null;
            val = arg1.invoke(cible, arg2);
            this.calque.hide();
            return val;
        }
    
    }
    En gros, il ne se passe rien que ce soit en mode debug ou le temps que le Thread.sleep(5000) soit fini sur l'écran. Je dois attendre que le return val soit fait pour que les opérations de la méthode .show() apparaissent sur l'écran. Sniff.

    Je vous remercie d'avance pour votre aide et vous souhaite une bonne journée.

    Cordialement,

    Vincent

    (des modifications à faire avec Quantumtoolkit ou Toolkit de javafx ou Platform, peut-être une histoire de runlater, suis perdu. Désolé du dérangement)

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Bon j'avoue ne pas avoir tout compris ni le besoin d'utiliser un proxy au lieu d'une interface mais pour ce que j'en pense tu dois sans doute bloquer le JavaFX Application Thread pendant 5 bonnes secondes (il suffit d'imprimer le thread courant juste avant le sleep()) donc vi ça bloque tout et c'est mal.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    En fait, j'ai mis le sleep un peu bêtement sur l'exemple de test et je l'ai remplacé par la suite par une méthode assez longue. En gros, il s'agit de mettre en place l'affichage d'un spinner (pas de progressbar, il a été choisi un fichier animé gif) lors de l'appel de méthodes qui seront assez longues sur des instances de plusieurs classes (elles contiennent pas mal de méthodes). J'ai testé aussi avec aop:around de spring, j'en reviens au même résultat. Tout ce qui a attrait à la partie GUI est bloqué lorsque je passe dans la méthode invoke du proxy (ou la simple méthode @around lorsque j'utilise le framework spring). Cela se débloque que quand tout est fini. Après, je me suis aperçu que si je passe par la création au sein de ces méthodes d'un nouveau stage ou d'un dialog (avec pour owner la window principale), là, leur affichage se fait dès le début de la méthode (donc avant le lancement des opérations sur lesquelles je veux mettre un spinner). Mais malheureusement, dans les deux cas, je perds quand même l'animation du gif pendant toute la durée de la méthode. J'ai fait plusieurs tentatives avec des tasks, des thread, des modalités différentes, je ne récupère pas l'animation. Mais bon, je ne suis pas super doué et donc je viens demander un peu d'aide car je m'y prends sûrement très mal. Merci pour votre première réponse.

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Est-ce que tu peux me fournir le code d'un test très très simple (ex: un unique spinner dans une scène toute vide, un gif anime tout bête) qui fasse exactement la même chose et l'attacher sous forme de projet ZIP dans ta reponse ? Sans pouvoir comprendre comment tu opères ni pourquoi un proxy est necessaire, je ne saisis pas trop ni ce que tu veux faire, ni comment potentiellement le corriger.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    Bonjour,

    Je t'ai joins comme convenu ce que tu m'as demandé. En fait, sur l'essai maintenant cela marche avec l'utilisation de classes du package javafx.concurrent. Néanmoins, quand je lance l'opération sur le gros projet, cela ne marche toujours pas. Enfin, là je viens de rajouter l'utilisation des services (cet après midi en faisant des essais je ne passais que par des tâches mais cela marchait quand même sur le projet de test ) en m'inspirant des informations trouvées sur ce que tu sembles avoir écrit http://fabrice-bouye.developpez.com/...d-javafx/#LV-C et du site d'Oracle. Sur le gros projet, il s'agit de l'interception d'appels de services (côté client) qui vont lancer des opérations plutôt longues du côté serveur (passage par rest et base de donnée PGSql).

    Bref, je te remercie pour ton aide.

    Je te souhaite une bonne soirée et j'espère que mon code sera compréhensible lors de sa lecture (je ne suis pas un expert). La classe la plus importante dans le cadre de la réalisation des opérations est com.vinou.divers.aspect.CalqueShowInvocation

    Cordialement,

    Vincent
    Fichiers attachés Fichiers attachés

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Aaaah !
    un projet Maven et sous Spring... C'est pas vraiment ce que j'appelle un test minimal reproduisant le soucis en question.

    Bon alors, sans essayer de préjuger aucunement de la bonne manière dont Spring est sensé être utilisé ou de la meilleure façon de faire dans ce domaine (chui un noob ! ) , il me semble qu'une partie du soucis vient du fait que tu sembles attendre une exécution linéaire des choses alors qu'au contraire, tout est sensé fonctionné en asynchrone : c'est a dire qu'on lance des methodes dans le vide, elles retournent tout de suite, mais lors de l’exécution réelle elles font un effet de bord qui a un retour dans l'UI (ce qui est la manière normale de faire avec Service+Task, Platform.runLater() ou même SwingWorker ou SwingUtilities.invokeLater qui fonctionnent ainsi d'ailleurs)

    Pour ce que j'en comprends, le workflow d’exécution devrait être similaire a :

    JFXAP = JavaFX Application Thread.
    WT = Worker thread.

    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
    33
    34
    35
    36
    37
    38
    39
    // Au chargement du FXML.
    FXMLoader.load()  
        ->  SampleController.new()
        ->  SampleController.initialize() 
            -> SpringApplicationContext.getBean();                 // JFXAP: crée un pointeur de AnchorPane.
            -> apInst.setAp();		                       // JFXAP: passe une référence sur le AnchorPane racine du FXML.
        <- // JFXAP: retour.
     
    // Lors du clic sur le bouton.
    FXML (Bouton) 
        -> SampleController.Essai()
            -> SpringApplicationContext.getBean();                 // JFXAP: crée un pointeur de test.
            -> clPrTest.method();                                    
               -> CalqueShowInvocation.show();                     // JFXAP: invoque implicitement lors de l'appel a method().
               -> // JFXAP: recupere le pointeur d'AnchorPane.
               -> // JFXAP: cree un calque.
               -> // JFXAP: ajoute le calque dans l'AnchorPane.
               -> // JFXAP: charge le GIF anime.
               -> // JFXAP: met le GIF anime en place dans le calque.
               -> // JFXAP: creation de services/thread.
               -> // JFXAP: lancement de service/thread.
           <- // JFXAP: retour.
       <- // JFXAP: retour.
     
    // Lors de l’exécution de la tache.
    Task.call()                                                   // WT: on est dans le thread du service.
        -> jp.proceed();                                          // WT: invoque explicitement dans le service/thread.
            -> cClassePrTest.method();              	      // WT: invoque implicitement par proceed().
            <-                                                    // WT: fin exécution distante longue sur serveur. 
        <- // WT: retour.
     
    // "Plus tard", à la fin de la tache.
    Fin du service/thread 
        -> Service.getOnSucceeded().handle()                      // JFXAP: invoqué lorsque le service réussit.
            -> AnchorPane.getChildren().remove()                  // JFXAP: retrait du calque.             
        <- // JFXAP: retour.
    // Ou:
        -> Service.getOnFailed().handle()                         // JFXAP: invoqué lorsque le service échoue.
            -> [...]
    Donc, pour ce faire, j'ai remplacé le corps de la méthode show() de la classe CalqueShowInvocation par :

    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
    33
    34
    35
    36
    37
    38
    39
    40
    ApInstance apInst = SpringApplicationContext.getBean(ApInstance.class);
     
    AnchorPane ap = apInst.getAp();
    Calque cl = new Calque();
    ap.getChildren().add(cl);
    String urlImg = "com/vinou/spinner.gif";
    ImageView imgV = new ImageView();
    imgV.setFitHeight(320);
    imgV.setFitWidth(320);
    Image image = new Image(urlImg);
    imgV.setImage(image);
    cl.getChildren().add(imgV);
    cl.setVisible(true);
    Service<Void> showService = new Service<Void>() {
     
        @Override
        protected Task<Void> createTask() {
            return new Task<Void>() {
     
                @Override
                protected Void call() throws Exception {
                    try {
                        jp.proceed();
                    } catch (Exception ex) { // Rethrow.                            
                        throw ex;
                    } catch (Throwable t) { // Unexpected, pack and rethrow.
                        Exception unexpected = new Exception(t);
                        throw unexpected;
                    }
                    return null;
                }
            };
        }
    };
    showService.setOnSucceeded(workerStateEvent -> ap.getChildren().remove(cl));
    showService.setOnFailed(workerStateEvent -> {
        Throwable t = workerStateEvent.getSource().getException();
        // Gerer les erreurs ici.
    });
    showService.start();
    Et il devrait être possible d'utiliser un thread a la place du service bien sur, quelque chose du genre (le workflow est un peu différent bien sur ca on a pas les callbacks de service qui s’exécutent dans JFXAP) :

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Thread th = new Thread() {
     
        @Override
        public void run() {
            try {
                jp.proceed();
                // Quand ca se passe bien.
                Platform.runLater(() -> ap.getChildren().remove(cl));
            } catch (Throwable t) {
                // Gerer les erreurs ici.
            }
        }
    };
    th.start();

    Ce qui fait que le calque disparait bien lorsque les 100K itérations sont terminées. Mais bon, j'ignore si c'est la bonne maniere de faire et surtout j'ignore si ca fonctionnera dans ton envirronement client-serveur (et pis il manque la gestion des erreurs bien sur).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    Bonjour,

    Je te remercie pour tes réponses, cela arrange les choses. Néanmoins, il reste un point sur lequel je suis bloqué et qui va sûrement paraître bête. Dans l'exemple que je t'ai envoyé, la méthode show(ProceedingJoinPoint jp) ne renvoie rien. Néanmoins, au niveau du travail, je suis censé récupérer une instance de la classe Object en résultat de jp.proceed(). La méthode show()doit la renvoyer. Or, il semblerait que je récupère mal cette instance vu que le résultat retourné est null et donc cela veut dire que jp.proceed() n'est pas terminé.

    Pour le moment je fais de cette façon sur la fin de la méthode show() (je pars ici à partir du service) :

    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
    Service<Object> showService = new Service<Object>() {
     
        @Override
        protected Task<Object> createTask() {
            return new Task<Object>() {
     
                @Override
                protected Object call() throws Exception {
                    Object obj = null;
    		try {
                        obj = jp.proceed();
                    } catch (Exception ex) { // Rethrow.                            
                        throw ex;
                    } catch (Throwable t) { // Unexpected, pack and rethrow.
                        Exception unexpected = new Exception(t);
                        throw unexpected;
                    }
                    return obj;
                }
            };
        }
    };
    showService.setOnSucceeded(workerStateEvent -> ap.getChildren().remove(cl));
    showService.setOnFailed(workerStateEvent -> {
        Throwable t = workerStateEvent.getSource().getException();
        // Gerer les erreurs ici.
    });
    showService.start();
    return showService.getValue();
    
    Toujours sur le gros projet, j'ai testé en pointant sur une méthode spécifique (changement dans le tag @around du paramètre execution) qui me renvoie une instance d'une classe connue qui porte pour nom Direction.
    Si je rajoute les opérations ci-dessous, au sein de la méthode setOnSucceeded du service, j'ai la preuve que l'objet est récupéré complètement (les données liées à l'adresse sont affichées).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    	Direction objDir = (Direction) workerStateEvent.getSource().getValue();
    	System.out.println(objDir.getAdresse());
    Aussi, comment pourrais-je faire pour sortir proprement l'objet de la méthode show() quand tout est terminé ? Je ne vois pas en gros comment intercepter le fait que tout est terminé et lancer le return. En effet, j'ai fait plusieurs essais dont notamment déclarer le nom de la task en dehors et le récupérer à la fin via un get(), cela ne change rien ou augmente les problèmes.

    Je te remercie pour ton aide et te souhaite une bonne soirée.

    AJOUT: J'ai réussi à recréer le problème sur le projet de test. En fait ici, je renvoie "tutu" dans la méthode appelée par jp.proceed(). Je retourne cette valeur dans show() via showService.getValue(). Dans le sampleController, la valeur est récupérée et est censée remplacer le libellé du bouton. Néanmoins, le bouton n'a plus de libellé lorsque tout est censé être fini. Par contre, j'ai mis dans le setOnSucceed du service:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    System.out.println("valeur ds setonSucceeded: "+ (String)workerStateEvent.getSource().getValue());
    Lorsque tout est fini, dans la console, la valeur "tutu" apparaît bien. Néanmoins, le bouton n'a plus de libellé (cela devrait être "tutu" aussi). Je joins le projet modifié comme hier en pièce jointe au message, dés fois que cela puisse aider rapport au fait que je n'explique pas très bien les choses.
    Fichiers attachés Fichiers attachés

  8. #8
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Oui mais justement c'est bien la le soucis, cet appel va sans doute tout le temps retourner null (les chances que ca ne le soit pas etant plutot reduites) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    showService.start();
    return showService.getValue();
    A la ligne #1 on démarre le service. Cette méthode met le service dans un état scheduling et retourne immédiatement.
    A la ligne #2 on récupère son résultat. Or a ce moment, généralement, a moins d'avoir un system hyper rapide, le service est encore en état scheduling. Dans le meilleurs des cas, il a peut-etre démarré mais comme c'est une tache longue de toute manière il est sans doute en train de l’exécuter. De toute manière, on s'en fiche ça se déroule dans un autre thread. Donc dans 99.99% des cas ça retournera tout le temps null.

    En théorie, il faudrait sans doute faire un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Proxy result = 
    [...]
    showService.setOnSucceeded(workerStateEvent -> {
        ap.getChildren().remove(cl));
        Direction objDir = (Direction) workerStateEvent.getSource().getValue();
        result.set(objDir);
    });
    showService.start();
    return result;
    Il faut bien comprendre qu'ici la ligne #9 (qui retourne un proxy vide) est exécutée bien bien bien longtemps AVANT la ligne #6 qui met l'objet dans le proxy. La ligne #6 est exécutée, certes sur JFXAP, mais "plus tard" une fois l'autre service/thread finie.

    Maintenant, la bonne question est "qu'est ce que doit être ce proxy ?". As-tu un mécanisme en Spring pour cela ? Sachant qu’après ton proxy doit quand même emmètre les événements qu'il faut pour que quoi que ce soit qu'il y ait derrière, cela soit mis au courant que la bonne valeur est enfin arrivée dans le proxy a la fin du traitement.

    Par exemple, dans un contexte purement FX, je serai tente de faire quelque chose du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ObjectProperty<Toto> result = new SimpleStringProperty();
    Service<Toto> showService = ...
    showService.setOnSucceeded(workerStateEvent -> {
        ap.getChildren().remove(cl));
        Toto value = (Toto ) workerStateEvent.getSource().getValue();
        result.set(value);
    });
    showService.start();
    return result;
    Ce qui permet de faire "ailleurs" dans le code (du contrôleur par exemple) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ObjectProperty<Toto> operationResult = demarreOperationAsynchrone(); // Lance la tache dans un thread autre et retourne tout de suite un résultat vide.
    operationResult.addListener(observable -> {
        Toto value = operationResult.get();
        // Faire les modifs appropriées dans la GUI.
    });
    Mais bon, je ne sais pas comment cela doit être fait de la manière correcte en Spring. Si tu as déjà programmé des UI équivalentes en Spring + Swing, comment se fait le traitement de taches de longues durées / déportées sur d'autres systèmes ? Le principe devrait être fortement similaire normalement (si on ne veut pas bloquer la GUI avec du mono-thread).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  9. #9
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    A voir :
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  10. #10
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    Je te remercie grandement pour tes réponses et les liens que tu m'as donnés. En fait, j'ai tenté sur le projet de test d'utiliser synchronized sur l'objet (que j'ai passé de String à StringProperty) pour bloquer jusqu'à la fin de l'opération le return. Mais bon, maintenant c'est l'affichage (cl.setVisible(true)) qui se fait trop tard et apparaît même pas une demi seconde (l'opération d'itération d'affichage du texte dans la console est déjà lancée à ce moment là) et disparaît ensuite. Le libellé du bouton récupère par contre bien la valeur "tutu" à la fin. Juste pour montrer, je mets le bout de code ci-dessous à partir du moment où je lance la méthode d'affichage du calque :
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
            .... 
    	cl.setVisible(true);
            obj = new SimpleStringProperty("");
          
     
    		Service<StringProperty> showService = new Service<StringProperty>(){
    
    			  @Override
    			  protected Task<StringProperty> createTask() {
    			    return new Task<StringProperty>(){
    			     	
    			     @Override
    			     protected StringProperty call() throws Exception {
    			    	 
    			    	 
    			    	try {
    			    		synchronized(obj){
    						obj.setValue((String) jp.proceed());
    						obj.notifyAll();
    			    		}
    
    					} catch (Throwable e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    			        return obj;
    			    	 
    			      }
    			     			    
    			    };		    
    			  }
    			};
    			          					
    			showService.setOnSucceeded(workerStateEvent -> {
    				ap.getChildren().remove(cl);
    				StringProperty val = (StringProperty) workerStateEvent.getSource().getValue();
    				System.out.println("valeur ds setonSucceeded: "+ val.getValue());
    			});
    			showService.setOnFailed(workerStateEvent -> {
    			    Throwable t = workerStateEvent.getSource().getException();
    			    System.out.println("ERREUR:"+ t.getMessage());
    			});
    			
    			
    			
    			
    			synchronized(obj){
    			     showService.start();
    			     obj.wait();
    			     return obj.getValue();
    			}
    	}
    Je te remercie en tout cas pour ton aide et je vais me pencher ce week-end sur les liens que tu m'as gentillement passés. Merci beaucoup.

    Bonne Soirée.

    Cordialement,

    Vincent

  11. #11
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Citation Envoyé par vinou33 Voir le message
    Je te remercie grandement pour tes réponses et les liens que tu m'as donnés. En fait, j'ai tenté sur le projet de test d'utiliser synchronized sur l'objet (que j'ai passé de String à StringProperty) pour bloquer jusqu'à la fin de l'opération le return.
    Oui mais non tu ne peux justement pas faire ça avec cette archi !!!!!!
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  12. #12
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    Arf donc je les retire. Pourrais tu s'il te plait à l'occasion m'expliquer pourquoi je ne peux pas faire ça (synchronized) au niveau de cette architecture ? Cela ne pose-t-il pas juste un blocage sur obj et impose que l'opération jp.proceed soit terminée pour que le return se fasse ? Il me manque vraiment beaucoup à apprendre...

  13. #13
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Car à partir du moment où tu invoques wait() ça bloque JFXAP durant tout le temps de ta tâche jusqu'à l'appel à notifyAll() et donc dans le cadre de ton très long appel coté serveur ça va à nouveau geler toute l'UI or justement depuis le début c'est ce que tu ne veux pas faire.
    Dans le cadre d'une exécution normale de JFXAP, cette méthode doit retourner le plus rapidement possible, la tâche doit s'exécuter dans un autre thread et on doit avoir une notification asynchrone en fin de tâche. C'est ce qu'on cherche à obtenir depuis le début.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  14. #14
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    Merci pour l'information. Ménage, lessive, repassage des draps sont finis, je vais pouvoir m'y remettre cet après-midi. Je pense un peu à Executor sur l'asynchrone et aux callables déclarés dans des instances de Future. Mais bon, la documentation d'abord et peut-etre envisager une autre approche que AOP et around.

    Aller, bon après-midi.

    Vincent.

Discussions similaires

  1. Utilisation de la classe Méthod et de la méthode Invoke
    Par peche dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 12/04/2010, 15h49
  2. Réponses: 8
    Dernier message: 19/06/2006, 15h31
  3. [Reflexion] Pb méthode invoke
    Par Delhio dans le forum API standards et tierces
    Réponses: 5
    Dernier message: 13/05/2006, 22h13
  4. [VB.NET 1.1] [Thread] Méthode invoke
    Par toniolol dans le forum Windows Forms
    Réponses: 5
    Dernier message: 15/02/2006, 16h04
  5. Réponses: 4
    Dernier message: 05/06/2005, 14h05

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