Transform视图界面创建及执行机制

创建Transform视图

读取*.ktr文件创建Transform视图流程

Spoon.java

private void loadLastUsedFile(
      LastUsedFile lastUsedFile, String repositoryName, boolean trackIt, boolean isStartup ) throws KettleException {
if ( lastUsedFile.isTransformation() ) {
        openFile( lastUsedFile.getFilename(), variables, rep != null );
      }
      if ( lastUsedFile.isJob() ) {
        openFile( lastUsedFile.getFilename(), variables, false );
      }

}

Spoon.java

public void openFile( String filename, VariableSpace variableSpace, boolean importfile ) {

  // otherwise try by looking at the root node if we were able to parse file
    // as XML
    if ( listener == null && root != null ) {
      for ( FileListener li : fileListeners ) {
        if ( li.acceptsXml( root.getNodeName() ) ) {
          listener = li;
          break;
        }
      }
    }

  loaded = listener.open( root, filename, importfile );
}

FileListener.java

public interface FileListener {

  public boolean open( Node transNode, String fname, boolean importfile ) throws KettleMissingPluginsException;

  public boolean save( EngineMetaInterface meta, String fname, boolean isExport );

  public void syncMetaName( EngineMetaInterface meta, String name );

  public boolean accepts( String fileName );

  public boolean acceptsXml( String nodeName );

  public String[] getSupportedExtensions();

  public String[] getFileTypeDisplayNames( Locale locale );

  public String getRootNodeName();
}

TransFileListener.java

public boolean open( Node transNode, String fname, String connection, boolean importfile )
    throws KettleMissingPluginsException {

    final Spoon spoon = Spoon.getInstance();
     TransMeta transMeta = new TransMeta();
     transMeta.loadXML( transNode, fname, spoon.getMetaStore(), spoon.getRepository(), ,..)
     spoon.addTransGraph( transMeta );

}

TransMeta.java loadXML 解析 *.ktr文件

  public void loadXML( Node transnode, String fname, IMetaStore metaStore, Repository rep, boolean setInternalVariables,
                       VariableSpace parentVariableSpace, OverwritePrompter prompter )
    throws KettleXMLException, KettleMissingPluginsException {
// Handle Steps
        int s = XMLHandler.countNodes( transnode, StepMeta.XML_TAG );      
        for ( int i = 0; i < s; i++ ) {
          Node stepnode = XMLHandler.getSubNodeByNr( transnode, StepMeta.XML_TAG, i );
          StepMeta stepMeta = new StepMeta( stepnode, databases, metaStore );
          stepMeta.setParentTransMeta( this ); // for tracing, retain hierarchy         
          StepMeta check = findStep( stepMeta.getName() );
          if ( check != null ) {
            if ( !check.isShared() ) {            
              addOrReplaceStep( stepMeta );
            } else {
              check.setDraw( stepMeta.isDrawn() ); // Just keep the drawn flag and location
              check.setLocation( stepMeta.getLocation() );
            }
          } else {
            addStep( stepMeta ); // simply add it.
          }
        }

  // Handle Hops
        //
        Node ordernode = XMLHandler.getSubNode( transnode, XML_TAG_ORDER );
        n = XMLHandler.countNodes( ordernode, TransHopMeta.XML_HOP_TAG );       
        for ( int i = 0; i < n; i++ ) {     
          Node hopnode = XMLHandler.getSubNodeByNr( ordernode, TransHopMeta.XML_HOP_TAG, i );
          TransHopMeta hopinf = new TransHopMeta( hopnode, steps );
          hopinf.setErrorHop( isErrorNode( errorHandlingNode, hopnode ) );
          addTransHop( hopinf );
        }

}

StepMeta.java类构造函数

public StepMeta( Node stepnode, List<DatabaseMeta> databases, IMetaStore metaStore ) throws KettleXMLException,
    KettlePluginLoaderException {
    this();
    PluginRegistry registry = PluginRegistry.getInstance();
      // Create a new StepMetaInterface object...
      PluginInterface sp = registry.findPluginWithId( StepPluginType.class, stepid, true );
      if ( sp == null ) {
        setStepMetaInterface( new MissingTrans( name, stepid ) );
      } else {
        setStepMetaInterface( (StepMetaInterface) registry.loadClass( sp ) );
      }
      if ( this.stepMetaInterface != null ) {
        if ( sp != null ) {
          stepid = sp.getIds()[0]; // revert to the default in case we loaded an alternate version
        }

        // Load the specifics from XML...
        if ( stepMetaInterface != null ) {
          loadXmlCompatibleStepMeta( stepMetaInterface, stepnode, databases );
          stepMetaInterface.loadXML( stepnode, databases, metaStore );
        }
      }       

  }

TextFileInputMeta类实现了*.ktr中type为TextFileInput的step的下的参数解析

public class TextFileInputMeta extends BaseFileInputMeta<BaseFileInputAdditionalField, BaseFileInputFiles, BaseFileField>
    implements StepMetaInterface, ResolvableResource, CsvInputAwareMeta {


@Override
  public void loadXML( Node stepnode, List<DatabaseMeta> databases, IMetaStore metaStore ) throws KettleXMLException {
    try {
      inputFiles.acceptingFilenames = YES.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "accept_filenames" ) );
      inputFiles.passingThruFields =
          YES.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "passing_through_fields" ) );
      inputFiles.acceptingField = XMLHandler.getTagValue( stepnode, "accept_field" );
      content.separator = XMLHandler.getTagValue( stepnode, "separator" );
      content.enclosure = XMLHandler.getTagValue( stepnode, "enclosure" );   
      String nempty = XMLHandler.getTagValue( stepnode, "noempty" );
      content.noEmptyLines = YES.equalsIgnoreCase( nempty ) || nempty == null;
      content.includeFilename = YES.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "include" ) );
      content.filenameField = XMLHandler.getTagValue( stepnode, "include_field" );
      content.includeRowNumber = YES.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "rownum" ) );
      content.rowNumberByFile = YES.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "rownumByFile" ) );
      content.rowNumberField = XMLHandler.getTagValue( stepnode, "rownum_field" );
      content.fileFormat = XMLHandler.getTagValue( stepnode, "format" );
      content.encoding = XMLHandler.getTagValue( stepnode, "encoding" );
      content.length = XMLHandler.getTagValue( stepnode, "length" );
      Node filenode = XMLHandler.getSubNode( stepnode, "file" );
      Node fields = XMLHandler.getSubNode( stepnode, "fields" );
      Node filtersNode = XMLHandler.getSubNode( stepnode, "filters" );
      int nrfiles = XMLHandler.countNodes( filenode, "name" );
      int nrfields = XMLHandler.countNodes( fields, "field" );
      int nrfilters = XMLHandler.countNodes( filtersNode, "filter" );
      allocate( nrfiles, nrfields, nrfilters );
      for ( int i = 0; i < nrfiles; i++ ) {
        Node filenamenode = XMLHandler.getSubNodeByNr( filenode, "name", i );       
        inputFiles.fileName[i] = loadSource( filenode, filenamenode, i, metaStore );
     

      }
      content.fileType = XMLHandler.getTagValue( stepnode, "file", "type" );
      content.fileCompression = XMLHandler.getTagValue( stepnode, "file", "compression" );
      if ( content.fileCompression == null ) {
        content.fileCompression = "None";
        if ( YES.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "zipped" ) ) ) {
          content.fileCompression = "Zip";
        }
      }
      // Backward compatibility : just one filter     
    
      // Is there a limit on the number of rows we process?
      content.rowLimit = Const.toLong( XMLHandler.getTagValue( stepnode, "limit" ), 0L );
      errorHandling.errorIgnored = YES.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "error_ignored" ) );    
      // Backward compatible
      content.dateFormatLenient = !NO.equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "date_format_lenient" ) );
      additionalOutputFields.shortFilenameField = XMLHandler.getTagValue( stepnode, "shortFileFieldName" );
      additionalOutputFields.pathField = XMLHandler.getTagValue( stepnode, "pathFieldName" );     
    } catch ( Exception e ) {
      throw new KettleXMLException( "Unable to load step info from XML", e );
    }

  }


}
@InjectionSupported( localizationPrefix = "TextFileOutput.Injection.", groups = { "OUTPUT_FIELDS" } )
public class TextFileOutputMeta extends BaseFileOutputMeta implements StepMetaInterface, ResolvableResource {
@Override
  public void loadXML( Node stepnode, List<DatabaseMeta> databases, IMetaStore metaStore ) throws KettleXMLException {
    readData( stepnode, metaStore );
  }

  protected void readData( Node stepnode, IMetaStore metastore ) throws KettleXMLException {
    try {
      separator = XMLHandler.getTagValue( stepnode, "separator" );
      if ( separator == null ) {
        separator = "";
      }

      enclosure = XMLHandler.getTagValue( stepnode, "enclosure" );
      if ( enclosure == null ) {
        enclosure = "";
      }
    
      enclosureForced = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "enclosure_forced" ) );      
    
      headerEnabled = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "header" ) );
      footerEnabled = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "footer" ) );
      fileFormat = XMLHandler.getTagValue( stepnode, "format" );
      setFileCompression( XMLHandler.getTagValue( stepnode, "compression" ) );
       
      fileName = loadSource( stepnode, metastore );
      servletOutput = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "servlet_output" ) );
      doNotOpenNewFileInit =
          "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "do_not_open_new_file_init" ) );
      extension = XMLHandler.getTagValue( stepnode, "file", "extention" );
      fileAppended = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "append" ) );
      stepNrInFilename = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "split" ) );
      partNrInFilename = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "file", "haspartno" ) );     
      fileNameInField = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, "fileNameInField" ) );
      fileNameField = XMLHandler.getTagValue( stepnode, "fileNameField" );
    
      Node fields = XMLHandler.getSubNode( stepnode, "fields" );
      int nrfields = XMLHandler.countNodes( fields, "field" );
    
      allocate( nrfields );
      for ( int i = 0; i < nrfields; i++ ) {
        Node fnode = XMLHandler.getSubNodeByNr( fields, "field", i );
        outputFields[i] = new TextFileField();
        outputFields[i].setName( XMLHandler.getTagValue( fnode, "name" ) );      
      }
    } catch ( Exception e ) {
      throw new KettleXMLException( "Unable to load step info from XML", e );
    }

  }


}

拖动插件到Transform视图区流程

类型为DragAndDropContainer.TYPE_BASE_STEP_TYPE
TransGraph.java

@Override
      public void drop( DropTargetEvent event ) {
          switch ( container.getType() ) {
            // Put an existing one on the canvas.
            case DragAndDropContainer.TYPE_STEP:
              // Drop hidden step onto canvas....
              stepMeta = transMeta.findStep( container.getData() );              
              break;
            // Create a new step
            case DragAndDropContainer.TYPE_BASE_STEP_TYPE:         
              stepMeta = spoon.newStep( transMeta, id, name, name, false, true );          
              break;
    
            // Create a new TableInput step using the selected connection...
            case DragAndDropContainer.TYPE_DATABASE_CONNECTION:
              newstep = true;
              String connectionName = container.getData();
              TableInputMeta tii = new TableInputMeta();
              tii.setDatabaseMeta( transMeta.findDatabase( connectionName ) );
              PluginRegistry registry = PluginRegistry.getInstance();
              String stepID = registry.getPluginId( StepPluginType.class, tii );
              PluginInterface stepPlugin = registry.findPluginWithId( StepPluginType.class, stepID );
              String stepName = transMeta.getAlternativeStepname( stepPlugin.getName() );
              stepMeta = new StepMeta( stepID, stepName, tii );
              if ( spoon.editStep( transMeta, stepMeta ) != null ) {
                transMeta.addStep( stepMeta );
                spoon.refreshTree();
                spoon.refreshGraph();
              } else {
                return;
              }
              break;
    
            // Drag hop on the canvas: create a new Hop...
            case DragAndDropContainer.TYPE_TRANS_HOP:
              newHop();
              return;
    
            default:
              // Nothing we can use: give an error!
              modalMessageDialog( getString( "TransGraph.Dialog.ItemCanNotBePlacedOnCanvas.Title" ),
                getString( "TransGraph.Dialog.ItemCanNotBePlacedOnCanvas.Message" ), SWT.OK );
              return;
          }         
          stepMeta.drawStep();
          stepMeta.setSelected( true );         
      }

双击插件到Transform视图区流程

Spoon.java

  private void doubleClickedInTree( Tree tree, boolean shift ) {
  if ( selection instanceof PluginInterface ) {
        PluginInterface plugin = (PluginInterface) selection;
        if ( plugin.getPluginType().equals( StepPluginType.class ) ) {
          TransGraph transGraph = getActiveTransGraph();
          if ( transGraph != null ) {
            transGraph.addStepToChain( plugin, shift );
          }
        }
        if ( plugin.getPluginType().equals( JobEntryPluginType.class ) ) {
          JobGraph jobGraph = getActiveJobGraph();
          if ( jobGraph != null ) {
            jobGraph.addJobEntryToChain( object.getItemText(), shift );
          }
        }
   }
   }
}

TransGraph.java

TransGraph.java

public void addStepToChain( PluginInterface stepPlugin, boolean shift ) {
    TransMeta transMeta = spoon.getActiveTransformation();   
    StepMeta newStep =
      spoon.newStep( transMeta, stepPlugin.getIds()[ 0 ], stepPlugin.getName(), stepPlugin.getName(), false, true );
     TransHopMeta hop = new TransHopMeta( lastChained, newStep );
      spoon.newHop( transMeta, hop );  
  }

Spoon.java

public StepMeta newStep( TransMeta transMeta, String id, String name, String description, boolean openit, boolean rename ) {
    PluginRegistry registry = PluginRegistry.getInstance();
    PluginInterface stepPlugin = id != null ? registry.findPluginWithId( StepPluginType.class, id )
      : registry.findPluginWithName( StepPluginType.class, description );
      if ( stepPlugin != null ) {
        StepMetaInterface info = (StepMetaInterface) registry.loadClass( stepPlugin );
        info.setDefault();
        if ( openit ) {
          StepDialogInterface dialog = this.getStepEntryDialog( info, transMeta, name );
          if ( dialog != null ) {
            name = dialog.open();
          }
        }
        inf = new StepMeta( stepPlugin.getIds()[0], name, info );
        if ( name != null ) {
          // OK pressed in the dialog: we have a step-name
          String newName = name;
          StepMeta stepMeta = transMeta.findStep( newName );
          int nr = 2;
          while ( stepMeta != null ) {
            newName = name + " " + nr;
            stepMeta = transMeta.findStep( newName );
            nr++;
          }          
          transMeta.addStep( inf );
          refreshTree();
       
    }
    
    return inf;

  }


Transform的Run机制

Transform的Run界面触发

TransGraph.java

private void addToolBar() {
// Added 1/11/2016 to implement dropdown option for "Run"
      ToolItem runItem = new ToolItem( swtToolbar, SWT.DROP_DOWN, 0 );     
      runItem.addSelectionListener( new SelectionAdapter() {
        @Override
        public void widgetSelected( SelectionEvent e ) {
          if ( e.detail == SWT.DROP_DOWN ) {
            Menu menu = new Menu( shell, SWT.POP_UP );
            MenuItem item1 = new MenuItem( menu, SWT.PUSH );          
            item1.addSelectionListener( new SelectionAdapter() {
              @Override
              public void widgetSelected( SelectionEvent e1 ) {
                runTransformation();
              }
            } );

            MenuItem item2 = new MenuItem( menu, SWT.PUSH );           
            item2.addSelectionListener( new SelectionAdapter() {
              @Override
              public void widgetSelected( SelectionEvent e2 ) {
                runOptionsTransformation();
              }
            } );
          
          } else {
            runTransformation();
          }
        }
    //类似有

stopTransformation();   

}

Transform的Run执行机制

TransGraph.java

public void runTransformation() {
    spoon.runFile();
  }

Spoon.java

  public void runFile() {
    executeFile( true, false, false, false, false, null, false, false );
  }

Spoon.java

jpublic void executeFile( boolean local, boolean remote, boolean cluster, boolean preview, boolean debug,
      Date replayDate, boolean safe, boolean show ) {
    TransMeta transMeta = getActiveTransformation();
    if ( transMeta != null ) {   
      executeTransformation( transMeta, local, remote, cluster, preview, debug, replayDate,
safe,transExecutionConfiguration.getLogLevel() );
    }
    JobMeta jobMeta = getActiveJob();
    if ( jobMeta != null ) {     
      executeJob( jobMeta, local, remote, replayDate, safe, null, 0 );
    }

  }

Spoon.java

public void executeTransformation( final TransMeta transMeta, final boolean local, final boolean remote,
    final boolean cluster, final boolean preview, final boolean debug, final Date replayDate,
    final boolean safe, final LogLevel logLevel ) {
    if ( RepositorySecurityUI.verifyOperations( shell, rep, RepositoryOperation.EXECUTE_TRANSFORMATION ) ) {
      return;
    }    
    Thread thread = new Thread() {
      @Override
      public void run() {
        getDisplay().asyncExec( new Runnable() {
          @Override
          public void run() {
            try {
              delegates.trans.executeTransformation(
                transMeta, local, remote, cluster, preview, debug, replayDate, safe, logLevel );
            } catch ( Exception e ) {
              new ErrorDialog(
                shell, "Execute transformation", "There was an error during transformation execution", e );
            }
          }
        } );
      }
    };
    thread.start();

  }

SpoonTransformationDelegate.java

public class SpoonTransformationDelegate extends SpoonDelegate {
public void executeTransformation( final TransMeta transMeta, final boolean local, final boolean remote,
      final boolean cluster, final boolean preview, final boolean debug, final Date replayDate, final boolean safe,
      LogLevel logLevel ) throws KettleException {
  // Is this a local execution?
      //
      if ( executionConfiguration.isExecutingLocally() ) {
        if ( debug || preview ) {
          activeTransGraph.debug( executionConfiguration, transDebugMeta );
        } else {
          activeTransGraph.start( executionConfiguration );
        }

        // Are we executing remotely?
        //
      } else if ( executionConfiguration.isExecutingRemotely() ) {}


   }

}

TransGraph.java

public synchronized void start( TransffExecutionConfiguration executionConfiguration ) throws KettleException
{
final Thread parentThread = Thread.currentThread();

  shell.getDisplay().asyncExec( new Runnable() {
    @Override
    public void run() {
      addAllTabs();
      prepareTrans( parentThread, args );
    }
  } );

}

}

TransGraph.java

public void addAllTabs() {    
    transHistoryDelegate.addTransHistory();
    transLogDelegate.addTransLog();
    transGridDelegate.addTransGrid();
    transPerfDelegate.addTransPerf();
    transMetricsDelegate.addTransMetrics();
    transPreviewDelegate.addTransPreview();
}

  private synchronized void prepareTrans( final Thread parentThread, final String[] args ) {
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        try {
          trans.prepareExecution( args );

TransGraph.java



  private synchronized void prepareTrans( final Thread parentThread, final String[] args ) {
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        try {
          trans.prepareExecution( args );

          // Do we capture data?
          //
          if ( transPreviewDelegate.isActive() ) {
            transPreviewDelegate.capturePreviewData( trans, transMeta.getSteps() );
          }
    
          initialized = true;
        } catch ( KettleException e ) {
          log.logError( trans.getName() + ": preparing transformation execution failed", e );
          checkErrorVisuals();
        }
        halted = trans.hasHaltedSteps();
        if ( trans.isReadyToStart() ) {
          checkStartThreads(); // After init, launch the threads.
        } else {
          initialized = false;
          running = false;
          checkErrorVisuals();
        }
      }
    };
    Thread thread = new Thread( runnable );
    thread.start();

  }

  private void checkStartThreads() {
    if ( initialized && !running && trans != null ) {
      startThreads();
    }
  }

  private synchronized void startThreads() {
      trans.startThreads();   
  }

Trans.java

public void startThreads() throws KettleException {
    switch ( transMeta.getTransformationType() ) {
      case Normal:
        // Now start all the threads...      
        for ( int i = 0; i < steps.size(); i++ ) {
          final StepMetaDataCombi combi = steps.get( i );
          RunThread runThread = new RunThread( combi );
          Thread thread = new Thread( runThread );
          thread.setName( getName() + " - " + combi.stepname );
          } );
          thread.start();
        }
        break;
      case SerialSingleThreaded:        
        break;
      case SingleThreaded:      
        break;
      default:
        break;
    }   
  }

RunThread.java中的run方法

public class RunThread implements Runnable {

  public RunThread( StepMetaDataCombi combi ) {
    this.step = combi.step;
    this.meta = combi.meta;
    this.data = combi.data;
    this.log = step.getLogChannel();
  }

  public void run() {

      step.setRunning( true );      
      // Wait
      while ( step.processRow( meta, data ) ) {
        if ( step.isStopped() ) {
          break;
        }
      }

   }
}
public void capturePreviewData( final Trans trans, List<StepMeta> stepMetas ) {
    final TransMeta transMeta = trans.getTransMeta();
    for ( final StepMeta stepMeta : stepMetas ) {
      try {
     

        StepInterface step = trans.findRunThread( stepMeta.getName() );
    
        if ( step != null ) {
    
          switch ( previewMode ) {
            case LAST:
              step.addRowListener( new RowAdapter() {
                @Override
                public void rowWrittenEvent( RowMetaInterface rowMeta, Object[] row ) throws KettleStepException {
                  try {
                    rowsData.add( new RowMetaAndData( rowMeta, rowMeta.cloneRow( row ) ) );
                    if ( rowsData.size() > PropsUI.getInstance().getDefaultPreviewSize() ) {
                      rowsData.remove( 0 );
                    }
                  } catch ( Exception e ) {
                    throw new KettleStepException( "Unable to clone row for metadata : " + rowMeta, e );
                  }
                }
              } );
              break;
            default:
              step.addRowListener( new RowAdapter() {
    
                @Override
                public void rowWrittenEvent( RowMetaInterface rowMeta, Object[] row ) throws KettleStepException {
                  if ( rowsData.size() < PropsUI.getInstance().getDefaultPreviewSize() ) {
                    try {
                      rowsData.add( new RowMetaAndData( rowMeta, rowMeta.cloneRow( row ) ) );
                    } catch ( Exception e ) {
                      throw new KettleStepException( "Unable to clone row for metadata : " + rowMeta, e );
                    }
                  }
                }
              } );
              break;
          }
        }
      } catch ( Exception e ) {
        loggingText.append( Const.getStackTracker( e ) );
      }
    }

  

    } );

  }

Transform的Debug机制

Transform的Previewer机制

posted @ 2022-04-11 21:45  焦涛  阅读(119)  评论(0)    收藏  举报