Visualizzazione dei risultati da 1 a 2 su 2
  1. #1

    [JAVA] JProgressBar kettle setProgress() problema

    Ciao a tutti/e,
    premetto che prima di postare ho cercato su Internet e ho utilizzato la ricerca del forum, ma forse per distrazione mia non ho trovato ciò che cercavo.

    Sto utilizzando le swing, i Task e Kettle per eseguire delle lavorazioni.
    Quello che devo fare è eseguire un Task che esegue una lavorazione kettle per l'aggiornamento di un DB Derby tramite actionPerformed di un JButton.
    Il tutto funziona bene fino a quando non mi hanno chiesto di aggiungere una barra di progressione per vedere a che punto è la lavorazione essendo molto lunga (un paio d'ore).

    Ho scritto una classe KettleTask che estende Task: la classe esegue le lavorazioni e cerca di determinare a che punto è la lavorazione:
    codice:
    package herarc;
    
    import java.util.List;
    import javax.swing.JButton;
    import javax.swing.JLabel;
    import org.jdesktop.application.Application;
    import org.pentaho.di.core.KettleEnvironment;
    import org.pentaho.di.core.Result;
    import org.pentaho.di.core.util.EnvUtil;
    import org.pentaho.di.job.Job;
    import org.pentaho.di.job.JobEntryListener;
    import org.pentaho.di.job.JobMeta;
    import org.pentaho.di.job.entry.JobEntryCopy;
    import org.pentaho.di.job.entry.JobEntryInterface;
    
    /**
     *
     * @author marco
     */
    public class KettleTask extends org.jdesktop.application.Task<Object, Void> {
    
        /*
         * ATTRIBUTI
         */
        private int constructor;              //Contiene il costruttore utilizzato
        private int process;                   //numero del processo Kettle da eseguire
        private Job job;                        //contiene il job etl in esecuzione
        private JobMeta jobMeta;           //contiene il meta job, utile per job
        private String res;                    //contiene il risultato del job
        private JButton button;              //pulsante da abilitare una volta terminata l'esecuzione etl
        private JLabel label;                  //Label per mostrare i messaggi kettle all'utente
        private String file;                    //contiene il nome del file etl da eseguire
    
        /*
         * COSTRUTTORI
         */
        //esegue il file in base al numero del processo
        public KettleTask(Application app, int p, JButton b, JLabel l) {
            super(app);
            this.setConstructor(0);
            this.setProcess(p);
            this.setFile();
            this.setButton(b);
            this.setLabel(l);
        }
    
        //esegue il file che gli viene passato come parametro
        public KettleTask(Application app, String file, JButton b, JLabel l) {
            super(app);
            this.setConstructor(1);
            this.setFile(file);
            this.setButton(b);
            this.setLabel(l);
        }
    
        /*
         * METODI DI OVERRIDES
         */
        @Override
        //metodo che viene eseguito durante l'esecuzione del job
        protected Void doInBackground() throws Exception {
            this.initKettle();
            this.setProcessProgressValues();
            this.runKettle();
            return null;
        }
    
        @Override
        //metodo che viene eseguito quando il processo è terminato
        protected void finished() {
            this.getButton().setEnabled(true);
            super.finished();
        }
    
        /*
         * METODI
         */
        //metodo che inizializza Kettle
        public void initKettle() {
            this.getButton().setEnabled(false);
            try {
                KettleEnvironment.init();
                EnvUtil.environmentInit();
                this.setJobMeta(new JobMeta(this.getFile(), null));
                this.setJob(new Job(null, this.getJobMeta()));
            } catch (Exception ex) {
                System.out.print("Errore kettle:\n" + ex);
            }
        }
        //metodo che lancia Kettle
    
        public void runKettle() {
            this.getJob().start();
            this.getJob().waitUntilFinished();
            if (this.getJob().getErrors() == 0) {
                this.updateRes("\nTrasformazione eseguita.\nErrori Rilevati: " + job.getResult().getNrErrors());
            } else {
                this.setRes("Errore durante la trasformazione!");
            }
        }
        //Controlla lo stato delle lavorazioni kettle e lo manda alla maschera
        public void setProcessProgressValues() {
            this.getJob().addJobEntryListener(new JobEntryListener() {
    
                int i = 0;
    
                public void beforeExecution(Job job, JobEntryCopy jec, JobEntryInterface jei) {
                    i++;
                    List<JobEntryCopy> jobCopies1 = job.getJobMeta().getJobCopies();
                    int size = jobCopies1.size() - 2;
                    float perc = ((float) i / (float) size) * 100;
                    System.out.print("inizio job " + i + " di " + size + " (" + (int) perc + "%)\n");
                    setProgress((int) perc);
                }
    
                public void afterExecution(Job job, JobEntryCopy jec, JobEntryInterface jei, Result result) {
                    //System.out.print("termino un job\n");
                }
            });
    
        }
    
        public void setProcessFile() {
            switch (this.getProcess()) {
                case 0:
                    this.setFile("kettle/job_recre.kjb");
                    break;
                case 1:
                    this.setFile("kettle/carica_importi.kjb");
                    break;
            }
        }
    
        /*
         * METODI DI SET/GET E UPDATE
         */
        //setter
        private void setConstructor(int c) {
            this.constructor = c;
        }
    
        private void setProcess(int n) {
            this.process = n;
        }
    
        private void setJob(Job j) {
            this.job = j;
        }
    
        private void setJobMeta(JobMeta j) {
            this.jobMeta = j;
        }
    
        private void setRes(String r) {
            this.res = r;
        }
    
        private void setButton(JButton b) {
            this.button = b;
        }
    
        private void setLabel(JLabel l) {
            this.label = l;
        }
    
        private void setFile(String f) {
            this.file = f;
        }
    
        private void setFile() {
            this.setProcessFile();
        }
        //getter
        public int getConstructor() {
            return this.constructor;
        }
    
        public int getProcess() {
            return this.process;
        }
    
        public Job getJob() {
            return this.job;
        }
    
        public JobMeta getJobMeta() {
            return this.jobMeta;
        }
    
        public String getRes() {
            return this.res;
        }
    
        public JButton getButton() {
            return this.button;
        }
    
        public JLabel getLabel() {
            return this.label;
        }
    
        public String getFile() {
            return this.file;
        }
        //update
    
        private void updateRes(String s) {
            this.res = this.res + s;
        }
    }
    DI seguito inserisco il codice che dovrebbe mostrare la progressione:
    codice:
    public void propertyChange(java.beans.PropertyChangeEvent evt) {
                    String propertyName = evt.getPropertyName();
                    if ("started".equals(propertyName)) {
                        //mostro la progressBar
                        showProgressBar();
                        if (!busyIconTimer.isRunning()) {
                            statusAnimationLabel.setIcon(busyIcons[0]);
                            busyIconIndex = 0;
                            busyIconTimer.start();
                        }
                    } else if ("done".equals(propertyName)) {
                        //nascondo la progressBar
                        if (bar.isVisible()) {
                            hideProgressBar();
                        }
                        busyIconTimer.stop();
                        statusAnimationLabel.setIcon(idleIcon);
                    } else if ("message".equals(propertyName)) {
                        String text = (String) (evt.getNewValue());
                        statusMessageLabel.setText((text == null) ? "" : text);
                        messageTimer.restart();
                    } else if ("progress".equals(propertyName)) {
                        //setto valore nella progressBar
                        int value = (Integer) evt.getNewValue();
                        bar.setValue(value);
                    }
                }
            });
    E questo invece è il codice che viene eseguito alla pressione del JButton:
    codice:
        private void aggiornaDBButtonActionPerformed(java.awt.event.ActionEvent evt) {                                         
            Task kettleTask = new KettleTask(getApplication(), 0, aggiornaDBButton, progressLabel);
            org.jdesktop.application.ApplicationContext appC = Application.getInstance().getContext();
            TaskService ts = appC.getTaskService();
            TaskMonitor tm = appC.getTaskMonitor();
            ts.execute(kettleTask);
            tm.setForegroundTask(kettleTask);
        }
    Uso NetBeans 6.9.1 e quindi la gestione del progress tramite TaskMonitor è quella di default del progetto che ho creato con l'IDE in questione.

    Il tutto funziona se non per il setProgress() che non ne vuole sapere di essere eseguito, come se qualcosa tenesse tutto bloccato fino alla fine del doInBackground(), nonostante setProcessProgressValues() comunque funzioni perché il System.out.print(...) viene eseguito correttamente con i dati giusti.

    Facendo delle prove ho notato che modificando la classe KettleTask in questo modo il progresso mi funziona e la progressBar viene aggiornata:
    codice:
    ...
    ...
    ...
    ...
        @Override
        //metodo che viene eseguito durante l'esecuzione del job
        protected Void doInBackground() throws Exception {
            this.initKettle();
            this.runKettle();
            return null;
        }
    ...
    ...
    ...
    ...
    public void initKettle() {
            this.getButton().setEnabled(false);
            try {
                KettleEnvironment.init();
                EnvUtil.environmentInit();
                setProgress(50);
                this.setJobMeta(new JobMeta(this.getFile(), null));
                this.setJob(new Job(null, this.getJobMeta()));
            } catch (Exception ex) {
                System.out.print("Errore kettle:\n" + ex);
            }
        }
    Se invece invoco setProgress(50); dopo this.setJobMeta(...); come di seguito la progressBar non viene aggiornata:
    codice:
    ...
    ...
    ...
    ...
        @Override
        //metodo che viene eseguito durante l'esecuzione del job
        protected Void doInBackground() throws Exception {
            this.initKettle();
            this.runKettle();
            return null;
        }
    ...
    ...
    ...
    ...
    public void initKettle() {
            this.getButton().setEnabled(false);
            try {
                KettleEnvironment.init();
                EnvUtil.environmentInit();
                this.setJobMeta(new JobMeta(this.getFile(), null));
                setProgress(50);
                this.setJob(new Job(null, this.getJobMeta()));
            } catch (Exception ex) {
                System.out.print("Errore kettle:\n" + ex);
            }
        }
    Non posso chiaramente richiamare setProcessProgressValues(); prima della creazione dell'oggetto Job o JobMeta perché incorrerei in un nullPointerException.

    Nessuno di voi conosce un modo per far si che setProgress(50) funzioni anche dopo la creazione dell'oggetto JobMeta() e Job()?

    Ringrazio in anticipo chiunque dedicherà il suo tempo e le sue competenze a questo problema.

  2. #2
    Mi sento molto stupido, ho risolto nella maniera più ovvia!
    Posto la soluzione in modo che possa servire anche a qualcun altro.
    Bastava aggiungere:
    codice:
    Thread.sleep(100);
    prima di
    codice:
    setProgress(perc)
    in questo modo:
    codice:
        public void setProcessProgressValues() {
            this.getJob().addJobEntryListener(new JobEntryListener() {
    
                int i = 0;
    
                public void beforeExecution(Job job, JobEntryCopy jec, JobEntryInterface jei) {
                    i++;
                    List<JobEntryCopy> jobCopies1 = job.getJobMeta().getJobCopies();
                    int size = jobCopies1.size() - 2;
                    float perc = ((float) i / (float) size) * 100;
                    System.out.print("job " + i + " di " + size + " (" + (int) perc + "%)\n");
                    setMessage("job " + i + " di " + size + " (" + (int) perc + "%)\n");
                    try {
                        Thread.sleep(100);
                        setProgress((int) perc);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(KettleTask.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
    
                public void afterExecution(Job job, JobEntryCopy jec, JobEntryInterface jei, Result result) {
                }
            });
    
        }
    Posto la classe KettleTask nel caso qualcuno abbia bisogno di eseguire job Kettle da java mostrando una progressione, magari non sarà perfetta e sicuramente da adattare alle esigenze dei vari utilizzi (per esempio l'uso di transformation piuttosto che job), ma almeno do il mio contributo per evitare che qualcuno impazzisca per questa cosa come ho fatto io!
    codice:
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.JButton;
    import javax.swing.JLabel;
    import org.jdesktop.application.Application;
    import org.jdesktop.application.Task;
    import org.pentaho.di.core.KettleEnvironment;
    import org.pentaho.di.core.Result;
    import org.pentaho.di.core.util.EnvUtil;
    import org.pentaho.di.job.Job;
    import org.pentaho.di.job.JobEntryListener;
    import org.pentaho.di.job.JobMeta;
    import org.pentaho.di.job.entry.JobEntryCopy;
    import org.pentaho.di.job.entry.JobEntryInterface;
    
    /**
     *
     * @author marco
     */
    public class KettleTask extends org.jdesktop.application.Task<Object, Void> {
    
        /*
         * ATTRIBUTI
         */
        private Job job;                        //contiene il job etl in esecuzione
        private JobMeta jobMeta;                //contiene il meta job, utile per job
        private String res;                     //contiene il risultato del job
        private JButton button;                 //pulsante da abilitare una volta terminata l'esecuzione etl
        private String file;                    //contiene il nome del file etl da eseguire
    
        /*
         * COSTRUTTORE
         */
        public KettleTask(Application app, String file, JButton b) {
            super(app);
            this.setFile(file);
            this.setButton(b);
        }
    
        /*
         * METODI DI OVERRIDES
         */
        @Override
        //metodo che viene eseguito durante l'esecuzione del job
        protected Void doInBackground() throws Exception {
            this.initKettle();
            this.setProcessProgressValues();
            this.runKettle();
            return null;
        }
    
        @Override
        //metodo che viene eseguito quando il processo è terminato
        protected void finished() {
            this.getButton().setEnabled(true);
            super.finished();
        }
    
        /*
         * METODI
         */
        //metodo che inizializza Kettle
        public void initKettle() {
            this.getButton().setEnabled(false);
            try {
                KettleEnvironment.init();
                EnvUtil.environmentInit();
                this.setJobMeta(new JobMeta(this.getFile(), null));
                this.setJob(new Job(null, this.getJobMeta()));
            } catch (Exception ex) {
                System.out.print("Errore kettle:\n" + ex);
            }
        }
        //metodo che lancia Kettle
    
        public void runKettle() {
            this.getJob().start();
            this.getJob().waitUntilFinished();
            if (this.getJob().getErrors() == 0) {
                this.updateRes("\nTrasformazione eseguita.\nErrori Rilevati: " + job.getResult().getNrErrors());
            } else {
                this.setRes("Errore durante la trasformazione!");
            }
        }
        //Controlla lo stato delle lavorazioni kettle e lo manda alla maschera
    
        public void setProcessProgressValues() {
            this.getJob().addJobEntryListener(new JobEntryListener() {
    
                int i = 0;
    
                public void beforeExecution(Job job, JobEntryCopy jec, JobEntryInterface jei) {
                    i++;
                    List<JobEntryCopy> jobCopies1 = job.getJobMeta().getJobCopies();
                    int size = jobCopies1.size() - 2;
                    float perc = ((float) i / (float) size) * 100;
                    System.out.print("job " + i + " di " + size + " (" + (int) perc + "%)\n");
                    try {
                        Thread.sleep(100);
                        setProgress((int) perc);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(KettleTask.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
    
                public void afterExecution(Job job, JobEntryCopy jec, JobEntryInterface jei, Result result) {
                }
            });
    
        }
    
        /*
         * METODI DI SET/GET E UPDATE
         */
        //set
        private void setProcess(int n) {
            this.process = n;
        }
    
        private void setJob(Job j) {
            this.job = j;
        }
    
        private void setJobMeta(JobMeta j) {
            this.jobMeta = j;
        }
    
        private void setRes(String r) {
            this.res = r;
        }
    
        private void setButton(JButton b) {
            this.button = b;
        }
    
        private void setFile(String f) {
            this.file = f;
        }
    
        private void setFile() {
            this.setProcessFile();
        }
    
        //get
        public int getProcess() {
            return this.process;
        }
    
        public Job getJob() {
            return this.job;
        }
    
        public JobMeta getJobMeta() {
            return this.jobMeta;
        }
    
        public String getRes() {
            return this.res;
        }
    
        public JButton getButton() {
            return this.button;
        }
    
        public String getFile() {
            return this.file;
        }
        //update
    
        private void updateRes(String s) {
            this.res = this.res + s;
        }
    }
    L'utilizzo della classe avviene tramite actionPerformed di un pulsante come qui di seguito:
    codice:
        private void jButtonActionPerformed(java.awt.event.ActionEvent evt) {                                         
            showProgressBar();
            jButton.setEnabled(false);
            Task kettleTask = new KettleTask(getApplication(), "kettle_job.etl", jButton);
            org.jdesktop.application.ApplicationContext appC = Application.getInstance().getContext();
            TaskService ts = appC.getTaskService();
            TaskMonitor tm = appC.getTaskMonitor();
            ts.execute(kettleTask);
            tm.setForegroundTask(kettleTask);
        }
    la funzione showProgressBar() non fa altro che mostrare la barra di progressione, ma è un argomento che non ho intenzione di trattare ora.
    Il costruttore della classe KettleTask prende in ingresso l'applicazione stessa getApplication(), il nome del file etl da eseguire e il pulsante che lo esegue in modo da poterlo disabilitare durante l'esecuzione del job e successivamente abilitarlo quando il task conclude le sue operazioni.

    L'utilizzo della progressBar può essere qualcosa del genere:
    codice:
    TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
    taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
    
                public void propertyChange(java.beans.PropertyChangeEvent evt) {
                    String propertyName = evt.getPropertyName();
                    if ("progress".equals(propertyName)) {
                        //setto valore nella progressBar
                        int value = (Integer) evt.getNewValue();
                        progressBar.setValue(value);
                    }
                }
    Questa parte di ascolto dei task può essere inserita nel costruttore della swing view.

    In questo modo riusciamo ad eseguire Kettle in un task separato dall'applicazione e a controllarne lo stato di avanzamento, ovviamente lo stato di avanzamento non include una stima temporale.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.