Newsgroup: it.comp.java
Titolo: Process output e GUI

Ciao a tutti,
il mio problema è credo abbastanza comune e variamente documentato ma
non riesco a risolverlo completamente.
La mia applicazione Java è un'interfaccia GUI che ha il solo scopo di
lanciare un processo esterno sviluppato in C.
Quello che vorrei ottenere è la visualizzazione in tempo reale
dell'output del processo su una textarea della mia GUI.
Quello che finora ho ottenuto è in effetti la corretta esecuzione
dell'eseguibile e la visualizzazione dell'output che però avviene solo
al termine del processo. Durante tutta l'elaborazione l'interfaccia è
bloccata.
I passi che seguo sono questi:
- il pulsante di lancio ha impostata una Action
- nel metodo che viene richiamato dalla Action creo l'oggetto Task
- nel metodo doInBackground del Task lancio il processo con
Process.exec()
- prendo lo standard input e standard error del processo e li faccio
gestire da un Thread separato che ad ogni riga letta fa un'append su
una TextArea della mia applicazione
Quindi oltre al thread principale dell'applicazione durante il lancio
dell'eseguibile viene
- creato un nuovo thread
- dentro questo thread si crea il processo esterno
- dentro questo thread si creano due nuovi thread che leggono gli
Stream del processo
- questi threads di lettura fanno l'append sulla TextArea.
Sbaglio qualcosa concettualmente?
Se serve poi posso postare un po' di codice.
Grazie
Ciao
John


Ancora nessuna risposta, sigh!
Vedrò di mettere insieme un po' di codice da postarvi anche se è un
po' dispersivo.
Ciao

Va bene ecco il codice del mio Task.
Riesco a far funzionare quasi tutto ma c'è ancora una cosa che non va.
Forse il tutto dipende dall'eseguibile che lancio, sviluppato in C,
che in alcune circostanze va in errore "abnormal program termination"
con tanto di finestrella Microsoft Visual C++ Debug Library che
appare. L'errore dipende dai parametri di esecuzione, so come
riprodurlo anche da linea di comando e quindi non dipende dalla mia
interfaccia grafica.
Quel che non capisco è perchè in questo caso la cattura dell'output
non ritorna niente, mentre nel caso di lancio da linea di comando
nell'output a console vedo dove si è interrotto il programma e che
errore ha dato.
private class RunLRTaskWithViewer extends
org.jdesktop.application.Task<Object, Void> {
        RunTaskViewer rv; //JPanel
        String execCmd;
        String[] open;
        File workingDir;
        RunLRTaskWithViewer(org.jdesktop.application.Application app)
{
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to RunLRTask fields, here.
            super(app);
            try
            {
                rv =(RunTaskViewer) jPanelExec;
                execCmd = MainParametersModel.LR_EXE_FILE + " " +
                                getRunningModel().getFilename() + " "
+
                                getMainParamsModel().getOptionalParams
();
                open = convertInputString(execCmd);
                workingDir = new File(getMainParamsModel().getPathLR
());
                open[0] = workingDir.toString() + "\\" + open[0];
            }
            catch (Exception ex)
            {
                LaserRegioniApp.lrLogger.severe("Errore run
applicazione: " + ex.getMessage());
            }
        }
        @Override protected Object doInBackground() {
            try {
                // Your Task's code here.  This method runs
                // on a background thread, so don't reference
                // the Swing GUI from here.
                ProcessBuilder pb = new ProcessBuilder(open);
                pb.directory(workingDir);
                pb.redirectErrorStream(true);
                Process proc = pb.start();
                // any output?
                StreamGobbler outputGobbler = new StreamGobbler
(proc.getInputStream(), "OUTPUT");
                StreamGobbler errorGobbler = new StreamGobbler
(proc.getErrorStream(), "ERROR");
                // kick them off
                errorGobbler.start();
                outputGobbler.start();
                return proc.waitFor();
            }
            catch (InterruptedException iex)
            {
                LaserRegioniApp.lrLogger.severe("Errore esecuzione: "
+ iex.getMessage());
                return null;
            }
            catch (IOException ex)
            {
                LaserRegioniApp.lrLogger.severe("Errore esecuzione: "
+ ex.getMessage());
                return null;
            }
        }
        @Override protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
            rv.writeMessage("\n" + "Exit value = " + result);
        }
        /***
     * Classe per la lettura e il reindirizzamento di uno stream
     * sulla textarea di questo pannello
     */
    class StreamGobbler extends Thread
    {
        InputStream is;
        String type;
        StreamGobbler(InputStream is, String type)
        {
 
this.is
 = is;
            this.type = type;
        }
            @Override
        public void run()
        {
            try
            {
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String line=null;
                while ( (line = br.readLine()) != null)
                    rv.writeMessage("\n" + type + ">" + line);
                } catch (IOException ioe)
                  {
                    ioe.printStackTrace();
                  }
        }
    }
    }
Grazie
Ciao
John

 John
Sei riuscito a risolvere il problema ?


No, in realtà non sono riuscito a fare altre prove significative.
Magari non c'entra niente, ma secondo te può dipendere dal fatto che
l'eseguibile che lancio è compilato con le librerie di debug?
cercherò di procurarmi una versione compilata per la release e vedere
se il comportamento è lo stesso.
Tu vedi qualche problema o errore concettuale nel codice che ho
postato?
Grazie
Ciao
John

Aggiungo questa ipotesi: forse l'abort del processo che lancio non
lascia il tempo ai threads che leggono l'output di svolgere il proprio
lavoro?
è un'ipotesi plausibile?
Non so più cosa pensare.
Ciao
John


Per aggiornare la precedente ipotesi.
Visto che uso un BufferedReader su un InputStremReader cosa succede
quando il processo (e quindi l'InputStream) viene abortito? Io mi
aspettavo che il mio thread lanciasse una IOException e che quindi il
problema fosse proprio lì ma non vedo nessuna eccezione.
Ciao
John

Ho finalmente provato con una versione dell'eseguibile esterno
compilata in modalità RELEASE e il problema non si presenta più.
Quando il processo esterno va in errore il mio thread riesce comunque
a leggere correttamente l'output e riportare il testo sulla textarea.
Ciao
John