Package org.pentaho.platform.plugin.services.importexport

Source Code of org.pentaho.platform.plugin.services.importexport.CommandLineProcessor

/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* Copyright 2006 - 2013 Pentaho Corporation.  All rights reserved.
*/

package org.pentaho.platform.plugin.services.importexport;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataMultiPart;
import com.sun.xml.ws.developer.JAXWSProperties;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.repository2.unified.IUnifiedRepository;
import org.pentaho.platform.plugin.services.messages.Messages;
import org.pentaho.platform.repository.RepositoryFilenameUtils;
import org.pentaho.platform.repository2.unified.webservices.jaxws.IUnifiedRepositoryJaxwsWebService;
import org.pentaho.platform.repository2.unified.webservices.jaxws.UnifiedRepositoryToWebServiceAdapter;
import org.pentaho.platform.security.policy.rolebased.actions.AdministerSecurityAction;
import org.pentaho.platform.util.RepositoryPathEncoder;

import javax.ws.rs.core.MediaType;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
* Handles the parsing of command line arguments and creates an import process based upon them
*
* @author <a href="mailto:dkincade@pentaho.com">David M. Kincade</a>
*/
public class CommandLineProcessor {
  private static final String API_REPO_FILES_IMPORT = "/api/repo/files/import";

  private static final String ANALYSIS_DATASOURCE_IMPORT = "/plugin/data-access/api/mondrian/postAnalysis";

  private static final String METADATA_DATASOURCE_IMPORT = "/plugin/data-access/api/metadata/postimport";

  private static final String METADATA_DATASOURCE_EXT = "xmi";

  private static final String ZIP_EXT = "zip";

  private static final Log log = LogFactory.getLog( CommandLineProcessor.class );

  private static final Options options = new Options();

  private static Exception exception;

  private CommandLine commandLine;

  private RequestType requestType;

  private IUnifiedRepository repository;

  private static enum RequestType {
    HELP, IMPORT, EXPORT, REST
  }

  private static enum DatasourceType {
    JDBC, METADATA, ANALYSIS
  }

  private static enum ResourceType {
    SOLUTIONS, DATASOURCE
  }

  private static Client client = null;

