Chamada a Aplicativos e Bibliotecas Externas – Parte 02

Dando continuidade a chamada a aplicativos e bibliotecas externas.

Armadilhas no uso de Runtime.exec()

Vamos mostrar primeiro algumas armadilhas que temos que evitar antes de executar algum comando usando Runtime.exec()


            - IllegalThreadStateException
        

A primeira armadilha é a exceção “IllegalThreadStateException”. A primeira coisa que fazemos quando vamos testar um método de uma API é codificar o método da forma mais obvia possível. Tendo isso em vista, vamos mostrar a primeira armadilha na execução do método exec(). Para podermos ver o valor que nosso processo retorna usamos o método exitValue() da classe Process. No exemplo abaixo vamos tentar listar os arquivos do diretório corrente (“dir” no Windows, e “ls” no Linux).

Listagem 1. ListagemComErro

            String osName = System.getProperty("os.name" );
            String[] cmd = new String[3];
            if( osName.equals( "Windows 2000" ) ){
                 cmd[0] = "cmd.exe" ;
                 cmd[1] = "/C" ;
                 cmd[2] = "dir /w";
            }else if( osName.equals( "Linux" ) ){
                 cmd[0] = "/bin/sh" ;
                 cmd[1] = "ls" ;
              cmd[2] = "-la";
         }else{
              //faz alguma coisa                
         }
         Process p = Runtime.getRuntime().exec(cmd);
         int exitVal = p.exitValue();
         System.out.println("Process exitValue: " + exitVal);
        

Explicação da Listagem 1:

Retorno:

Ao executarmos o código, recebemos a seguinte mensagem de erro:


            java.lang.IllegalThreadStateException: process has not exited

         at java.lang.ProcessImpl.exitValue(Native Method)

         at tests.ListagemComErro.main(ListagemComErro.java:10)
        

Explicação:

Se um processo não terminou ainda de executar, a chamada ao método exitValue() vai causar uma exceção do tipo “IllegalThreadStateException”, e é por isso que o programa não funcionou. Se você precisar saber o status de retorno do fim da execução de um programa externo, você deve utilizar o método waitFor(), que retorna o valor de status de termino do programa apenas após ele ser realmente finalizado. A única possibilidade de se usar exitValue() ao invés de waitFor(), é quando você não quer que seu programa fique parado esperando o termino de um processo. Nesse caso, você pode fazer algo como passar um parâmetro boolean chamado wait dentro do método exitValue() para determinar se a thread em execução deve ou não esperar pelo termino da execução.

Resumindo, ou você coloca a chamada ao método exitValue() dentro de um bloco try/catch e cuida da exceção “IllegalThreadStateException”, ou você espera o processo terminar de executar.

Execução sem output

Listagem 2. ListagemComErro2

            String osName = System.getProperty("os.name" );
            String[] cmd = new String[3];
            public class ListagemComErro2
            {
                public static void main(String args[])
                {
                    try
                    {
                         if( osName.equals( "Windows 2000" ) ){
                           cmd[0] = "cmd.exe" ;
                          cmd[1] = "/C" ;
                          cmd[2] = "dir /w";
                         }else if( osName.equals( "Linux" ) ){           
                           cmd[0] = "/bin/sh" ;
                           cmd[1] = "ls" ;
                          cmd[2] = "-la";
                     }else{
                          //faz alguma coisa
                     }
                      Process p = Runtime.getRuntime().exec(cmd);
                      int exitVal = p.waitFor();
                      System.out.println("Process exitValue: " + exitVal);
                 } catch (Throwable t){
                     t.printStackTrace();
                   }
             }
         }
        

Explicação da Listagem 2:

Como já expliquei a maioria das linhas na listagem anterior, aqui listarei somente as linhas que estão diferentes.

Retorno:

A execução do programa ‘ListagemComErro2’ não produz saída nenhuma, o programa trava e não completa nunca.

Explicação:

Como cada plataforma disponibiliza um tamanho limitado de buffer para os fluxos de entrada e saída padrões, uma falha na escrita do fluxo de entrada ou de leitura do fluxo de saída de um subprocesso pode fazer com que este subprocesso trave, ou, ate mesmo, ocasione um ‘deadlock’ (programa termina de forma anormal).

Se você procurar na documentação do SDK, você verá que isto é mencionado lá, porém, não nos dizem como fazer para manipular tais fluxos.


            - Erro de execução com Status de Saida igual a 2 (“arquivo não encontrado”)
        
Listagem 3. ListagemComErro3

                        import java.util.*;
            import java.io.*;
            public class ListagemComErro3
            {
                public static void main(String args[])
                {
                    try
                    {
                        Process p = Runtime.getRuntime().exec(“dir.exe”);
                     InputStream stdin = p.getInputStream();
                     BufferedReader br = new BufferedReader( new InputStreamReader(stdin) );
                     String line = null;
                     while ( (line = br.readLine()) != null)
                             System.out.println(line);
                     int exitVal = p.waitFor();            
                     System.out.println("Process exitValue: " + exitVal);
                 } catch (Throwable t)
                   {
                         t.printStackTrace();
                   }
             }
         }
        

explicação da Listagem 3:

Retorno:

Ao executarmos o código, recebemos a seguinte mensagem de erro:


            java.io.IOException: CreateProcess: dir error=2
        at java.lang.Win32Process.create(Native Method)
        at java.lang.Win32Process.(Unknown Source)
        at java.lang.Runtime.execInternal(Native Method)
        at java.lang.Runtime.exec(Unknown Source)
        at java.lang.Runtime.exec(Unknown Source)
        at java.lang.Runtime.exec(Unknown Source)
        at java.lang.Runtime.exec(Unknown Source)
        at ListagemComErro3.main(ListagemComErro3.java:12)
        

Explicação:

Um status de saída com valor 2 significa “arquivo não encontrado”, que neste caso, indica que o arquivo executado por nosso programa (dir.exe) não pode ser encontrado. Isso ocorre porque o diretório command, onde ficam esses comandos de sistema, são parte do interpretador de comandos do Windows e não um programa executável independente. Para executar esse tipo de comando, você tem que passar como comando principal “cmd.exe” e o parâmetro “/C” e só então passar o comando “dir.exe” como parâmetro. A mesma regra se aplica ao linux, antes de executar um comando você tem que colocar como comando principal “/bin/sh” e depois o comando a ser executado “ls” e seus parâmetros “-la”.caso haja necessidade.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados