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

读取*.kbj文件创建Job视图

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 );
      }

}

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();
}

打开*.kjb流程
Spoon.java中的openFile
JobFileListener.java中

public boolean open( Node jobNode, String fname, String connection, boolean importfile ) {
      JobMeta jobMeta = new JobMeta();
      jobMeta.loadXML( jobNode, fname, spoon.getRepository(), spoon.getMetaStore(), false, spoon );
      spoon.delegates.jobs.addJobGraph( jobMeta );
    }

JobMeta.java loadXML 解析 *.kjb文件文件

public void loadXML( Node jobnode, String fname, Repository rep, IMetaStore metaStore,
      boolean ignoreRepositorySharedObjects, OverwritePrompter prompter ) throws KettleXMLException { 
      /*
       * read the job entries...
       */
      Node entriesnode = XMLHandler.getSubNode( jobnode, "entries" );
      int tr = XMLHandler.countNodes( entriesnode, "entry" );
      for ( int i = 0; i < tr; i++ ) {
        Node entrynode = XMLHandler.getSubNodeByNr( entriesnode, "entry", i );
        // System.out.println("Reading entry:\n"+entrynode);
        ......
        JobEntryCopy je = new JobEntryCopy( entrynode, databases, slaveServers, rep, metaStore );       
        // Add the JobEntryCopy...
        addJobEntry( je );
      }
    
      Node hopsnode = XMLHandler.getSubNode( jobnode, "hops" );
      int ho = XMLHandler.countNodes( hopsnode, "hop" );
      for ( int i = 0; i < ho; i++ ) {
        Node hopnode = XMLHandler.getSubNodeByNr( hopsnode, "hop", i );
        JobHopMeta hi = new JobHopMeta( hopnode, this );
        jobhops.add( hi );
      }
     }

JobEntryCopy.java类构造函数

public JobEntryCopy( Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers, Repository rep,
      IMetaStore metaStore ) throws KettleXMLException {

      String stype = XMLHandler.getTagValue( entrynode, "type" );
      PluginRegistry registry = PluginRegistry.getInstance();
      PluginInterface jobPlugin = registry.findPluginWithId( JobEntryPluginType.class, stype, true );
      if ( jobPlugin == null ) {
        String name = XMLHandler.getTagValue( entrynode, "name" );
        entry = new MissingEntry( name, stype );
      } else {
        entry = registry.loadClass( jobPlugin, JobEntryInterface.class );//得到不同的Entry,比如JobEntryTrans、JobEntryEval、JobEntrySpecial
      // Get an empty JobEntry of the appropriate class...、
      if ( entry != null ) {
        if ( jobPlugin != null ) {
          entry.setPluginId( jobPlugin.getIds()[0] );
        }
        entry.setMetaStore( metaStore ); // inject metastore
        entry.loadXML( entrynode, databases, slaveServers, rep, metaStore );    
      }
    
  }

JobEntryInterface.java

public interface JobEntryInterface {
  Result execute( Result prev_result, int nr ) throws KettleException;
  void setParentJob( Job job );
  Job getParentJob();
  String getName();
  void setName( String name );
  String getPluginId();  
  void setPluginId( String pluginId );
  String getDescription();
  void setDescription( String description );
  void loadXML( Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers,
    Repository rep, IMetaStore metaStore ) throws KettleXMLException;
  String getXML();
  boolean isStart();
  boolean isDummy();
  boolean evaluates();
  boolean isUnconditional();
  boolean isEvaluation();
  boolean isTransformation();
  boolean isJob();
  boolean isShell();  
  boolean isMail();
  boolean isSpecial();  
  String getFilename();
}

JobEntryTrans.java //实现*.kjb中为TRANS节点的解析
*

public class JobEntryTrans extends JobEntryBase implements Cloneable, JobEntryInterface, HasRepositoryDirectories,
JobEntryRunConfigurableInterface {

@Override
  public void loadXML( Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers,
                       Repository rep, IMetaStore metaStore ) throws KettleXMLException {
    try {
      super.loadXML( entrynode, databases, slaveServers );

      String method = XMLHandler.getTagValue( entrynode, "specification_method" );
      specificationMethod = ObjectLocationSpecificationMethod.getSpecificationMethodByCode( method );
    
      String transId = XMLHandler.getTagValue( entrynode, "trans_object_id" );
      transObjectId = Utils.isEmpty( transId ) ? null : new StringObjectId( transId );
      filename = XMLHandler.getTagValue( entrynode, "filename" );
      transname = XMLHandler.getTagValue( entrynode, "transname" );

......
}
}

JobEntryEval.java //实现*.kjb中为EVAL节点的解析

public class JobEntryEval extends JobEntryBase implements Cloneable, JobEntryInterface {
public void loadXML( Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers,
    Repository rep, IMetaStore metaStore ) throws KettleXMLException {
    try {
      super.loadXML( entrynode, databases, slaveServers );
      script = XMLHandler.getTagValue( entrynode, "script" );
    } catch ( Exception e ) {
      throw new KettleXMLException( BaseMessages.getString( PKG, "JobEntryEval.UnableToLoadFromXml" ), e );
    }
  }
}

Job视图界面创建

拖动插件到Job 视图区流程

类型为DragAndDropContainer.TYPE_BASE_JOB_ENTRY

TransGraph.java


   public void drop( DropTargetEvent event ) {
        // no data to copy, indicate failure in event.detail
        if ( event.data == null ) {
          event.detail = DND.DROP_NONE;
          return;
        }
     switch ( container.getType() ) {      

   case DragAndDropContainer.TYPE_BASE_JOB_ENTRY: // Create a new Job Entry on the canvas
     JobEntryCopy jge = spoon.newJobEntry( jobMeta, entry, false );    
     if ( jge != null ) 
     {  
     redraw();              
      }
     break;

}
}

双击插件到视图区流程

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 );
          }
        }
   }
}

JobGraph.java

  public void addJobEntryToChain( String typeDesc, boolean shift ) {
    JobMeta jobMeta = spoon.getActiveJob();
    if ( jobMeta == null ) {
      return;
    }
    JobEntryCopy newEntry = spoon.newJobEntry( jobMeta, typeDesc, false );
    if ( newEntry == null ) {
      return;
    }  
    if ( lastChained != null ) {
      spoon.newJobHop( jobMeta, lastChained, newEntry );
    }

  }

Spoon.java

 public JobEntryCopy newJobEntry( JobMeta jobMeta, String type_desc, boolean openit ) {
    PluginRegistry registry = PluginRegistry.getInstance();
    PluginInterface jobPlugin;
      jobPlugin = PluginRegistry.getInstance().findPluginWithName( JobEntryPluginType.class, type_desc );            // Generate the appropriate class...
        JobEntryInterface jei = (JobEntryInterface) registry.loadClass( jobPlugin );
        jei.setPluginId( jobPlugin.getIds()[0] );
        jei.setName( entry_name );
         jobMeta.addJobEntry( jge );       
  }


Job执行

界面触发

JobGraph.java

 private void addToolBar() {
  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 ) {
            runJob();
          }
        } );
        MenuItem item2 = new MenuItem( menu, SWT.PUSH );         
        item2.addSelectionListener( new SelectionAdapter() {
          @Override
          public void widgetSelected( SelectionEvent e2 ) {
            runOptionsJob();
          }
        } );
     
      } else {
        runJob();
      }
    }
  } );

}

Job的Run机制

JobGraph.java

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

Spoon.java

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

Spoon.java

public 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 executeJob( JobMeta jobMeta, boolean local, boolean remote, Date replayDate, boolean safe,
   delegates.jobs.executeJob( jobMeta, local, remote, replayDate, safe, startCopyName, startCopyNr );

  }

SpoonJobDelegate.java

public class SpoonJobDelegate extends SpoonDelegate {
  public void executeJob( JobMeta jobMeta, boolean local, boolean remote, Date replayDate, boolean safe,
    String startCopyName, int startCopyNr ) throws KettleException {
     //前面会弹出对话框,确认后才能后续操作
    if ( executionConfiguration.isExecutingLocally() ) {
        jobGraph.startJob( executionConfiguration );
      } else if ( executionConfiguration.isExecutingRemotely() ) {}
}

JobGraph.java

public synchronized void startJob( JobExecutionConfiguration executionConfiguration ) throws KettleException {
if ( spoon.rep != null ) {
              runJobMeta = spoon.rep.loadJob( jobMeta.getName(), jobMeta.getRepositoryDirectory(), null, null );
            } else {
              runJobMeta = new JobMeta( null, jobMeta.getFilename(), null, jobMeta.getMetaStore(), null );//解析*.kjb的xml文件
            }
job = new Job( spoon.rep, runJobMeta, spoonLoggingObject );
job.getJobMeta().activateParameters();          
            job.start();       
            // Link to the new jobTracker!
            jobGridDelegate.jobTracker = job.getJobTracker();
}

JobGraph.java

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

//注意Job继承自Thread
Job.java

public class Job extends Thread implements VariableSpace, NamedParams, HasLogChannelInterface, LoggingObjectInterface,
    ExecutorInterface, ExtensionDataInterface {

}

TransGraph.java

  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-08 18:07  焦涛  阅读(87)  评论(0)    收藏  举报