/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2013 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.xul.common.preview;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.ValueMetaInterface;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.TransPreviewFactory;
import org.pentaho.di.trans.debug.BreakPointListener;
import org.pentaho.di.trans.debug.StepDebugMeta;
import org.pentaho.di.trans.debug.TransDebugMeta;
import org.pentaho.di.trans.step.BaseStepMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;
import org.pentaho.ui.xul.XulDomContainer;
import org.pentaho.ui.xul.XulException;
import org.pentaho.ui.xul.XulLoader;
import org.pentaho.ui.xul.XulRunner;
import org.pentaho.ui.xul.XulSettingsManager;
import org.pentaho.ui.xul.binding.BindingFactory;
import org.pentaho.ui.xul.components.XulProgressmeter;
import org.pentaho.ui.xul.containers.XulDialog;
import org.pentaho.ui.xul.impl.AbstractXulEventHandler;
import org.pentaho.ui.xul.impl.XulEventHandler;
/**
* User: gmoran Date: Jan 28, 2013
*/
public abstract class AbstractPreviewRowsXulDialog extends AbstractXulEventHandler {
protected Object parent;
private String xulFile;
private XulDomContainer container;
private XulRunner runner;
protected XulDialog xulDialog;
protected BindingFactory bf;
protected LogChannel log;
private BaseStepMeta meta = null;
private int maxRows;
private XulProgressmeter progressMeter;
public AbstractPreviewRowsXulDialog( Object parent, BaseStepMeta stepMeta, int maxRows ) {
this.xulFile = "org/pentaho/di/ui/xul/common/preview/xul/preview_rows.xul";
this.parent = parent;
this.meta = stepMeta;
this.maxRows = maxRows;
log = new LogChannel( "Row Preview" );
try {
initializeXul();
progressMeter = (XulProgressmeter) document.getElementById( "progress" );
} catch ( Exception e ) {
log.logError( "Error initializing dialog...", e );
throw new IllegalStateException( "Cannot load dialog due to error in initialization.", e );
}
}
public void init() {
final List<String> columns = new ArrayList<String>();
final List<Object[]> data = new ArrayList<Object[]>();
previewStep( data, columns );
createPreviewRows( data, columns );
}
/**
* TODO: This method should not be necessary once a XulTable can take bindings for creating xulcolumn definitions at
* runtime and mapping the data to the columns.
*
* @param data
* @param columns
*/
protected abstract void createPreviewRows( List<Object[]> data, List<String> columns );
/**
* TODO: This method needs to communicate and control a UI wait status indicator (aka, progress monitor)
*
* @param data
* @param columns
*/
protected void previewStep( List<Object[]> data, List<String> columns ) {
TransMeta previewMeta =
TransPreviewFactory.generatePreviewTransformation( null, (StepMetaInterface) meta, "data_sync" );
final Trans trans = new Trans( previewMeta );
try {
trans.prepareExecution( null );
TransDebugMeta transDebugMeta = new TransDebugMeta( previewMeta );
StepMeta stepMeta = previewMeta.findStep( "data_sync" );
StepDebugMeta stepDebugMeta = new StepDebugMeta( stepMeta );
stepDebugMeta.setReadingFirstRows( true );
stepDebugMeta.setRowCount( maxRows );
transDebugMeta.getStepDebugMetaMap().put( stepMeta, stepDebugMeta );
transDebugMeta.addRowListenersToTransformation( trans );
transDebugMeta.addBreakPointListers( new BreakPointListener() {
public void breakPointHit( TransDebugMeta transDebugMeta, StepDebugMeta stepDebugMeta,
RowMetaInterface rowBufferMeta, List<Object[]> rowBuffer ) {
System.out.println( "break point hit...".concat( String.valueOf( stepDebugMeta.getRowCount() ) ) );
trans.stopAll();
}
} );
trans.startThreads();
/*
* if (previewMeta.getTransformationType() == TransformationType.Normal) { trans.waitUntilFinished(); }
*/
int previousPct = 0;
while ( !trans.isFinished() ) {
// How many rows are done?
int nrDone = 0;
int nrTotal = 0;
for ( StepDebugMeta debug : transDebugMeta.getStepDebugMetaMap().values() ) {
nrDone += debug.getRowBuffer().size();
nrTotal += debug.getRowCount();
}
int pct = 100 * nrDone / nrTotal;
int worked = pct - previousPct;
if ( worked > 0 ) {
this.progressMeter.setValue( worked );
}
previousPct = pct;
// Change the percentage...
try {
Thread.sleep( 500 );
} catch ( InterruptedException e ) {
// Ignore sleep interruption exception
}
}
trans.stopAll();
data.addAll( stepDebugMeta.getRowBuffer() );
RowMetaInterface rowMeta = stepDebugMeta.getRowBufferMeta();
for ( int i = 0; i < rowMeta.size(); i++ ) {
ValueMetaInterface v = rowMeta.getValueMeta( i );
columns.add( v.getName() );
}
} catch ( KettleException e ) {
this.logError( "Data preview failed.", e );
}
}
/**
* The implementors of this method should call the sibling method initializeXul(XulLoder, BindingFactory, XulRunner,
* parent) with the desired Xul implementation classes - SWT or Swing.
*
* @throws XulException
*/
protected abstract void initializeXul() throws XulException;
protected void initializeXul( XulLoader loader, BindingFactory bindingFactory, XulRunner runner, Object parent ) throws XulException {
bf = bindingFactory;
this.runner = runner;
loader.registerClassLoader( getClass().getClassLoader() );
loader.setSettingsManager( getSettingsManager() );
loader.setOuterContext( parent );
container = loader.loadXul( xulFile, getResourceBundle() );
bf.setDocument( container.getDocumentRoot() );
for ( XulEventHandler h : getEventHandlers() ) {
container.addEventHandler( h );
}
this.runner.addContainer( container );
// try and get the dialog
xulDialog = (XulDialog) container.getDocumentRoot().getRootElement();
runner.initialize();
}
public abstract XulSettingsManager getSettingsManager();
public abstract ResourceBundle getResourceBundle();
protected BindingFactory getBindingFactory() {
return bf;
}
protected List<XulEventHandler> getEventHandlers() {
return Collections.singletonList( (XulEventHandler) this );
}
public String getName() {
return "handler";
}
// TODO: decide what to return here...
public String open() {
xulDialog.show();
return null;
}
public void close() {
xulDialog.hide();
}
public abstract void onAccept();
public abstract void onCancel();
protected abstract Class<?> getClassForMessages();
public abstract void dispose();
public boolean isBasic() {
return log.isBasic();
}
public boolean isDetailed() {
return log.isDetailed();
}
public boolean isDebug() {
return log.isDebug();
}
public boolean isRowLevel() {
return log.isRowLevel();
}
public void logMinimal( String message ) {
log.logMinimal( message );
}
public void logMinimal( String message, Object... arguments ) {
log.logMinimal( message, arguments );
}
public void logBasic( String message ) {
log.logBasic( message );
}
public void logBasic( String message, Object... arguments ) {
log.logBasic( message, arguments );
}
public void logDetailed( String message ) {
log.logDetailed( message );
}
public void logDetailed( String message, Object... arguments ) {
log.logDetailed( message, arguments );
}
public void logDebug( String message ) {
log.logDebug( message );
}
public void logDebug( String message, Object... arguments ) {
log.logDebug( message, arguments );
}
public void logRowlevel( String message ) {
log.logRowlevel( message );
}
public void logRowlevel( String message, Object... arguments ) {
log.logRowlevel( message, arguments );
}
public void logError( String message ) {
log.logError( message );
}
public void logError( String message, Throwable e ) {
log.logError( message, e );
}
public void logError( String message, Object... arguments ) {
log.logError( message, arguments );
}
}