All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pentaho.di.imp.Import Maven / Gradle / Ivy

The newest version!
/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2018 by Hitachi Vantara : 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.imp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.Props;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.gui.HasOverwritePrompter;
import org.pentaho.di.core.gui.OverwritePrompter;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.plugins.RepositoryPluginType;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.xml.XMLHandler;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.imp.rule.ImportRuleInterface;
import org.pentaho.di.job.JobMeta;
import org.pentaho.di.pan.CommandLineOption;
import org.pentaho.di.repository.CanLimitDirs;
import org.pentaho.di.repository.IRepositoryImporter;
import org.pentaho.di.repository.RepositoriesMeta;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.repository.RepositoryDirectoryInterface;
import org.pentaho.di.repository.RepositoryImportFeedbackInterface;
import org.pentaho.di.repository.RepositoryMeta;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.version.BuildVersion;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

public class Import {
  private static final Class PKG = Import.class; // i18n

  public static final String STRING_IMPORT = "Import";
  public static final String ROOT_DIRECTORY = "/";
  public static final String PUBLIC_DIRECTORY = "public";
  public static final String HOME_DIRECTORY = "home";

  private static class ImportFeedback implements RepositoryImportFeedbackInterface, HasOverwritePrompter {
    private final LogChannelInterface log;
    private final boolean continueOnError;
    private final boolean replace;
    private final BufferedReader reader;

    public ImportFeedback( LogChannelInterface log, boolean continueOnError, boolean replace, BufferedReader reader ) {
      this.log = log;
      this.continueOnError = continueOnError;
      this.replace = replace;
      this.reader = reader;
    }

    @Override
    public void updateDisplay() {
    }

    @Override
    public boolean transOverwritePrompt( TransMeta transMeta ) {
      return replace;
    }

    @Override
    public void showError( String title, String message, Exception e ) {
      log.logError( title + " : " + message, e );
    }

    @Override
    public void setLabel( String labelText ) {
      log.logBasic( labelText );
    }

    @Override
    public boolean jobOverwritePrompt( JobMeta jobMeta ) {
      return replace;
    }

    @Override
    public boolean askContinueOnErrorQuestion( String title, String message ) {
      return continueOnError;
    }

    @Override
    public void addLog( String line ) {
      log.logBasic( line );
    }

    @Override
    public boolean isAskingOverwriteConfirmation() {
      return false;
    }

    @Override
    public OverwritePrompter getOverwritePrompter() {
      return new OverwritePrompter() {
        private final String yes = BaseMessages.getString( PKG, "Import.Yes" );
        private final String no = BaseMessages.getString( PKG, "Import.No" );
        private final String none = BaseMessages.getString( PKG, "Import.None" );
        private final String all = BaseMessages.getString( PKG, "Import.All" );
        private final String prompt = "[" + yes + "," + no + "," + none + "," + all + "]";

        @Override
        public boolean overwritePrompt( String message, String rememberText, String rememberPropertyName ) {
          log.logBasic( message );
          String line;
          Boolean result = null;
          boolean remember = false;
          while ( result == null ) {
            log.logBasic( prompt );
            try {
              line = reader.readLine().trim();
            } catch ( IOException e ) {
              throw new RuntimeException( BaseMessages.getString( PKG, "Import.CouldntReadline" ) );
            }
            if ( line.equalsIgnoreCase( yes ) || line.equalsIgnoreCase( all ) ) {
              result = true;
            } else if ( line.equalsIgnoreCase( no ) || line.equalsIgnoreCase( none ) ) {
              result = false;
            }
            if ( line.equalsIgnoreCase( all ) || line.equalsIgnoreCase( none ) ) {
              remember = true;
            }
          }
          Props.getInstance().setProperty( rememberPropertyName, ( !remember ) ? "Y" : "N" );
          return result;
        }
      };
    }
  }