  static {
    // create the Options
    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_HELP_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_HELP_NAME" ), false, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_HELP_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_IMPORT_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_IMPORT_NAME" ), false, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_IMPORT_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_EXPORT_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_EXPORT_NAME" ), false, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_EXPORT_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_USERNAME_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_USERNAME_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_USERNAME_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_URL_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_CHARSET_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_CHARSET_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_CHARSET_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_PATH_DESCRIPTION" ) );

    // import only ACL additions
    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PERMISSION_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PERMISSION_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_PERMISSION_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_RETAIN_OWNERSHIP_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_RETAIN_OWNERSHIP_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_RETAIN_OWNERSHIP_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_WITH_MANIFEST_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_WITH_MANIFEST_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_WITH_MANIFEST_DESCRIPTION" ) );

    // rest services
    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_REST_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_REST_NAME" ), false, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_REST_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_SERVICE_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_SERVICE_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_SERVICE_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PARAMS_KEY" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PARAMS_NAME" ), true, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_OPTION_PARAMS_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_CATALOG_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_CATALOG_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_CATALOG_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_DATASOURCE_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_DATASOURCE_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_DATASOURCE_DESCRIPTION" ) );

    options.addOption(
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_XMLA_ENABLED_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_XMLA_ENABLED_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_XMLA_ENABLED_DESCRIPTION" ) );

    options.addOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_METADATA_DOMAIN_ID_KEY" ),
        Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_METADATA_DOMAIN_ID_NAME" ), true, Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_METADATA_DOMAIN_ID_DESCRIPTION" ) );
  }

  /**
   * How this class is executed from the command line.
   *
   * @param args
   */
  public static void main( String[] args ) throws Exception {

    try {
      // reset the exception information
      exception = null;

      final CommandLineProcessor commandLineProcessor = new CommandLineProcessor( args );

      // new service only
      switch ( commandLineProcessor.getRequestType() ) {
        case HELP:
          printHelp();
          break;

        case IMPORT:
          commandLineProcessor.performImport();
          break;

        case EXPORT:
          commandLineProcessor.performExport();
          break;
        case REST:
          commandLineProcessor.performREST();
          break;
      }
    } catch ( ParseException parseException ) {
      exception = parseException;
      System.err.println( parseException.getLocalizedMessage() );
      System.out.println( parseException.getLocalizedMessage() );
      printHelp();
      log.error( parseException.getMessage(), parseException );
    } catch ( Exception e ) {
      exception = e;
      e.printStackTrace();
      log.error( e.getMessage(), e );
    }
  }

  /**
   * call FileResource REST service example: {path+}/children example: {path+}/parameterizable example:
   * {path+}/properties example: /delete?params={fileid1, fileid2}
   *
   * @throws ParseException
   */
  private void performREST() throws ParseException, InitializationException {

    String contextURL =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_NAME" ), true, false );
    String path =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_NAME" ), true, false );
    String logFile =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_NAME" ), false, true );
    String exportURL = contextURL + "/api/repo/files/";
    if ( path != null ) {
      String effPath = RepositoryPathEncoder.encodeRepositoryPath( path );
      exportURL += effPath;
    }
    String service =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_SERVICE_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_SERVICE_NAME" ), true, false );
    String params =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PARAMS_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PARAMS_NAME" ), false, true );
    exportURL += "/" + service;
    if ( params != null ) {
      exportURL += "?params=" + params;
    }

    initRestService();
    WebResource resource = client.resource( exportURL );

    // Response response
    Builder builder = resource.type( MediaType.APPLICATION_JSON ).type( MediaType.TEXT_XML_TYPE );
    ClientResponse response = builder.put( ClientResponse.class );
    if ( response != null && response.getStatus() == 200 ) {

      String message = Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_COMPLETED" ).concat( "\n" );
      message +=
          Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_STATUS", response.getStatus() );
      message += "\n";

      if ( logFile != null && !"".equals( logFile ) ) {
        message += Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_FILE_WRITTEN", logFile );
        System.out.println( message );
        writeFile( message, logFile );
      }
    } else {
      System.out.println( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0002_INVALID_RESPONSE" ) );
    }
  }

  /**
   * Used only for REST Jersey calls
   *
   * @throws ParseException
   */
  private void initRestService() throws ParseException, InitializationException {
    // get information about the remote connection
    String username =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_USERNAME_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_USERNAME_NAME" ), true, false );
    String password =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_NAME" ), true, false );
    ClientConfig clientConfig = new DefaultClientConfig();
    clientConfig.getFeatures().put( JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE );
    client = Client.create( clientConfig );
    client.addFilter( new HTTPBasicAuthFilter( username, password ) );

    // check if the user has permissions to upload/download data
    String contextURL =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_NAME" ), true, false );
    WebResource resource = client.resource( contextURL + "/api/authorization/action/isauthorized?authAction="
        + AdministerSecurityAction.NAME );
    String response = resource.get( String.class );
    if ( !response.equals( "true" ) ) {
      throw new InitializationException( Messages.getInstance().getString(
          "CommandLineProcessor.ERROR_0006_NON_ADMIN_CREDENTIALS" ) );
    }
  }

  /**
   * Returns information about any exception encountered (if one was generated)
   *
   * @return the {@link Exception} that was generated, or {@code null} if none was generated
   */
  public static Exception getException() {
    return exception;
  }

  /**
   * Parses the command line and handles the situation where it isn't a valid import or export or rest request
   *
   * @param args
   *          the command line arguments
   * @throws ParseException
   *           indicates that neither (or both) an import and/or export have been request
   */
  protected CommandLineProcessor( String[] args ) throws ParseException {
    // parse the command line arguments
    commandLine = new PosixParser().parse( options, args );
    if ( commandLine.hasOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_HELP_NAME" ) )
        || commandLine.hasOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_HELP_KEY" ) ) ) {
      requestType = RequestType.HELP;
    } else {
      if ( commandLine.hasOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_REST_NAME" ) )
          || commandLine.hasOption( Messages.getInstance().
            getString( "CommandLineProcessor.INFO_OPTION_REST_KEY" ) ) ) {
        requestType = RequestType.REST;
      } else {
        final boolean importRequest =
            commandLine.hasOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_IMPORT_KEY" ) );
        final boolean exportRequest =
            commandLine.hasOption( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_EXPORT_KEY" ) );

        if ( importRequest == exportRequest ) {
          throw new ParseException( Messages.getInstance().getErrorString(
              "CommandLineProcessor.ERROR_0003_PARSE_EXCEPTION" ) );
        }
        requestType = ( importRequest ? RequestType.IMPORT : RequestType.EXPORT );
      }
    }
  }

  // ========================== Instance Members / Methods
  // ==========================

  protected RequestType getRequestType() {
    return requestType;
  }

  /**
   * --import --url=http://localhost:8080/pentaho --username=admin --password=password --file-path=metadata.xmi
   * --resource-type=DATASOURCE --datasource-type=METADATA --overwrite=true --metadata-domain-id=steel-wheels
   *
   * @param contextURL
   * @param metadataDatasourceFile
   * @param overwrite
   * @throws ParseException
   * @throws IOException
   */
  private void performMetadataDatasourceImport( String contextURL, File metadataDatasourceFile,
      String overwrite ) throws ParseException, IOException {
    File metadataFileInZip = null;
    InputStream metadataFileInZipInputStream = null;

    String metadataImportURL = contextURL + METADATA_DATASOURCE_IMPORT;

    String domainId =
        getOptionValue( Messages.getInstance().getString(
          "CommandLineProcessor.INFO_OPTION_METADATA_DOMAIN_ID_KEY" ),
            Messages.getInstance().getString(
              "CommandLineProcessor.INFO_OPTION_METADATA_DOMAIN_ID_NAME" ), true, false );

    WebResource resource = client.resource( metadataImportURL );

    FormDataMultiPart part = new FormDataMultiPart();

    final String name = RepositoryFilenameUtils.separatorsToRepository( metadataDatasourceFile.getName() );
    final String ext = RepositoryFilenameUtils.getExtension( name );

    try {
      if ( ext.equals( ZIP_EXT ) ) {
        ZipInputStream zipInputStream = new ZipInputStream( new FileInputStream( metadataDatasourceFile ) );
        ZipEntry entry = zipInputStream.getNextEntry();
        while ( entry != null ) {
          final String entryName = RepositoryFilenameUtils.separatorsToRepository( entry.getName() );
          final String extension = RepositoryFilenameUtils.getExtension( entryName );
          File tempFile = null;
          boolean isDir = entry.getSize() == 0;
          if ( !isDir ) {
            tempFile = File.createTempFile( "zip", null );
            tempFile.deleteOnExit();
            FileOutputStream fos = new FileOutputStream( tempFile );
            IOUtils.copy( zipInputStream, fos );
            fos.close();
          }
          if ( extension.equals( METADATA_DATASOURCE_EXT ) ) {
            if ( metadataFileInZip == null ) {
              metadataFileInZip = new File( entryName );
              metadataFileInZipInputStream = new FileInputStream( metadataFileInZip );
            }
          }

          zipInputStream.closeEntry();
          entry = zipInputStream.getNextEntry();
        }
        zipInputStream.close();

        part.field( "overwrite", "true".equals( overwrite ) ? "true" : "false", MediaType.MULTIPART_FORM_DATA_TYPE );
        part.field( "domainId", domainId, MediaType.MULTIPART_FORM_DATA_TYPE ).field( "metadataFile",
            metadataFileInZipInputStream, MediaType.MULTIPART_FORM_DATA_TYPE );

        // If the import service needs the file name do the following.
        part.getField( "metadataFile" ).setContentDisposition(
            FormDataContentDisposition.name( "metadataFile" ).fileName( metadataFileInZip.getName() ).build() );

        // Response response
        ClientResponse response = resource.type( MediaType.MULTIPART_FORM_DATA ).post( ClientResponse.class, part );
        if ( response != null ) {
          String message = response.getEntity( String.class );
          System.out.println( Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_RECEIVED",
              message ) );
        }

      } else {
        FileInputStream metadataDatasourceInputStream = new FileInputStream( metadataDatasourceFile );

        part.field( "overwrite", "true".equals( overwrite ) ? "true" : "false", MediaType.MULTIPART_FORM_DATA_TYPE );
        part.field( "domainId", domainId, MediaType.MULTIPART_FORM_DATA_TYPE ).field( "metadataFile",
            metadataDatasourceInputStream, MediaType.MULTIPART_FORM_DATA_TYPE );

        // If the import service needs the file name do the following.
        part.getField( "metadataFile" ).setContentDisposition(
            FormDataContentDisposition.name( "metadataFile" ).fileName( metadataDatasourceFile.getName() ).build() );

        // Response response
        ClientResponse response = resource.type( MediaType.MULTIPART_FORM_DATA ).post( ClientResponse.class, part );
        if ( response != null ) {
          String message = response.getEntity( String.class );
          System.out.println( Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_RECEIVED",
              message ) );
        }
        metadataDatasourceInputStream.close();
      }
    } finally {
      metadataFileInZipInputStream.close();
      part.cleanup();
    }

  }

  /**
   * --import --url=http://localhost:8080/pentaho --username=admin --password=password
   * --file-path=analysis/steelwheels.mondrian.xml --resource-type=DATASOURCE --datasource-type=ANALYSIS
   * --overwrite=true --analysis-datasource=steelwheels
   *
   * @param contextURL
   * @param analysisDatasourceFile
   * @param overwrite
   * @throws ParseException
   * @throws IOException
   */
  private void performAnalysisDatasourceImport( String contextURL, File analysisDatasourceFile,
      String overwrite ) throws ParseException, IOException {
    String analysisImportURL = contextURL + ANALYSIS_DATASOURCE_IMPORT;

    String catalogName =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_CATALOG_Key" ),
            Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_CATALOG_NAME" ), false, true );
    String datasourceName =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_DATASOURCE_KEY" ),
            Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_DATASOURCE_NAME" ), false,
            true );
    String xmlaEnabledFlag =
        getOptionValue(
            Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_XMLA_ENABLED_KEY" ), Messages
                .getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_ANALYSIS_XMLA_ENABLED_NAME" ),
            false, true );

    WebResource resource = client.resource( analysisImportURL );
    FileInputStream inputStream = new FileInputStream( analysisDatasourceFile );
    String parms = "Datasource=" + datasourceName + ";overwrite=" + overwrite;

    FormDataMultiPart part = new FormDataMultiPart();
    part.field( "overwrite", "true".equals( overwrite ) ? "true" : "false", MediaType.MULTIPART_FORM_DATA_TYPE );

    if ( catalogName != null ) {
      part.field( "catalogName", catalogName, MediaType.MULTIPART_FORM_DATA_TYPE );
    }
    if ( datasourceName != null ) {
      part.field( "datasourceName", datasourceName, MediaType.MULTIPART_FORM_DATA_TYPE );
    }
    part.field( "parameters", parms, MediaType.MULTIPART_FORM_DATA_TYPE );

    part.field( "xmlaEnabledFlag", "true".equals( xmlaEnabledFlag ) ? "true" : "false",
        MediaType.MULTIPART_FORM_DATA_TYPE );
    part.field( "uploadAnalysis", inputStream, MediaType.MULTIPART_FORM_DATA_TYPE );

    // If the import service needs the file name do the following.
    part.getField( "uploadAnalysis" ).setContentDisposition(
        FormDataContentDisposition.name( "uploadAnalysis" ).fileName( analysisDatasourceFile.getName() ).build() );

    // Response response
    ClientResponse response = resource.type( MediaType.MULTIPART_FORM_DATA ).post( ClientResponse.class, part );
    if ( response != null ) {
      String message = response.getEntity( String.class );
      response.close();
      System.out.println( Messages.getInstance()
          .getString( "CommandLineProcessor.INFO_REST_RESPONSE_RECEIVED", message ) );
    }
    inputStream.close();
    part.cleanup();
  }

  /**
   * @throws ParseException
   * @throws IOException
   */
  private void performDatasourceImport() throws ParseException, IOException {
    String contextURL =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_Key" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_NAME" ), true, false );
    String filePath =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_NAME" ), true, false );
    String datasourceType =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_KEY" ),
            Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_NAME" ), true, false );
    String overwrite =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_NAME" ), false, true );

    /*
     * wrap in a try/finally to ensure input stream is closed properly
     */
    try {
      initRestService();

      File file = new File( filePath );
      if ( datasourceType != null ) {
        if ( datasourceType.equals( DatasourceType.ANALYSIS.name() ) ) {
          performAnalysisDatasourceImport( contextURL, file, overwrite );
        } else if ( datasourceType.equals( DatasourceType.METADATA.name() ) ) {
          performMetadataDatasourceImport( contextURL, file, overwrite );
        }
      }

    } catch ( Exception e ) {
      System.err.println( e.getMessage() );
      log.error( e.getMessage() );
    }

  }

  /*
   * --import --url=http://localhost:8080/pentaho - -username=admin --password=password
   * --charset=UTF-8 --path=:public --file-path=C:/Users/tband/Downloads/pentaho-solutions.zip
   * --logfile=c:/Users/tband/Desktop/logfile.log --permission=true --overwrite=true --retainOwnership=true (required
   * fields- default is false)
   */

  private void performImport() throws ParseException, IOException {
    String contextURL =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_Key" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_NAME" ), true, false );
    String filePath =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_NAME" ), true, false );
    String resourceType =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_KEY" ),
            Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_NAME" ), false, true );
    // We are importing datasources
    if ( resourceType != null && resourceType.equals( ResourceType.DATASOURCE.name() ) ) {
      performDatasourceImport();
    } else {
      String charSet =
          getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_CHARSET_KEY" ), Messages
              .getInstance().getString( "CommandLineProcessor.INFO_OPTION_CHARSET_NAME" ), false, true );
      String logFile =
          getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_KEY" ), Messages
              .getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_NAME" ), false, true );
      String path =
          getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_KEY" ), Messages
              .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_NAME" ), true, false );

      String importURL = contextURL + API_REPO_FILES_IMPORT;
      File fileIS = new File( filePath );
      InputStream in = new FileInputStream( fileIS );
      FormDataMultiPart part = new FormDataMultiPart();

      /*
       * wrap in a try/finally to ensure input stream is closed properly
       */
      try {
        initRestService();
        WebResource resource = client.resource( importURL );

        String overwrite =
            getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_KEY" ),
                Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_NAME" ), true, false );
        String retainOwnership =
            getOptionValue(
                Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_RETAIN_OWNERSHIP_KEY" ), Messages
                    .getInstance().getString( "CommandLineProcessor.INFO_OPTION_RETAIN_OWNERSHIP_NAME" ), true, false );
        String permission =
            getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PERMISSION_KEY" ),
                Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PERMISSION_NAME" ), true, false );

        part.field( "importDir", path, MediaType.MULTIPART_FORM_DATA_TYPE );
        part.field( "overwriteAclPermissions", "true".equals( overwrite ) ? "true" : "false",
            MediaType.MULTIPART_FORM_DATA_TYPE );
        part.field( "retainOwnership", "true".equals( retainOwnership ) ? "true" : "false",
            MediaType.MULTIPART_FORM_DATA_TYPE );
        part.field( "charSet", charSet == null ? "UTF-8" : charSet );
        part.field( "applyAclPermissions", "true".equals( permission ) ? "true" : "false",
            MediaType.MULTIPART_FORM_DATA_TYPE ).field( "fileUpload", in, MediaType.MULTIPART_FORM_DATA_TYPE );

        // If the import service needs the file name do the following.
        part.field( "fileNameOverride", fileIS.getName(), MediaType.MULTIPART_FORM_DATA_TYPE );
        part.getField( "fileUpload" ).setContentDisposition(
            FormDataContentDisposition.name( "fileUpload" ).fileName( fileIS.getName() ).build() );

        // Response response
        ClientResponse response = resource.type( MediaType.MULTIPART_FORM_DATA ).post( ClientResponse.class, part );
        if ( response != null ) {
          String message = response.getEntity( String.class );
          System.out.println( Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_RECEIVED",
              message ) );
          if ( logFile != null && !"".equals( logFile ) ) {
            writeFile( message, logFile );
          }
          response.close();
        }
      } catch ( Exception e ) {
        System.err.println( e.getMessage() );
        log.error( e.getMessage() );
        writeFile( e.getMessage(), logFile );
      } finally {
        // close input stream and cleanup the jersey resources
        client.destroy();
        part.cleanup();
        in.close();
      }
    }
  }

  /**
   * REST Service Export
   *
   * @throws ParseException
   *           --export --url=http://localhost:8080/pentaho --username=admin --password=password
   *           --file-path=c:/temp/export.zip --charset=UTF-8 --path=public/pentaho-solutions/steel-wheels
   *           --logfile=c:/temp/steel-wheels.log --withManifest=true
   * @throws java.io.IOException
   */
  private void performExport() throws ParseException, IOException, InitializationException {
    String contextURL =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_NAME" ), true, false );
    String path =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PATH_NAME" ), true, false );
    String withManifest =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_WITH_MANIFEST_KEY" ),
            Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_WITH_MANIFEST_NAME" ), false, true );
    String effPath = RepositoryPathEncoder.encodeURIComponent( RepositoryPathEncoder.encodeRepositoryPath( path ) );
    if ( effPath.lastIndexOf( ":" ) == effPath.length() - 1 // remove trailing slash
        && effPath.length() > ) { // allow user to enter "--path=/"
      effPath = effPath.substring( 0, effPath.length() - 1 );
    }
    String logFile =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_NAME" ), false, true );
    String exportURL =
        contextURL + "/api/repo/files/" + effPath + "/download?withManifest="
            + ( "false".equals( withManifest ) ? "false" : "true" );

    // path is validated before executing
    String filepath =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_NAME" ), true, false );

    if ( !isValidExportPath( filepath, logFile ) ) {
      throw new ParseException( Messages.getInstance().getString( "CommandLineProcessor.ERROR_0005_INVALID_FILE_PATH"
          , filepath ) );
    }

    initRestService();
    WebResource resource = client.resource( exportURL );

    // Response response
    Builder builder = resource.type( MediaType.MULTIPART_FORM_DATA ).accept( MediaType.TEXT_HTML_TYPE );
    ClientResponse response = builder.get( ClientResponse.class );
    if ( response != null && response.getStatus() == 200 ) {
      String filename =
          getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_KEY" ), Messages
              .getInstance().getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_NAME" ), true, false );
      final InputStream input = response.getEntityInputStream();
      createZipFile( filename, input );
      input.close();
      String message = Messages.getInstance().getString( "CommandLineProcessor.INFO_EXPORT_COMPLETED" ).concat( "\n" );
      message += Messages.getInstance().getString( "CommandLineProcessor.INFO_RESPONSE_STATUS", response.getStatus() );
      message += "\n";
      message += Messages.getInstance().getString( "CommandLineProcessor.INFO_EXPORT_WRITTEN_TO", filename );
      if ( logFile != null && !"".equals( logFile ) ) {
        System.out.println( message );
        writeFile( message, logFile );
      }
    } else {
      System.out.println( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0002_INVALID_RESPONSE" ) );
      if ( response != null && response.getStatus() == 404 ) {
        throw new ParseException( Messages.getInstance().getErrorString(
            "CommandLineProcessor.ERROR_0004_UNKNOWN_SOURCE", path ) );
      }
    }
  }

  private boolean isValidExportPath( String filePath, String logFile ) {

    boolean isValid = false;

    if ( filePath != null && filePath.toLowerCase().endsWith( ".zip" ) ) {

      int fileNameIdx = filePath.replace( "\\", "/" ).lastIndexOf( "/" );
      if ( fileNameIdx >= 0 ) {
        String directoryPath = filePath.substring( 0, fileNameIdx );

        File f = new File( directoryPath );
        if ( f != null && f.exists() && f.isDirectory() ) {
          isValid = true;
        }
      }
    }

    if ( !isValid && logFile != null && !"".equals( logFile ) ) {
      writeFile( "Invalid file-path:" + filePath, logFile );
    }

    return isValid;
  }

  /**
   * create the zip file from the input stream
   *
   * @param filename
   * @param input
   *          InputStream
   */
  private void createZipFile( String filename, final InputStream input ) {
    OutputStream output = null;
    try {
      output = new FileOutputStream( filename );
      byte[] buffer = new byte[8 * 1024];
      int bytesRead;
      while ( ( bytesRead = input.read( buffer ) ) != -1 ) {
        output.write( buffer, 0, bytesRead );
      }

      buffer = null;
    } catch ( IOException e ) {
      e.printStackTrace();
    } finally {
      if ( output != null ) {
        try {
          output.close();
        } catch ( Exception e ) {
          e.printStackTrace();
        }
      }
    }
  }

  public synchronized void setRepository( final IUnifiedRepository repository ) {
    if ( repository == null ) {
      throw new IllegalArgumentException();
    }
    this.repository = repository;
  }

  /**
   * Why does this return a web service? Going directly to the IUnifiedRepository requires the following:
   * <p/>
   * <ul>
   * <li>PentahoSessionHolder setup including password and tenant ID. (The server doesn't even process passwords today--
   * it assumes that Spring Security processed it. This would require code changes.)</li>
   * <li>User must specify path to Jackrabbit files (i.e. system/jackrabbit).</li>
   * </ul>
   */
  protected synchronized IUnifiedRepository getRepository() throws ParseException {
    if ( repository != null ) {
      return repository;
    }

    final String NAMESPACE_URI = "http://www.pentaho.org/ws/1.0"; //$NON-NLS-1$
    final String SERVICE_NAME = "unifiedRepository"; //$NON-NLS-1$

    String urlString =
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_KEY" ),
            Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_URL_NAME" ), true, false ).trim();
    if ( urlString.endsWith( "/" ) ) {
      urlString = urlString.substring( 0, urlString.length() - 1 );
    }
    urlString = urlString + "/webservices/" + SERVICE_NAME + "?wsdl";

    URL url;
    try {
      url = new URL( urlString );
    } catch ( MalformedURLException e ) {
      throw new IllegalArgumentException( e );
    }

    Service service = Service.create( url, new QName( NAMESPACE_URI, SERVICE_NAME ) );
    IUnifiedRepositoryJaxwsWebService port = service.getPort( IUnifiedRepositoryJaxwsWebService.class );
    // http basic authentication
    ( (BindingProvider) port ).getRequestContext().put(
        BindingProvider.USERNAME_PROPERTY,
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_USERNAME_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_USERNAME_NAME" ), true, false ) );
    ( (BindingProvider) port ).getRequestContext().put(
        BindingProvider.PASSWORD_PROPERTY,
        getOptionValue( Messages.getInstance().getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_KEY" ), Messages
            .getInstance().getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_NAME" ), true, true ) );
    // accept cookies to maintain session on server
    ( (BindingProvider) port ).getRequestContext().put( BindingProvider.SESSION_MAINTAIN_PROPERTY, true );
    // support streaming binary data
    // TODO mlowery this is not portable between JAX-WS implementations
    // (uses com.sun)
    ( (BindingProvider) port ).getRequestContext().put( JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192 );
    SOAPBinding binding = (SOAPBinding) ( (BindingProvider) port ).getBinding();
    binding.setMTOMEnabled( true );
    final UnifiedRepositoryToWebServiceAdapter unifiedRepositoryToWebServiceAdapter =
        new UnifiedRepositoryToWebServiceAdapter( port );
    repository = unifiedRepositoryToWebServiceAdapter;
    return unifiedRepositoryToWebServiceAdapter;
  }

  /**
   * Returns the option value from the command line
   *
   * @param option
   *          the option whose value should be returned (NOTE: {@code null} will be returned if the option was not
   *          provided)
   * @param required
   *          indicates if the option is required
   * @param emptyOk
   *          indicates if a blank value is acceptable
   * @return the value provided from the command line, or {@code null} if none was provided
   * @throws ParseException
   *           indicates the required or non-blank value was not provided
   */
  protected String getOptionValue( final String option, final boolean required, final boolean emptyOk ) throws
      ParseException {
    final String value = StringUtils.trim( commandLine.getOptionValue( option ) );
    if ( required && StringUtils.isEmpty( value ) ) {
      throw new ParseException( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0001_MISSING_ARG",
          option ) );
    }
    if ( !emptyOk && StringUtils.isEmpty( value ) ) {
      throw new ParseException( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0001_MISSING_ARG",
          option ) );
    }
    return value;
  }

  /**
   * Returns the option value from the command line
   *
   * @param shortOption
   *          the single character option whose value should be returned (NOTE: {@code null} will be returned if the
   *          option was not provided)
   * @param longOption
   *          the string option whose value should be returned (NOTE: {@code null} will be returned if the option was
   *          not provided)
   * @param required
   *          indicates if the option is required
   * @param emptyOk
   *          indicates if a blank value is acceptable
   * @return the value provided from the command line, or {@code null} if none was provided
   * @throws ParseException
   *           indicates the required or non-blank value was not provided
   */
  protected String getOptionValue( final String shortOption, final String longOption, final boolean required,
      final boolean emptyOk ) throws ParseException {
    // first try the short option parameter
    String value = StringUtils.trim( commandLine.getOptionValue( shortOption ) );
    if ( StringUtils.isEmpty( value ) ) {
      // if its empty, try the long option
      value = StringUtils.trim( commandLine.getOptionValue( longOption ) );
    }
    if ( required && StringUtils.isEmpty( value ) ) {
      throw new ParseException( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0001_MISSING_ARG",
          longOption ) );
    }
    if ( !emptyOk && StringUtils.isEmpty( value ) ) {
      throw new ParseException( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0001_MISSING_ARG",
          longOption ) );
    }
    return value;
  }

  /**
   * internal helper to write output file
   *
   * @param message
   * @param logFile
   */
  private void writeFile( String message, String logFile ) {
    try {
      File file = new File( logFile );
      FileOutputStream fout = FileUtils.openOutputStream( file );
      IOUtils.copy( IOUtils.toInputStream( message ), fout );
      fout.close();
    } catch ( Exception ex ) {
      ex.printStackTrace();
    }

  }

  /**
   *
   */
  protected static void printHelp() {
    HelpFormatter formatter = new HelpFormatter();
    formatter.printHelp( Messages.getInstance().getString( "CommandLineProcessor.INFO_PRINTHELP_CMDLINE" ), Messages
        .getInstance().getString( "CommandLineProcessor.INFO_PRINTHELP_HEADER" ), options, Messages.getInstance()
        .getString( "CommandLineProcessor.INFO_PRINTHELP_FOOTER" ) );
  }
}
TOP

Related Classes of org.pentaho.platform.plugin.services.importexport.CommandLineProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.