0

J'ai construit une application Spring CLI qui communique avec un serveur de manière asynchrone. Le serveur a été donné, je ne l'ai pas créé, fondamentalement mon application est requise pour ouvrir un socket TCP et y envoyer un JSON, puis il renvoie un JSON. Il est obligatoire de ne pas utiliser les paramètres CLI, mais dans le rappel de la requête, je souhaite montrer à l'utilisateur un ensemble d'options qu'il doit sélectionner en insérant le numéro correspondant sur la CLI. Très probablement je ne fais pas juste quelque chose, parce qu'après avoir entré la commande, je vois spring> sur la console (c'est un comportement attendu) et il bloquera le rappel asynchrone à moins que j'appuie sur quelque chose (rien n'est imprimé à la CLI quand je reçois le rappel à moins que j'appuie sur un tas d'entrées - c'est inattendu). Pour lire depuis la console jusqu'ici j'ai utilisé la ligne de commande de JLine, ce que je voudrais réaliser est que quand j'obtiens la réponse du serveur et que le rappel est servi, la console est donnée au thread sur lequel le callback est exécuté (I imprime instantanément le contenu du rappel à la console, et je suis capable de lire l'entrée sans trucs).Async IO gérer dans Spring CLI avec Java comment?

Certains code:

public void runReceiver(){ 
    receiverThread = new Thread(() -> { 
     byte[] digit = null; 
     int nb; 
     Iterator<CommandListener> it; 
     CommandListener listener; 
     String message; 
     List<CommandListener> listenersToRemove = new ArrayList<>(); 
     while (true) { 
      try { 
       nb = communicatorInput.readInt(); 
       digit = new byte[nb]; 
       communicatorInput.readFully(digit); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      it = listeners.iterator(); 
      while (it.hasNext()){ 
       listener = it.next(); 

       if (digit != null && digit.length > 0) { 
        message = new String(digit); 
        // the message was not acknowledged 
        if(message.contains("NACK")){ 
         try { 
          listener.onError(message); 
          if (listener.isDone()) { 
           listenersToRemove.add(listener); 
          } 
         } catch (Exception e){ 
          e.printStackTrace(); 
         } 
        } else try { 
         listener.onCompleted(message); 
        } catch (InvalidObjectException e){ 
         Main.logger.debug(String.format("Response could not be parsed as %s", listener.getCommandType())); 
        } catch (Exception e){ 
         e.printStackTrace(); 
        } 

        if (listener.isDone()) { 
         listenersToRemove.add(listener); 
        } 
       } 
      } 
      listeners.removeAll(listenersToRemove); 
     } 
    }, "receiverThread"); 

    receiverThread.setDaemon(true); 
    receiverThread.start(); 

Ensuite, une commande CLI (il attend pas entrée ici):

@CliCommand(value="start", help = "Starts stuff") 
public void start() throws IOException, InterruptedException { 
    // this method is passed to the thread with the listener 
    getAvailabilities().updateAvailabilities("all", "all", "all", someListener); 
} 

Et le rappel de cet écouteur:

someListener = new CommandListener() { 
      private String source = "Start some listener"; 
      @Override 
      public void onCompleted(String r) throws IOException { 
       System.out.println("Which would you like to start?"); 

       getAvailabilities().printAvailableBrands(); 

       String brandNumber = ""; 
       while(Objects.equals(brandNumber, "")){ 
        System.out.println("Please enter the number of the Brand: "); 
       //when the callback arrives here I still only see ">spring:" and I get nothing printed on the console 
        brandNumber = cr.readLine(); 
        if(!isInputAllowed(brandNumber, getAvailabilities().AvailableBrands.size())){ 
         brandNumber = ""; 
        } 
       } 
       BrandName = getAvailabilities().AvailableBrands.get(Integer.parseInt(brandNumber) - 1); 
       //updating the availabilities narrows down the things I list to the console, so I send an update after every selection 
       getAvailabilities().updateAvailabilities("all", BrandName, "all", getInterfaceListener); 
       done = true; 
      } 

Cela pourrait légèrement se connecter au problème qui parfois lors du débogage de l'interface de ligne de commande dans Idea, il obtient des entrées whacky, par exemple. quand j'insère start il est dit No such command as ar, et si j'appuie à nouveau sur entrée, ça va dire (une partie de) le reste: No such command as stt.

Répondre

0

Le problème est ici:

if (listener.isDone()) { 
    listenersToRemove.add(listener); 
} 

Si vous voulez que vos auditeurs à exécuter de manière asynchrone, vous ne devriez pas vérifier leur achèvement tout de suite sur le même fil car il sera très probablement revenir faux.

La question que vous pourriez avoir est que vos auditeurs planifier une tâche, mais pas le temps de finir comme vous les enlever immédiatement après la boucle:

listeners.removeAll(listenersToRemove); 

Il est très difficile de dire ce que votre logique est mais je suppose que dans la prochaine itération votre liste est vide.