  public static void main( String[] a ) throws KettleException {
    BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
    KettleEnvironment.init();
    Props.init( Props.TYPE_PROPERTIES_SPOON );

    List args = pickupCmdArguments( a );

    StringBuilder optionRepname, optionUsername, optionPassword, optionDirname;
    StringBuilder optionLimitDir, optionFilename, optionRules, optionComment;
    StringBuilder optionReplace, optionContinueOnError, optionVersion, optionFileDir, optionNoRules;

    CommandLineOption[] options =
      new CommandLineOption[] {
        // Basic options
        //
        createOption( "rep", "Import.CmdLine.RepName", optionRepname = new StringBuilder() ),
        createOption( "user", "Import.CmdLine.RepUsername", optionUsername = new StringBuilder() ),
        createOption( "pass", "Import.CmdLine.RepPassword", optionPassword = new StringBuilder() ),
        createOption( "dir", "Import.CmdLine.RepDir", optionDirname = new StringBuilder() ),
        createOption( "limitdir", "Import.CmdLine.LimitDir", optionLimitDir = new StringBuilder() ),
        createOption( "file", "Import.CmdLine.File", optionFilename = new StringBuilder() ),
        createOption( "filedir", "Import.CmdLine.FileDir", optionFileDir = new StringBuilder() ),
        createOption( "rules", "Import.CmdLine.RulesFile", optionRules = new StringBuilder() ),
        createOption( "norules", "Import.CmdLine.NoRules", optionNoRules = new StringBuilder(), true, false ),
        createOption( "comment", "Import.CmdLine.Comment", optionComment = new StringBuilder(), false, false ),
        createOption( "replace", "Import.CmdLine.Replace", optionReplace = new StringBuilder(), true, false ),
        createOption( "coe", "Import.CmdLine.ContinueOnError", optionContinueOnError = new StringBuilder(), true, false ),
        createOption( "version", "Import.CmdLine.Version", optionVersion = new StringBuilder(), true, false ),

        new CommandLineOption(
          "", BaseMessages.getString( PKG, "Import.CmdLine.ExtraFiles" ), new StringBuilder(), false, true,
          true ),
      };

    if ( args.isEmpty() ) {
      CommandLineOption.printUsage( options );
      exitJVM( 9 );
    }

    final LogChannelInterface log = new LogChannel( STRING_IMPORT );
    CommandLineOption.parseArguments( args, options, log );

    // The arguments that are still left in args are in fact filenames that need to be imported.
    // This list is otherwise empty.
    // To that we add the normal filename option
    //
    List filenames = new ArrayList( args );
    if ( !Utils.isEmpty( optionFilename ) ) {
      filenames.add( optionFilename.toString() );
    }


    String kettleRepname = Const.getEnvironmentVariable( "KETTLE_REPOSITORY", null );
    String kettleUsername = Const.getEnvironmentVariable( "KETTLE_USER", null );
    String kettlePassword = Const.getEnvironmentVariable( "KETTLE_PASSWORD", null );

    if ( !Utils.isEmpty( kettleRepname ) ) {
      optionRepname = new StringBuilder( kettleRepname );
    }
    if ( !Utils.isEmpty( kettleUsername ) ) {
      optionUsername = new StringBuilder( kettleUsername );
    }
    if ( !Utils.isEmpty( kettlePassword ) ) {
      optionPassword = new StringBuilder( kettlePassword );
    }


    if ( !Utils.isEmpty( optionVersion ) ) {
      BuildVersion buildVersion = BuildVersion.getInstance();
      log.logBasic( BaseMessages.getString(
        PKG, "Import.Log.KettleVersion", buildVersion.getVersion(), buildVersion.getRevision(), buildVersion
          .getBuildDate() ) );
      if ( a.length == 1 ) {
        exitJVM( 6 );
      }
    }


    // Verify repository options...
    //
    if ( Utils.isEmpty( optionRepname ) ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.NoRepProvided" ) );
      exitJVM( 1 );
    }

    if ( Utils.isEmpty( filenames ) ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.NoExportFileProvided" ) );
      exitJVM( 1 );
    }

    if ( Utils.isEmpty( optionDirname ) ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.NoRepositoryDirectoryProvided" ) );
      exitJVM( 1 );
    }

    if ( Utils.isEmpty( optionRules )
      && Utils.isEmpty( optionNoRules ) && !"Y".equalsIgnoreCase( optionNoRules.toString() ) ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.NoRulesFileProvided" ) );
      exitJVM( 1 );
    }


    // Load the rules file!
    //
    ImportRules importRules = new ImportRules();
    String rulesFile = optionRules.toString();

    if ( !Utils.isEmpty( rulesFile ) ) {
      try {
        Document document = XMLHandler.loadXMLFile( rulesFile );
        Node rulesNode = XMLHandler.getSubNode( document, ImportRules.XML_TAG );
        importRules.loadXML( rulesNode );
        log.logMinimal( BaseMessages.getString( PKG, "Import.Log.RulesLoaded", rulesFile, Integer.toString(
          importRules.getRules().size() ) ) );
        for ( ImportRuleInterface rule : importRules.getRules() ) {
          log.logBasic( " - " + rule.toString() );
        }
      } catch ( KettleException e ) {
        log.logError( BaseMessages.getString( PKG, "Import.Log.ExceptionLoadingRules", rulesFile ), e );
        exitJVM( 7 );
      }
    }

    // Get the list of limiting source directories
    //
    List limitDirs;
    if ( !Utils.isEmpty( optionLimitDir ) ) {
      String[] directories = optionLimitDir.toString().split( "," );
      limitDirs = Arrays.asList( directories );
    } else {
      limitDirs = Collections.emptyList();
    }

    // Find the repository metadata...
    //
    RepositoriesMeta repsinfo = new RepositoriesMeta();
    repsinfo.getLog().setLogLevel( log.getLogLevel() );
    try {
      repsinfo.readData();
    } catch ( Exception e ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.UnableToLoadRepositoryInformation" ), e );
      exitJVM( 1 );
    }

    RepositoryMeta repositoryMeta = repsinfo.findRepository( optionRepname.toString() );
    if ( repositoryMeta == null ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.RepositoryCouldNotBeFound", optionRepname
        .toString() ) );
      exitJVM( 1 );
    }

    if ( Utils.isEmpty( optionRepname ) ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.NoRepProvided" ) );
      exitJVM( 1 );
    }

    // Load the repository object as a plugin...
    //
    Repository repository = null;
    try {
      repository =
        PluginRegistry.getInstance().loadClass( RepositoryPluginType.class, repositoryMeta, Repository.class );
      repository.init( repositoryMeta );
      repository.getLog().setLogLevel( log.getLogLevel() );
    } catch ( Exception e ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.UnableToLoadOrInitializeRepository" ) );
      exitJVM( 1 );
    }
    try {
      repository.connect( optionUsername != null ? optionUsername.toString() : null, optionPassword != null
        ? optionPassword.toString() : null );
    } catch ( KettleException ke ) {
      log.logError( ke.getMessage() );
      exitJVM( 1 );
    } catch ( Exception e ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.UnableToConnectToRepository" ) );
      exitJVM( 1 );
    }

    final boolean replace =
      Utils.isEmpty( optionReplace ) ? false : ValueMetaString.convertStringToBoolean( optionReplace.toString() );
    final boolean continueOnError =
      Utils.isEmpty( optionContinueOnError ) ? false : ValueMetaString.convertStringToBoolean( optionContinueOnError
        .toString() );

    // Start the import!
    //
    log.logMinimal( BaseMessages.getString( PKG, "Import.Log.Starting" ) );

    Date start, stop;
    SimpleDateFormat df = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss.SSS" );
    start = new Date(  );
    int returnCode = 0;
    try {
      RepositoryDirectoryInterface tree = repository.loadRepositoryDirectoryTree();

      RepositoryDirectoryInterface targetDirectory = tree.findDirectory( optionDirname.toString() );
      if ( targetDirectory == null ) {
        log.logError( BaseMessages.getString(
          PKG, "Import.Error.UnableToFindTargetDirectoryInRepository", optionDirname.toString() ) );
        exitJVM( 1 );
      }

      // Perform the actual import
      IRepositoryImporter importer = repository.getImporter();
      importer.setImportRules( importRules );
      if ( !limitDirs.isEmpty() ) {
        if ( importer instanceof CanLimitDirs ) {
          ( (CanLimitDirs) importer ).setLimitDirs( limitDirs );
        } else {
          throw new KettleException( BaseMessages.getString( PKG, "Import.CouldntLimitDirs", importer.getClass()
              .getCanonicalName() ) );
        }
      }
      RepositoryImportFeedbackInterface feedbackInterface = new ImportFeedback( log, continueOnError, replace, reader );

      // Import files in a certain directory
      importer.importAll( feedbackInterface, optionFileDir.toString(), filenames.toArray( new String[filenames
        .size()] ), targetDirectory, replace, continueOnError, optionComment.toString() );

      // If the importer has exceptions, then our return code is 2
      List exceptions = importer.getExceptions();
      if ( exceptions != null && !exceptions.isEmpty() ) {
        log.logError( BaseMessages.getString( PKG, "Import.Error.UnexpectedErrorDuringImport" ), exceptions
          .get( 0 ) );
        returnCode = 2;
      }
    } catch ( Exception e ) {
      log.logError( BaseMessages.getString( PKG, "Import.Error.UnexpectedErrorDuringImport" ), e );
      exitJVM( 2 );
    }
    log.logMinimal( BaseMessages.getString( PKG, "Import.Log.Finished" ) );

    stop = new Date(  );

    String begin = df.format( start );
    String end = df.format( stop );
    log.logMinimal( BaseMessages.getString( PKG, "Import.Log.StartStop", begin, end ) );

    long seconds = ( stop.getTime() - start.getTime() ) / 1000;
    if ( seconds <= 60 ) {
      log.logMinimal( BaseMessages.getString( PKG, "Import.Log.ProcessEndAfter", String.valueOf( seconds ) ) );
    } else if ( seconds <= 60 * 60 ) {
      int min = (int) ( seconds / 60 );
      int rem = (int) ( seconds % 60 );
      log.logMinimal( BaseMessages.getString( PKG, "Import.Log.ProcessEndAfterLong", String.valueOf( min ), String
        .valueOf( rem ), String.valueOf( seconds ) ) );
    } else if ( seconds <= 60 * 60 * 24 ) {
      int rem;
      int hour = (int) ( seconds / ( 60 * 60 ) );
      rem = (int) ( seconds % ( 60 * 60 ) );
      int min = rem / 60;
      rem = rem % 60;
      log.logMinimal( BaseMessages.getString(
        PKG, "Import.Log.ProcessEndAfterLonger", String.valueOf( hour ), String.valueOf( min ), String
          .valueOf( rem ), String.valueOf( seconds ) ) );
    } else {
      int rem;
      int days = (int) ( seconds / ( 60 * 60 * 24 ) );
      rem = (int) ( seconds % ( 60 * 60 * 24 ) );
      int hour = rem / ( 60 * 60 );
      rem = rem % ( 60 * 60 );
      int min = rem / 60;
      rem = rem % 60;
      log.logMinimal( BaseMessages.getString(
        PKG, "Import.Log.ProcessEndAfterLongest", String.valueOf( days ), String.valueOf( hour ), String
          .valueOf( min ), String.valueOf( rem ), String.valueOf( seconds ) ) );
    }

    exitJVM( returnCode );

  }

  private static List pickupCmdArguments( String[] a ) {
    List args = new ArrayList( a.length );
    for ( String arg : a ) {
      if ( !arg.isEmpty() ) {
        args.add( arg );
      }
    }
    return args;
  }

  private static CommandLineOption createOption( String option, String i18nKey, StringBuilder sb ) {
    return new CommandLineOption( option, BaseMessages.getString( PKG, i18nKey ), sb );
  }

  private static CommandLineOption createOption( String option, String i18nKey, StringBuilder sb, boolean yesNo, boolean hidden  ) {
    return new CommandLineOption( option, BaseMessages.getString( PKG, i18nKey ), sb, yesNo, hidden );
  }

  /**
   * Parse an argument as an integer.
   *
   * @param option
   *          Command Line Option to parse argument of
   * @param def
   *          Default if the argument is not set
   * @return The parsed argument or the default if the argument was not specified
   * @throws KettleException
   *           Error parsing provided argument as an integer
   */
  protected static int parseIntArgument( final CommandLineOption option, final int def ) throws KettleException {
    if ( !Utils.isEmpty( option.getArgument() ) ) {
      try {
        return Integer.parseInt( option.getArgument().toString() );
      } catch ( NumberFormatException ex ) {
        throw new KettleException( BaseMessages.getString( PKG, "Import.Error.InvalidNumberArgument", option
          .getOption(), option.getArgument() ) );
      }
    }
    return def;
  }

  private static void exitJVM( int status ) {
    System.exit( status );
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy