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

Langage Java Discussion :

ProcessBuilder ne semblant pas s'executer mais ne retourne pas d'erreurs


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 23
    Par défaut ProcessBuilder ne semblant pas s'executer mais ne retourne pas d'erreurs
    Bonjour tout le monde, dans le but de créer une interface pour RSync sous linux, j'utilise Java et la commande ProcessBuilder particulièrement. Sauf que je suis dans l'impasse, comme dit dans le titre, le ProcessBuilder ne semble avoir aucun effet. Le code ci dessous sert à ajouter une ligne dans le crontab( planificateur de tâche sous linux). La commande est fonctionnelle car j'ai pu la testé. Si vous avez une idée, proposez, je testerai dès la lecture de votre post. Merci d'avance.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
        public void CreationDeLaTacheCrontab(String utilisateur){
                String HomeDirectory = System.getenv("HOME");
                String commande = periodicite+" rsync -ra -e \"ssh -l "+utilisateur+" -i "+HomeDirectory+"/.pentarsync/"+utilisateur+".clef /home/"+utilisateur+"/ 172.16.69.2:/home/client/PPE4/config.txt";
     
               try{ 
                   ProcessBuilder creationTache = new ProcessBuilder("crontab","-l","|","awk","'/^#/!_[$0]++", ";END", "{print\""+commande+"\"}'","|","crontab","-");
                   creationTache.start();
               }
               catch(Exception e){e.printStackTrace();}
               }

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,



    • Quel est la commande exacte en ligne de commande ? (celle qui marche)
    • Tu ne traites pas les flux d'entrée/sorties ! Si tu ne veux pas les traiter il faut les fermer...
      Mais là il faudrait au moins lire les flux de sorties pour voir un éventuel message d'erreur (le plus simple étant d'utiliser inheritIO() de Java 7).
    • C'est quoi cette gestion crados des exceptions ?



    a++

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 23
    Par défaut
    La commande est la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    crontab -l | awk '/^#/!_[$0]++ ;END {print "@hourly rsync -ra -e \"ssh -l lionel -i $HOME/.pentarsync/lionel.clef /home/lionel/ 172.16.69.2:/home/client/PPE4/config.txt"}' | crontab -
    Pour le reste, je ne suis jamais qu'un étudiant en cours de formation ayant du se former seul sur Java. Aussi il rique d'y avoir deux trois trucs qui peuvent te bruler les yeux, j'en suis désolé . Si pour ta deuxième question, tu as un example de code, je serai ravi de le tester.


    Et encore merci pour la réponse

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Déjà tu as mal découpé tes arguments. en effet lorsque tu tapes 'a b' dans le shell, cela représente un seul argument valant la chaine a b. Donc en fait la chaine entre simple quote devrait être un seul et unique argument, par exemple quelque chose comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new ProcessBuilder("awk", "/^#/!_[$0]++ ;END {print \"@hourly rsync -ra -e \"ssh -l lionel -i $HOME/.pentarsync/lionel.clef /home/lionel/ 172.16.69.2:/home/client/PPE4/config.txt\"}");
    Mais tu ne pourras pas utiliser ProcessBuilder comme cela. En effet je n'avais pas fait gaffe au pipe...
    ProcessBuilder permet de lancer un programme avec des arguments.... or tu lances une ligne de commande composé de plusieurs programmes...
    Cela ne marchera pas tel quel avec ProcessBuilder... il faudrait le découper en 3 ce qui risque d'être assez galère !


    Mais heureusement il y a une solution plus simple pour lancer une ligne de commande, c'est de passer par le shell système (/bin/sh -c sous les Unix - sous Windows on utilisera cmd.exe /C).
    La commande à appeler est simple : /bin/sh -c "commande"
    Du coup le code peut se simplifier de la manière suivante (code Java 7) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	public static int unixSystem(String commandLine) throws IOException, InterruptedException {
    		// 1. On crée le shell avec la ligne de commande en paramètre
    		Process process = new ProcessBuilder("/bin/sh", "-c", commandLine)
    			// On hérite les I/O (cela les associes à System.in/out/err 
    			.inheritIO()
    			.start();
     
    		// (pas besoin de gérer les flux ils sont hérités)
     
    		// On attend jusqu'à la fin du process :
    		return process.waitFor();
    	}
    Avec commandLine qui correspond à la commande tel que tu la tapes dans la ligne de commande.
    Les flux d'entré/sorties sont mappés sur ceux de java (System.in, System.out et System.err).

    Du coup tu l'utilise comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    unixSystem("crontab -l | awk '/^#/........}' | crontab -");


    Par contre il peut y avoir un problème : si la commande affiche un message de confirmation, cela peut bloquer les deux process s'il n'y a personne pour effectuer la saisie (apps graphique sans console, serveur, etc.).
    Du coup il est préférable de fermer le flux d'entrée, ce qui génèrera une erreur dans le programme appelé s'il est utilisé :
    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
    	public static int unixSystem(String commandLine) throws IOException, InterruptedException {
    		// 1. On crée le shell avec la ligne de commande en paramètre
    		Process process = new ProcessBuilder("/bin/sh", "-c", commandLine)
    			// On hérite les flux de sortie uniquement
    			.redirectOutput(Redirect.INHERIT)
    			.redirectError(Redirect.INHERIT)
    			.start();
    		try {
    			// On ferme le flux d'entrée du process :
    			process.getOutputStream().close();
     
    			// (pas besoin de gérer les autres flux ils sont hérités)
     
    			// On attend jusqu'à la fin du process :
    			return process.waitFor();
    		} finally {
    			// garde-fou qui kille le process en cas de problème
    			process.destroy();
    		}
    	}

    Maintenant si tu es sous une version antérieur, il va falloir traiter les flux toi-même, c'est à dire au minimum les fermer ou bien lire/ecrire des données dedans :
    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
    	public static int unixSystem(String commandLine) throws IOException, InterruptedException {
    		// 1. On crée le shell avec la ligne de commande en paramètre
    		Process process = new ProcessBuilder("/bin/sh", "-c", commandLine)
    			// On redirige le flux d'erreur dans le flux standard
    			// (c'est plus simple à gérer)
    			.redirectErrorStream(true)
    			.start();
    		try {
    			// On ferme le flux d'entrée du process :
    			process.getOutputStream().close();
     
    			// On doit gérer le flux de sortie standard
    			// (qui contient aussi le flux d'erreur)
    			InputStream processOutput = process.getInputStream();
    			try {
    				byte[] buf = new byte[8192];
    				int len;
    				// On se contente de recopier dans System.out
    				while ((len=processOutput.read(buf))>0) {
    					System.out.write(buf, 0, len);
    				}
    			} finally {
    				processOutput.close();
    			}
     
    			// On attend jusqu'à la fin du process :
    			return process.waitFor();
    		} finally {
    			// garde-fou qui kille le process en cas de problème
    			process.destroy();
    		}
    	}





    Concernant la gestion des exceptions, c'est le e.printStackTrace() que je décris.
    Ok c'est déjà bien tu n'as pas laissé le bloc catch vide... mais qu'est-ce que cela signifie ?

    Tu as un gros problème car le programme que tu lances ne peut pas être exécuté pour une raison quelquonque... et tu te contentes d'afficher un message en continuant le programme comme si de rien n'était !
    Pire ton programme ne sait pas qu'il y a une erreur et pourrait continuer en pensant que tout s'est bien passé...


    Je ne connais pas le contexte de ton application, mais :
    • Si c'est une application serveur ou un batch, il y a de forte chance que cela parte dans un fichier de log que personne ne lira.
    • Si c'est une application desktop graphique, l’utilisateur ne verra pas le message et croira que tout s'est déroulé normalement.
    • Si c'est une application console, il verra un message qu'il ne comprend pas... et pourrait penser que c'est normal puisque le programme continue son cours normalement !!!

    Pire dans certains cas cela peut engendrer d'autre erreur par la suite, qui serait difficile à comprendre si on ne voit pas l'erreur originale...


    Pour moi si tu traites l'erreur c'est que tu sais qu'elle peut survenir, et que tu as une "solution de secours".
    Cela ne me semble pas le cas ici, et il serait préférable de laisser remonter l'erreur quitte à l'encapsuler dans une RuntimeException pour qu'elle ne fassent plus chier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     catch (IOException e) {
         throw new RuntimeException(e);
    }
    Comme ca en cas d'erreur cela fait planter le thread courant ou le programme.
    Pour moi dans ce cas il s'agit d'erreur qui ne devrait pas survenir une fois le programme en production... et donc si ca plante c'est qu'il y a un gros problème et je préfère laisser remonter l'erreur pour avoir l'info au plus vite.

    Pour la mise en prod, on pourra mettre un exception-handler pour traiter toutes ces erreurs (afficher un message à l'utilisateur, logger l'erreur voir envoyer un rapport d'erreur par email, ...)


    a++

  5. #5
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 23
    Par défaut
    Merci, pour une réponse c'est une réponse, complète comme je ne pouvais pas en rêvé plus. Je mettrai en ça application demain et mon petit doigt me dit qu'un sujet de plus sera résolu grâce à toi adiGuba.

    Un grand MERCI

    -- EDIT --
    J'ai une question (oui encore une) comment peut tu utiliser des fonctions propres au ProcessBuilder et au Process en même temps? Je m'explique .redirectErrorStream() appartient au ProcessBuilder et .getOutputStream() au Process. Dans ton code tu semble n'avoir aucunes contraintes pour l'utilisation des deux types or chez moi c'est différent.

  6. #6
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 23
    Par défaut
    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
     
     
            String HomeDirectory = System.getenv("HOME");
            String maCommande = "crontab -l | awk '/^#/!_[$0]++ ;END {print "+periodicite+" rsync -ra -e \"ssh -l "+utilisateur+" -i +HomeDirectory+"/.pentarsync/"+utilisateur+".clef /home/"+utilisateur+"/ 172.16.69.2:/home/client/PPE4/config.txt}' | crontab -";
     
            CreationDeLaTacheCrontab(maCommande);
    [ . . . ]
     
     
     
        public static void CreationDeLaTacheCrontab(String uneCommande) throws IOException, InterruptedException{
            ProcessBuilder p = new ProcessBuilder("/bin/sh", "-c", uneCommande);
            p.redirectErrorStream(true);
            Process process = p.start();
     
     
     
            try{
                process.getOutputStream().close();
     
                InputStream processOutput = process.getInputStream();
     
                try{
                    byte[] buf= new byte[8192];
                    int len;
     
                    while((len=processOutput.read(buf))>0){
                        System.out.write(buf,0,len);
                    }
                }finally{
                    processOutput.close();
                }
     
            } finally{
                process.destroy();
            }
    Voilà ce que j'ai fais, et voila ce qu'il me retourne comme message :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    awk: 1: unexpected character '@'
    awk: line 1: runaway string constant "ssh -l lio ...
    A aucun moment je n'utilise d'@ dans ma commande et je n'en ai pas besoin. Alors pourquoi ce message!?

  7. #7
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Fais un system.out.println de "maCommande" pour vérifier que la chaine est bien formé.


    a++

  8. #8
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Citation Envoyé par Nemesium Voir le message
    J'ai une question (oui encore une) comment peut tu utiliser des fonctions propres au ProcessBuilder et au Process en même temps? Je m'explique .redirectErrorStream() appartient au ProcessBuilder et .getOutputStream() au Process. Dans ton code tu semble n'avoir aucunes contraintes pour l'utilisation des deux types or chez moi c'est différent.
    Il n'y a pas de raison. ProcessBuilder.start() retourne un Process, tu peux très bien utiliser les méthodes sur le Process

  9. #9
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 23
    Par défaut
    Ouais je m'en suis rendu compte mais plus tard, c'est juste que ça me générer une erreur. Ca c'est corrigé maintenant.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XL-97] run time error 9 a l'execution mais fonctionne en pas a pas
    Par yaume91 dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 02/02/2013, 12h09
  2. Réponses: 2
    Dernier message: 17/03/2011, 14h52
  3. Réponses: 1
    Dernier message: 11/09/2007, 17h06
  4. fonction qui ne s'execute pas mais qui ne retourne pas d'erreur
    Par duplo dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 03/06/2006, 21h43
  5. Réponses: 4
    Dernier message: 08/01/2006, 18h26

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