/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.pentaho.di.ui.spoon.job; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.Result; import org.pentaho.di.core.gui.JobTracker; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.job.JobEntryResult; import org.pentaho.di.ui.core.gui.GUIResource; import org.pentaho.di.ui.core.widget.TreeMemory; import org.pentaho.di.ui.spoon.Spoon; import org.pentaho.di.ui.spoon.delegates.SpoonDelegate; public class JobGridDelegate extends SpoonDelegate { private static Class<?> PKG = JobGraph.class; // for i18n purposes, needed by Translator2!! public static final long REFRESH_TIME = 100L; public static final long UPDATE_TIME_VIEW = 1000L; private static final String STRING_CHEF_LOG_TREE_NAME = "Job Log Tree"; private JobGraph jobGraph; private CTabItem jobGridTab; private Tree wTree; public JobTracker jobTracker; public int previousNrItems; private int nrRow = 0; /** * @param spoon * @param transGraph */ public JobGridDelegate( Spoon spoon, JobGraph transGraph ) { super( spoon ); this.jobGraph = transGraph; } /** * Add a grid with the execution metrics per step in a table view * */ public void addJobGrid() { // First, see if we need to add the extra view... // if ( jobGraph.extraViewComposite == null || jobGraph.extraViewComposite.isDisposed() ) { jobGraph.addExtraView(); } else { if ( jobGridTab != null && !jobGridTab.isDisposed() ) { // just set this one active and get out... // jobGraph.extraViewTabFolder.setSelection( jobGridTab ); return; } } jobGridTab = new CTabItem( jobGraph.extraViewTabFolder, SWT.NONE ); jobGridTab.setImage( GUIResource.getInstance().getImageShowGrid() ); jobGridTab.setText( BaseMessages.getString( PKG, "Spoon.TransGraph.GridTab.Name" ) ); addControls(); jobGridTab.setControl( wTree ); jobGraph.extraViewTabFolder.setSelection( jobGridTab ); } /** * Add the controls to the tab */ private void addControls() { // Create the tree table... wTree = new Tree( jobGraph.extraViewTabFolder, SWT.V_SCROLL | SWT.H_SCROLL ); wTree.setHeaderVisible( true ); TreeMemory.addTreeListener( wTree, STRING_CHEF_LOG_TREE_NAME ); TreeColumn column1 = new TreeColumn( wTree, SWT.LEFT ); column1.setText( BaseMessages.getString( PKG, "JobLog.Column.JobJobEntry" ) ); column1.setWidth( 200 ); TreeColumn column2 = new TreeColumn( wTree, SWT.LEFT ); column2.setText( BaseMessages.getString( PKG, "JobLog.Column.Comment" ) ); column2.setWidth( 200 ); TreeColumn column3 = new TreeColumn( wTree, SWT.LEFT ); column3.setText( BaseMessages.getString( PKG, "JobLog.Column.Result" ) ); column3.setWidth( 100 ); TreeColumn column4 = new TreeColumn( wTree, SWT.LEFT ); column4.setText( BaseMessages.getString( PKG, "JobLog.Column.Reason" ) ); column4.setWidth( 200 ); TreeColumn column5 = new TreeColumn( wTree, SWT.LEFT ); column5.setText( BaseMessages.getString( PKG, "JobLog.Column.Filename" ) ); column5.setWidth( 200 ); TreeColumn column6 = new TreeColumn( wTree, SWT.RIGHT ); column6.setText( BaseMessages.getString( PKG, "JobLog.Column.Nr" ) ); column6.setWidth( 50 ); TreeColumn column7 = new TreeColumn( wTree, SWT.RIGHT ); column7.setText( BaseMessages.getString( PKG, "JobLog.Column.LogDate" ) ); column7.setWidth( 120 ); FormData fdTree = new FormData(); fdTree.left = new FormAttachment( 0, 0 ); fdTree.top = new FormAttachment( 0, 0 ); fdTree.right = new FormAttachment( 100, 0 ); fdTree.bottom = new FormAttachment( 100, 0 ); wTree.setLayoutData( fdTree ); final Timer tim = new Timer( "JobGrid: " + jobGraph.getMeta().getName() ); TimerTask timtask = new TimerTask() { public void run() { Display display = jobGraph.getDisplay(); if ( display != null && !display.isDisposed() ) { display.asyncExec( new Runnable() { public void run() { // Check if the widgets are not disposed. // This happens is the rest of the window is not yet disposed. // We ARE running in a different thread after all. // // TODO: add a "auto refresh" check box somewhere if ( !wTree.isDisposed() ) { refreshTreeTable(); } } } ); } } }; tim.schedule( timtask, 10L, 2000L ); // refresh every 2 seconds... jobGraph.jobLogDelegate.getJobLogTab().addDisposeListener( new DisposeListener() { public void widgetDisposed( DisposeEvent disposeEvent ) { tim.cancel(); } } ); } /** * Refresh the data in the tree-table... Use the data from the JobTracker in the job */ private void refreshTreeTable() { if ( jobTracker != null ) { int nrItems = jobTracker.getTotalNumberOfItems(); if ( nrItems != previousNrItems ) { // Allow some flickering for now ;-) wTree.removeAll(); // Re-populate this... TreeItem treeItem = new TreeItem( wTree, SWT.NONE ); String jobName = jobTracker.getJobName(); if ( Utils.isEmpty( jobName ) ) { if ( !Utils.isEmpty( jobTracker.getJobFilename() ) ) { jobName = jobTracker.getJobFilename(); } else { jobName = BaseMessages.getString( PKG, "JobLog.Tree.StringToDisplayWhenJobHasNoName" ); } } treeItem.setText( 0, jobName ); TreeMemory.getInstance().storeExpanded( STRING_CHEF_LOG_TREE_NAME, new String[] { jobName }, true ); for ( int i = 0; i < jobTracker.nrJobTrackers(); i++ ) { addTrackerToTree( jobTracker.getJobTracker( i ), treeItem ); } previousNrItems = nrItems; TreeMemory.setExpandedFromMemory( wTree, STRING_CHEF_LOG_TREE_NAME ); } } } private void addTrackerToTree( JobTracker jobTracker, TreeItem parentItem ) { try { if ( jobTracker != null ) { TreeItem treeItem = new TreeItem( parentItem, SWT.NONE ); if ( nrRow % 2 != 0 ) { treeItem.setBackground( GUIResource.getInstance().getColorBlueCustomGrid() ); } nrRow++; if ( jobTracker.nrJobTrackers() > 0 ) { // This is a sub-job: display the name at the top of the list... treeItem.setText( 0, BaseMessages.getString( PKG, "JobLog.Tree.JobPrefix" ) + jobTracker.getJobName() ); // then populate the sub-job entries ... for ( int i = 0; i < jobTracker.nrJobTrackers(); i++ ) { addTrackerToTree( jobTracker.getJobTracker( i ), treeItem ); } } else { JobEntryResult result = jobTracker.getJobEntryResult(); if ( result != null ) { String jobEntryName = result.getJobEntryName(); if ( !Utils.isEmpty( jobEntryName ) ) { treeItem.setText( 0, jobEntryName ); treeItem.setText( 4, Const.NVL( result.getJobEntryFilename(), "" ) ); } else { treeItem.setText( 0, BaseMessages.getString( PKG, "JobLog.Tree.JobPrefix2" ) + jobTracker.getJobName() ); } String comment = result.getComment(); if ( comment != null ) { treeItem.setText( 1, comment ); } Result res = result.getResult(); if ( res != null ) { treeItem.setText( 2, res.getResult() ? BaseMessages.getString( PKG, "JobLog.Tree.Success" ) : BaseMessages.getString( PKG, "JobLog.Tree.Failure" ) ); treeItem.setText( 5, Long.toString( res.getEntryNr() ) ); if ( res.getResult() ) { treeItem.setForeground( GUIResource.getInstance().getColorSuccessGreen() ); } else { treeItem.setForeground( GUIResource.getInstance().getColorRed() ); } } String reason = result.getReason(); if ( reason != null ) { treeItem.setText( 3, reason ); } Date logDate = result.getLogDate(); if ( logDate != null ) { treeItem.setText( 6, new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" ).format( logDate ) ); } } } treeItem.setExpanded( true ); } } catch ( Exception e ) { log.logError( Const.getStackTracker( e ) ); } } public CTabItem getJobGridTab() { return jobGridTab; } public void setJobTracker( JobTracker jobTracker ) { this.jobTracker = jobTracker; } }