[Java] Ejecutar programa externo

dagavi

Buenas,

Estoy realizando un proyecto en la universidad en la que me surge la necesidad de poder ejecutar programas externos desde mi programa, concretamente deseo poder ejecutar keytool y openssl.

Actualmente he creado un script en bash y batch con los comandos que funciona correctamente. Este script lo llamaría desde el programa Java, sin embargo la gracia estaría en meter directamente las llamadas que hay dentro de los scripts en vez de llamar al script.

He visto que para ejecutar programas externos dispongo de ProcessBuilder, sin embargo no consigo ejecutar ni keytool ni openssl.

He llegado a conseguir ejecutar uno de los scripts antes creados, concretamente desde windows y ejecutando:

ProcessBuilder pb = new ProcessBuilder(
    "cmd",
    "/C",
    runtimeDir + "crearCertificado.bat",
    username,
    password
);
pb.start();

Esto ha funcionado. Se ejecuta "cmd" que a su vez ejecuta "crearCertificado.bat" (lo de ejecutar cmd /C es lo que he visto en todos los ejemplos).

Sin embargo si lo cambio por la linea de keytool no me hace nada, en ninguna de las formas que lo he probado (que hansido todas las que se me han ocurrido):
· Lo he probado poniendo "keytool" y sus argumentos
· Con todo el path hasta keytool (ya que como véis al CMD le paso el path entero al .bat si no tampoco lo conseguía ejecutar -.-)
· Los dos puntos anteriores pero tal y como he ejecutado el bat (cmd /C punto_anterior)

ProcessBuilder pb = new ProcessBuilder(
    "keytool",
        "-keystore", keystore,
        "-genkey",
        "-alias", alias,
        "-dname",
          "\"CN=" + username + ",",
            "OU=BiC User,", 
            "O=BiC,",
            "L=Barcelona,",
            "S=Barcelona,",
            "C=ES\"",
        "-keyalg", "RSA",
        "-keysize", Integer.toString(keysize),
        "-validity", Integer.toString(validity),
        "-storepass", password,
        "-keypass", password
);
pb.directory(runtimeDir);
Process p = pb.start();
printProcessBuilder(pb);

También he probado poniendo algunos argumentos más juntos, por ejemplo en vez de separar "-keystore" y su valor con una coma, pos con concatenación de string normal y corriente: "-keystore " + keystore

En todos los casos al visualizar que comando se ejecuta con

for (String command : pb.command()) {
    System.out.print(command + " ");
}

El comando es correcto. Incluso me pongo en el directorio donde está y lo copio y pego y funciona, sin embargo el propio programa no me ejecuta el keytool, sin embargo, como digo, si he podido llegar a ejecutar el script batch.

¿Que ocurre?

Gracias!

LOc0

ProcessBuilder no la he usado nunca, pero ¿has probado con la clase Runtime http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Runtime.html ?

Salu2 ;)

1 1 respuesta
dagavi

Nada, que no consigo que Keytool me genere aunque sea el archivo de keystore ni con Runtime (por lo que he leido ProcessBuilder es una actualización respecto a ejecutar cosas a partir de runtime).

Como si consigo ejecutar los scripts (pero no directamente el comando que hay dentro de ellos) por ahora seguiré con una versión un poco más chapucera: poner el script también como una cosa que se pueda configurar desde el archivo XML de configuración, aunque no me gusta es una solución parcial (el proyecto tampoco necesita elegancia/buena programación, así que aunque sea warrillo tampoco pasa nada).

Así que he editado el script para que acepte todos los parámetros que tenia configurables (en vez de dejarlos como constantes dentro del código que los pille de un argumento) y el resultado es el mismo, a la espera de seguir haciendo alguna pequeña prueba a ver si consigo ejecutar keytool en vez de solo "script.bat"

ProcessBuilder pb = new ProcessBuilder(
    runtimeDir + System.getProperty("file.separator") + scriptPath,
    username, password,
    keystore, alias, petition, cert,
    Integer.toString(keysize), Integer.toString(validity),
    CAalias, CAcert, CAkey, CApass
);
pb.directory(runtimeDir);
pb.start();
JuAn4k4

Yo he probado en un minuto a hacer:


public final static void main(String[] args) {
        try {
            // Execute a command with an argument
            String command = "keytool -list";
            Process child = Runtime.getRuntime().exec(command);
        // Get the input stream and read from it
            InputStream in = child.getInputStream();
            int c;
            while ((c = in.read()) != -1) {
                System.out.print((char) c);
            }
            in.close();


    } catch (IOException e) {
        e.printStackTrace();
    }
   }

Para parametros con espacios tendras que usar array de String para el commands + params:

String[] commands = new String[]{"grep", "hello world", "/tmp/f.txt"};
    commands = new String[]{"grep", "hello world", "c:\\Documents and Settings\\f.txt"};
    Process child = Runtime.getRuntime().exec(commands);

Y va perfectamente.

1 1 respuesta
dagavi

#4 "Para parametros con espacios tendras que usar array de String para el commands + params: "

Creo que eso es el problema, y concretamente en la línea: OU=BiC User
Al tene respacios dejaría de ir, por ahora estoy tirando con el inputstream que has puesto (mira que no se me había ocurrido hacerlo -.-) viendo que retorna y funciona OK, iré metiendo más comandos.

Muchas gracias a los 2, #2 y #4 , ya funciona sin tener que recurrir a chapuzas de meter un script en medio xD

Usuarios habituales

  • dagavi
  • JuAn4k4
  • LOc0