From e47e4a28ab843e39c20c33fdf77fd55bfec273ee Mon Sep 17 00:00:00 2001 From: "HDS\\rammansoor" Date: Sun, 22 Dec 2024 11:10:40 -0500 Subject: [PATCH] [BISERVER-15169] Adding debug logging to backup and restore process --- .../api}/importexport/ExportException.java | 4 +- .../{util => importexport}/IExportHelper.java | 7 +- .../api/util/IPentahoPlatformExporter.java | 5 + .../api/util/IRepositoryExportLogger.java | 80 ++ .../pentaho-solutions/system/importExport.xml | 3 + .../exporter/PentahoPlatformExporter.java | 179 ++- .../importer/LocaleFilesProcessor.java | 43 +- .../services/importer/PRPTImportHandler.java | 7 +- .../importer/PentahoPlatformImporter.java | 8 +- .../importer/SolutionImportHandler.java | 520 +++++++-- .../importexport/BaseExportProcessor.java | 17 +- .../importexport/CommandLineProcessor.java | 227 ++-- .../importexport/DefaultExportHandler.java | 1 + .../services/importexport/ExportHandler.java | 1 + .../importexport/IRepositoryImportLogger.java | 75 +- .../Log4JRepositoryExportLog.java | 90 ++ .../Log4JRepositoryExportLogger.java | 184 +++ .../Log4JRepositoryImportLog.java | 37 +- .../Log4JRepositoryImportLogger.java | 33 +- .../importexport/RepositoryTextLayout.java | 170 +++ .../importexport/SimpleExportProcessor.java | 11 +- .../importexport/ZipExportProcessor.java | 56 +- .../web/http/api/resources/FileResource.java | 1013 ++++++++--------- .../resources/RepositoryImportResource.java | 86 +- .../api/resources/services/FileService.java | 378 +++--- .../services/messages/messages.properties | 98 +- .../web/http/messages/messages.properties | 5 +- .../exporter/PentahoPlatformExporterTest.java | 63 +- .../importer/LocaleFilesProcessorTest.java | 60 +- .../importer/LocaleImportHandlerTest.java | 94 +- .../importer/PlatformImporterTest.java | 9 +- .../importexport/BaseExportProcessorTest.java | 5 +- .../importexport/ZipExportProcessorTest.java | 40 +- 33 files changed, 2419 insertions(+), 1190 deletions(-) rename {extensions/src/main/java/org/pentaho/platform/plugin/services => api/src/main/java/org/pentaho/platform/api}/importexport/ExportException.java (94%) rename api/src/main/java/org/pentaho/platform/api/{util => importexport}/IExportHelper.java (74%) create mode 100644 api/src/main/java/org/pentaho/platform/api/util/IRepositoryExportLogger.java create mode 100644 extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLog.java create mode 100644 extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLogger.java create mode 100644 extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/RepositoryTextLayout.java diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ExportException.java b/api/src/main/java/org/pentaho/platform/api/importexport/ExportException.java similarity index 94% rename from extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ExportException.java rename to api/src/main/java/org/pentaho/platform/api/importexport/ExportException.java index f822c06b1b8..caf9575044c 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ExportException.java +++ b/api/src/main/java/org/pentaho/platform/api/importexport/ExportException.java @@ -11,7 +11,7 @@ ******************************************************************************/ -package org.pentaho.platform.plugin.services.importexport; +package org.pentaho.platform.api.importexport; /* * This program is free software; you can redistribute it and/or modify it under the @@ -34,7 +34,7 @@ * Exception that indicates an error during import processing User: dkincade */ public class ExportException extends Exception { - public ExportException() { + public ExportException( ) { } public ExportException( final String message ) { diff --git a/api/src/main/java/org/pentaho/platform/api/util/IExportHelper.java b/api/src/main/java/org/pentaho/platform/api/importexport/IExportHelper.java similarity index 74% rename from api/src/main/java/org/pentaho/platform/api/util/IExportHelper.java rename to api/src/main/java/org/pentaho/platform/api/importexport/IExportHelper.java index 192edcf2ab7..81147808949 100644 --- a/api/src/main/java/org/pentaho/platform/api/util/IExportHelper.java +++ b/api/src/main/java/org/pentaho/platform/api/importexport/IExportHelper.java @@ -11,8 +11,11 @@ ******************************************************************************/ -package org.pentaho.platform.api.util; +package org.pentaho.platform.api.importexport; + public interface IExportHelper { - public void doExport( Object exportArg ); + public void doExport( Object exportArg ) throws ExportException; + + public String getName(); } diff --git a/api/src/main/java/org/pentaho/platform/api/util/IPentahoPlatformExporter.java b/api/src/main/java/org/pentaho/platform/api/util/IPentahoPlatformExporter.java index a03dc838056..249f8df0166 100644 --- a/api/src/main/java/org/pentaho/platform/api/util/IPentahoPlatformExporter.java +++ b/api/src/main/java/org/pentaho/platform/api/util/IPentahoPlatformExporter.java @@ -13,6 +13,11 @@ package org.pentaho.platform.api.util; +import org.pentaho.platform.api.importexport.IExportHelper; + public interface IPentahoPlatformExporter { void addExportHelper( IExportHelper helper ); + + IRepositoryExportLogger getRepositoryExportLogger(); + } diff --git a/api/src/main/java/org/pentaho/platform/api/util/IRepositoryExportLogger.java b/api/src/main/java/org/pentaho/platform/api/util/IRepositoryExportLogger.java new file mode 100644 index 00000000000..74cc5cc16b1 --- /dev/null +++ b/api/src/main/java/org/pentaho/platform/api/util/IRepositoryExportLogger.java @@ -0,0 +1,80 @@ +/*! ****************************************************************************** + * + * Pentaho + * + * Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file. + * + * Change Date: 2029-07-20 + ******************************************************************************/ + +package org.pentaho.platform.api.util; + +import org.apache.commons.logging.Log; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.StringLayout; + +import java.io.OutputStream; + +public interface IRepositoryExportLogger extends Log { + + + /** + * Initiates an import job. Each call creates a new log associated with the current thread. + * + * @param outputStream Will receive the html content of the log + * @param logLevel The log level to be logged. + * @param layout The layout to be use. + */ + void startJob( OutputStream outputStream, Level logLevel, StringLayout layout ); + + /** + * Initiates an import job. Each call creates a new log associated with the current thread. + * + * @param outputStream Will receive the html content of the log + * @param logLevel The log level to be logged. + */ + void startJob( OutputStream outputStream, Level logLevel ); + + /** + * Makes an "End Import Job" log entry and releases memory associated with this log. + */ + void endJob(); + + /** + * Log informational data. Should be called when the starting a new file and when finishing that file. + * + * @param s The information message to be logged. + */ + void info( String s ); + + /** + * Log an error. + * + * @param s The Error message to be logged. + */ + void error( String s ); + + /** + * Log debug information + * + * @param s The debug message to be logged + */ + void debug( String s ); + + /** + * Log error information + * + * @param e The exception to be logged. + */ + void error( Exception e ); + + /** + * Allows a class to check if an ImportLogger has been instantiated for the current thread. + * + * @return true if the logger is present. + */ + boolean hasLogger(); +} diff --git a/assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/importExport.xml b/assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/importExport.xml index 0a3195e3ff8..eca37e5f509 100644 --- a/assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/importExport.xml +++ b/assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/importExport.xml @@ -209,6 +209,9 @@ + + + diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporter.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporter.java index 476e8f3d6da..3b232d03066 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporter.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporter.java @@ -27,14 +27,12 @@ import org.pentaho.platform.api.repository.datasource.IDatasourceMgmtService; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; -import org.pentaho.platform.api.scheduler2.IJobScheduleRequest; import org.pentaho.platform.api.scheduler2.IScheduler; -import org.pentaho.platform.api.scheduler2.IJob; -import org.pentaho.platform.api.scheduler2.SchedulerException; import org.pentaho.platform.api.usersettings.IAnyUserSettingService; import org.pentaho.platform.api.usersettings.IUserSettingService; import org.pentaho.platform.api.usersettings.pojo.IUserSetting; -import org.pentaho.platform.api.util.IExportHelper; +import org.pentaho.platform.api.importexport.ExportException; +import org.pentaho.platform.api.importexport.IExportHelper; import org.pentaho.platform.api.util.IPentahoPlatformExporter; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.core.system.TenantUtils; @@ -42,7 +40,6 @@ import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalog; import org.pentaho.platform.plugin.services.importexport.DatabaseConnectionConverter; import org.pentaho.platform.plugin.services.importexport.DefaultExportHandler; -import org.pentaho.platform.plugin.services.importexport.ExportException; import org.pentaho.platform.plugin.services.importexport.ExportFileNameEncoder; import org.pentaho.platform.plugin.services.importexport.ExportManifestUserSetting; import org.pentaho.platform.plugin.services.importexport.RoleExport; @@ -118,7 +115,11 @@ public void addExportHelper( IExportHelper helper ) { public void runExportHelpers() { for ( IExportHelper helper : exportHelpers ) { - helper.doExport( this ); + try { + helper.doExport( this ); + } catch ( ExportException exportException ) { + getRepositoryExportLogger().error( "Error performing backup of component [ " + helper.getName() + " ] Cause [ " + exportException.getLocalizedMessage() + " ]" ); + } } } @@ -130,6 +131,7 @@ public void runExportHelpers() { @Override public File performExport( RepositoryFile exportRepositoryFile ) throws ExportException, IOException { + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_PROCESS" ) ); // always export root exportRepositoryFile = getUnifiedRepository().getFile( ROOT ); @@ -139,7 +141,12 @@ public File performExport( RepositoryFile exportRepositoryFile ) throws ExportEx zos = new ZipOutputStream( new FileOutputStream( exportFile ) ); - exportFileContent( exportRepositoryFile ); + try { + exportFileContent( exportRepositoryFile ); + } catch ( ExportException | IOException exception ) { + getRepositoryExportLogger().error( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR_EXPORT_FILE_CONTENT", exception.getLocalizedMessage() ) ); + } + exportDatasources(); exportMondrianSchemas(); exportMetadataModels(); @@ -157,7 +164,7 @@ public File performExport( RepositoryFile exportRepositoryFile ) throws ExportEx getExportManifest().toXml( zos ); } catch ( Exception e ) { // todo: add to messages.properties - log.error( "Error generating export XML" ); + getRepositoryExportLogger().error( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR_GENERATING_EXPORT_XML" ) ); } zos.closeEntry(); @@ -169,34 +176,56 @@ public File performExport( RepositoryFile exportRepositoryFile ) throws ExportEx initManifest(); zos = null; + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_PROCESS" ) ); + return exportFile; } protected void exportDatasources() { - log.debug( "export datasources" ); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_JDBC_DATASOURCE" ) ); // get all connection to export + int successfulExportJDBCDSCount = 0; + int databaseConnectionsSize = 0; try { - for ( IDatabaseConnection datasource : getDatasourceMgmtService().getDatasources() ) { + List databaseConnections = getDatasourceMgmtService().getDatasources(); + if ( databaseConnections != null ) { + databaseConnectionsSize = databaseConnections.size(); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_COUNT_JDBC_DATASOURCE_TO_EXPORT", databaseConnectionsSize ) ); + } + for ( IDatabaseConnection datasource : databaseConnections ) { if ( datasource instanceof org.pentaho.database.model.DatabaseConnection ) { + getRepositoryExportLogger().debug( "Starting to perform backup of datasource [ " + datasource.getName() + " ]" ); getExportManifest().addDatasource( DatabaseConnectionConverter.model2export( datasource ) ); + getRepositoryExportLogger().debug( "Finished performing backup of datasource [ " + datasource.getName() + " ]" ); + successfulExportJDBCDSCount++; } } } catch ( DatasourceMgmtServiceException e ) { - log.warn( e.getMessage(), e ); + getRepositoryExportLogger().warn( "Unable to retrieve JDBC datasource(s). Cause [" + e.getMessage() + " ]" ); + getRepositoryExportLogger().debug( "Unable to retrieve JDBC datasource(s). Cause [" + e.getMessage() + " ]", e ); } + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_SUCCESSFUL_JDBC_DATASOURCE_EXPORT_COUNT", successfulExportJDBCDSCount, databaseConnectionsSize ) ); + + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_JDBC_DATASOURCE" ) ); } protected void exportMetadataModels() { - log.debug( "export metadata models" ); - + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_METADATA" ) ); + int successfulExportMetadataDSCount = 0; + int metadataDSSize = 0; // get all of the metadata models Set domainIds = getMetadataDomainRepository().getDomainIds(); + if ( domainIds != null ) { + metadataDSSize = domainIds.size(); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_COUNT_METADATA_DATASOURCE_TO_EXPORT", metadataDSSize ) ); + } for ( String domainId : domainIds ) { // get all of the files for this model Map domainFilesData = getDomainFilesData( domainId ); - + getRepositoryExportLogger().debug( "Starting to backup metadata datasource [ " + domainId + " ]" ); for ( String fileName : domainFilesData.keySet() ) { + getRepositoryExportLogger().trace( "Adding metadata file [ " + fileName + " ]" ); // write the file to the zip String metadataFilePath = METADATA_PATH_IN_ZIP + fileName; if ( !metadataFilePath.endsWith( ".xmi" ) ) { @@ -218,9 +247,9 @@ protected void exportMetadataModels() { metadata.setDomainId( domainId ); metadata.setFile( metadataFilePath ); getExportManifest().addMetadata( metadata ); - + successfulExportMetadataDSCount++; } catch ( IOException e ) { - log.warn( e.getMessage(), e ); + getRepositoryExportLogger().warn( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR_METADATA_DATASOURCE_EXPORT", e.getMessage() ), e ); } finally { IOUtils.closeQuietly( inputStream ); try { @@ -229,22 +258,33 @@ protected void exportMetadataModels() { // can't close the entry of input stream } } + getRepositoryExportLogger().trace( "Successfully added metadata file [ " + fileName + " ] to the manifest" ); } + getRepositoryExportLogger().debug( "Successfully perform backup of metadata datasource [ " + domainId + " ]" ); } + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_SUCCESSFUL_METADATA_DATASOURCE_EXPORT_COUNT", successfulExportMetadataDSCount, metadataDSSize ) ); + + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_METADATA" ) ); } protected void exportMondrianSchemas() { - log.debug( "export mondrian schemas" ); - + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_MONDRIAN_DATASOURCE" ) ); // Get the mondrian catalogs available in the repo + int successfulExportMondrianDSCount = 0; + int mondrianDSSize = 0; List catalogs = getMondrianCatalogService().listCatalogs( getSession(), false ); + if ( catalogs != null ) { + mondrianDSSize = catalogs.size(); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_COUNT_MONDRIAN_DATASOURCE_TO_EXPORT", mondrianDSSize ) ); + } for ( MondrianCatalog catalog : catalogs ) { - + getRepositoryExportLogger().debug( "Starting to perform backup mondrian datasource [ " + catalog.getName() + " ]" ); // get the files for this catalog Map files = getMondrianCatalogRepositoryHelper().getModrianSchemaFiles( catalog.getName() ); ExportManifestMondrian mondrian = new ExportManifestMondrian(); for ( String fileName : files.keySet() ) { + getRepositoryExportLogger().trace( "Starting to add filename [ " + fileName + " ] with datasource [" + catalog.getName() + " ] to the bundle" ); // write the file to the zip String path = ANALYSIS_PATH_IN_ZIP + catalog.getName() + "/" + fileName; @@ -274,10 +314,10 @@ protected void exportMondrianSchemas() { mondrianParameters.put( "EnableXmla", Boolean.toString( xmlaEnabled ) ); StreamSupport.stream( catalog.getConnectProperties().spliterator(), false ) - .filter( p -> !mondrianParameters.containsKey( p.getKey() ) ) - //if value is escaped it should be unescaped to avoid double escape after export in xml file, because - //marshaller executes escaping as well - .forEach( p -> mondrianParameters.put( p.getKey(), StringEscapeUtils.unescapeXml( p.getValue() ) ) ); + .filter( p -> !mondrianParameters.containsKey( p.getKey() ) ) + //if value is escaped it should be unescaped to avoid double escape after export in xml file, because + //marshaller executes escaping as well + .forEach( p -> mondrianParameters.put( p.getKey(), StringEscapeUtils.unescapeXml( p.getValue() ) ) ); mondrian.setParameters( mondrianParameters ); } @@ -286,7 +326,7 @@ protected void exportMondrianSchemas() { zos.putNextEntry( zipEntry ); IOUtils.copy( inputStream, zos ); } catch ( IOException e ) { - log.warn( e.getMessage(), e ); + getRepositoryExportLogger().error( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR_MONDRIAN_DATASOURCE_EXPORT" ) ); } finally { IOUtils.closeQuietly( inputStream ); try { @@ -298,8 +338,13 @@ protected void exportMondrianSchemas() { } if ( mondrian.getCatalogName() != null && mondrian.getFile() != null ) { getExportManifest().addMondrian( mondrian ); + getRepositoryExportLogger().debug( "Successfully added filename [ " + mondrian.getFile() + " ] with catalog [" + mondrian.getCatalogName() + " ] to the bundle" ); + successfulExportMondrianDSCount++; } } + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_SUCCESSFUL_MONDRIAN_DATASOURCE_EXPORT_COUNT", successfulExportMondrianDSCount, mondrianDSSize ) ); + + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_MONDRIAN_DATASOURCE" ) ); } protected boolean parseXmlaEnabled( String dataSourceInfo ) { @@ -315,13 +360,15 @@ protected boolean parseXmlaEnabled( String dataSourceInfo ) { } protected void exportUsersAndRoles() { - log.debug( "export users & roles" ); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_USER" ) ); + int successfulExportUsers = 0; + int usersSize = 0; IUserRoleListService userRoleListService = PentahoSystem.get( IUserRoleListService.class ); UserDetailsService userDetailsService = PentahoSystem.get( UserDetailsService.class ); IRoleAuthorizationPolicyRoleBindingDao roleBindingDao = PentahoSystem.get( - IRoleAuthorizationPolicyRoleBindingDao.class ); + IRoleAuthorizationPolicyRoleBindingDao.class ); ITenant tenant = TenantUtils.getCurrentTenant(); // get the user settings for this user @@ -329,88 +376,126 @@ protected void exportUsersAndRoles() { //User Export List userList = userRoleListService.getAllUsers( tenant ); + if ( userList != null ) { + usersSize = userList.size(); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_COUNT_USER_TO_EXPORT", usersSize ) ); + } for ( String user : userList ) { + getRepositoryExportLogger().debug( "Starting backup of user [ " + user + " ] " ); UserExport userExport = new UserExport(); userExport.setUsername( user ); userExport.setPassword( userDetailsService.loadUserByUsername( user ).getPassword() ); for ( String role : userRoleListService.getRolesForUser( tenant, user ) ) { + getRepositoryExportLogger().trace( "user [ " + user + " ] has an associated role [ " + role + " ]" ); userExport.setRole( role ); } if ( service != null && service instanceof IAnyUserSettingService ) { + getRepositoryExportLogger().debug( "Starting backup of user specific settings for user [ " + user + " ] " ); IAnyUserSettingService userSettings = (IAnyUserSettingService) service; List settings = userSettings.getUserSettings( user ); if ( settings != null ) { for ( IUserSetting setting : settings ) { + getRepositoryExportLogger().debug( "Adding user specific setting [ " + + setting.getSettingName() + " ] with value [ " + setting.getSettingValue() + " ] to backup" ); userExport.addUserSetting( new ExportManifestUserSetting( setting ) ); + getRepositoryExportLogger().debug( "Successfully added user specific setting [ " + + setting.getSettingName() + " ] with value [ " + setting.getSettingValue() + " ] to backup" ); } } + getRepositoryExportLogger().debug( "Finished backup of user specific settings for user [ " + user + " ] " ); } this.getExportManifest().addUserExport( userExport ); + successfulExportUsers++; + getRepositoryExportLogger().debug( "Successfully perform backup of user [ " + user + " ] " ); } // export the global user settings if ( service != null ) { + getRepositoryExportLogger().debug( "Starting backup of global user settings" ); List globalUserSettings = service.getGlobalUserSettings(); if ( globalUserSettings != null ) { for ( IUserSetting setting : globalUserSettings ) { getExportManifest().addGlobalUserSetting( new ExportManifestUserSetting( setting ) ); } } + getRepositoryExportLogger().debug( "Finished backup of global user settings" ); } + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_SUCCESSFUL_ROLE_EXPORT_COUNT", successfulExportUsers, usersSize ) ); + + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_USER" ) ); + + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_ROLE" ) ); + int successfulExportRoles = 0; + int rolesSize = 0; //RoleExport List roles = userRoleListService.getAllRoles(); + if ( roles != null ) { + rolesSize = roles.size(); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_COUNT_ROLE_TO_EXPORT", rolesSize ) ); + } for ( String role : roles ) { + getRepositoryExportLogger().debug( "Starting backup of role [ " + role + " ] " ); RoleExport roleExport = new RoleExport(); roleExport.setRolename( role ); roleExport.setPermission( roleBindingDao.getRoleBindingStruct( null ).bindingMap.get( role ) ); exportManifest.addRoleExport( roleExport ); + successfulExportRoles++; + getRepositoryExportLogger().debug( "Finished backup of role [ " + role + " ] " ); } + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_SUCCESSFUL_ROLE_EXPORT_COUNT", successfulExportRoles, rolesSize ) ); + + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_ROLE" ) ); } protected void exportMetastore() throws IOException { - log.debug( "export the metastore" ); + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_METASTORE" ) ); try { + getRepositoryExportLogger().debug( "Starting to copy metastore to a temp location" ); Path tempDirectory = Files.createTempDirectory( METASTORE ); IMetaStore xmlMetaStore = new XmlMetaStore( tempDirectory.toString() ); MetaStoreUtil.copy( getRepoMetaStore(), xmlMetaStore ); - + getRepositoryExportLogger().debug( "Finished to copying metastore to a temp location" ); + getRepositoryExportLogger().debug( "Starting to zip the metastore" ); File zippedMetastore = Files.createTempFile( METASTORE, EXPORT_TEMP_FILENAME_EXT ).toFile(); ZipOutputStream zipOutputStream = new ZipOutputStream( new FileOutputStream( zippedMetastore ) ); zipFolder( tempDirectory.toFile(), zipOutputStream, tempDirectory.toString() ); zipOutputStream.close(); - + getRepositoryExportLogger().debug( "Finished zipping the metastore" ); // now that we have the zipped content of an xml metastore, we need to write that to the export bundle FileInputStream zis = new FileInputStream( zippedMetastore ); String zipFileLocation = METASTORE + METASTORE_BACKUP_EXT; ZipEntry metastoreZipFileZipEntry = new ZipEntry( zipFileLocation ); + getRepositoryExportLogger().debug( "Starting to add the metastore zip to the bundle" ); zos.putNextEntry( metastoreZipFileZipEntry ); try { IOUtils.copy( zis, zos ); + getRepositoryExportLogger().debug( "Finished adding the metastore zip to the bundle" ); } catch ( IOException e ) { throw e; } finally { zis.close(); zos.closeEntry(); } - + getRepositoryExportLogger().debug( "Starting to add the metastore to the manifest" ); // add an ExportManifest entry for the metastore. ExportManifestMetaStore exportManifestMetaStore = new ExportManifestMetaStore( zipFileLocation, - getRepoMetaStore().getName(), - getRepoMetaStore().getDescription() ); + getRepoMetaStore().getName(), + getRepoMetaStore().getDescription() ); getExportManifest().setMetaStore( exportManifestMetaStore ); zippedMetastore.deleteOnExit(); tempDirectory.toFile().deleteOnExit(); - + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_SUCCESSFUL_EXPORT_METASTORE" ) ); } catch ( Exception e ) { - log.error( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR.ExportingMetaStore" ) ); - log.debug( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR.ExportingMetaStore" ), e ); + getRepositoryExportLogger().error( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR.ExportingMetaStore" ) ); + getRepositoryExportLogger().debug( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR.ExportingMetaStore" ), e ); } + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_METASTORE" ) ); } protected IMetaStore getRepoMetaStore() { @@ -419,7 +504,8 @@ protected IMetaStore getRepoMetaStore() { metastore = MetaStoreExportUtil.connectToRepository( null ).getRepositoryMetaStore(); } catch ( KettleException e ) { // can't get the metastore to import into - log.debug( "Can't get the metastore to import into" ); + getRepositoryExportLogger().debug( "Can't get the metastore to import into" ); + } } return metastore; @@ -462,6 +548,7 @@ protected void zipFolder( File file, ZipOutputStream zos, String pathPrefixToRem } protected void exportFileContent( RepositoryFile exportRepositoryFile ) throws IOException, ExportException { + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_START_EXPORT_REPOSITORY_OBJECT" ) ); // get the file path String filePath = new File( this.path ).getParent(); if ( filePath == null ) { @@ -474,19 +561,33 @@ protected void exportFileContent( RepositoryFile exportRepositoryFile ) throws I throw new FileNotFoundException( "JCR file not found: " + this.path ); } + if ( exportRepositoryFile.isFolder() ) { // Handle recursive export + getRepositoryExportLogger().trace( "Repository object [ " + exportRepositoryFile.getName() + "] is a folder" ); getExportManifest().getManifestInformation().setRootFolder( path.substring( 0, path.lastIndexOf( "/" ) + 1 ) ); // don't zip root folder without name if ( !ClientRepositoryPaths.getRootFolderPath().equals( exportRepositoryFile.getPath() ) ) { + getRepositoryExportLogger().trace( "Adding a name to the root folder" ); zos.putNextEntry( new ZipEntry( getFixedZipEntryName( exportRepositoryFile, filePath ) ) ); } + getRepositoryExportLogger().debug( "Starting recursive backup of a folder [ " + exportRepositoryFile.getName() + " ]" ); exportDirectory( exportRepositoryFile, zos, filePath ); } else { + getRepositoryExportLogger().trace( "Repository object [ " + exportRepositoryFile.getName() + "] is a file" ); getExportManifest().getManifestInformation().setRootFolder( path.substring( 0, path.lastIndexOf( "/" ) + 1 ) ); - exportFile( exportRepositoryFile, zos, filePath ); + + try { + getRepositoryExportLogger().debug( "Starting backup of a file [ " + exportRepositoryFile.getName() + " ]" ); + exportFile( exportRepositoryFile, zos, filePath ); + } catch ( ExportException | IOException exception ) { + getRepositoryExportLogger().error( Messages.getInstance().getString( "PentahoPlatformExporter.ERROR_EXPORT_REPOSITORY_OBJECT", exportRepositoryFile.getName() ) ); + } finally { + getRepositoryExportLogger().debug( "Finished the backup of a file [ " + exportRepositoryFile.getName() + " ]" ); + } } + getRepositoryExportLogger().info( Messages.getInstance().getString( "PentahoPlatformExporter.INFO_END_EXPORT_REPOSITORY_OBJECT" ) ); } protected Map getDomainFilesData( String domainId ) { @@ -534,7 +635,7 @@ public MondrianCatalogRepositoryHelper getMondrianCatalogRepositoryHelper() { } public void setMondrianCatalogRepositoryHelper( - MondrianCatalogRepositoryHelper mondrianCatalogRepositoryHelper ) { + MondrianCatalogRepositoryHelper mondrianCatalogRepositoryHelper ) { this.mondrianCatalogRepositoryHelper = mondrianCatalogRepositoryHelper; } @@ -546,7 +647,7 @@ public IMondrianCatalogService getMondrianCatalogService() { } public void setMondrianCatalogService( - IMondrianCatalogService mondrianCatalogService ) { + IMondrianCatalogService mondrianCatalogService ) { this.mondrianCatalogService = mondrianCatalogService; } diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessor.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessor.java index a582b64e87c..229a94d8872 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessor.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessor.java @@ -46,9 +46,8 @@ * this class is used to handle .properties files that are XACTION or URL files that contain the metadata used for * localization. These files may contain additional information that will allow the properties file to be stored and * used by XACTION and URL as well as localize the title and description. - * + * * @author tband /ezequiel / tkafalas - * */ public class LocaleFilesProcessor { @@ -68,7 +67,6 @@ public LocaleFilesProcessor() { } /** - * * @param file * @param parentPath * @param bytes @@ -127,11 +125,11 @@ public boolean isLocaleFile( IRepositoryFileBundle file, String parentPath, byte switch ( sourceVersion ) { case 1: localeFile = new LocaleFileDescriptor( name, PROPERTIES_EXT, description, filePath, localeRepositoryFile, - inputStream ); + inputStream ); break; case 2: localeFile = - new LocaleFileDescriptor( name, LOCALE_EXT, description, filePath, localeRepositoryFile, inputStream ); + new LocaleFileDescriptor( name, LOCALE_EXT, description, filePath, localeRepositoryFile, inputStream ); break; default: localeFile = new LocaleFileDescriptor( name, description, filePath, localeRepositoryFile, inputStream ); @@ -172,12 +170,12 @@ public Properties loadProperties( InputStream inputStream ) throws IOException { } public boolean createLocaleEntry( String filePath, String name, String title, String description, - RepositoryFile file, InputStream is ) throws IOException { + RepositoryFile file, InputStream is ) throws IOException { return createLocaleEntry( filePath, name, title, description, file, is, 2 ); } public boolean createLocaleEntry( String filePath, String name, String title, String description, - RepositoryFile file, InputStream is, int sourceVersion ) throws IOException { + RepositoryFile file, InputStream is, int sourceVersion ) throws IOException { boolean success = false; // need to spoof the locales to think this is the actual parent .prpt and not the meta.xml @@ -205,7 +203,8 @@ public boolean createLocaleEntry( String filePath, String name, String title, St return success; } - public void processLocaleFiles( IPlatformImporter importer ) throws PlatformImportException { + public int processLocaleFiles( IPlatformImporter importer ) throws PlatformImportException { + int successfulProcessCount = 0; RepositoryFileImportBundle.Builder bundleBuilder = new RepositoryFileImportBundle.Builder(); IPlatformMimeResolver mimeResolver = PentahoSystem.get( IPlatformMimeResolver.class ); String mimeType = mimeResolver.resolveMimeForFileName( FILE_LOCALE_RESOLVER ); @@ -219,11 +218,11 @@ public void processLocaleFiles( IPlatformImporter importer ) throws PlatformImpo //substringing the actual name for the dot char, make sure that things like get converted //to , since it can exist a file which we don't want to import String actualFileName = localeFile.getFile().getName().indexOf( "." ) != -1 - ? - localeFile.getFile().getName().substring( 0, localeFile.getFile().getName().indexOf( "." ) ) - : - localeFile.getFile().getName(); - filesWithLocaleFiles.add( localeFile.getPath() + actualFileName ); + ? + localeFile.getFile().getName().substring( 0, localeFile.getFile().getName().indexOf( "." ) ) + : + localeFile.getFile().getName(); + filesWithLocaleFiles.add( localeFile.getPath() + actualFileName ); } } @@ -232,20 +231,23 @@ public void processLocaleFiles( IPlatformImporter importer ) throws PlatformImpo if ( !StringUtils.isEmpty( extension ) && extension.equals( PROPERTIES_EXT ) ) { //.properties files are only added if there is no .locale file for the file String actualFileName = localeFile.getFile().getName().indexOf( "." ) != -1 - ? - localeFile.getFile().getName().substring( 0, localeFile.getFile().getName().indexOf( "." ) ) - : - localeFile.getFile().getName(); + ? + localeFile.getFile().getName().substring( 0, localeFile.getFile().getName().indexOf( "." ) ) + : + localeFile.getFile().getName(); if ( filesWithLocaleFiles.contains( localeFile.getPath() + actualFileName ) ) { continue; } } - proceed( importer, bundleBuilder, mimeType, localeFile ); + if ( proceed( importer, bundleBuilder, mimeType, localeFile ) ) { + successfulProcessCount++; + } } + return successfulProcessCount; } - protected void proceed( IPlatformImporter importer, RepositoryFileImportBundle.Builder bundleBuilder, String mimeType, - LocaleFileDescriptor localeFile ) throws PlatformImportException { + protected boolean proceed( IPlatformImporter importer, RepositoryFileImportBundle.Builder bundleBuilder, String mimeType, + LocaleFileDescriptor localeFile ) throws PlatformImportException { bundleBuilder.name( localeFile.getName() ); bundleBuilder.comment( localeFile.getDescription() ); bundleBuilder.path( localeFile.getPath() ); @@ -254,6 +256,7 @@ protected void proceed( IPlatformImporter importer, RepositoryFileImportBundle.B bundleBuilder.mime( mimeType ); IPlatformImportBundle platformImportBundle = bundleBuilder.build(); importer.importFile( platformImportBundle ); + return true; } @VisibleForTesting diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PRPTImportHandler.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PRPTImportHandler.java index 26f26fddff6..16840b190bc 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PRPTImportHandler.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PRPTImportHandler.java @@ -51,7 +51,7 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce String fileName = importBundle.getName(); String filePath = - ( importBundle.getPath().equals( "/" ) || importBundle.getPath().equals( "\\" ) ) ? "" : importBundle.getPath(); + ( importBundle.getPath().equals( "/" ) || importBundle.getPath().equals( "\\" ) ) ? "" : importBundle.getPath(); // If is locale file store it for later processing. // need to extract this from meta.xml @@ -76,7 +76,7 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce } private void fillLocaleEntry( LocaleFilesProcessor localeFilesProcessor, DocumentMetaData metaData, String filePath, - String fileName, RepositoryFile rf ) throws IOException { + String fileName, RepositoryFile rf ) throws IOException { String description = (String) metaData.getBundleAttribute( ODFMetaAttributeNames.DublinCore.NAMESPACE, ODFMetaAttributeNames.DublinCore.DESCRIPTION ); if ( StringUtils.isEmpty( description, true ) ) { @@ -95,9 +95,10 @@ private void fillLocaleEntry( LocaleFilesProcessor localeFilesProcessor, Documen // keep it protected for test goal, we should not add any logic for this method such we just // incapsulate getting information from external class + /** * extract metadata from input bundle - * + * * @param bytes * @return * @throws PlatformImportException if we are failed to create metadata from input data diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PentahoPlatformImporter.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PentahoPlatformImporter.java index 4fc79b802e2..fc632db8eea 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PentahoPlatformImporter.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/PentahoPlatformImporter.java @@ -54,6 +54,8 @@ public class PentahoPlatformImporter implements IPlatformImporter { private IPlatformMimeResolver mimeResolver; private IRepositoryImportLogger repositoryImportLogger; private IRepositoryContentConverterHandler repositoryContentConverterHandler; + private static final String IMPORT = "import"; + private static final String RESTORE = "restore"; public PentahoPlatformImporter( List handlerList, IRepositoryContentConverterHandler repositoryContentConverterHandler ) { @@ -141,8 +143,8 @@ public void importFile( IPlatformImportBundle file ) throws PlatformImportExcept Throwable cause = ce.getCause(); if ( cause instanceof KettleMissingPluginsException ) { throw new PlatformImportException( messages - .getString( "PentahoPlatformImporter.ERROR_0008_PUBLISH_JOB_OR_TRANS_WITH_MISSING_PLUGINS", cause.getLocalizedMessage() ), - PlatformImportException.PUBLISH_JOB_OR_TRANS_WITH_MISSING_PLUGINS, cause + .getString( "PentahoPlatformImporter.ERROR_0008_PUBLISH_JOB_OR_TRANS_WITH_MISSING_PLUGINS", cause.getLocalizedMessage() ), + PlatformImportException.PUBLISH_JOB_OR_TRANS_WITH_MISSING_PLUGINS, cause ); } } catch ( Exception e1 ) { @@ -179,7 +181,7 @@ private void logImportFile( IPlatformImportBundle file ) { // If doing a mondrian publish then there will be no active logger if ( repositoryImportLogger.hasLogger() && repositoryFilePath != null && repositoryFilePath.length() > 0 ) { repositoryImportLogger.setCurrentFilePath( repositoryFilePath ); - repositoryImportLogger.warn( file.getName() ); + repositoryImportLogger.debug( "Starting " + ( repositoryImportLogger.isPerformingRestore() ? RESTORE : IMPORT ) + " of file " + file.getName() ); } } diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/SolutionImportHandler.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/SolutionImportHandler.java index 6958969d2ce..d5d1e56cc96 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/SolutionImportHandler.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importer/SolutionImportHandler.java @@ -96,6 +96,7 @@ public class SolutionImportHandler implements IPlatformImportHandler { private List mimeTypes; private boolean overwriteFile; private List files; + private boolean isPerformingRestore = false; public SolutionImportHandler( List mimeTypes ) { this.mimeTypes = mimeTypes; @@ -113,28 +114,32 @@ public Log getLogger() { @Override public void importFile( IPlatformImportBundle bundle ) throws PlatformImportException, DomainIdNullException, - DomainAlreadyExistsException, DomainStorageException, IOException { - + DomainAlreadyExistsException, DomainStorageException, IOException { + IPlatformImporter platformImporter = PentahoSystem.get( IPlatformImporter.class ); + isPerformingRestore = platformImporter.getRepositoryImportLogger().isPerformingRestore(); + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_PROCESS" ) ); + } RepositoryFileImportBundle importBundle = (RepositoryFileImportBundle) bundle; + + // Processing file + if ( isPerformingRestore ) { + getLogger().debug( " Start: pre processing files and folder from the bundle" ); + } if ( !processZip( bundle.getInputStream() ) ) { // Something went wrong, do not proceed! return; } - - LocaleFilesProcessor localeFilesProcessor = new LocaleFilesProcessor(); + if ( isPerformingRestore ) { + getLogger().debug( " End: pre processing files and folder from the bundle" ); + } setOverwriteFile( bundle.overwriteInRepository() ); - - IPlatformImporter importer = PentahoSystem.get( IPlatformImporter.class ); - cachedImports = new HashMap<>(); //Process Manifest Settings ExportManifest manifest = getImportSession().getManifest(); - String manifestVersion = null; // Process Metadata if ( manifest != null ) { - manifestVersion = manifest.getManifestInformation().getManifestVersion(); - // import the users Map> roleToUserMap = importUsers( manifest.getUserExports() ); @@ -150,36 +155,32 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce // import the metastore importMetaStore( manifest.getMetaStore(), bundle.overwriteInRepository() ); - // Add DB Connections - List datasourceList = manifest.getDatasourceList(); - if ( datasourceList != null ) { - IDatasourceMgmtService datasourceMgmtSvc = PentahoSystem.get( IDatasourceMgmtService.class ); - for ( org.pentaho.platform.plugin.services.importexport.exportManifest.bindings.DatabaseConnection databaseConnection : datasourceList ) { - if ( databaseConnection.getDatabaseType() == null ) { - // don't try to import the connection if there is no type it will cause an error - // However, if this is the DI Server, and the connection is defined in a ktr, it will import automatically - getLogger().warn( Messages.getInstance() - .getString( "SolutionImportHandler.ConnectionWithoutDatabaseType", databaseConnection.getName() ) ); - continue; - } - try { - IDatabaseConnection existingDBConnection = - datasourceMgmtSvc.getDatasourceByName( databaseConnection.getName() ); - if ( existingDBConnection != null && existingDBConnection.getName() != null ) { - if ( isOverwriteFile() ) { - databaseConnection.setId( existingDBConnection.getId() ); - datasourceMgmtSvc.updateDatasourceByName( databaseConnection.getName(), - DatabaseConnectionConverter.export2model( databaseConnection ) ); - } - } else { - datasourceMgmtSvc.createDatasource( DatabaseConnectionConverter.export2model( databaseConnection ) ); - } - } catch ( Exception e ) { - e.printStackTrace(); - } - } - } + // import jdbc datasource + importJDBCDataSource( manifest ); } + // import files and folders + importRepositoryFilesAndFolders( manifest, bundle ); + + // import schedules + if ( manifest != null ) { + importSchedules( manifest.getScheduleList() ); + } + } + + protected void importRepositoryFilesAndFolders( ExportManifest manifest, IPlatformImportBundle bundle ) throws IOException { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_FILEFOLDER" ) ); + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_FILEFOLDER", files.size() ) ); + } + Integer successfulFilesImportCount = 0; + String manifestVersion = null; + if ( manifest != null ) { + manifestVersion = manifest.getManifestInformation().getManifestVersion(); + } + RepositoryFileImportBundle importBundle = (RepositoryFileImportBundle) bundle; + + LocaleFilesProcessor localeFilesProcessor = new LocaleFilesProcessor(); + IPlatformImporter importer = PentahoSystem.get( IPlatformImporter.class ); for ( IRepositoryFileBundle fileBundle : files ) { String fileName = fileBundle.getFile().getName(); @@ -189,15 +190,26 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce actualFilePath = ExportFileNameEncoder.decodeZipFileName( actualFilePath ); } String repositoryFilePath = - RepositoryFilenameUtils.concat( PentahoPlatformImporter.computeBundlePath( actualFilePath ), fileName ); + RepositoryFilenameUtils.concat( PentahoPlatformImporter.computeBundlePath( actualFilePath ), fileName ); if ( cachedImports.containsKey( repositoryFilePath ) ) { + getLogger().debug( "Repository object with path [ " + repositoryFilePath + " ] found in the cache" ); byte[] bytes = IOUtils.toByteArray( fileBundle.getInputStream() ); RepositoryFileImportBundle.Builder builder = cachedImports.get( repositoryFilePath ); builder.input( new ByteArrayInputStream( bytes ) ); - importer.importFile( build( builder ) ); - continue; + try { + importer.importFile( build( builder ) ); + if ( isPerformingRestore ) { + getLogger().debug( "Successfully restored repository object with path [ " + repositoryFilePath + " ] from the cache" ); + } + successfulFilesImportCount++; + continue; + } catch ( PlatformImportException e ) { + if ( isPerformingRestore ) { + getLogger().error( Messages.getInstance().getString( "SolutionImportHandler.ERROR_IMPORTING_REPOSITORY_OBJECT", repositoryFilePath, e.getLocalizedMessage() ) ); + } + } } RepositoryFileImportBundle.Builder bundleBuilder = new RepositoryFileImportBundle.Builder(); @@ -221,14 +233,14 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce // If is locale file store it for later processing. if ( localeFilesProcessor.isLocaleFile( fileBundle, importBundle.getPath(), bytes ) ) { getLogger().trace( Messages.getInstance() - .getString( "SolutionImportHandler.SkipLocaleFile", repositoryFilePath ) ); + .getString( "SolutionImportHandler.SkipLocaleFile", repositoryFilePath ) ); continue; } bundleBuilder.input( bundleInputStream ); bundleBuilder.mime( solutionHelper.getMime( fileName ) ); String filePath = - ( decodedFilePath.equals( "/" ) || decodedFilePath.equals( "\\" ) ) ? "" : decodedFilePath; + ( decodedFilePath.equals( "/" ) || decodedFilePath.equals( "\\" ) ) ? "" : decodedFilePath; repositoryFilePath = RepositoryFilenameUtils.concat( importBundle.getPath(), filePath ); } @@ -240,13 +252,13 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce sourcePath = fileName; } else { sourcePath = - RepositoryFilenameUtils.concat( PentahoPlatformImporter.computeBundlePath( actualFilePath ), fileName ); + RepositoryFilenameUtils.concat( PentahoPlatformImporter.computeBundlePath( actualFilePath ), fileName ); } //This clause was added for processing ivb files so that it would not try process acls on folders that the user //may not have rights to such as /home or /public if ( manifest != null && manifest.getExportManifestEntity( sourcePath ) == null && fileBundle.getFile() - .isFolder() ) { + .isFolder() ) { continue; } @@ -273,7 +285,17 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce } IPlatformImportBundle platformImportBundle = build( bundleBuilder ); - importer.importFile( platformImportBundle ); + try { + importer.importFile( platformImportBundle ); + successfulFilesImportCount++; + if ( isPerformingRestore ) { + getLogger().debug( "Successfully restored repository object with path [ " + repositoryFilePath + " ]" ); + } + } catch ( PlatformImportException e ) { + if ( isPerformingRestore ) { + getLogger().error( Messages.getInstance().getString( "SolutionImportHandler.ERROR_IMPORTING_REPOSITORY_OBJECT", repositoryFilePath, e.getLocalizedMessage() ) ); + } + } if ( bundleInputStream != null ) { bundleInputStream.close(); @@ -281,12 +303,75 @@ public void importFile( IPlatformImportBundle bundle ) throws PlatformImportExce } } - if ( manifest != null ) { - importSchedules( manifest.getScheduleList() ); + // Process locale files. + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_LOCALEFILE" ) ); + } + int successfulLocaleFilesProcessed = 0; + try { + successfulLocaleFilesProcessed = localeFilesProcessor.processLocaleFiles( importer ); + } catch ( PlatformImportException e ) { + if ( isPerformingRestore ) { + getLogger().error( Messages.getInstance().getString( "SolutionImportHandler.ERROR_IMPORTING_LOCALE_FILE", e.getLocalizedMessage() ) ); + } + } finally { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_LOCALEFILE" ) ); + } } - // Process locale files. - localeFilesProcessor.processLocaleFiles( importer ); + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_SUCCESSFUL_REPOSITORY_IMPORT_COUNT", successfulFilesImportCount + successfulLocaleFilesProcessed, files.size() ) ); + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_FILEFOLDER" ) ); + } + } + + protected void importJDBCDataSource( ExportManifest manifest ) { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_DATASOURCE" ) ); + } + // Add DB Connections + List datasourceList = manifest.getDatasourceList(); + if ( datasourceList != null ) { + int successfulDatasourceImportCount = 0; + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_DATASOURCE", datasourceList.size() ) ); + } + IDatasourceMgmtService datasourceMgmtSvc = PentahoSystem.get( IDatasourceMgmtService.class ); + for ( org.pentaho.platform.plugin.services.importexport.exportManifest.bindings.DatabaseConnection databaseConnection : datasourceList ) { + if ( databaseConnection.getDatabaseType() == null ) { + // don't try to import the connection if there is no type it will cause an error + // However, if this is the DI Server, and the connection is defined in a ktr, it will import automatically + getLogger().warn( Messages.getInstance() + .getString( "SolutionImportHandler.ConnectionWithoutDatabaseType", databaseConnection.getName() ) ); + continue; + } + try { + IDatabaseConnection existingDBConnection = + datasourceMgmtSvc.getDatasourceByName( databaseConnection.getName() ); + if ( existingDBConnection != null && existingDBConnection.getName() != null ) { + if ( isOverwriteFile() ) { + databaseConnection.setId( existingDBConnection.getId() ); + datasourceMgmtSvc.updateDatasourceByName( databaseConnection.getName(), + DatabaseConnectionConverter.export2model( databaseConnection ) ); + } + } else { + datasourceMgmtSvc.createDatasource( DatabaseConnectionConverter.export2model( databaseConnection ) ); + } + successfulDatasourceImportCount++; + } catch ( Exception e ) { + if ( isPerformingRestore ) { + getLogger().error( Messages.getInstance().getString( "SolutionImportHandler.ERROR_IMPORTING_JDBC_DATASOURCE", databaseConnection.getName(), e.getLocalizedMessage() ) ); + } + } + } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_SUCCESSFUL_DATASOURCE_IMPORT_COUNT", successfulDatasourceImportCount, datasourceList.size() ) ); + } + } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_DATASOURCE" ) ); + } } List getAllJobs( ISchedulerResource schedulerResource ) { @@ -295,17 +380,32 @@ List getAllJobs( ISchedulerResource schedulerResource ) { private RepositoryFile getFile( IPlatformImportBundle importBundle, IRepositoryFileBundle fileBundle ) { String repositoryFilePath = - repositoryPathConcat( importBundle.getPath(), fileBundle.getPath(), fileBundle.getFile().getName() ); + repositoryPathConcat( importBundle.getPath(), fileBundle.getPath(), fileBundle.getFile().getName() ); return repository.getFile( repositoryFilePath ); } protected void importSchedules( List scheduleList ) throws PlatformImportException { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_SCHEDULE" ) ); + } if ( CollectionUtils.isNotEmpty( scheduleList ) ) { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_SCHEDULUE", scheduleList.size() ) ); + } + int successfulScheduleImportCount = 0; IScheduler scheduler = PentahoSystem.get( IScheduler.class, "IScheduler2", null ); //$NON-NLS-1$ ISchedulerResource schedulerResource = scheduler.createSchedulerResource(); + if ( isPerformingRestore ) { + getLogger().debug( "Pausing the scheduler before the start of the restore process" ); + } schedulerResource.pause(); + if ( isPerformingRestore ) { + getLogger().debug( "Successfully paused the scheduler" ); + } for ( IJobScheduleRequest jobScheduleRequest : scheduleList ) { - + if ( isPerformingRestore ) { + getLogger().debug( "Restoring schedule name [ " + jobScheduleRequest.getJobName() + "] inputFile [ " + jobScheduleRequest.getInputFile() + " ] outputFile [ " + jobScheduleRequest.getOutputFile() + "]" ); + } boolean jobExists = false; List jobs = getAllJobs( schedulerResource ); @@ -317,15 +417,19 @@ protected void importSchedules( List scheduleList ) throws mapParamsRequest.put( paramRequest.getName(), paramRequest.getValue() ); } + // We will check the existing job in the repository. If the job being imported exists, we will remove it from the repository for ( IJob job : jobs ) { if ( ( mapParamsRequest.get( RESERVEDMAPKEY_LINEAGE_ID ) != null ) - && ( mapParamsRequest.get( RESERVEDMAPKEY_LINEAGE_ID ) - .equals( job.getJobParams().get( RESERVEDMAPKEY_LINEAGE_ID ) ) ) ) { + && ( mapParamsRequest.get( RESERVEDMAPKEY_LINEAGE_ID ) + .equals( job.getJobParams().get( RESERVEDMAPKEY_LINEAGE_ID ) ) ) ) { jobExists = true; } if ( overwriteFile && jobExists ) { + if ( isPerformingRestore ) { + getLogger().debug( "Schedule [ " + jobScheduleRequest.getJobName() + "] already exists and overwrite flag is set to true. Removing the job so we can add it again" ); + } IJobRequest jobRequest = scheduler.createJobRequest(); jobRequest.setJobId( job.getJobId() ); schedulerResource.removeJob( jobRequest ); @@ -342,7 +446,14 @@ protected void importSchedules( List scheduleList ) throws if ( response.getEntity() != null ) { // get the schedule job id from the response and add it to the import session ImportSession.getSession().addImportedScheduleJobId( response.getEntity().toString() ); + if ( isPerformingRestore ) { + getLogger().debug( "Successfully restored schedule [ " + jobScheduleRequest.getJobName() + " ] " ); + } + successfulScheduleImportCount++; } + } else { + getLogger().error( Messages.getInstance().getString( "SolutionImportHandler.ERROR_IMPORTING_SCHEDULE", jobScheduleRequest.getJobName(), response.getEntity() != null + ? response.getEntity().toString() : "" ) ); } } catch ( Exception e ) { // there is a scenario where if the file scheduled has a space in the file name, that it won't work. the @@ -353,15 +464,15 @@ protected void importSchedules( List scheduleList ) throws // so, if we failed to import and there is a space in the path, try again but this time with replacing // the space(s) if ( jobScheduleRequest.getInputFile().contains( " " ) || jobScheduleRequest.getOutputFile() - .contains( " " ) ) { - getLogger().info( Messages.getInstance() - .getString( "SolutionImportHandler.SchedulesWithSpaces", jobScheduleRequest.getInputFile() ) ); + .contains( " " ) ) { + getLogger().debug( Messages.getInstance() + .getString( "SolutionImportHandler.SchedulesWithSpaces", jobScheduleRequest.getInputFile() ) ); File inFile = new File( jobScheduleRequest.getInputFile() ); File outFile = new File( jobScheduleRequest.getOutputFile() ); String inputFileName = inFile.getParent() + RepositoryFile.SEPARATOR - + inFile.getName().replace( " ", "_" ); + + inFile.getName().replace( " ", "_" ); String outputFileName = outFile.getParent() + RepositoryFile.SEPARATOR - + outFile.getName().replace( " ", "_" ); + + outFile.getName().replace( " ", "_" ); jobScheduleRequest.setInputFile( inputFileName ); jobScheduleRequest.setOutputFile( outputFileName ); try { @@ -369,48 +480,68 @@ protected void importSchedules( List scheduleList ) throws // on windows systems, the backslashes will result in the file not being found in the repository jobScheduleRequest.setInputFile( inputFileName.replace( File.separator, RepositoryFile.SEPARATOR ) ); jobScheduleRequest - .setOutputFile( outputFileName.replace( File.separator, RepositoryFile.SEPARATOR ) ); + .setOutputFile( outputFileName.replace( File.separator, RepositoryFile.SEPARATOR ) ); } Response response = createSchedulerJob( schedulerResource, jobScheduleRequest ); if ( response.getStatus() == Response.Status.OK.getStatusCode() ) { if ( response.getEntity() != null ) { // get the schedule job id from the response and add it to the import session ImportSession.getSession().addImportedScheduleJobId( response.getEntity().toString() ); + successfulScheduleImportCount++; } } } catch ( Exception ex ) { - // log it and keep going. we should stop processing all schedules just because one fails. + // log it and keep going. we shouldn't stop processing all schedules just because one fails. getLogger().error( Messages.getInstance() - .getString( "SolutionImportHandler.ERROR_0001_ERROR_CREATING_SCHEDULE", e.getMessage() ), ex ); + .getString( "SolutionImportHandler.ERROR_0001_ERROR_CREATING_SCHEDULE", "[ " + jobScheduleRequest.getJobName() + " ] cause [ " + ex.getMessage() + " ]" ), ex ); } } else { - // log it and keep going. we should stop processing all schedules just because one fails. + // log it and keep going. we shouldn't stop processing all schedules just because one fails. getLogger().error( Messages.getInstance() - .getString( "SolutionImportHandler.ERROR_0001_ERROR_CREATING_SCHEDULE", e.getMessage() ) ); + .getString( "SolutionImportHandler.ERROR_0001_ERROR_CREATING_SCHEDULE", "[ " + jobScheduleRequest.getJobName() + " ]" ) ); } } } else { getLogger().info( Messages.getInstance() - .getString( "DefaultImportHandler.ERROR_0009_OVERWRITE_CONTENT", jobScheduleRequest.toString() ) ); + .getString( "DefaultImportHandler.ERROR_0009_OVERWRITE_CONTENT", jobScheduleRequest.toString() ) ); } } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance() + .getString( "SolutionImportHandler.INFO_SUCCESSFUL_SCHEDULE_IMPORT_COUNT", successfulScheduleImportCount, scheduleList.size() ) ); + } schedulerResource.start(); + if ( isPerformingRestore ) { + getLogger().debug( "Successfully started the scheduler" ); + } + } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_SCHEDULE" ) ); } } protected void importMetaStore( ExportManifestMetaStore manifestMetaStore, boolean overwrite ) { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_METASTORE" ) ); + } if ( manifestMetaStore != null ) { // get the zipped metastore from the export bundle RepositoryFileImportBundle.Builder bundleBuilder = - new RepositoryFileImportBundle.Builder() - .path( manifestMetaStore.getFile() ) - .name( manifestMetaStore.getName() ) - .withParam( "description", manifestMetaStore.getDescription() ) - .charSet( UTF_8 ) - .overwriteFile( overwrite ) - .mime( "application/vnd.pentaho.metastore" ); + new RepositoryFileImportBundle.Builder() + .path( manifestMetaStore.getFile() ) + .name( manifestMetaStore.getName() ) + .withParam( "description", manifestMetaStore.getDescription() ) + .charSet( UTF_8 ) + .overwriteFile( overwrite ) + .mime( "application/vnd.pentaho.metastore" ); cachedImports.put( manifestMetaStore.getFile(), bundleBuilder ); + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_SUCCESSFUL_IMPORT_METASTORE" ) ); + } + } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_METASTORE" ) ); } } @@ -424,8 +555,14 @@ protected Map> importUsers( List users ) { Map> roleToUserMap = new HashMap<>(); IUserRoleDao roleDao = PentahoSystem.get( IUserRoleDao.class ); ITenant tenant = new Tenant( "/pentaho/" + TenantUtils.getDefaultTenant(), true ); - + int successFullUserImportCount = 0; + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_USER" ) ); + } if ( users != null && roleDao != null ) { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_USER", users.size() ) ); + } for ( UserExport user : users ) { String password = user.getPassword(); getLogger().debug( Messages.getInstance().getString( "USER.importing", user.getUsername() ) ); @@ -444,118 +581,214 @@ protected Map> importUsers( List users ) { String[] userRoles = user.getRoles().toArray( new String[] {} ); try { + if ( isPerformingRestore ) { + getLogger().debug( "Restoring user [ " + user.getUsername() + " ] " ); + } roleDao.createUser( tenant, user.getUsername(), password, null, userRoles ); + if ( isPerformingRestore ) { + getLogger().debug( "Successfully restored user [ " + user.getUsername() + " ]" ); + } + successFullUserImportCount++; } catch ( AlreadyExistsException e ) { // it's ok if the user already exists, it is probably a default user - getLogger().info( Messages.getInstance().getString( "USER.Already.Exists", user.getUsername() ) ); + getLogger().debug( Messages.getInstance().getString( "USER.Already.Exists", user.getUsername() ) ); try { if ( isOverwriteFile() ) { + if ( isPerformingRestore ) { + getLogger().debug( "Overwrite is set to true. So restoring user [ " + user.getUsername() + " ]" ); + } // set the roles, maybe they changed roleDao.setUserRoles( tenant, user.getUsername(), userRoles ); // set the password just in case it changed roleDao.setPassword( tenant, user.getUsername(), password ); + successFullUserImportCount++; } } catch ( Exception ex ) { // couldn't set the roles or password either + getLogger().warn( Messages.getInstance() + .getString( "ERROR.OverridingExistingUser", user.getUsername() ) ); getLogger().debug( Messages.getInstance() - .getString( "ERROR.OverridingExistingUser", user.getUsername() ), ex ); + .getString( "ERROR.OverridingExistingUser", user.getUsername() ), ex ); } } catch ( Exception e ) { + getLogger().debug( Messages.getInstance() + .getString( "ERROR.OverridingExistingUser", user.getUsername() ), e ); getLogger().error( Messages.getInstance() - .getString( "ERROR.OverridingExistingUser", user.getUsername() ), e ); + .getString( "ERROR.OverridingExistingUser", user.getUsername() ) ); + } + if ( isPerformingRestore ) { + getLogger().debug( "Restoring user [ " + user.getUsername() + " ] specific settings" ); } importUserSettings( user ); + if ( isPerformingRestore ) { + getLogger().debug( "Successfully restored user [ " + user.getUsername() + " ] specific settings" ); + } } } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_SUCCESSFUL_USER_COUNT", successFullUserImportCount, users.size() ) ); + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_USER" ) ); + } return roleToUserMap; } protected void importGlobalUserSettings( List globalSettings ) { + if ( isPerformingRestore ) { + getLogger().debug( "************************[ Start: Restore global user settings] *************************" ); + } IUserSettingService settingService = PentahoSystem.get( IUserSettingService.class ); if ( settingService != null ) { for ( ExportManifestUserSetting globalSetting : globalSettings ) { if ( isOverwriteFile() ) { + if ( isPerformingRestore ) { + getLogger().trace( "Overwrite flag is set to true." ); + } settingService.setGlobalUserSetting( globalSetting.getName(), globalSetting.getValue() ); + if ( isPerformingRestore ) { + getLogger().debug( "Finished restore of global user setting with name [ " + globalSetting.getName() + " ]" ); + } } else { + if ( isPerformingRestore ) { + getLogger().trace( "Overwrite flag is set to false." ); + } IUserSetting userSetting = settingService.getGlobalUserSetting( globalSetting.getName(), null ); if ( userSetting == null ) { settingService.setGlobalUserSetting( globalSetting.getName(), globalSetting.getValue() ); + if ( isPerformingRestore ) { + getLogger().debug( "Finished restore of global user setting with name [ " + globalSetting.getName() + " ]" ); + } } } } } + if ( isPerformingRestore ) { + getLogger().debug( "************************[ End: Restore global user settings] *************************" ); + } } protected void importUserSettings( UserExport user ) { IUserSettingService settingService = PentahoSystem.get( IUserSettingService.class ); IAnyUserSettingService userSettingService = null; + int userSettingsListSize = 0; + int successfulUserSettingsImportCount = 0; if ( settingService != null && settingService instanceof IAnyUserSettingService ) { userSettingService = (IAnyUserSettingService) settingService; } - + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_USER_SETTING" ) ); + } if ( userSettingService != null ) { List exportedSettings = user.getUserSettings(); + userSettingsListSize = user.getUserSettings().size(); + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_USER_SETTING", userSettingsListSize, user.getUsername() ) ); + } try { for ( ExportManifestUserSetting exportedSetting : exportedSettings ) { + if ( isPerformingRestore ) { + getLogger().debug( "Restore user specific setting [ " + exportedSetting.getName() + " ]" ); + } if ( isOverwriteFile() ) { + if ( isPerformingRestore ) { + getLogger().debug( "Overwrite is set to true. So restoring setting [ " + exportedSetting.getName() + " ]" ); + } userSettingService.setUserSetting( user.getUsername(), - exportedSetting.getName(), exportedSetting.getValue() ); + exportedSetting.getName(), exportedSetting.getValue() ); + if ( isPerformingRestore ) { + getLogger().debug( "Finished restore of user specific setting with name [ " + exportedSetting.getName() + " ]" ); + } } else { // see if it's there first before we set this setting + if ( isPerformingRestore ) { + getLogger().debug( "Overwrite is set to false. Only restore setting [ " + exportedSetting.getName() + " ] if is does not exist" ); + } IUserSetting userSetting = - userSettingService.getUserSetting( user.getUsername(), exportedSetting.getName(), null ); + userSettingService.getUserSetting( user.getUsername(), exportedSetting.getName(), null ); if ( userSetting == null ) { // only set it if we didn't find that it exists already - userSettingService.setUserSetting( user.getUsername(), - exportedSetting.getName(), exportedSetting.getValue() ); + userSettingService.setUserSetting( user.getUsername(), exportedSetting.getName(), exportedSetting.getValue() ); + if ( isPerformingRestore ) { + getLogger().debug( "Finished restore of user specific setting with name [ " + exportedSetting.getName() + " ]" ); + } } } + successfulUserSettingsImportCount++; + if ( isPerformingRestore ) { + getLogger().debug( "Successfully restored setting [ " + exportedSetting.getName() + " ]" ); + } } } catch ( SecurityException e ) { String errorMsg = Messages.getInstance().getString( "ERROR.ImportingUserSetting", user.getUsername() ); getLogger().error( errorMsg ); getLogger().debug( errorMsg, e ); + } finally { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance() + .getString( "SolutionImportHandler.INFO_SUCCESSFUL_USER_SETTING_IMPORT_COUNT", successfulUserSettingsImportCount, userSettingsListSize ) ); + getLogger().info( Messages.getInstance() + .getString( "SolutionImportHandler.INFO_END_IMPORT_USER_SETTING" ) ); + } } } } protected void importRoles( List roles, Map> roleToUserMap ) { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_ROLE" ) ); + } if ( roles != null ) { IUserRoleDao roleDao = PentahoSystem.get( IUserRoleDao.class ); ITenant tenant = new Tenant( "/pentaho/" + TenantUtils.getDefaultTenant(), true ); IRoleAuthorizationPolicyRoleBindingDao roleBindingDao = PentahoSystem.get( - IRoleAuthorizationPolicyRoleBindingDao.class ); + IRoleAuthorizationPolicyRoleBindingDao.class ); Set existingRoles = new HashSet<>(); - + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_ROLE", roles.size() ) ); + } + int successFullRoleImportCount = 0; for ( RoleExport role : roles ) { getLogger().debug( Messages.getInstance().getString( "ROLE.importing", role.getRolename() ) ); try { List users = roleToUserMap.get( role.getRolename() ); String[] userarray = users == null ? new String[] {} : users.toArray( new String[] {} ); IPentahoRole role1 = roleDao.createRole( tenant, role.getRolename(), null, userarray ); + successFullRoleImportCount++; } catch ( AlreadyExistsException e ) { existingRoles.add( role.getRolename() ); // it's ok if the role already exists, it is probably a default role - getLogger().info( Messages.getInstance().getString( "ROLE.Already.Exists", role.getRolename() ) ); + getLogger().debug( Messages.getInstance().getString( "ROLE.Already.Exists", role.getRolename() ) ); } try { if ( existingRoles.contains( role.getRolename() ) ) { //Only update an existing role if the overwrite flag is set if ( isOverwriteFile() ) { + if ( isPerformingRestore ) { + getLogger().debug( "Overwrite is set to true so restoring role [ " + role.getRolename() + "]" ); + } roleBindingDao.setRoleBindings( tenant, role.getRolename(), role.getPermissions() ); } } else { + if ( isPerformingRestore ) { + getLogger().debug( "Updating the role mapping from runtime roles to logical roles for [ " + role.getRolename() + "]" ); + } //Always write a roles permissions that were not previously existing roleBindingDao.setRoleBindings( tenant, role.getRolename(), role.getPermissions() ); } + successFullRoleImportCount++; } catch ( Exception e ) { - getLogger().info( Messages.getInstance() - .getString( "ERROR.SettingRolePermissions", role.getRolename() ), e ); + getLogger().error( Messages.getInstance() + .getString( "ERROR.SettingRolePermissions", role.getRolename() ), e ); } } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_SUCCESSFUL_ROLE_COUNT", successFullRoleImportCount, roles.size() ) ); + } + } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_ROLE" ) ); } } @@ -566,30 +799,59 @@ protected void importRoles( List roles, Map> ro * @param preserveDsw whether or not to preserve DSW settings */ protected void importMetadata( List metadataList, boolean preserveDsw ) { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_METADATA_DATASOURCE" ) ); + } if ( null != metadataList ) { + int successfulMetadataModelImport = 0; + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_METADATA_DATASOURCE", metadataList.size() ) ); + } for ( ExportManifestMetadata exportManifestMetadata : metadataList ) { + if ( isPerformingRestore ) { + getLogger().debug( "Restoring [ " + exportManifestMetadata.getDomainId() + " ] datasource" ); + } String domainId = exportManifestMetadata.getDomainId(); if ( domainId != null && !domainId.endsWith( XMI_EXTENSION ) ) { domainId = domainId + XMI_EXTENSION; } RepositoryFileImportBundle.Builder bundleBuilder = - new RepositoryFileImportBundle.Builder().charSet( UTF_8 ) - .hidden( RepositoryFile.HIDDEN_BY_DEFAULT ).schedulable( RepositoryFile.SCHEDULABLE_BY_DEFAULT ) - // let the parent bundle control whether or not to preserve DSW settings - .preserveDsw( preserveDsw ) - .overwriteFile( isOverwriteFile() ) - .mime( "text/xmi+xml" ) - .withParam( DOMAIN_ID, domainId ); + new RepositoryFileImportBundle.Builder().charSet( UTF_8 ) + .hidden( RepositoryFile.HIDDEN_BY_DEFAULT ).schedulable( RepositoryFile.SCHEDULABLE_BY_DEFAULT ) + // let the parent bundle control whether or not to preserve DSW settings + .preserveDsw( preserveDsw ) + .overwriteFile( isOverwriteFile() ) + .mime( "text/xmi+xml" ) + .withParam( DOMAIN_ID, domainId ); cachedImports.put( exportManifestMetadata.getFile(), bundleBuilder ); + if ( isPerformingRestore ) { + getLogger().debug( " Successfully restored [ " + exportManifestMetadata.getDomainId() + " ] datasource" ); + } + successfulMetadataModelImport++; + } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_SUCCESSFUL_METDATA_DATASOURCE_COUNT", successfulMetadataModelImport, metadataList.size() ) ); } } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_METADATA_DATASOURCE" ) ); + } } protected void importMondrian( List mondrianList ) { + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_MONDRIAN_DATASOURCE" ) ); + } if ( null != mondrianList ) { + int successfulMondrianSchemaImport = 0; + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_COUNT_MONDRIAN_DATASOURCE", mondrianList.size() ) ); + } for ( ExportManifestMondrian exportManifestMondrian : mondrianList ) { - + if ( isPerformingRestore ) { + getLogger().debug( "Restoring [ " + exportManifestMondrian.getCatalogName() + " ] mondrian datasource" ); + } String catName = exportManifestMondrian.getCatalogName(); Parameters parametersMap = exportManifestMondrian.getParameters(); StringBuilder parametersStr = new StringBuilder(); @@ -598,11 +860,11 @@ protected void importMondrian( List mondrianList ) { } RepositoryFileImportBundle.Builder bundleBuilder = - new RepositoryFileImportBundle.Builder().charSet( UTF_8 ).hidden( RepositoryFile.HIDDEN_BY_DEFAULT ) - .schedulable( RepositoryFile.SCHEDULABLE_BY_DEFAULT ).name( catName ).overwriteFile( - isOverwriteFile() ).mime( "application/vnd.pentaho.mondrian+xml" ) - .withParam( "parameters", parametersStr.toString() ) - .withParam( DOMAIN_ID, catName ); // TODO: this is definitely named wrong at the very least. + new RepositoryFileImportBundle.Builder().charSet( UTF_8 ).hidden( RepositoryFile.HIDDEN_BY_DEFAULT ) + .schedulable( RepositoryFile.SCHEDULABLE_BY_DEFAULT ).name( catName ).overwriteFile( + isOverwriteFile() ).mime( "application/vnd.pentaho.mondrian+xml" ) + .withParam( "parameters", parametersStr.toString() ) + .withParam( DOMAIN_ID, catName ); // TODO: this is definitely named wrong at the very least. // pass as param if not in parameters string String xmlaEnabled = "" + exportManifestMondrian.isXmlaEnabled(); bundleBuilder.withParam( "EnableXmla", xmlaEnabled ); @@ -612,13 +874,23 @@ protected void importMondrian( List mondrianList ) { String annotationsFile = exportManifestMondrian.getAnnotationsFile(); if ( annotationsFile != null ) { RepositoryFileImportBundle.Builder annotationsBundle = - new RepositoryFileImportBundle.Builder().path( MondrianCatalogRepositoryHelper.ETC_MONDRIAN_JCR_FOLDER - + RepositoryFile.SEPARATOR + catName ).name( "annotations.xml" ).charSet( UTF_8 ).overwriteFile( - isOverwriteFile() ).mime( "text/xml" ).hidden( RepositoryFile.HIDDEN_BY_DEFAULT ).schedulable( - RepositoryFile.SCHEDULABLE_BY_DEFAULT ).withParam( DOMAIN_ID, catName ); + new RepositoryFileImportBundle.Builder().path( MondrianCatalogRepositoryHelper.ETC_MONDRIAN_JCR_FOLDER + + RepositoryFile.SEPARATOR + catName ).name( "annotations.xml" ).charSet( UTF_8 ).overwriteFile( + isOverwriteFile() ).mime( "text/xml" ).hidden( RepositoryFile.HIDDEN_BY_DEFAULT ).schedulable( + RepositoryFile.SCHEDULABLE_BY_DEFAULT ).withParam( DOMAIN_ID, catName ); cachedImports.put( annotationsFile, annotationsBundle ); } + successfulMondrianSchemaImport++; + if ( isPerformingRestore ) { + getLogger().debug( " Successfully restored [ " + exportManifestMondrian.getCatalogName() + " ] mondrian datasource" ); + } } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_SUCCESSFUL_MONDRIAN_DATASOURCE_IMPORT_COUNT", successfulMondrianSchemaImport, mondrianList.size() ) ); + } + } + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_MONDRIAN_DATASOURCE" ) ); } } @@ -630,15 +902,15 @@ protected void importMondrian( List mondrianList ) { boolean fileIsScheduleInputSource( ExportManifest manifest, String sourcePath ) { boolean isSchedulable = false; if ( sourcePath != null && manifest != null - && manifest.getScheduleList() != null ) { + && manifest.getScheduleList() != null ) { String path = sourcePath.startsWith( "/" ) ? sourcePath : "/" + sourcePath; isSchedulable = manifest.getScheduleList().stream() - .anyMatch( schedule -> path.equals( schedule.getInputFile() ) ); + .anyMatch( schedule -> path.equals( schedule.getInputFile() ) ); } if ( isSchedulable ) { getLogger().warn( Messages.getInstance() - .getString( "ERROR.ScheduledWithoutPermission", sourcePath ) ); + .getString( "ERROR.ScheduledWithoutPermission", sourcePath ) ); getLogger().warn( Messages.getInstance().getString( "SCHEDULE.AssigningPermission", sourcePath ) ); } @@ -681,12 +953,15 @@ private String repositoryPathConcat( String path, String... subPaths ) { private boolean processZip( InputStream inputStream ) { this.files = new ArrayList<>(); + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_START_IMPORT_REPOSITORY_OBJECT" ) ); + } try ( ZipInputStream zipInputStream = new ZipInputStream( inputStream ) ) { FileService fileService = new FileService(); ZipEntry entry = zipInputStream.getNextEntry(); while ( entry != null ) { final String entryName = RepositoryFilenameUtils.separatorsToRepository( entry.getName() ); - getLogger().trace( Messages.getInstance().getString( "ZIPFILE.ProcessingEntry", entryName ) ); + getLogger().debug( Messages.getInstance().getString( "ZIPFILE.ProcessingEntry", entryName ) ); final String decodedEntryName = ExportFileNameEncoder.decodeZipFileName( entryName ); File tempFile = null; boolean isDir = entry.isDirectory(); @@ -698,9 +973,10 @@ private boolean processZip( InputStream inputStream ) { } if ( !fileService.isValidFileName( decodedEntryName ) ) { + getLogger().error( Messages.getInstance().getString( "DefaultImportHandler.ERROR_0011_INVALID_FILE_NAME", decodedEntryName ) ); throw new PlatformImportException( - Messages.getInstance().getString( "DefaultImportHandler.ERROR_0011_INVALID_FILE_NAME", - entryName ), PlatformImportException.PUBLISH_PROHIBITED_SYMBOLS_ERROR ); + Messages.getInstance().getString( "DefaultImportHandler.ERROR_0011_INVALID_FILE_NAME", + entryName ), PlatformImportException.PUBLISH_PROHIBITED_SYMBOLS_ERROR ); } tempFile = File.createTempFile( "zip", null ); @@ -710,23 +986,27 @@ private boolean processZip( InputStream inputStream ) { } } else { if ( !fileService.isValidFileName( decodedEntryName ) ) { + getLogger().error( Messages.getInstance().getString( "DefaultImportHandler.ERROR_0011_INVALID_FILE_NAME", decodedEntryName ) ); throw new PlatformImportException( - Messages.getInstance().getString( "DefaultImportHandler.ERROR_0012_INVALID_FOLDER_NAME", - entryName ), PlatformImportException.PUBLISH_PROHIBITED_SYMBOLS_ERROR ); + Messages.getInstance().getString( "DefaultImportHandler.ERROR_0012_INVALID_FOLDER_NAME", + entryName ), PlatformImportException.PUBLISH_PROHIBITED_SYMBOLS_ERROR ); } } File file = new File( entryName ); RepositoryFile repoFile = - new RepositoryFile.Builder( file.getName() ).folder( isDir ).hidden( false ).build(); + new RepositoryFile.Builder( file.getName() ).folder( isDir ).hidden( false ).build(); String parentDir = - file.getParent() == null ? RepositoryFile.SEPARATOR : file.getParent() - + RepositoryFile.SEPARATOR; + file.getParent() == null ? RepositoryFile.SEPARATOR : file.getParent() + + RepositoryFile.SEPARATOR; IRepositoryFileBundle repoFileBundle = - new RepositoryFileBundle( repoFile, null, parentDir, tempFile, UTF_8, null ); + new RepositoryFileBundle( repoFile, null, parentDir, tempFile, UTF_8, null ); if ( EXPORT_MANIFEST_XML_FILE.equals( file.getName() ) ) { initializeAclManifest( repoFileBundle ); } else { + if ( isPerformingRestore ) { + getLogger().debug( "Adding file " + repoFile.getName() + " to list for later processing " ); + } files.add( repoFileBundle ); } zipInputStream.closeEntry(); @@ -734,10 +1014,12 @@ private boolean processZip( InputStream inputStream ) { } } catch ( IOException | PlatformImportException e ) { getLogger().error( Messages.getInstance() - .getErrorString( "ZIPFILE.ExceptionOccurred", e.getLocalizedMessage() ), e ); + .getErrorString( "ZIPFILE.ExceptionOccurred", e.getLocalizedMessage() ), e ); return false; } - + if ( isPerformingRestore ) { + getLogger().info( Messages.getInstance().getString( "SolutionImportHandler.INFO_END_IMPORT_REPOSITORY_OBJECT" ) ); + } return true; } @@ -765,7 +1047,7 @@ public IPlatformImportBundle build( RepositoryFileImportBundle.Builder builder ) // handlers that extend this class may override this method and perform operations // over the job prior to its creation at scheduler.createJob() public Response createSchedulerJob( ISchedulerResource scheduler, IJobScheduleRequest jobScheduleRequest ) - throws IOException { + throws IOException { Response rs = scheduler != null ? (Response) scheduler.createJob( jobScheduleRequest ) : null; if ( jobScheduleRequest.getJobState() != JobState.NORMAL ) { IJobRequest jobRequest = PentahoSystem.get( IScheduler.class, "IScheduler2", null ).createJobRequest(); diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessor.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessor.java index bfde564ba87..912cc82c1d0 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessor.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessor.java @@ -35,6 +35,8 @@ import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; +import org.pentaho.platform.api.importexport.ExportException; +import org.pentaho.platform.api.util.IRepositoryExportLogger; import java.io.File; import java.io.IOException; @@ -55,6 +57,9 @@ public abstract class BaseExportProcessor { IUnifiedRepository unifiedRepository; + IRepositoryExportLogger repositoryExportLogger; + + protected static final String EXPORT_MANIFEST_FILENAME = "exportManifest.xml"; protected static final String EXPORT_INFO_DATE_FORMAT = "dd-MM-yyyy"; protected static final String EXPORT_INFO_TIME_FORMAT = "hh:mm:ss z"; @@ -106,6 +111,14 @@ public void setUnifiedRepository( IUnifiedRepository unifiedRepository ) { this.unifiedRepository = unifiedRepository; } + public IRepositoryExportLogger getRepositoryExportLogger() { + return repositoryExportLogger; + } + + public void setRepositoryExportLogger( IRepositoryExportLogger repositoryExportLogger ) { + this.repositoryExportLogger = repositoryExportLogger; + } + /** * Performs the export process, returns a zip File object * @@ -119,13 +132,13 @@ public void setUnifiedRepository( IUnifiedRepository unifiedRepository ) { */ public abstract void exportDirectory( RepositoryFile repositoryDir, OutputStream outputStream, String filePath ) - throws ExportException, IOException; + throws ExportException, IOException; /** * @param repositoryFile * @param outputStream */ public abstract void exportFile( RepositoryFile repositoryFile, OutputStream outputStream, String filePath ) - throws ExportException, IOException; + throws ExportException, IOException; } diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/CommandLineProcessor.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/CommandLineProcessor.java index 33b5e38d3e5..85d1fe31271 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/CommandLineProcessor.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/CommandLineProcessor.java @@ -25,7 +25,9 @@ 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.core.util.MultivaluedMapImpl; import com.sun.jersey.multipart.FormDataMultiPart; +import com.sun.mail.iap.Response; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; @@ -43,6 +45,7 @@ import org.pentaho.platform.util.RepositoryPathEncoder; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -91,6 +94,10 @@ public class CommandLineProcessor { private static final String MULTIPART_FIELD_OVERWRITE_FILE = "overwriteFile"; private static final String MULTIPART_FIELD_APPLY_ACL_SETTINGS = "applyAclSettings"; private static final String MULTIPART_FIELD_OVERWRITE_ACL_SETTINGS = "overwriteAclSettings"; + private static final String MULTIVALUE_FIELD_LOG_FILE = "logFile"; + private static final String MULTIVALUE_FIELD_LOG_LEVEL = "logLevel"; + private static final String MULTIVALUE_FIELD_BACKUP_BUNDLE_PATH = "backupBundlePath"; + private static final String MULTIVALUE_FIELD_OUTPUT_FILE_NAME_LEVEL = "outputFile"; private static final String METADATA_DATASOURCE_EXT = "xmi"; @@ -107,7 +114,7 @@ public class CommandLineProcessor { private final CommandLine commandLine; private final RequestType requestType; - + private static final String DEFAULT_LOG_LEVEL = "INFO"; private static final String INFO_OPTION_HELP_KEY = "h"; private static final String INFO_OPTION_HELP_NAME = "help"; private static final String INFO_OPTION_IMPORT_KEY = "i"; @@ -130,6 +137,8 @@ public class CommandLineProcessor { private static final String INFO_OPTION_CHARSET_NAME = "charset"; private static final String INFO_OPTION_LOGFILE_KEY = "l"; private static final String INFO_OPTION_LOGFILE_NAME = "logfile"; + private static final String INFO_OPTION_LOGLEVEL_NAME = "logLevel"; + private static final String INFO_OPTION_LOGLEVEL_KEY = "lL"; private static final String INFO_OPTION_PATH_KEY = "f"; private static final String INFO_OPTION_PATH_NAME = "path"; private static final String INFO_OPTION_OVERWRITE_KEY = "o"; @@ -186,74 +195,77 @@ public enum ResourceType { // create the Options options.addOption( INFO_OPTION_HELP_KEY, INFO_OPTION_HELP_NAME, false, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_HELP_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_HELP_DESCRIPTION" ) ); options.addOption( INFO_OPTION_IMPORT_KEY, INFO_OPTION_IMPORT_NAME, false, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_IMPORT_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_IMPORT_DESCRIPTION" ) ); options.addOption( INFO_OPTION_EXPORT_KEY, INFO_OPTION_EXPORT_NAME, false, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_EXPORT_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_EXPORT_DESCRIPTION" ) ); options.addOption( INFO_OPTION_USERNAME_KEY, INFO_OPTION_USERNAME_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_USERNAME_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_USERNAME_DESCRIPTION" ) ); options.addOption( INFO_OPTION_PASSWORD_KEY, INFO_OPTION_PASSWORD_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_PASSWORD_DESCRIPTION" ) ); options.addOption( INFO_OPTION_URL_KEY, INFO_OPTION_URL_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_URL_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_URL_DESCRIPTION" ) ); options.addOption( INFO_OPTION_FILEPATH_KEY, INFO_OPTION_FILEPATH_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_FILEPATH_DESCRIPTION" ) ); options.addOption( INFO_OPTION_CHARSET_KEY, INFO_OPTION_CHARSET_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_CHARSET_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_CHARSET_DESCRIPTION" ) ); options.addOption( INFO_OPTION_LOGFILE_KEY, INFO_OPTION_LOGFILE_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_LOGFILE_DESCRIPTION" ) ); + + options.addOption( INFO_OPTION_LOGLEVEL_KEY, INFO_OPTION_LOGLEVEL_NAME, true, Messages.getInstance() + .getString( "CommandLineProcessor.INFO_OPTION_LOGLEVEL_DESCRIPTION" ) ); options.addOption( INFO_OPTION_PATH_KEY, INFO_OPTION_PATH_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_PATH_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_PATH_DESCRIPTION" ) ); // import only ACL additions options.addOption( INFO_OPTION_OVERWRITE_KEY, INFO_OPTION_OVERWRITE_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_OVERWRITE_DESCRIPTION" ) ); options.addOption( INFO_OPTION_PERMISSION_KEY, INFO_OPTION_PERMISSION_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_PERMISSION_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_PERMISSION_DESCRIPTION" ) ); options.addOption( INFO_OPTION_RETAIN_OWNERSHIP_KEY, INFO_OPTION_RETAIN_OWNERSHIP_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_RETAIN_OWNERSHIP_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_RETAIN_OWNERSHIP_DESCRIPTION" ) ); options.addOption( INFO_OPTION_WITH_MANIFEST_KEY, INFO_OPTION_WITH_MANIFEST_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_WITH_MANIFEST_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_WITH_MANIFEST_DESCRIPTION" ) ); // rest services options.addOption( INFO_OPTION_REST_KEY, INFO_OPTION_REST_NAME, false, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_REST_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_REST_DESCRIPTION" ) ); // backup options.addOption( INFO_OPTION_BACKUP_KEY, INFO_OPTION_BACKUP_NAME, false, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_BACKUP_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_BACKUP_DESCRIPTION" ) ); // restore options.addOption( INFO_OPTION_RESTORE_KEY, INFO_OPTION_RESTORE_NAME, false, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_RESTORE_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_RESTORE_DESCRIPTION" ) ); options.addOption( INFO_OPTION_SERVICE_KEY, INFO_OPTION_SERVICE_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_SERVICE_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_SERVICE_DESCRIPTION" ) ); options.addOption( INFO_OPTION_PARAMS_KEY, INFO_OPTION_PARAMS_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_PARAMS_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_PARAMS_DESCRIPTION" ) ); options.addOption( INFO_OPTION_RESOURCE_TYPE_KEY, INFO_OPTION_RESOURCE_TYPE_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_RESOURCE_TYPE_DESCRIPTION" ) ); options.addOption( INFO_OPTION_DATASOURCE_TYPE_KEY, INFO_OPTION_DATASOURCE_TYPE_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_DATASOURCE_TYPE_DESCRIPTION" ) ); options.addOption( INFO_OPTION_ANALYSIS_CATALOG_KEY, INFO_OPTION_ANALYSIS_CATALOG_NAME, true, Messages.getInstance() - .getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_CATALOG_DESCRIPTION" ) ); + .getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_CATALOG_DESCRIPTION" ) ); options.addOption( INFO_OPTION_ANALYSIS_DATASOURCE_KEY, INFO_OPTION_ANALYSIS_DATASOURCE_NAME, true, Messages.getInstance() .getString( "CommandLineProcessor.INFO_OPTION_ANALYSIS_DATASOURCE_DESCRIPTION" ) ); @@ -352,7 +364,7 @@ private void performREST() throws ParseException, KettleException, URISyntaxExce String message = Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_COMPLETED" ).concat( "\n" ); message += - Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_STATUS", response.getStatus() ); + Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_STATUS", response.getStatus() ); message += "\n"; if ( StringUtils.isNotBlank( logFile ) ) { @@ -404,10 +416,8 @@ public static Exception getException() { /** * 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 + * @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 @@ -423,13 +433,13 @@ protected CommandLineProcessor( String[] args ) throws ParseException { requestType = RequestType.RESTORE; } else { final boolean importRequest = - commandLine.hasOption( INFO_OPTION_IMPORT_KEY ); + commandLine.hasOption( INFO_OPTION_IMPORT_KEY ); final boolean exportRequest = - commandLine.hasOption( INFO_OPTION_EXPORT_KEY ); + commandLine.hasOption( INFO_OPTION_EXPORT_KEY ); if ( importRequest == exportRequest ) { throw new ParseException( Messages.getInstance().getErrorString( - "CommandLineProcessor.ERROR_0003_PARSE_EXCEPTION" ) ); + "CommandLineProcessor.ERROR_0003_PARSE_EXCEPTION" ) ); } requestType = ( importRequest ? RequestType.IMPORT : RequestType.EXPORT ); } @@ -455,7 +465,7 @@ protected RequestType getRequestType() { */ private void performMetadataDatasourceImport( String contextURL, File metadataDatasourceFile, String overwrite, String logFile, String path ) - throws ParseException, IOException { + throws ParseException, IOException { File metadataFileInZip = null; InputStream metadataFileInZipInputStream = null; @@ -500,14 +510,14 @@ private void performMetadataDatasourceImport( String contextURL, File metadataDa zipInputStream.close(); part.field( MULTIPART_FIELD_OVERWRITE, "true".equals( overwrite ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_DOMAIN_ID, domainId, MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_METADATA_FILE, metadataFileInZipInputStream, MediaType.MULTIPART_FORM_DATA_TYPE ); // If the import service needs the file name do the following. part.getField( MULTIPART_FIELD_METADATA_FILE ) - .setContentDisposition( FormDataContentDisposition.name( MULTIPART_FIELD_METADATA_FILE ) - .fileName( metadataFileInZip.getName() ).build() ); + .setContentDisposition( FormDataContentDisposition.name( MULTIPART_FIELD_METADATA_FILE ) + .fileName( metadataFileInZip.getName() ).build() ); // Response response ClientResponse response = resource.type( MediaType.MULTIPART_FORM_DATA ).post( ClientResponse.class, part ); @@ -520,13 +530,13 @@ private void performMetadataDatasourceImport( String contextURL, File metadataDa FileInputStream metadataDatasourceInputStream = new FileInputStream( metadataDatasourceFile ); part.field( MULTIPART_FIELD_OVERWRITE, "true".equals( overwrite ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_DOMAIN_ID, domainId, MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_METADATA_FILE, metadataDatasourceInputStream, MediaType.MULTIPART_FORM_DATA_TYPE ); // If the import service needs the file name do the following. part.getField( MULTIPART_FIELD_METADATA_FILE ).setContentDisposition( FormDataContentDisposition.name( MULTIPART_FIELD_METADATA_FILE ) - .fileName( metadataDatasourceFile.getName() ).build() ); + .fileName( metadataDatasourceFile.getName() ).build() ); // Response response ClientResponse response = resource.type( MediaType.MULTIPART_FORM_DATA ).post( ClientResponse.class, part ); @@ -555,7 +565,7 @@ private void performMetadataDatasourceImport( String contextURL, File metadataDa */ private void performAnalysisDatasourceImport( String contextURL, File analysisDatasourceFile, String overwrite, String logFile, String path ) - throws ParseException, IOException { + throws ParseException, IOException { String analysisImportURL = contextURL + API_MONDRIAN_POST_ANALYSIS; @@ -579,13 +589,13 @@ private void performAnalysisDatasourceImport( String contextURL, File analysisDa part.field( MULTIPART_FIELD_PARAMETERS, parms, MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_XMLA_ENABLED_FLAG, "true".equals( xmlaEnabledFlag ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_UPLOAD_ANALYSIS, inputStream, MediaType.MULTIPART_FORM_DATA_TYPE ); // If the import service needs the file name do the following. part.getField( MULTIPART_FIELD_UPLOAD_ANALYSIS ) - .setContentDisposition( FormDataContentDisposition.name( MULTIPART_FIELD_UPLOAD_ANALYSIS ) - .fileName( analysisDatasourceFile.getName() ).build() ); + .setContentDisposition( FormDataContentDisposition.name( MULTIPART_FIELD_UPLOAD_ANALYSIS ) + .fileName( analysisDatasourceFile.getName() ).build() ); WebResource.Builder resourceBuilder = resource.type( MediaType.MULTIPART_FORM_DATA ); ClientResponse response = resourceBuilder.post( ClientResponse.class, part ); @@ -666,19 +676,19 @@ private void performImport() throws ParseException, IOException { part.field( MULTIPART_FIELD_IMPORT_DIR, path, MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_OVERWRITE_ACL_PERMISSIONS, "true".equals( overwrite ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_RETAIN_OWNERSHIP, "true".equals( retainOwnership ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_CHAR_SET, charSet == null ? StandardCharsets.UTF_8.name() : charSet ); part.field( MULTIPART_FIELD_APPLY_ACL_PERMISSIONS, "true".equals( permission ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); part.field( MULTIPART_FIELD_FILE_UPLOAD, in, MediaType.MULTIPART_FORM_DATA_TYPE ); // If the import service needs the file name do the following. part.field( MULTIPART_FIELD_FILE_NAME_OVERRIDE, fileIS.getName(), MediaType.MULTIPART_FORM_DATA_TYPE ); part.getField( MULTIPART_FIELD_FILE_UPLOAD ) - .setContentDisposition( FormDataContentDisposition.name( MULTIPART_FIELD_FILE_UPLOAD ).fileName( - fileIS.getName() ).build() ); + .setContentDisposition( FormDataContentDisposition.name( MULTIPART_FIELD_FILE_UPLOAD ).fileName( + fileIS.getName() ).build() ); WebResource.Builder resourceBuilder = resource.type( MediaType.MULTIPART_FORM_DATA ); ClientResponse response = resourceBuilder.post( ClientResponse.class, part ); @@ -692,51 +702,65 @@ private void performImport() throws ParseException, IOException { writeToFile( e.getMessage(), logFile ); } finally { // close input stream and cleanup the jersey resources - client.destroy(); - part.cleanup(); - in.close(); + if ( client != null ) { + client.destroy(); + } + if ( part != null ) { + part.cleanup(); + } + if ( in != null ) { + in.close(); + } } } } private void logResponseMessage( String logFile, String path, ClientResponse response, RequestType requestType ) { + boolean badLogFilePath = false; if ( response.getStatus() == ClientResponse.Status.OK.getStatusCode() ) { errorMessage = Messages.getInstance().getString( "CommandLineProcessor.INFO_" + requestType.toString() + "_SUCCESSFUL" ); } else if ( response.getStatus() == ClientResponse.Status.FORBIDDEN.getStatusCode() ) { errorMessage = Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0007_FORBIDDEN", path ); } else if ( response.getStatus() == ClientResponse.Status.NOT_FOUND.getStatusCode() ) { errorMessage = - Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0004_UNKNOWN_SOURCE", path ); + Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0004_UNKNOWN_SOURCE", path ); + } else if ( response.getStatus() == ClientResponse.Status.BAD_REQUEST.getStatusCode() ) { + errorMessage = + Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0009_INVALID_LOG_FILE_PATH", logFile ); + badLogFilePath = true; } StringBuilder message = new StringBuilder( errorMessage ); - message.append( System.getProperty( "line.separator" ) ); - if ( response.hasEntity() ) { - message.append( Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_RECEIVED", - response.getEntity( String.class ) ) ); - } - System.out.println( message ); - if ( StringUtils.isNotBlank( logFile ) ) { - writeToFile( message.toString(), logFile ); + if ( !badLogFilePath ) { + message.append( System.getProperty( "line.separator" ) ); + if ( response.hasEntity() ) { + message.append( Messages.getInstance().getString( "CommandLineProcessor.INFO_REST_RESPONSE_RECEIVED", + response.getEntity( String.class ) ) ); + } + System.out.println( message ); + if ( StringUtils.isNotBlank( logFile ) ) { + writeToFile( message.toString(), logFile ); + } + } else { + System.out.println( message ); } } /** * REST Service Backup * - * @throws ParseException - * --backup --url=http://localhost:8080/pentaho --username=admin --password=password - * --logfile=c:/temp/steel-wheels.log --file-path=c:/temp/backup.zip + * @throws ParseException --backup --url=http://localhost:8080/pentaho --username=admin --password=password + * --logfile=c:/temp/steel-wheels.log --file-path=c:/temp/backup.zip */ private void performBackup() throws ParseException, KettleException, URISyntaxException { String contextURL = getOptionValue( INFO_OPTION_URL_NAME, true, false ); String logFile = getOptionValue( INFO_OPTION_LOGFILE_NAME, false, true ); - + String logLevel = getOptionValue( INFO_OPTION_LOGLEVEL_NAME, false, true ); // Output file is validated before executing String outputFile = getOptionValue( INFO_OPTION_FILEPATH_NAME, true, false ); if ( !isValidExportPath( outputFile, logFile ) ) { throw new ParseException( Messages.getInstance().getString( "CommandLineProcessor.ERROR_0005_INVALID_FILE_PATH", - outputFile ) ); + outputFile ) ); } initRestService( contextURL ); @@ -748,23 +772,28 @@ private void performBackup() throws ParseException, KettleException, URISyntaxEx // Build the complete URL to use String backupURL = buildURL( contextURL, API_REPO_FILES_BACKUP ); - WebResource resource = client.resource( backupURL ); // Response response - Builder builder = resource.type( MediaType.APPLICATION_FORM_URLENCODED ).accept( MediaType.TEXT_HTML_TYPE ); - ClientResponse response = builder.get( ClientResponse.class ); + MultivaluedMap postBody = new MultivaluedMapImpl(); + postBody.add( MULTIVALUE_FIELD_LOG_FILE, logFile ); + postBody.add( MULTIVALUE_FIELD_LOG_LEVEL, logLevel != null && logLevel.length() > 0 ? logLevel : DEFAULT_LOG_LEVEL ); + postBody.add( MULTIVALUE_FIELD_OUTPUT_FILE_NAME_LEVEL, outputFile ); + + ClientResponse response = resource.type( MediaType.APPLICATION_FORM_URLENCODED_TYPE ).post( ClientResponse.class, postBody ); if ( response != null && response.getStatus() == 200 ) { writeEntityToFile( response, outputFile ); - String message = Messages.getInstance().getString( "CommandLineProcessor.INFO_EXPORT_COMPLETED" ).concat( "\n" ); + String message = Messages.getInstance().getString( "CommandLineProcessor.INFO_BACKUP_COMPLETED" ).concat( "\n" ); message += Messages.getInstance().getString( "CommandLineProcessor.INFO_RESPONSE_STATUS", response.getStatus() ); message += "\n"; - message += Messages.getInstance().getString( "CommandLineProcessor.INFO_EXPORT_WRITTEN_TO", outputFile ); + message += Messages.getInstance().getString( "CommandLineProcessor.INFO_BACKUP_WRITTEN_TO", outputFile ); if ( StringUtils.isNotBlank( logFile ) ) { System.out.println( message ); writeToFile( message, logFile ); } + } else if ( response != null && response.getStatus() == 400 ) { + System.out.println( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0009_INVALID_LOG_FILE_PATH", logFile ) ); } else { System.out.println( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0002_INVALID_RESPONSE" ) ); } @@ -799,6 +828,7 @@ private void performRestore() throws ParseException { String contextURL = getOptionValue( INFO_OPTION_URL_NAME, true, false ); String filePath = getOptionValue( INFO_OPTION_FILEPATH_NAME, true, false ); String logFile = getOptionValue( INFO_OPTION_LOGFILE_NAME, false, true ); + String logLevel = getOptionValue( INFO_OPTION_LOGLEVEL_NAME, false, true ); String importURL = contextURL + API_REPO_FILES_SYSTEM_RESTORE; File fileIS = new File( filePath ); @@ -814,17 +844,22 @@ private void performRestore() throws ParseException { part.field( MULTIPART_FIELD_FILE_UPLOAD, in, MediaType.MULTIPART_FORM_DATA_TYPE ); String overwrite = getOptionValue( INFO_OPTION_OVERWRITE_NAME, true, false ); part.field( MULTIPART_FIELD_OVERWRITE_FILE, "true".equals( overwrite ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); String applyAclSettings = getOptionValue( INFO_OPTION_APPLY_ACL_SETTINGS_NAME, false, true ); part.field( MULTIPART_FIELD_APPLY_ACL_SETTINGS, !"false".equals( applyAclSettings ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); + MediaType.MULTIPART_FORM_DATA_TYPE ); String overwriteAclSettings = getOptionValue( INFO_OPTION_OVERWRITE_ACL_SETTINGS_NAME, false, true ); part.field( MULTIPART_FIELD_OVERWRITE_ACL_SETTINGS, "true".equals( overwriteAclSettings ) ? "true" : "false", - MediaType.MULTIPART_FORM_DATA_TYPE ); - + MediaType.MULTIPART_FORM_DATA_TYPE ); + part.field( MULTIVALUE_FIELD_LOG_FILE, logFile, MediaType.MULTIPART_FORM_DATA_TYPE ); + part.field( MULTIVALUE_FIELD_LOG_LEVEL, logLevel != null && logLevel.length() > 0 ? logLevel : DEFAULT_LOG_LEVEL, MediaType.MULTIPART_FORM_DATA_TYPE ); + part.field( MULTIVALUE_FIELD_BACKUP_BUNDLE_PATH, filePath, MediaType.MULTIPART_FORM_DATA_TYPE ); // Response response ClientResponse response = resource.type( MediaType.MULTIPART_FORM_DATA ).post( ClientResponse.class, part ); - if ( response != null ) { + if ( response != null && response.getStatus() == Response.BAD ) { + errorMessage = Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0009_INVALID_LOG_FILE_PATH", logFile ); + System.out.println( errorMessage ); + } else if ( response != null ) { logResponseMessage( logFile, filePath, response, RequestType.RESTORE ); response.close(); } @@ -840,10 +875,10 @@ private void performRestore() throws ParseException { /** * REST Service Export - * - * --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 + *

+ * --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 */ private void performExport() throws ParseException, KettleException, URISyntaxException { String contextURL = getOptionValue( INFO_OPTION_URL_NAME, true, false ); @@ -851,20 +886,20 @@ private void performExport() throws ParseException, KettleException, URISyntaxEx String withManifest = getOptionValue( 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() > 1 ) { // allow user to enter "--path=/" + && effPath.length() > 1 ) { // allow user to enter "--path=/" effPath = effPath.substring( 0, effPath.length() - 1 ); } String logFile = getOptionValue( INFO_OPTION_LOGFILE_NAME, false, true ); String exportURL = - contextURL + API_REPO_FILES + effPath + "/download?withManifest=" + ( "false".equals( withManifest ) - ? "false" : "true" ); + contextURL + API_REPO_FILES + effPath + "/download?withManifest=" + ( "false".equals( withManifest ) + ? "false" : "true" ); // Output file is validated before executing String outputFile = getOptionValue( INFO_OPTION_FILEPATH_NAME, true, false ); if ( !isValidExportPath( outputFile, logFile ) ) { throw new ParseException( Messages.getInstance().getString( "CommandLineProcessor.ERROR_0005_INVALID_FILE_PATH", - outputFile ) ); + outputFile ) ); } initRestService( contextURL ); @@ -917,24 +952,20 @@ private boolean isValidExportPath( String filePath, String logFile ) { /** * 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 + * @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 + * @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 { + throws ParseException { final String value = StringUtils.trim( commandLine.getOptionValue( option ) ); if ( StringUtils.isEmpty( value ) && ( required || !emptyOk ) ) { throw new ParseException( Messages.getInstance().getErrorString( "CommandLineProcessor.ERROR_0001_MISSING_ARG", - option ) ); + option ) ); } return StringUtils.removeStart( value, "=" ); @@ -981,7 +1012,7 @@ private void writeToFile( String str, String pathName ) { * @see #writeToFile(String, String) */ private static void writeToFile( InputStream inputStream, File file ) throws IOException { - try ( FileOutputStream fos = new FileOutputStream( file ) ) { + try ( FileOutputStream fos = new FileOutputStream( file, true ) ) { IOUtils.copy( inputStream, fos ); } } @@ -989,8 +1020,8 @@ private static void writeToFile( InputStream inputStream, File file ) throws IOE 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" ) ); + .getInstance().getString( "CommandLineProcessor.INFO_PRINTHELP_HEADER" ), options, Messages.getInstance() + .getString( "CommandLineProcessor.INFO_PRINTHELP_FOOTER" ) ); } /** @@ -1002,12 +1033,12 @@ protected static void printHelp() { */ private static boolean checkUserAuthorization( String contextURL, String securityAction ) { WebResource authResource = - client.resource( contextURL + API_AUTHORIZATION_ACTION_IS_AUTHORIZED + "?authAction=" - + securityAction ); + client.resource( contextURL + API_AUTHORIZATION_ACTION_IS_AUTHORIZED + "?authAction=" + + securityAction ); boolean isAuthorized = Boolean.parseBoolean( authResource.get( String.class ) ); if ( !isAuthorized ) { System.err.println( Messages.getInstance().getString( - "CommandLineProcessor.ERROR_0006_NON_ADMIN_CREDENTIALS" ) ); + "CommandLineProcessor.ERROR_0006_NON_ADMIN_CREDENTIALS" ) ); } return isAuthorized; } diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/DefaultExportHandler.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/DefaultExportHandler.java index f7c67e6fb2f..4d928e557ab 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/DefaultExportHandler.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/DefaultExportHandler.java @@ -45,6 +45,7 @@ import org.pentaho.platform.api.repository2.unified.IRepositoryContentConverterHandler; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; +import org.pentaho.platform.api.importexport.ExportException; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.repository.RepositoryFilenameUtils; diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ExportHandler.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ExportHandler.java index e18e9ea4a76..2ce13f3cc42 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ExportHandler.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ExportHandler.java @@ -34,6 +34,7 @@ */ import org.pentaho.platform.api.repository2.unified.RepositoryFile; +import org.pentaho.platform.api.importexport.ExportException; import java.io.IOException; import java.io.InputStream; diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/IRepositoryImportLogger.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/IRepositoryImportLogger.java index edb9f15e37c..002290f3f9a 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/IRepositoryImportLogger.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/IRepositoryImportLogger.java @@ -15,6 +15,7 @@ import org.apache.commons.logging.Log; import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.StringLayout; import java.io.OutputStream; @@ -22,51 +23,57 @@ * * Below is a sample of how to use this class to generate a log file. 1) You must use startJob(OutputStream, * ImportPath) to instantiate the log and supply it with an output stream to hold the log and the root folder of the * import. - * + *

* 2) Call setCurrentFilePath() each time you start processing a new import file. The log shows the file being imported * so it must be registered. - * + *

* 3) Call endJob() when the import is done to log the finish and release resources. If the the import terminates * abnormally this call should be in the finally block. - * - * + *

+ *

* Sample code taken from RepositoryImportLogTest - * + *

* FileOutputStream fileStream = new FileOutputStream(outputFile); logger = * PentahoSystem.get(IRepositoryImportLogger.class); - * + *

* //You must call this method to start posting the log. logger.startJob(fileStream, "/import/Path"); - * + *

* logger.setCurrentFilePath("/path/file1path"); logger.debug("Some more detail here"); logger.info("Success"); - * + *

* logger.setCurrentFilePath("path/file2path"); - * + *

* //Simulate an exception try { throw new RuntimeException("forced exception"); } catch (Exception e) { * logger.error(e); } //End of job logger.endJob(); - * + * * @author TKafalas - * */ public interface IRepositoryImportLogger extends Log { + + /** + * Initiates an import job. Each call creates a new log associated with the current thread. + * + * @param outputStream Will receive the html content of the log + * @param importRootPath The root import dir receiving the import + * @param logLevel The log level to be logged. + * @param layout The layout to be use. + */ + void startJob( OutputStream outputStream, String importRootPath, Level logLevel, StringLayout layout ); + /** * Initiates an import job. Each call creates a new log associated with the current thread. - * - * @param outputStream - * Will receive the html content of the log - * @param importRootPath - * The root import dir receiving the import - * @param logLevel - * The log level to be logged. + * + * @param outputStream Will receive the html content of the log + * @param importRootPath The root import dir receiving the import + * @param logLevel The log level to be logged. */ void startJob( OutputStream outputStream, String importRootPath, Level logLevel ); /** * Registers the file being worked on. Each log entry will list the path to the file being processed. Call this method * just before processing the next file. It will automatically post a "Start File Import" entry in the log. - * - * @param currentFilePath - * path to file being imported + * + * @param currentFilePath path to file being imported */ void setCurrentFilePath( String currentFilePath ); @@ -77,40 +84,40 @@ public interface IRepositoryImportLogger extends Log { /** * Log informational data. Should be called when the starting a new file and when finishing that file. - * - * @param s - * The information message to be logged. + * + * @param s The information message to be logged. */ void info( String s ); /** * Log an error. - * - * @param s - * The Error message to be logged. + * + * @param s The Error message to be logged. */ void error( String s ); /** * Log debug information - * - * @param s - * The debug message to be logged + * + * @param s The debug message to be logged */ void debug( String s ); /** * Log error information - * - * @param e - * The exception to be logged. + * + * @param e The exception to be logged. */ void error( Exception e ); /** * Allows a class to check if an ImportLogger has been instantiated for the current thread. - * + * * @return true if the logger is present. */ boolean hasLogger(); + + boolean isPerformingRestore(); + + void setPerformingRestore( boolean value ); } diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLog.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLog.java new file mode 100644 index 00000000000..b04dc3e6498 --- /dev/null +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLog.java @@ -0,0 +1,90 @@ +/*! ****************************************************************************** + * + * Pentaho + * + * Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file. + * + * Change Date: 2029-07-20 + ******************************************************************************/ +package org.pentaho.platform.plugin.services.importexport; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.StringLayout; +import org.pentaho.platform.api.util.LogUtil; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; + + +public class Log4JRepositoryExportLog { + + private Logger logger; + private OutputStream outputStream; + private String logName; + private Level logLevel; + private Appender appender; + private StringLayout layout; + + /** + * Constructs an object that keeps track of additional fields for Log4j logging and writes/formats an html file to the + * output stream provided. + * + * @param outputStream + */ + Log4JRepositoryExportLog( OutputStream outputStream, Level logLevel, StringLayout layout ) { + this.outputStream = outputStream; + this.logLevel = logLevel; + this.layout = layout; + init(); + } + + /** + * Constructs an object that keeps track of additional fields for Log4j logging and writes/formats an html file to the + * output stream provided. + * + * @param outputStream + */ + Log4JRepositoryExportLog( OutputStream outputStream, Level logLevel ) { + this.outputStream = outputStream; + this.logLevel = logLevel; + RepositoryImportHTMLLayout htmlLayout = new RepositoryImportHTMLLayout( logLevel ); + htmlLayout.setTitle( "Repository Backup Log" ); + this.layout = htmlLayout; + init(); + } + + private void init() { + logName = "RepositoryExportLog." + getThreadName(); + logger = LogManager.getLogger( logName ); + LogUtil.setLevel( logger, logLevel ); + appender = + LogUtil.makeAppender( logName, new OutputStreamWriter( outputStream, Charset.forName( "utf-8" ) ), this.layout ); + LogUtil.addAppender( appender, logger, logLevel ); + } + + public Logger getLogger() { + return logger; + } + + + protected void endJob() { + try { + outputStream.write( appender.getLayout().getFooter() ); + } catch ( Exception e ) { + System.out.println( e ); + // Don't try logging a log error. + } + LogUtil.removeAppender( appender, logger ); + } + + private String getThreadName() { + return Thread.currentThread().getName(); + } +} diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLogger.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLogger.java new file mode 100644 index 00000000000..3dfde711e4a --- /dev/null +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryExportLogger.java @@ -0,0 +1,184 @@ +/*! ****************************************************************************** + * + * Pentaho + * + * Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file. + * + * Change Date: 2029-07-20 + ******************************************************************************/ + + +package org.pentaho.platform.plugin.services.importexport; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.StringLayout; +import org.pentaho.platform.api.util.IRepositoryExportLogger; + +import java.io.OutputStream; + +/** + * {@inherit} + * + * @author TKafalas + */ +public class Log4JRepositoryExportLogger implements IRepositoryExportLogger { + + private ThreadLocal repositoryExportLog = new ThreadLocal(); + + public Log4JRepositoryExportLogger() { + } + + public void remove() { + repositoryExportLog.remove(); + } + + public void startJob( OutputStream outputStream, Level logLevel, StringLayout layout ) { + repositoryExportLog.set( new Log4JRepositoryExportLog( outputStream, logLevel, layout ) ); + } + + public void startJob( OutputStream outputStream, Level logLevel ) { + repositoryExportLog.set( new Log4JRepositoryExportLog( outputStream, logLevel ) ); + } + + public void endJob() { + getLog4JRepositoryImportLog().endJob(); + } + + public void info( String s ) { + getLogger().info( s ); + } + + public void error( String s ) { + getLogger().error( s ); + } + + public void debug( String s ) { + getLogger().debug( s ); + } + + public void warn( String s ) { + getLogger().debug( s ); + } + + @Override + public void error( Exception e ) { + getLogger().error( e.getMessage(), e ); + + } + + private Log4JRepositoryExportLog getLog4JRepositoryImportLog() { + Log4JRepositoryExportLog currentLog = repositoryExportLog.get(); + if ( currentLog == null ) { + throw new IllegalStateException( "No job started for current Thread" ); + } + return currentLog; + } + + private Logger getLogger() { + return getLog4JRepositoryImportLog().getLogger(); + } + + public boolean hasLogger() { + return ( repositoryExportLog.get() == null ) ? false : true; + } + + @Override + public void debug( Object arg0 ) { + getLogger().debug( arg0 ); + } + + @Override + public void debug( Object arg0, Throwable arg1 ) { + getLogger().debug( arg0, arg1 ); + } + + @Override + public void error( Object arg0 ) { + getLogger().error( arg0 ); + } + + @Override + public void error( Object arg0, Throwable arg1 ) { + getLogger().error( arg0, arg1 ); + + } + + @Override + public void fatal( Object arg0 ) { + getLogger().fatal( arg0 ); + + } + + @Override + public void fatal( Object arg0, Throwable arg1 ) { + getLogger().fatal( arg0, arg1 ); + + } + + @Override + public void info( Object arg0 ) { + getLogger().info( arg0 ); + + } + + @Override + public void info( Object arg0, Throwable arg1 ) { + getLogger().info( arg0, arg1 ); + + } + + @Override + public boolean isDebugEnabled() { + return getLogger().isDebugEnabled(); + } + + @Override + public boolean isErrorEnabled() { + return Level.ERROR.isMoreSpecificThan( getLogger().getLevel() ); + } + + @Override + public boolean isFatalEnabled() { + return Level.FATAL.isMoreSpecificThan( getLogger().getLevel() ); + } + + @Override + public boolean isInfoEnabled() { + return getLogger().isInfoEnabled(); + } + + @Override + public boolean isTraceEnabled() { + return getLogger().isTraceEnabled(); + } + + @Override + public boolean isWarnEnabled() { + return Level.WARN.isMoreSpecificThan( getLogger().getLevel() ); + } + + @Override + public void trace( Object arg0 ) { + getLogger().trace( arg0 ); + } + + @Override + public void trace( Object arg0, Throwable arg1 ) { + getLogger().trace( arg0, arg1 ); + } + + @Override + public void warn( Object arg0 ) { + getLogger().warn( arg0 ); + } + + @Override + public void warn( Object arg0, Throwable arg1 ) { + getLogger().warn( arg0, arg1 ); + } + +} diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLog.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLog.java index f0c77a9840a..597f67a5b26 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLog.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLog.java @@ -15,19 +15,13 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.WriterAppender; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.StringLayout; import org.pentaho.platform.api.util.LogUtil; import org.slf4j.MDC; @@ -41,17 +35,35 @@ public class Log4JRepositoryImportLog { private String importRootPath; private Level logLevel; private Appender appender; + private StringLayout layout; /** * Constructs an object that keeps track of additional fields for Log4j logging and writes/formats an html file to the * output stream provided. - * + * + * @param outputStream + */ + Log4JRepositoryImportLog( OutputStream outputStream, String importRootPath, Level logLevel, StringLayout layout ) { + this.outputStream = outputStream; + this.importRootPath = importRootPath; + this.logLevel = logLevel; + this.layout = layout; + init(); + } + + /** + * Constructs an object that keeps track of additional fields for Log4j logging and writes/formats an html file to the + * output stream provided. + * * @param outputStream */ Log4JRepositoryImportLog( OutputStream outputStream, String importRootPath, Level logLevel ) { this.outputStream = outputStream; this.importRootPath = importRootPath; this.logLevel = logLevel; + RepositoryImportHTMLLayout htmlLayout = new RepositoryImportHTMLLayout( logLevel ); + htmlLayout.setTitle( "Repository Import Log" ); + this.layout = htmlLayout; init(); } @@ -59,10 +71,8 @@ private void init() { logName = "RepositoryImportLog." + getThreadName(); logger = LogManager.getLogger( logName ); LogUtil.setLevel( logger, logLevel ); - RepositoryImportHTMLLayout htmlLayout = new RepositoryImportHTMLLayout( logLevel ); - htmlLayout.setTitle( "Repository Import Log" ); appender = - LogUtil.makeAppender( logName, new OutputStreamWriter( outputStream, Charset.forName( "utf-8" ) ), htmlLayout ); + LogUtil.makeAppender( logName, new OutputStreamWriter( outputStream, StandardCharsets.UTF_8 ), this.layout ); LogUtil.addAppender( appender, logger, logLevel ); } @@ -78,8 +88,7 @@ public String getCurrentFilePath() { } /** - * @param currentFilePath - * the currentFilePath to set + * @param currentFilePath the currentFilePath to set */ public void setCurrentFilePath( String currentFilePath ) { this.currentFilePath = currentFilePath; diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLogger.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLogger.java index bd64224b180..898b204d717 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLogger.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/Log4JRepositoryImportLogger.java @@ -15,37 +15,50 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.StringLayout; import java.io.OutputStream; /** * {@inherit} - * + * * @author TKafalas - * */ public class Log4JRepositoryImportLogger implements IRepositoryImportLogger { private ThreadLocal repositoryImportLog = new ThreadLocal(); + private boolean isPerformingRestore = false; + public Log4JRepositoryImportLogger() { } + public void startJob( OutputStream outputStream, String importRootPath, Level logLevel, StringLayout layout ) { + repositoryImportLog.set( new Log4JRepositoryImportLog( outputStream, importRootPath, logLevel, layout ) ); + getLog4JRepositoryImportLog().setCurrentFilePath( getLog4JRepositoryImportLog().getImportRootPath() ); + if ( !isPerformingRestore ) { + getLogger().info( "Start Import Job" ); + } + } + public void startJob( OutputStream outputStream, String importRootPath, Level logLevel ) { repositoryImportLog.set( new Log4JRepositoryImportLog( outputStream, importRootPath, logLevel ) ); getLog4JRepositoryImportLog().setCurrentFilePath( getLog4JRepositoryImportLog().getImportRootPath() ); - getLogger().info( "Start Import Job" ); + if ( !isPerformingRestore ) { + getLogger().info( "Start Import Job" ); + } } public void endJob() { getLog4JRepositoryImportLog().setCurrentFilePath( getLog4JRepositoryImportLog().getImportRootPath() ); - getLogger().info( "End Import Job" ); getLog4JRepositoryImportLog().endJob(); + if ( !isPerformingRestore ) { + getLogger().info( "End Import Job" ); + } } public void setCurrentFilePath( String currentFilePath ) { getLog4JRepositoryImportLog().setCurrentFilePath( currentFilePath ); - getLogger().info( "Start File Import" ); } public void info( String s ) { @@ -86,6 +99,16 @@ public boolean hasLogger() { return ( repositoryImportLog.get() == null ) ? false : true; } + @Override + public boolean isPerformingRestore() { + return isPerformingRestore; + } + + @Override + public void setPerformingRestore( boolean value ) { + this.isPerformingRestore = value; + } + @Override public void debug( Object arg0 ) { getLogger().debug( arg0 ); diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/RepositoryTextLayout.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/RepositoryTextLayout.java new file mode 100644 index 00000000000..2e911166e9e --- /dev/null +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/RepositoryTextLayout.java @@ -0,0 +1,170 @@ +/*! ****************************************************************************** + * + * Pentaho + * + * Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file. + * + * Change Date: 2029-07-20 + ******************************************************************************/ + +package org.pentaho.platform.plugin.services.importexport; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.StringLayout; +import org.apache.logging.log4j.core.layout.ByteBufferDestination; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.Strings; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + +/** + * This class was derived from Log4j HTML + *

+ * Appenders using this layout should have their encoding set to UTF-8 or UTF-16, otherwise events containing non ASCII + * characters could result in corrupted log files. + * + * @author tkafalas + */ +public class RepositoryTextLayout implements StringLayout { + + protected static final int BUF_SIZE = 256; + protected static final int MAX_CAPACITY = 1024; + public static final String LINE_SEP = System.getProperty( "line.separator" ); + private static final String REGEXP = Strings.LINE_SEPARATOR.equals( "\n" ) ? "\n" : Strings.LINE_SEPARATOR + "|\n"; + + private Level loggerLogLevel; + + // output buffer appended to when format() is invoked + private StringBuffer sbuf = new StringBuffer( BUF_SIZE ); + + String title = "Log4J Log Messages"; + + public RepositoryTextLayout( Level loggerLogLevel ) { + super(); + this.loggerLogLevel = loggerLogLevel; + } + + /** + * The Title option takes a String value. This option sets the document title of the generated HTML document. + * + *

+ * Defaults to 'Log4J Log Messages'. + */ + public void setTitle( String title ) { + this.title = title; + } + + /** + * Returns the current value of the Title option. + */ + public String getTitle() { + return title; + } + + /** + * Returns the content type output by this layout, i.e "text/html". + */ + public String getContentType() { + return "text/plain"; + } + + @Override + public Map getContentFormat() { + return null; + } + + public String format( LogEvent event ) { + + Level logLevel = event.getLevel(); + if ( sbuf.capacity() > MAX_CAPACITY ) { + sbuf = new StringBuffer( BUF_SIZE ); + } else { + sbuf.setLength( 0 ); + } + + sbuf.append( LINE_SEP ); + + DateFormat df = new SimpleDateFormat( "MM/dd/yyyy HH:mm:ss" ); + Date date = new Date(); + date.setTime( event.getTimeMillis() ); + String time = null; + try { + time = df.format( date ); + } catch ( Exception ex ) { + StatusLogger.getLogger().error( "Error occurred while converting date.", ex ); + } + + sbuf.append( time ); + + // File/Folder + String currentFile = ThreadContext.get( "currentFile" ); + if ( currentFile != null && currentFile.length() > 0 ) { + sbuf.append( "\t" ); + sbuf.append( currentFile ); + } + // debug level + sbuf.append( "\t" ); + sbuf.append( String.valueOf( event.getLevel() ) ); + + // Message + sbuf.append( "\t" ); + sbuf.append( event.getMessage() ); + + return sbuf.toString(); + } + + /** + * Returns appropriate headers. + */ + public byte[] getHeader() { + StringBuffer sbuf = new StringBuffer(); + sbuf.append( title ); + return sbuf.toString().getBytes( StandardCharsets.UTF_8 ); + } + + @Override + public byte[] toByteArray( LogEvent event ) { + return format( event ).getBytes( StandardCharsets.UTF_8 ); + } + + @Override + public String toSerializable( LogEvent event ) { + return format( event ); + } + + /** + * Returns the appropriate footers. + */ + public byte[] getFooter() { + StringBuffer sbuf = new StringBuffer(); + sbuf.append( "\n\nEnd of Log\n\n" ); + return sbuf.toString().getBytes( StandardCharsets.UTF_8 ); + } + + /** + * The layout does not handle the throwable contained in logging events. Hence, this method return true. + */ + public boolean ignoresThrowable() { + return true; + } + + @Override + public Charset getCharset() { + return StandardCharsets.UTF_8; + } + + @Override + public void encode( LogEvent source, ByteBufferDestination destination ) { + + } +} diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/SimpleExportProcessor.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/SimpleExportProcessor.java index 9598a5951c1..8e1e46e99ad 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/SimpleExportProcessor.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/SimpleExportProcessor.java @@ -19,6 +19,7 @@ import org.apache.commons.logging.LogFactory; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; +import org.pentaho.platform.api.importexport.ExportException; import java.io.File; import java.io.FileNotFoundException; @@ -53,9 +54,8 @@ public SimpleExportProcessor( String path, IUnifiedRepository repository ) { /** * Performs the export process, returns a File object - * - * @throws ExportException - * indicates an error in import processing + * + * @throws ExportException indicates an error in import processing */ public File performExport( RepositoryFile exportRepositoryFile ) throws ExportException, IOException { OutputStream os; @@ -98,18 +98,17 @@ public File performExport( RepositoryFile exportRepositoryFile ) throws ExportEx */ @Override public void exportDirectory( RepositoryFile repositoryDir, OutputStream outputStream, String filePath ) - throws ExportException, IOException { + throws ExportException, IOException { throw new UnsupportedOperationException(); } /** - * * @param repositoryFile * @param outputStream */ @Override public void exportFile( RepositoryFile repositoryFile, OutputStream outputStream, String filePath ) - throws ExportException, IOException { + throws ExportException, IOException { // iterate through handlers to perform export for ( ExportHandler exportHandler : exportHandlerList ) { diff --git a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessor.java b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessor.java index 0b0b5a1964a..230ff14c984 100644 --- a/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessor.java +++ b/extensions/src/main/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessor.java @@ -23,6 +23,7 @@ import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl; import org.pentaho.platform.api.repository2.unified.RepositoryRequest; +import org.pentaho.platform.api.importexport.ExportException; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.plugin.services.importexport.exportManifest.ExportManifest; @@ -61,6 +62,9 @@ public class ZipExportProcessor extends BaseExportProcessor { private static final int SAFETY_TMP_FILE_SIZE = 50; + private Log logger; + + /** * Encapsulates the logic of registering import handlers, generating the manifest, and performing the export */ @@ -93,7 +97,7 @@ protected void initManifest() { exportManifest.getManifestInformation().setExportBy( session.getName() ); exportManifest.getManifestInformation().setExportDate( - dateFormat.format( todaysDate ) + " " + timeFormat.format( todaysDate ) ); + dateFormat.format( todaysDate ) + " " + timeFormat.format( todaysDate ) ); exportManifest.getManifestInformation().setManifestVersion( "2" ); } @@ -107,6 +111,7 @@ protected IPentahoSession getSession() { * @throws ExportException indicates an error in import processing */ public File performExport( RepositoryFile exportRepositoryFile ) throws ExportException, IOException { + logger = getRepositoryExportLogger(); File exportFile = null; // create temp file @@ -180,13 +185,28 @@ public void exportFile( RepositoryFile repositoryFile, OutputStream outputStream try ( InputStream is = exportHandler.doExport( repositoryFile, filePath ) ) { // if we don't get a valid input stream back, skip it if ( is != null ) { + if ( logger != null ) { + logger.debug( "Adding repository object [ " + repositoryFile.getName() + " ] to the manifest" ); + } + addToManifest( repositoryFile ); + if ( logger != null ) { + logger.debug( "Starting to add repository object [ " + repositoryFile.getName() + " ] to the bundle" ); + } String zipEntryName = getFixedZipEntryName( repositoryFile, filePath ); ZipEntry entry = new ZipEntry( zipEntryName ); zos.putNextEntry( entry ); IOUtils.copy( is, outputStream ); zos.closeEntry(); + + if ( logger != null ) { + logger.debug( "Successfully added repository object [ " + repositoryFile.getName() + " ] to the bundle" ); + logger.trace( "Starting to create locale entry for repository object [ " + ( ( repositoryFile != null ) ? repositoryFile.getName() : "" ) + " ] " ); + } createLocales( repositoryFile, filePath, repositoryFile.isFolder(), outputStream ); + if ( logger != null ) { + logger.trace( "Finished creating locale entry for repository object [ " + ( ( repositoryFile != null ) ? repositoryFile.getName() : "" ) + " ] " ); + } } } } @@ -217,31 +237,59 @@ protected void addToManifest( RepositoryFile repositoryFile ) throws ExportExcep @Override public void exportDirectory( RepositoryFile repositoryDir, OutputStream outputStream, String filePath ) throws ExportException, IOException { + if ( logger != null ) { + logger.debug( "Adding repository object [ " + repositoryDir.getName() + " ] to the manifest" ); + } addToManifest( repositoryDir ); List children = getUnifiedRepository().getChildren( new RepositoryRequest( String.valueOf( repositoryDir.getId() ), true, 1, null ) ); + if ( logger != null ) { + logger.debug( "Found [ " + children.size() + " ] children in folder [ " + repositoryDir.getName() + " ]" ); + } for ( RepositoryFile repositoryFile : children ) { // exclude 'etc' folder - datasources and etc. if ( isExportCandidate( repositoryFile.getPath() ) ) { + if ( logger != null ) { + logger.trace( "Repository object is a candidate for backup [ " + repositoryFile.getName() + " ]" ); + } if ( repositoryFile.isFolder() ) { + if ( logger != null ) { + logger.debug( "Repository Object [ " + repositoryFile.getName() + " ] is a folder. Adding it to the bundle" ); + } if ( outputStream.getClass().isAssignableFrom( ZipOutputStream.class ) ) { ZipOutputStream zos = (ZipOutputStream) outputStream; String zipEntryName = getFixedZipEntryName( repositoryFile, filePath ); ZipEntry entry = new ZipEntry( zipEntryName ); zos.putNextEntry( entry ); + if ( logger != null ) { + logger.debug( "Successfully added repository Object [ " + repositoryFile.getName() + " ] to the bundle" ); + } } exportDirectory( repositoryFile, outputStream, filePath ); } else { try { + if ( logger != null ) { + logger.debug( "Repository Object [ " + repositoryFile.getName() + " ] is a file. Adding it to the bundle" ); + } exportFile( repositoryFile, outputStream, filePath ); } catch ( ZipException e ) { // possible duplicate entry, log it and continue on with the other files in the directory log.debug( e.getMessage(), e ); } } + } else { + if ( logger != null ) { + logger.trace( "Repository object is a candidate for backup [ " + repositoryFile.getName() + " ] skipping it" ); + } } } + if ( logger != null ) { + logger.trace( "Starting to create locale entry for repository object [ " + repositoryDir.getName() + " ] " ); + } createLocales( repositoryDir, filePath, repositoryDir.isFolder(), outputStream ); + if ( logger != null ) { + logger.trace( "Finished creating locale entry for repository object [ " + repositoryDir.getName() + " ] " ); + } } protected boolean isExportCandidate( String path ) { @@ -294,7 +342,7 @@ protected String getZipEntryName( RepositoryFile repositoryFile, String filePath * @throws IOException */ protected void createLocales( RepositoryFile repositoryFile, String filePath, boolean isFolder, - OutputStream outputStream ) throws IOException { + OutputStream outputStream ) throws IOException { ZipEntry entry; String zipEntryName; String name; @@ -386,7 +434,7 @@ private InputStream createLocaleFile( String name, Properties properties, String try { localeFile = PentahoSystem - .getApplicationContext().createTempFile( getSession(), ExportFileNameEncoder.encodeZipFileName( name ), LOCALE_EXT, true ); + .getApplicationContext().createTempFile( getSession(), ExportFileNameEncoder.encodeZipFileName( name ), LOCALE_EXT, true ); } catch ( IOException e ) { // BISERVER-14140 - Retry when temp file name exceeds the limit of OS // Retry inside a catch because there isn't an accurate mechanism to determine the effective temp file max length @@ -394,7 +442,7 @@ private InputStream createLocaleFile( String name, Properties properties, String String smallerName = ExportFileNameEncoder.encodeZipFileName( name ).substring( 0, SAFETY_TMP_FILE_SIZE ); log.debug( "Error with original name file. Retrying with a smaller temp file name - " + smallerName ); localeFile = PentahoSystem - .getApplicationContext().createTempFile( getSession(), smallerName, LOCALE_EXT, true ); + .getApplicationContext().createTempFile( getSession(), smallerName, LOCALE_EXT, true ); } finally { if ( localeFile != null ) { localeFile.deleteOnExit(); diff --git a/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/FileResource.java b/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/FileResource.java index c5f1f69f1ad..814ab8fdf6a 100755 --- a/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/FileResource.java +++ b/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/FileResource.java @@ -45,7 +45,7 @@ import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.plugin.services.importer.PlatformImportException; -import org.pentaho.platform.plugin.services.importexport.ExportException; +import org.pentaho.platform.api.importexport.ExportException; import org.pentaho.platform.plugin.services.importexport.Exporter; import org.pentaho.platform.repository.RepositoryDownloadWhitelist; import org.pentaho.platform.repository.RepositoryFilenameUtils; @@ -83,6 +83,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Providers; import javax.xml.bind.JAXBContext; @@ -119,7 +120,7 @@ * * @author aaron */ -@Path ( "/repo/files/" ) +@Path( "/repo/files/" ) public class FileResource extends AbstractJaxRSResource { private static final String INVALID_SECURITY_PRINCIPAL_CHARACTERS = "[#,+\"\\\\<>]"; @@ -140,7 +141,8 @@ public class FileResource extends AbstractJaxRSResource { protected static IAuthorizationPolicy policy; - private @Context Providers providers; + private @Context + Providers providers; IRepositoryContentConverterHandler converterHandler; Map converters; @@ -164,31 +166,32 @@ public static String idToPath( String pathId ) { * Performs a system back up of the Pentaho system. This includes content, schedules, users, roles, datasources, and the metastore. * *

Example Request:
- * GET pentaho/api/repo/files/backup + * GET pentaho/api/repo/files/backup *

- * - * @param userAgent A string representing the type of browser to use. Currently only applicable if contains 'FireFox' as FireFox - * requires a header with encoding information (UTF-8) and a quoted filename, otherwise encoding information is not - * supplied and the filename is not quoted. - * + * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *      Encrypted file stream
    *    
*/ - @GET + @POST @Path( "/backup" ) + @Consumes( MediaType.APPLICATION_FORM_URLENCODED ) @StatusCodes( { - @ResponseCode( code = 200, condition = "Successfully exported the existing Pentaho System" ), - @ResponseCode( code = 403, condition = "User does not have administrative permissions" ), - @ResponseCode( code = 500, condition = "Failure to complete the export." ) } ) - public Response systemBackup( @HeaderParam ( "user-agent" ) String userAgent ) { + @ResponseCode( code = 200, condition = "Successfully exported the existing Pentaho System" ), + @ResponseCode( code = 400, condition = "User has provided a invalid file path" ), + @ResponseCode( code = 403, condition = "User does not have administrative permissions" ), + @ResponseCode( code = 500, condition = "Failure to complete the export." )} ) + public Response systemBackup( final MultivaluedMap formParams ) { FileService.DownloadFileWrapper wrapper; try { - wrapper = fileService.systemBackup( userAgent ); + wrapper = fileService.systemBackup( formParams.getFirst( "logFile" ), formParams + .getFirst( "logLevel" ), formParams.getFirst( "outputFile" ) ); return buildZipOkResponse( wrapper ); + } catch ( IllegalArgumentException iae ) { + throw new WebApplicationException( iae, Response.Status.BAD_REQUEST ); } catch ( IOException e ) { throw new WebApplicationException( e, Response.Status.INTERNAL_SERVER_ERROR ); } catch ( ExportException e ) { @@ -211,14 +214,18 @@ public Response systemBackup( @HeaderParam ( "user-agent" ) String userAgent ) { @Path( "/systemRestore" ) @Consumes( MediaType.MULTIPART_FORM_DATA ) @StatusCodes( { - @ResponseCode( code = 200, condition = "Successfully imported the Pentaho System" ), - @ResponseCode( code = 403, condition = "User does not have administrative permissions" ), - @ResponseCode( code = 500, condition = "Failure to complete the import." ) } ) - public Response systemRestore( @FormDataParam( "fileUpload" ) InputStream fileUpload, @FormDataParam ( "overwriteFile" ) String overwriteFile, - @FormDataParam ( "applyAclSettings" ) String applyAclSettings, @FormDataParam ( "overwriteAclSettings" ) String overwriteAclSettings ) { + @ResponseCode( code = 200, condition = "Successfully imported the Pentaho System" ), + @ResponseCode( code = 400, condition = "User has provided a invalid file path" ), + @ResponseCode( code = 403, condition = "User does not have administrative permissions" ), + @ResponseCode( code = 500, condition = "Failure to complete the import." )} ) + public Response systemRestore( @FormDataParam( "fileUpload" ) InputStream fileUpload, @FormDataParam( "overwriteFile" ) String overwriteFile, + @FormDataParam( "applyAclSettings" ) String applyAclSettings, @FormDataParam( "overwriteAclSettings" ) String overwriteAclSettings, + @FormDataParam( "logFile" ) String logFile, @FormDataParam( "logLevel" ) String logLevel, @FormDataParam( "backupBundlePath" ) String backupBundlePath ) { try { - fileService.systemRestore( fileUpload, overwriteFile, applyAclSettings, overwriteAclSettings ); + fileService.systemRestore( fileUpload, overwriteFile, applyAclSettings, overwriteAclSettings, logFile, logLevel, backupBundlePath ); return Response.ok().build(); + } catch ( IllegalArgumentException iae ) { + throw new WebApplicationException( iae, Response.Status.BAD_REQUEST ); } catch ( PlatformImportException e ) { throw new WebApplicationException( e, Response.Status.INTERNAL_SERVER_ERROR ); } catch ( SecurityException e ) { @@ -230,23 +237,22 @@ public Response systemRestore( @FormDataParam( "fileUpload" ) InputStream fileUp * Move a list of files to the user's trash folder. * *

Example Request:
- * PUT pentaho/api/repo/files/delete + * PUT pentaho/api/repo/files/delete *

- * + *

* Important Note: This end-point is not intended for concurrent execution by the * same user or session. It facilitates the User Console deletion UI, and should * not be used in a manner inconsistent with how that UI operates. * * @param params Comma separated list of the files to be moved to trash folder. - * * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT @Path( "/delete" ) - @Consumes( { MediaType.WILDCARD } ) + @Consumes( {MediaType.WILDCARD} ) @StatusCodes( { - @ResponseCode( code = 200, condition = "Successfully moved file to trash." ), - @ResponseCode( code = 500, condition = "Failure move the file to the trash." ) } ) + @ResponseCode( code = 200, condition = "Successfully moved file to trash." ), + @ResponseCode( code = 500, condition = "Failure move the file to the trash." )} ) public Response doDeleteFiles( String params ) { try { fileService.doDeleteFiles( params ); @@ -261,23 +267,22 @@ public Response doDeleteFiles( String params ) { * Permanently deletes the selected list of files from the repository. * *

Example Request:
- * PUT pentaho/api/repo/files/deletepermanent + * PUT pentaho/api/repo/files/deletepermanent *

- * + *

* Important Note: This end-point is not intended for concurrent execution by the * same user or session. It facilitates the User Console deletion UI, and should * not be used in a manner inconsistent with how that UI operates. * * @param params Comma separated list of the files to be deleted. - * * @return Server Response indicating the success of the operation. */ @PUT - @Path ( "/deletepermanent" ) - @Consumes ( { MediaType.WILDCARD } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully deleted the comma seperated list of fileIds from the system." ), - @ResponseCode ( code = 403, condition = "Failure to delete the file due to path not found." ) } ) + @Path( "/deletepermanent" ) + @Consumes( {MediaType.WILDCARD} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully deleted the comma seperated list of fileIds from the system." ), + @ResponseCode( code = 403, condition = "Failure to delete the file due to path not found." )} ) public Response doDeleteFilesPermanent( String params ) { try { fileService.doDeleteFilesPermanent( params ); @@ -292,23 +297,22 @@ public Response doDeleteFilesPermanent( String params ) { * Moves a list of files from its current location to another. * *

Example Request:
- * PUT pentaho/api/repo/files/{pathId}/move + * PUT pentaho/api/repo/files/{pathId}/move *

* * @param destPathId Colon separated path for the destination path. * @param params Comma separated list of files to be moved. - * * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT - @Path ( "{pathId : .+}/move" ) - @Consumes ( { MediaType.WILDCARD } ) - @Facet ( name = "Unsupported" ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully moved the file." ), - @ResponseCode ( code = 403, condition = "Failure to move the file due to path not found." ), - @ResponseCode ( code = 500, condition = "Failure to move the file." ) } ) - public Response doMove( @PathParam ( "pathId" ) String destPathId, String params ) { + @Path( "{pathId : .+}/move" ) + @Consumes( {MediaType.WILDCARD} ) + @Facet( name = "Unsupported" ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully moved the file." ), + @ResponseCode( code = 403, condition = "Failure to move the file due to path not found." ), + @ResponseCode( code = 500, condition = "Failure to move the file." )} ) + public Response doMove( @PathParam( "pathId" ) String destPathId, String params ) { try { fileService.doMoveFiles( destPathId, params ); return buildOkResponse(); @@ -328,8 +332,8 @@ public Response doMove( @PathParam ( "pathId" ) String destPathId, String params * Restores a list of files from the user's trash folder to their previous locations. * *

Example Request:
- * PUT pentaho/api/repo/files/restore - restore files to original location - * PUT pentaho/api/repo/files/restore?overwriteMode=2 - restore files to user home folder, RENAME mode + * PUT pentaho/api/repo/files/restore - restore files to original location + * PUT pentaho/api/repo/files/restore?overwriteMode=2 - restore files to user home folder, RENAME mode *

* * @param params comma separated list of file ids to be restored. @@ -342,16 +346,16 @@ public Response doMove( @PathParam ( "pathId" ) String destPathId, String params */ @PUT @Path( "/restore" ) - @Consumes( { MediaType.WILDCARD } ) + @Consumes( {MediaType.WILDCARD} ) @Facet( name = "Unsupported" ) @StatusCodes( { - @ResponseCode( code = 200, condition = "Successfully restored the file." ), - @ResponseCode( code = 307, condition = "Cannot restore in origin folder, can restore in home folder without " - + "conflicts" ), - @ResponseCode( code = 403, condition = "Failure to Restore the file." ), - @ResponseCode( code = 409, condition = "Cannot restore in origin folder, cannot restore in home folder without " - + "conflicts" ), - } ) + @ResponseCode( code = 200, condition = "Successfully restored the file." ), + @ResponseCode( code = 307, condition = "Cannot restore in origin folder, can restore in home folder without " + + "conflicts" ), + @ResponseCode( code = 403, condition = "Failure to Restore the file." ), + @ResponseCode( code = 409, condition = "Cannot restore in origin folder, cannot restore in home folder without " + + "conflicts" ), + } ) public Response doRestore( String params, @QueryParam( value = "overwriteMode" ) Integer mode ) { if ( mode != null ) { @@ -382,9 +386,9 @@ public Response doRestore( String params, * Creates a new file with the provided contents at a given path. * *

Example Request:
- * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml + * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml *
PUT data: - *

+   * 
    *    This PUT body does not contain data.
    *  
*

@@ -392,21 +396,20 @@ public Response doRestore( String params, * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param fileContents An Input Stream with the contents of the file to be created. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}" ) - @Consumes ( { MediaType.WILDCARD } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully created the file." ), - @ResponseCode ( code = 403, condition = "Failure to create the file due to permissions, file already exists, or invalid path id." ) } ) - public Response createFile( @PathParam ( "pathId" ) String pathId, InputStream fileContents ) { + @Path( "{pathId : .+}" ) + @Consumes( {MediaType.WILDCARD} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully created the file." ), + @ResponseCode( code = 403, condition = "Failure to create the file due to permissions, file already exists, or invalid path id." )} ) + public Response createFile( @PathParam( "pathId" ) String pathId, InputStream fileContents ) { try { checkCorrectExtension( pathId ); @@ -423,24 +426,23 @@ public Response createFile( @PathParam ( "pathId" ) String pathId, InputStream f * Copy selected list of files to a new specified location. * *

Example Request:
- * PUT pentaho/api/repo/files/{pathId}/children?mode=2 + * PUT pentaho/api/repo/files/{pathId}/children?mode=2 *

* * @param pathId Colon separated path for the destination for files to be copied. * @param mode Default is RENAME (2) which adds a number to the end of the file name. MODE_OVERWRITE (1) will just replace existing * or MODE_NO_OVERWRITE (3) will not copy if file exist. * @param params Comma separated list of file ids to be copied. - * * @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT - @Path ( "{pathId : .+}/children" ) - @Consumes ( { MediaType.TEXT_PLAIN } ) - @Facet ( name = "Unsupported" ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully copied the file." ), - @ResponseCode ( code = 500, condition = "Failure to Copy file due to exception while getting file with id fileid..." ), } ) - public Response doCopyFiles( @PathParam ( "pathId" ) String pathId, @QueryParam ( "mode" ) Integer mode, + @Path( "{pathId : .+}/children" ) + @Consumes( {MediaType.TEXT_PLAIN} ) + @Facet( name = "Unsupported" ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully copied the file." ), + @ResponseCode( code = 500, condition = "Failure to Copy file due to exception while getting file with id fileid..." ),} ) + public Response doCopyFiles( @PathParam( "pathId" ) String pathId, @QueryParam( "mode" ) Integer mode, String params ) { try { fileService.doCopyFiles( pathId, mode, params ); @@ -461,26 +463,25 @@ public Response doCopyFiles( @PathParam ( "pathId" ) String pathId, @QueryParam * Takes a pathId and returns a Response with the output stream based on the file located at the pathId. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml *

* * @param pathId Colon separated path for the repository file. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @GET - @Path ( "{pathId : .+}" ) - @Produces ( { MediaType.WILDCARD } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully get the file or directory." ), - @ResponseCode ( code = 404, condition = "Failed to find the file or resource." ), - @ResponseCode ( code = 500, condition = "Failed to open content." ) } ) - public Response doGetFileOrDir( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}" ) + @Produces( {MediaType.WILDCARD} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully get the file or directory." ), + @ResponseCode( code = 404, condition = "Failed to find the file or resource." ), + @ResponseCode( code = 500, condition = "Failed to open content." )} ) + public Response doGetFileOrDir( @PathParam( "pathId" ) String pathId ) { try { FileService.RepositoryFileToStreamWrapper wrapper = fileService.doGetFileOrDir( pathId ); return buildOkResponse( wrapper ); @@ -496,7 +497,7 @@ public Response doGetFileOrDir( @PathParam ( "pathId" ) String pathId ) { // @GET // @Path("{pathId : .+}") // @Produces({ APPLICATION_ZIP }) - public Response doGetDirAsZip( @PathParam ( "pathId" ) String pathId ) { + public Response doGetDirAsZip( @PathParam( "pathId" ) String pathId ) { String path = fileService.idToPath( pathId ); if ( !isPathValid( path ) ) { @@ -548,19 +549,18 @@ public Response doGetDirAsZip( RepositoryFile repositoryFile ) { * Determines whether a selected file supports parameters or not * * @param pathId Colon separated path for the repository file. - * - * @return ("true" or "false") + * @return (" true " or " false ") * @throws FileNotFoundException */ @GET - @Path ( "{pathId : .+}/parameterizable" ) - @Produces ( MediaType.TEXT_PLAIN ) - @Facet ( name = "Unsupported" ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully get the file or directory." ), - @ResponseCode ( code = 404, condition = "Failed to find the file or resource." ) } ) + @Path( "{pathId : .+}/parameterizable" ) + @Produces( MediaType.TEXT_PLAIN ) + @Facet( name = "Unsupported" ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully get the file or directory." ), + @ResponseCode( code = 404, condition = "Failed to find the file or resource." )} ) // have to accept anything for browsers to work - public String doIsParameterizable( @PathParam ( "pathId" ) String pathId ) throws FileNotFoundException { + public String doIsParameterizable( @PathParam( "pathId" ) String pathId ) throws FileNotFoundException { boolean hasParameterUi = false; RepositoryFile repositoryFile = getRepository().getFile( fileService.idToPath( pathId ) ); if ( repositoryFile != null ) { @@ -594,7 +594,7 @@ public String doIsParameterizable( @PathParam ( "pathId" ) String pathId ) throw Document document = parseText( outputStream.toString() ); // exclude all parameters that are of type "system", xactions set system params that have to be ignored. - @SuppressWarnings ( "rawtypes" ) + @SuppressWarnings( "rawtypes" ) List nodes = document.selectNodes( "parameters/parameter" ); for ( int i = 0; i < nodes.size() && !hasParameters; i++ ) { Element elem = (Element) nodes.get( i ); @@ -624,7 +624,7 @@ public String doIsParameterizable( @PathParam ( "pathId" ) String pathId ) throw * have Publish action. How the file comes down to the user and where it is saved is system and browser dependent. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/download?locale=de + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/download?locale=de *

* * @param pathId Colon separated path for the repository file. @@ -633,26 +633,25 @@ public String doIsParameterizable( @PathParam ( "pathId" ) String pathId ) throw * @param userAgent A string representing the type of browser to use. Currently only applicable if contains 'FireFox' as FireFox * requires a header with encoding information (UTF-8) and a quoted filename, otherwise encoding information is not * supplied and the filename is not quoted. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *      Encrypted file stream
    *    
*/ @GET - @Path ( "{pathId : .+}/download" ) - @Produces ( MediaType.WILDCARD ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successful download." ), - @ResponseCode ( code = 400, condition = "Usually a bad pathId." ), - @ResponseCode ( code = 403, condition = "pathId points at a file the user doesn't have access to." ), - @ResponseCode ( code = 404, condition = "File not found." ), - @ResponseCode ( code = 500, condition = "Failed to download file for another reason." ) } ) + @Path( "{pathId : .+}/download" ) + @Produces( MediaType.WILDCARD ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successful download." ), + @ResponseCode( code = 400, condition = "Usually a bad pathId." ), + @ResponseCode( code = 403, condition = "pathId points at a file the user doesn't have access to." ), + @ResponseCode( code = 404, condition = "File not found." ), + @ResponseCode( code = 500, condition = "Failed to download file for another reason." )} ) // have to accept anything for browsers to work - public Response doGetFileOrDirAsDownload( @HeaderParam ( "user-agent" ) String userAgent, - @PathParam ( "pathId" ) String pathId, @QueryParam ( "withManifest" ) String strWithManifest ) { + public Response doGetFileOrDirAsDownload( @HeaderParam( "user-agent" ) String userAgent, + @PathParam( "pathId" ) String pathId, @QueryParam( "withManifest" ) String strWithManifest ) { FileService.DownloadFileWrapper wrapper; try { wrapper = fileService.doGetFileOrDirAsDownload( userAgent, pathId, strWithManifest ); @@ -680,27 +679,26 @@ public Response doGetFileOrDirAsDownload( @HeaderParam ( "user-agent" ) String u * document. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/inline + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/inline *

* * @param pathId Colon separated path for the repository file. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *      <?xml version="1.0" encoding="UTF-8" standalone="yes"?><repositoryFileAclDto><entriesInheriting>true</entriesInheriting><id>d45d4972-989e-48d5-8bd0-f7024a77f08f</id><owner>admin</owner><ownerType>0</ownerType></repositoryFileAclDto>
    *    
*/ @GET - @Path ( "{pathId : .+}/inline" ) - @Produces ( MediaType.WILDCARD ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved file." ), - @ResponseCode ( code = 403, condition = "Failed to retrieve file due to permission problem." ), - @ResponseCode ( code = 404, condition = "Failed to retrieve file due because file was not found." ), - @ResponseCode ( code = 500, condition = "Failed to download file because of some other error." ) } ) - public Response doGetFileAsInline( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}/inline" ) + @Produces( MediaType.WILDCARD ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved file." ), + @ResponseCode( code = 403, condition = "Failed to retrieve file due to permission problem." ), + @ResponseCode( code = 404, condition = "Failed to retrieve file due because file was not found." ), + @ResponseCode( code = 500, condition = "Failed to download file because of some other error." )} ) + public Response doGetFileAsInline( @PathParam( "pathId" ) String pathId ) { try { FileService.RepositoryFileToStreamWrapper wrapper = fileService.doGetFileAsInline( pathId ); return buildOkResponse( wrapper ); @@ -720,32 +718,31 @@ public Response doGetFileAsInline( @PathParam ( "pathId" ) String pathId ) { * This method is used to update and save the acls of the selected file to the repository. * *

Example Request:
- * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl + * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl *
PUT data: - *

+   * 
    *    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><repositoryFileAclDto><entriesInheriting>true</entriesInheriting><id>d45d4972-989e-48d5-8bd0-f7024a77f08f</id><owner>admin</owner><ownerType>0</ownerType></repositoryFileAclDto>
    *  
*

* * @param pathId Colon separated path for the repository file. * @param aclXml Acl of the repository file RepositoryFileAclDto. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}/acl" ) - @Consumes ( { MediaType.APPLICATION_XML } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully saved file." ), - @ResponseCode ( code = 403, condition = "Failed to save acls due to missing or incorrect properties." ), - @ResponseCode ( code = 400, condition = "Failed to save acls due to malformed xml." ), - @ResponseCode ( code = 500, condition = "Failed to save acls due to another error." ) } ) - public Response setFileAcls( @PathParam ( "pathId" ) String pathId, StreamSource aclXml ) { + @Path( "{pathId : .+}/acl" ) + @Consumes( {MediaType.APPLICATION_XML} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully saved file." ), + @ResponseCode( code = 403, condition = "Failed to save acls due to missing or incorrect properties." ), + @ResponseCode( code = 400, condition = "Failed to save acls due to malformed xml." ), + @ResponseCode( code = 500, condition = "Failed to save acls due to another error." )} ) + public Response setFileAcls( @PathParam( "pathId" ) String pathId, StreamSource aclXml ) { /* * [BISERVER-14294] Ensuring the owner is set to a non-null, non-empty string value to prevent any issues * that might cause problems with the repository. Then following it up with a user existence check @@ -777,32 +774,31 @@ public Response setFileAcls( @PathParam ( "pathId" ) String pathId, StreamSource * This method is used to update and save the acls of the selected file to the repository. * *

Example Request:
- * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl + * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl *
PUT data: - *

+   * 
    *    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><repositoryFileAclDto><entriesInheriting>true</entriesInheriting><id>d45d4972-989e-48d5-8bd0-f7024a77f08f</id><owner>admin</owner><ownerType>0</ownerType></repositoryFileAclDto>
    *  
*

* * @param pathId Colon separated path for the repository file. * @param acl Acl of the repository file RepositoryFileAclDto. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}/acl" ) - @Consumes ( { MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully saved file." ), - @ResponseCode ( code = 403, condition = "Failed to save acls due to missing or incorrect properties." ), - @ResponseCode ( code = 400, condition = "Failed to save acls due to malformed xml." ), - @ResponseCode ( code = 500, condition = "Failed to save acls due to another error." ) } ) - public Response setFileAcls( @PathParam ( "pathId" ) String pathId, RepositoryFileAclDto acl ) { + @Path( "{pathId : .+}/acl" ) + @Consumes( {MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully saved file." ), + @ResponseCode( code = 403, condition = "Failed to save acls due to missing or incorrect properties." ), + @ResponseCode( code = 400, condition = "Failed to save acls due to malformed xml." ), + @ResponseCode( code = 500, condition = "Failed to save acls due to another error." )} ) + public Response setFileAcls( @PathParam( "pathId" ) String pathId, RepositoryFileAclDto acl ) { /* * [BISERVER-14294] Ensuring the owner is set to a non-null, non-empty string value to prevent any issues * that might cause problems with the repository. Then following it up with a user existence check @@ -853,63 +849,63 @@ protected Unmarshaller getUnmarshaller( Class clazz ) throws JAXBException { /** * Store content creator for the given path of created content. * - * @param pathId colon separated path for the repository file that was created by the contenCreator below - *
-   *                       :path:to:file:id
-   *                       
+ * @param pathId colon separated path for the repository file that was created by the contenCreator below + *
+   *                                                :path:to:file:id
+   *                                                
* @param contentCreatorXml Repository file that created the file at the above pathId location - *
-   *                       <repositoryFileDto>
-   *                       <createdDate>1402911997019</createdDate>
-   *                       <fileSize>3461</fileSize>
-   *                       <folder>false</folder>
-   *                       <hidden>false</hidden>
-   *                       <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id>
-   *                       <lastModifiedDate>1406647160536</lastModifiedDate>
-   *                       <locale>en</locale>
-   *                       <localePropertiesMapEntries>
-   *                       <localeMapDto>
-   *                       <locale>default</locale>
-   *                       <properties>
-   *                       <stringKeyStringValueDto>
-   *                       <key>file.title</key>
-   *                       <value>myFile</value>
-   *                       </stringKeyStringValueDto>
-   *                       <stringKeyStringValueDto>
-   *                       <key>jcr:primaryType</key>
-   *                       <value>nt:unstructured</value>
-   *                       </stringKeyStringValueDto>
-   *                       <stringKeyStringValueDto>
-   *                       <key>title</key>
-   *                       <value>myFile</value>
-   *                       </stringKeyStringValueDto>
-   *                       <stringKeyStringValueDto>
-   *                       <key>file.description</key>
-   *                       <value>myFile Description</value>
-   *                       </stringKeyStringValueDto>
-   *                       </properties>
-   *                       </localeMapDto>
-   *                       </localePropertiesMapEntries>
-   *                       <locked>false</locked>
-   *                       <name>myFile.prpt</name></name>
-   *                       <originalParentFolderPath>/public/admin</originalParentFolderPath>
-   *                       <ownerType>-1</ownerType>
-   *                       <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path>
-   *                       <title>myFile</title>
-   *                       <versionId>1.9</versionId>
-   *                       <versioned>true</versioned>
-   *                       </repositoryFileAclDto>
-   *                       
+ *
+   *                                                <repositoryFileDto>
+   *                                                <createdDate>1402911997019</createdDate>
+   *                                                <fileSize>3461</fileSize>
+   *                                                <folder>false</folder>
+   *                                                <hidden>false</hidden>
+   *                                                <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id>
+   *                                                <lastModifiedDate>1406647160536</lastModifiedDate>
+   *                                                <locale>en</locale>
+   *                                                <localePropertiesMapEntries>
+   *                                                <localeMapDto>
+   *                                                <locale>default</locale>
+   *                                                <properties>
+   *                                                <stringKeyStringValueDto>
+   *                                                <key>file.title</key>
+   *                                                <value>myFile</value>
+   *                                                </stringKeyStringValueDto>
+   *                                                <stringKeyStringValueDto>
+   *                                                <key>jcr:primaryType</key>
+   *                                                <value>nt:unstructured</value>
+   *                                                </stringKeyStringValueDto>
+   *                                                <stringKeyStringValueDto>
+   *                                                <key>title</key>
+   *                                                <value>myFile</value>
+   *                                                </stringKeyStringValueDto>
+   *                                                <stringKeyStringValueDto>
+   *                                                <key>file.description</key>
+   *                                                <value>myFile Description</value>
+   *                                                </stringKeyStringValueDto>
+   *                                                </properties>
+   *                                                </localeMapDto>
+   *                                                </localePropertiesMapEntries>
+   *                                                <locked>false</locked>
+   *                                                <name>myFile.prpt</name></name>
+   *                                                <originalParentFolderPath>/public/admin</originalParentFolderPath>
+   *                                                <ownerType>-1</ownerType>
+   *                                                <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path>
+   *                                                <title>myFile</title>
+   *                                                <versionId>1.9</versionId>
+   *                                                <versioned>true</versioned>
+   *                                                </repositoryFileAclDto>
+   *                                                
* @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT - @Path ( "{pathId : .+}/creator" ) - @Consumes ( { MediaType.APPLICATION_XML } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved file." ), - @ResponseCode ( code = 500, condition = "Failed to download file because of some other error." ) } ) - @Facet ( name = "Unsupported" ) - public Response doSetContentCreator( @PathParam ( "pathId" ) String pathId, StreamSource contentCreatorXml ) { + @Path( "{pathId : .+}/creator" ) + @Consumes( {MediaType.APPLICATION_XML} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved file." ), + @ResponseCode( code = 500, condition = "Failed to download file because of some other error." )} ) + @Facet( name = "Unsupported" ) + public Response doSetContentCreator( @PathParam( "pathId" ) String pathId, StreamSource contentCreatorXml ) { try { Unmarshaller unmarshaller = getUnmarshaller( RepositoryFileDto.class ); XMLStreamReader xsr = getSecureXmlStreamReader( contentCreatorXml ); @@ -930,61 +926,61 @@ public Response doSetContentCreator( @PathParam ( "pathId" ) String pathId, Stre * * @param pathId colon separated path for the repository file that was created by the contenCreator below *
-   *                       :path:to:file:id
-   *                       
+ * :path:to:file:id + *
* @param contentCreator Repository file that created the file at the above pathId location *
-   *                       <repositoryFileDto>
-   *                       <createdDate>1402911997019</createdDate>
-   *                       <fileSize>3461</fileSize>
-   *                       <folder>false</folder>
-   *                       <hidden>false</hidden>
-   *                       <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id>
-   *                       <lastModifiedDate>1406647160536</lastModifiedDate>
-   *                       <locale>en</locale>
-   *                       <localePropertiesMapEntries>
-   *                       <localeMapDto>
-   *                       <locale>default</locale>
-   *                       <properties>
-   *                       <stringKeyStringValueDto>
-   *                       <key>file.title</key>
-   *                       <value>myFile</value>
-   *                       </stringKeyStringValueDto>
-   *                       <stringKeyStringValueDto>
-   *                       <key>jcr:primaryType</key>
-   *                       <value>nt:unstructured</value>
-   *                       </stringKeyStringValueDto>
-   *                       <stringKeyStringValueDto>
-   *                       <key>title</key>
-   *                       <value>myFile</value>
-   *                       </stringKeyStringValueDto>
-   *                       <stringKeyStringValueDto>
-   *                       <key>file.description</key>
-   *                       <value>myFile Description</value>
-   *                       </stringKeyStringValueDto>
-   *                       </properties>
-   *                       </localeMapDto>
-   *                       </localePropertiesMapEntries>
-   *                       <locked>false</locked>
-   *                       <name>myFile.prpt</name></name>
-   *                       <originalParentFolderPath>/public/admin</originalParentFolderPath>
-   *                       <ownerType>-1</ownerType>
-   *                       <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path>
-   *                       <title>myFile</title>
-   *                       <versionId>1.9</versionId>
-   *                       <versioned>true</versioned>
-   *                       </repositoryFileAclDto>
-   *                       
+ * <repositoryFileDto> + * <createdDate>1402911997019</createdDate> + * <fileSize>3461</fileSize> + * <folder>false</folder> + * <hidden>false</hidden> + * <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id> + * <lastModifiedDate>1406647160536</lastModifiedDate> + * <locale>en</locale> + * <localePropertiesMapEntries> + * <localeMapDto> + * <locale>default</locale> + * <properties> + * <stringKeyStringValueDto> + * <key>file.title</key> + * <value>myFile</value> + * </stringKeyStringValueDto> + * <stringKeyStringValueDto> + * <key>jcr:primaryType</key> + * <value>nt:unstructured</value> + * </stringKeyStringValueDto> + * <stringKeyStringValueDto> + * <key>title</key> + * <value>myFile</value> + * </stringKeyStringValueDto> + * <stringKeyStringValueDto> + * <key>file.description</key> + * <value>myFile Description</value> + * </stringKeyStringValueDto> + * </properties> + * </localeMapDto> + * </localePropertiesMapEntries> + * <locked>false</locked> + * <name>myFile.prpt</name></name> + * <originalParentFolderPath>/public/admin</originalParentFolderPath> + * <ownerType>-1</ownerType> + * <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path> + * <title>myFile</title> + * <versionId>1.9</versionId> + * <versioned>true</versioned> + * </repositoryFileAclDto> + *
* @return A jax-rs Response object with the appropriate status code, header, and body. */ @PUT - @Path ( "{pathId : .+}/creator" ) - @Consumes ( { MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved file." ), - @ResponseCode ( code = 500, condition = "Failed to download file because of some other error." ) } ) - @Facet ( name = "Unsupported" ) - public Response doSetContentCreator( @PathParam ( "pathId" ) String pathId, RepositoryFileDto contentCreator ) { + @Path( "{pathId : .+}/creator" ) + @Consumes( {MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved file." ), + @ResponseCode( code = 500, condition = "Failed to download file because of some other error." )} ) + @Facet( name = "Unsupported" ) + public Response doSetContentCreator( @PathParam( "pathId" ) String pathId, RepositoryFileDto contentCreator ) { try { fileService.doSetContentCreator( pathId, contentCreator ); return buildOkResponse(); @@ -1001,15 +997,14 @@ public Response doSetContentCreator( @PathParam ( "pathId" ) String pathId, Repo * Retrieves the list of locale maps for the selected repository file. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/locales + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/locales *

* * @param pathId Colon separated path for the repository file. - * * @return List the list of locales. * *

Example Response:

- *
+   * 
    *    <localePropertiesMapEntries>
    *    <localeMapDto>
    *    <locale>default</locale>
@@ -1036,13 +1031,13 @@ public Response doSetContentCreator( @PathParam ( "pathId" ) String pathId, Repo
    *  
*/ @GET - @Path ( "{pathId : .+}/locales" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved locale information." ), - @ResponseCode ( code = 404, condition = "Failed to retrieve locales because the file was not found." ), - @ResponseCode ( code = 500, condition = "Unable to retrieve locales due to some other error." ) } ) - public List doGetFileLocales( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}/locales" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved locale information." ), + @ResponseCode( code = 404, condition = "Failed to retrieve locales because the file was not found." ), + @ResponseCode( code = 500, condition = "Unable to retrieve locales due to some other error." )} ) + public List doGetFileLocales( @PathParam( "pathId" ) String pathId ) { List locales = new ArrayList(); try { locales = fileService.doGetFileLocales( pathId ); @@ -1058,16 +1053,15 @@ public List doGetFileLocales( @PathParam ( "pathId" ) String pathI * Retrieve the list of locale properties for a given locale. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/localeProperties?locale=ja + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/localeProperties?locale=ja *

* * @param pathId Colon separated path for the repository file. * @param locale The specified locale. - * * @return A list of locale properties. * *

Example Response:

- *
+   * 
    *    <stringKeyStringValueDtoes>
    *    <stringKeyStringValueDto>
    *    <key>file.title</key>
@@ -1085,13 +1079,13 @@ public List doGetFileLocales( @PathParam ( "pathId" ) String pathI
    *  
*/ @GET - @Path ( "{pathId : .+}/localeProperties" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved locale properties." ), - @ResponseCode ( code = 500, condition = "Unable to retrieve locale properties due to some other error." ) } ) - public List doGetLocaleProperties( @PathParam ( "pathId" ) String pathId, - @QueryParam ( "locale" ) String locale ) { + @Path( "{pathId : .+}/localeProperties" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved locale properties." ), + @ResponseCode( code = 500, condition = "Unable to retrieve locale properties due to some other error." )} ) + public List doGetLocaleProperties( @PathParam( "pathId" ) String pathId, + @QueryParam( "locale" ) String locale ) { return fileService.doGetLocaleProperties( pathId, locale ); } @@ -1099,9 +1093,9 @@ public List doGetLocaleProperties( @PathParam ( "pathId * Save list of locale properties for a given locale. * *

Example Request:
- * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/localeProperties?locale=ja + * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/localeProperties?locale=ja *
PUT data: - *

+   * 
    *    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><stringKeyStringValueDtoes><stringKeyStringValueDto><key>file.title</key><value>チャート選択リスト</value></stringKeyStringValueDto><stringKeyStringValueDto><key>jcr:primaryType</key><value>nt:unstructured</value></stringKeyStringValueDto><stringKeyStringValueDto><key>file.description</key><value>複数のチャートタイプを表示します</value></stringKeyStringValueDto></stringKeyStringValueDtoes>
    *  
*

@@ -1109,21 +1103,20 @@ public List doGetLocaleProperties( @PathParam ( "pathId * @param pathId Colon separated path for the repository file. * @param locale A string representation of the locale to set properties on. * @param properties The list of locale properties. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}/localeProperties" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully updated locale properties." ), - @ResponseCode ( code = 500, condition = "Unable to update locale properties due to some other error." ) } ) - public Response doSetLocaleProperties( @PathParam ( "pathId" ) String pathId, @QueryParam ( "locale" ) String locale, + @Path( "{pathId : .+}/localeProperties" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully updated locale properties." ), + @ResponseCode( code = 500, condition = "Unable to update locale properties due to some other error." )} ) + public Response doSetLocaleProperties( @PathParam( "pathId" ) String pathId, @QueryParam( "locale" ) String locale, List properties ) { try { fileService.doSetLocaleProperties( pathId, locale, properties ); @@ -1137,30 +1130,29 @@ public Response doSetLocaleProperties( @PathParam ( "pathId" ) String pathId, @Q * Delete the locale for the selected file. * *

Example Request:
- * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/deleteLocale?locale=ja + * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/deleteLocale?locale=ja *
PUT data: - *

+   * 
    *    This PUT body does not contain data.
    *  
*

* * @param pathId Colon separated path for the repository file. * @param locale A string representations of the locale to be deleted. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}/deleteLocale" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully deleted the locale." ), - @ResponseCode ( code = 500, condition = "Unable to delete the locale properties due to some other error." ) } ) - public Response doDeleteLocale( @PathParam ( "pathId" ) String pathId, @QueryParam ( "locale" ) String locale ) { + @Path( "{pathId : .+}/deleteLocale" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully deleted the locale." ), + @ResponseCode( code = 500, condition = "Unable to delete the locale properties due to some other error." )} ) + public Response doDeleteLocale( @PathParam( "pathId" ) String pathId, @QueryParam( "locale" ) String locale ) { try { fileService.doDeleteLocale( pathId, locale ); return buildOkResponse(); @@ -1173,13 +1165,13 @@ public Response doDeleteLocale( @PathParam ( "pathId" ) String pathId, @QueryPar * Retrieves the properties of the root directory. * *

Example Request:
- * GET pentaho/api/repo/files/properties + * GET pentaho/api/repo/files/properties *

* * @return file properties object RepositoryFileDto for the root directory. * *

Example Response:

- *
+   * 
    *    <repositoryFileDto>
    *    <createdDate>1406731649407</createdDate>
    *    <fileSize>-1</fileSize>
@@ -1197,12 +1189,12 @@ public Response doDeleteLocale( @PathParam ( "pathId" ) String pathId, @QueryPar
    *  
*/ @GET - @Path ( "/properties" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the properties of the root directory." ), - @ResponseCode ( code = 404, condition = "Unable to retrieve the properties of the root directory due to file not found error." ), - @ResponseCode ( code = 500, condition = "Unable to retrieve the properties of the root directory due to some other error." ) } ) + @Path( "/properties" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the properties of the root directory." ), + @ResponseCode( code = 404, condition = "Unable to retrieve the properties of the root directory due to file not found error." ), + @ResponseCode( code = 500, condition = "Unable to retrieve the properties of the root directory due to some other error." )} ) public RepositoryFileDto doGetRootProperties() { return fileService.doGetRootProperties(); } @@ -1212,27 +1204,26 @@ public RepositoryFileDto doGetRootProperties() { * but will only return true if all permissions checked are valid. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.txt/canAccessMap?permissions=1 + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.txt/canAccessMap?permissions=1 *

* * @param pathId Colon separated path for the repository file. * @param permissions Pipe separated permissions to be checked. - * * @return List of permissions for the selected files. * *

Example Response:

- *
+   * 
    *    {"setting":[{"name":"1","value":"true"}]}
    *  
*/ @GET - @Path ( "{pathId : .+}/canAccessMap" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the permissions of the file." ), - @ResponseCode ( code = 500, condition = "Unable to retrieve the permissions of the file due to some other error." ) } ) - public List doGetCanAccessList( @PathParam ( "pathId" ) String pathId, - @QueryParam ( "permissions" ) String permissions ) { + @Path( "{pathId : .+}/canAccessMap" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the permissions of the file." ), + @ResponseCode( code = 500, condition = "Unable to retrieve the permissions of the file due to some other error." )} ) + public List doGetCanAccessList( @PathParam( "pathId" ) String pathId, + @QueryParam( "permissions" ) String permissions ) { return fileService.doGetCanAccessList( pathId, permissions ); } @@ -1240,9 +1231,9 @@ public List doGetCanAccessList( @PathParam ( "pathId" ) String pathId, * Checks whether the current user has permissions to the provided list of paths. * *

Example Request:
- * POST pentaho/api/repo/files/pathsAccessList + * POST pentaho/api/repo/files/pathsAccessList *
POST data: - *

+   * 
    *    <?xml version="1.0" encoding="UTF-8"?>
    *    <stringListWrapper>
    *    <strings>/public</strings>
@@ -1251,11 +1242,10 @@ public List doGetCanAccessList( @PathParam ( "pathId" ) String pathId,
    * 

* * @param pathsWrapper Collection of Strings containing the paths to be checked. - * * @return A collection of the permission settings for the paths. * *

Example Response:

- *
+   * 
    *    <settings>
    *    <setting>
    *    <name>
@@ -1277,12 +1267,12 @@ public List doGetCanAccessList( @PathParam ( "pathId" ) String pathId,
    *  
*/ @POST - @Path ( "/pathsAccessList" ) - @Consumes ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the permissions of the given paths." ), - @ResponseCode ( code = 500, condition = "Unable to retrieve the permissions of the given paths due to some other error." ) } ) + @Path( "/pathsAccessList" ) + @Consumes( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the permissions of the given paths." ), + @ResponseCode( code = 500, condition = "Unable to retrieve the permissions of the given paths due to some other error." )} ) public List doGetPathsAccessList( StringListWrapper pathsWrapper ) { return fileService.doGetPathsAccessList( pathsWrapper ); } @@ -1291,27 +1281,26 @@ public List doGetPathsAccessList( StringListWrapper pathsWrapper ) { * Check whether the current user has specific permission on the selected repository file. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/canAccess?permissions=1 + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/canAccess?permissions=1 *

* * @param pathId Colon separated path for the repository file. * @param permissions Pipe separated list of permissions. - * * @return String "true" if the user has requested permissions on the file, or "false" otherwise. * *

Example Response:

- *
+   * 
    *      true
    *    
*/ @GET - @Path ( "{pathId : .+}/canAccess" ) - @Produces ( MediaType.TEXT_PLAIN ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the permissions of the given paths." ), - @ResponseCode ( code = 500, condition = "Unable to retrieve the permissions of the given paths due to some other error." ) } ) - public String doGetCanAccess( @PathParam ( "pathId" ) String pathId, - @QueryParam ( "permissions" ) String permissions ) { + @Path( "{pathId : .+}/canAccess" ) + @Produces( MediaType.TEXT_PLAIN ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the permissions of the given paths." ), + @ResponseCode( code = 500, condition = "Unable to retrieve the permissions of the given paths due to some other error." )} ) + public String doGetCanAccess( @PathParam( "pathId" ) String pathId, + @QueryParam( "permissions" ) String permissions ) { return fileService.doGetCanAccess( pathId, permissions ); } @@ -1319,21 +1308,21 @@ public String doGetCanAccess( @PathParam ( "pathId" ) String pathId, * Checks to see if the current user is an administer of the platform and returns a boolean response. * *

Example Request:
- * GET pentaho/api/repo/files/canAdminister + * GET pentaho/api/repo/files/canAdminister *

* * @return String "true" if the user can administer the platform, or "false" otherwise. * *

Example Response:

- *
+   * 
    *      true
    *    
*/ @GET - @Path ( "/canAdminister" ) - @Produces ( MediaType.TEXT_PLAIN ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully returns a boolean value, either true or false" ) } ) + @Path( "/canAdminister" ) + @Produces( MediaType.TEXT_PLAIN ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully returns a boolean value, either true or false" )} ) public String doGetCanAdminister() { try { return fileService.doCanAdminister() ? "true" : "false"; @@ -1346,7 +1335,7 @@ public String doGetCanAdminister() { * Returns the list of reserved characters from the repository. * *

Example Request:
- * GET pentaho/api/repo/files/reservedCharacters + * GET pentaho/api/repo/files/reservedCharacters *

* * @return List of characters that are reserved by the repository. @@ -1357,10 +1346,10 @@ public String doGetCanAdminister() { *
*/ @GET - @Path ( "/reservedCharacters" ) - @Produces ( { MediaType.TEXT_PLAIN } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully returns a list of repositroy reserved characters" ) } ) + @Path( "/reservedCharacters" ) + @Produces( {MediaType.TEXT_PLAIN} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully returns a list of repositroy reserved characters" )} ) public Response doGetReservedChars() { StringBuffer buffer = fileService.doGetReservedChars(); return buildPlainTextOkResponse( buffer.toString() ); @@ -1370,7 +1359,7 @@ public Response doGetReservedChars() { * Returns the list of reserved characters from the repository. * *

Example Request:
- * GET pentaho/api/repo/files/reservedCharactersDisplay + * GET pentaho/api/repo/files/reservedCharactersDisplay *

* * @return List of characters that are reserved by the repository. @@ -1381,10 +1370,10 @@ public Response doGetReservedChars() { *
*/ @GET - @Path ( "/reservedCharactersDisplay" ) - @Produces ( { MediaType.TEXT_PLAIN } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully returns a list of repositroy reserved characters" ) } ) + @Path( "/reservedCharactersDisplay" ) + @Produces( {MediaType.TEXT_PLAIN} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully returns a list of repositroy reserved characters" )} ) public Response doGetReservedCharactersDisplay() { StringBuffer buffer = fileService.doGetReservedCharactersDisplay(); return buildPlainTextOkResponse( buffer.toString() ); @@ -1394,21 +1383,21 @@ public Response doGetReservedCharactersDisplay() { * Checks the users permission to determine if that user can create new content in the repository. * *

Example Request:
- * GET pentaho/api/repo/files/canCreate + * GET pentaho/api/repo/files/canCreate *

* * @return String "true" if the user can create new content, or "false" otherwise. * *

Example Response:

- *
+   * 
    *      true
    *    
*/ @GET - @Path ( "/canCreate" ) - @Produces ( MediaType.TEXT_PLAIN ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully returns true or false depending on the users permissions" ) } ) + @Path( "/canCreate" ) + @Produces( MediaType.TEXT_PLAIN ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully returns true or false depending on the users permissions" )} ) public String doGetCanCreate() { return fileService.doGetCanCreate(); } @@ -1417,21 +1406,21 @@ public String doGetCanCreate() { * Checks the users permission to determine if that user can edit an existing content in the repository. * *

Example Request:
- * GET pentaho/api/repo/files/canEdit + * GET pentaho/api/repo/files/canEdit *

* * @return String "true" if the user can edit existing content, or "false" otherwise. * *

Example Response:

- *
+   * 
    *      true
    *    
*/ @GET - @Path ( "/canEdit" ) - @Produces ( MediaType.TEXT_PLAIN ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully returns true or false depending on the users permissions" ) } ) + @Path( "/canEdit" ) + @Produces( MediaType.TEXT_PLAIN ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully returns true or false depending on the users permissions" )} ) public String doGetCanEdit() { return fileService.doGetCanEdit(); } @@ -1441,15 +1430,14 @@ public String doGetCanEdit() { * Retrieves the ACL settings of the requested repository file in either xml or json format. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/acl *

* * @param pathId colon separated path for the repository file. - * * @return RepositoryFileAclDto object containing the ACL settings of the requested file. * *

Example Response:

- *
+   * 
    *    <repositoryFileAclDto>
    *    <aces>
    *    <modifiable>true</modifiable>
@@ -1471,12 +1459,12 @@ public String doGetCanEdit() {
    *  
*/ @GET - @Path ( "{pathId : .+}/acl" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Returns the requested file permissions in xml or json format" ), - @ResponseCode ( code = 500, condition = "File failed to be retrieved. This could be caused by an invalid path, or the file does not exist." ) } ) - public RepositoryFileAclDto doGetFileAcl( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}/acl" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Returns the requested file permissions in xml or json format" ), + @ResponseCode( code = 500, condition = "File failed to be retrieved. This could be caused by an invalid path, or the file does not exist." )} ) + public RepositoryFileAclDto doGetFileAcl( @PathParam( "pathId" ) String pathId ) { return fileService.doGetFileAcl( pathId ); } @@ -1484,11 +1472,10 @@ public RepositoryFileAclDto doGetFileAcl( @PathParam ( "pathId" ) String pathId * Retrieves the properties of a selected repository file. * *

Example Request:
- * GET pentaho/api/repo/files/:/properties + * GET pentaho/api/repo/files/:/properties *

* * @param pathId Colon separated path for the repository file. - * * @return A RepositoryDto object containing the properties for the given file. * *

Example Response:

@@ -1522,12 +1509,12 @@ public RepositoryFileAclDto doGetFileAcl( @PathParam ( "pathId" ) String pathId *
*/ @GET - @Path ( "{pathId : .+}/properties" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the properties for a file." ), - @ResponseCode ( code = 204, condition = "Invalid file path." ) } ) - public RepositoryFileDto doGetProperties( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}/properties" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the properties for a file." ), + @ResponseCode( code = 204, condition = "Invalid file path." )} ) + public RepositoryFileDto doGetProperties( @PathParam( "pathId" ) String pathId ) { try { return fileService.doGetProperties( pathId ); } catch ( FileNotFoundException fileNotFound ) { @@ -1541,17 +1528,16 @@ public RepositoryFileDto doGetProperties( @PathParam ( "pathId" ) String pathId * Retrieves the file by creator id * * @param pathId Colon separated path for the destination for files to be copied. - * * @return file properties object RepositoryFileDto */ @GET - @Path ( "{pathId : .+}/creator" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @Facet ( name = "Unsupported" ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the content creator for a file." ), - @ResponseCode ( code = 403, condition = "Failure to move the file due to path not found." ) } ) - public RepositoryFileDto doGetContentCreator( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}/creator" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @Facet( name = "Unsupported" ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the content creator for a file." ), + @ResponseCode( code = 403, condition = "Failure to move the file due to path not found." )} ) + public RepositoryFileDto doGetContentCreator( @PathParam( "pathId" ) String pathId ) { try { return fileService.doGetContentCreator( pathId ); } catch ( Throwable t ) { @@ -1563,11 +1549,10 @@ public RepositoryFileDto doGetContentCreator( @PathParam ( "pathId" ) String pat * Retrieve the list of executed contents for a selected content from the repository. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/generatedContent?locale=de + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/generatedContent?locale=de *

* * @param pathId Colon separated path for the destination for files to be copied. - * * @return A list of RepositoryDto objects containing the executed contents for a selected content from the repository. * *

Example Response:

@@ -1617,12 +1602,12 @@ public RepositoryFileDto doGetContentCreator( @PathParam ( "pathId" ) String pat *
*/ @GET - @Path ( "{pathId : .+}/generatedContent" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the list of RepositoryFileDto objects." ), - @ResponseCode ( code = 200, condition = "Empty list of RepositoryFileDto objects." ) } ) - public List doGetGeneratedContent( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}/generatedContent" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the list of RepositoryFileDto objects." ), + @ResponseCode( code = 200, condition = "Empty list of RepositoryFileDto objects." )} ) + public List doGetGeneratedContent( @PathParam( "pathId" ) String pathId ) { List repositoryFileDtoList = new ArrayList(); try { repositoryFileDtoList = fileService.doGetGeneratedContent( pathId ); @@ -1638,12 +1623,11 @@ public List doGetGeneratedContent( @PathParam ( "pathId" ) St * Retrieve the executed contents for a selected repository file and a given user. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/generatedContentForUser?user=admin + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/generatedContentForUser?user=admin *

* * @param pathId Colon separated path for the destination for files to be copied. * @param user The username for the generated content folder. - * * @return A list of RepositoryDto objects containing the executed contents for a selected file from the repository. * *

Example Response:

@@ -1693,14 +1677,14 @@ public List doGetGeneratedContent( @PathParam ( "pathId" ) St *
*/ @GET - @Path ( "{pathId : .+}/generatedContentForUser" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the list of RepositoryFileDto objects." ), - @ResponseCode ( code = 200, condition = "Empty list of RepositoryFileDto objects." ), - @ResponseCode ( code = 500, condition = "Server Error." ) } ) - public List doGetGeneratedContentForUser( @PathParam ( "pathId" ) String pathId, - @QueryParam ( "user" ) String user ) { + @Path( "{pathId : .+}/generatedContentForUser" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the list of RepositoryFileDto objects." ), + @ResponseCode( code = 200, condition = "Empty list of RepositoryFileDto objects." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) + public List doGetGeneratedContentForUser( @PathParam( "pathId" ) String pathId, + @QueryParam( "user" ) String user ) { List repositoryFileDtoList = new ArrayList(); try { repositoryFileDtoList = fileService.doGetGeneratedContent( pathId, user ); @@ -1717,7 +1701,7 @@ public List doGetGeneratedContentForUser( @PathParam ( "pathI * Retrieve the recursive list of files from root of the repository based on the filters provided. * *

Example Request:
- * GET pentaho/api/repo/files/tree?showHidden=false&filter=*|FILES&_=1389042244670 + * GET pentaho/api/repo/files/tree?showHidden=false&filter=*|FILES&_=1389042244670 *

* * @param depth How many level should the search go. @@ -1739,7 +1723,6 @@ public List doGetGeneratedContentForUser( @PathParam ( "pathI * Omission of a member filter will return all members. It is invalid to both and includeMembers= and an * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. - * * @return A RepositoryFileTreeDto object containing the files at the root of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * *

Example Response:

@@ -1765,16 +1748,16 @@ public List doGetGeneratedContentForUser( @PathParam ( "pathI *
*/ @GET - @Path ( "/tree" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the list of files from root of the repository." ), - @ResponseCode ( code = 404, condition = "Invalid parameters." ), - @ResponseCode ( code = 500, condition = "Server Error." ) - } ) - public RepositoryFileTreeDto doGetRootTree( @QueryParam ( "depth" ) Integer depth, - @QueryParam ( "filter" ) String filter, @QueryParam ( "showHidden" ) Boolean showHidden, - @DefaultValue ( "false" ) @QueryParam ( "includeAcls" ) Boolean includeAcls ) { + @Path( "/tree" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the list of files from root of the repository." ), + @ResponseCode( code = 404, condition = "Invalid parameters." ), + @ResponseCode( code = 500, condition = "Server Error." ) + } ) + public RepositoryFileTreeDto doGetRootTree( @QueryParam( "depth" ) Integer depth, + @QueryParam( "filter" ) String filter, @QueryParam( "showHidden" ) Boolean showHidden, + @DefaultValue( "false" ) @QueryParam( "includeAcls" ) Boolean includeAcls ) { return fileService.doGetTree( FileUtils.PATH_SEPARATOR, depth, filter, showHidden, includeAcls ); } @@ -1782,7 +1765,7 @@ public RepositoryFileTreeDto doGetRootTree( @QueryParam ( "depth" ) Integer dept * Retrieve a list of child files from the root of the repository. * *

Example Request:
- * GET pentaho/api/repo/files/children?showHidden=false&filter=*|FILES&_=1389042244670 + * GET pentaho/api/repo/files/children?showHidden=false&filter=*|FILES&_=1389042244670 *

* * @param filter Filter to be applied for search. The filter can be broken down into 3 parts; File types, Child Node @@ -1804,7 +1787,6 @@ public RepositoryFileTreeDto doGetRootTree( @QueryParam ( "depth" ) Integer dept * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. * @param includeAcls Include permission information about the file in the output. - * * @return A RepositoryFileTreeDto object containing the files at the root of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * *

Example Response:

@@ -1830,14 +1812,14 @@ public RepositoryFileTreeDto doGetRootTree( @QueryParam ( "depth" ) Integer dept *
*/ @GET - @Path ( "/children" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the list of child files from root of the repository." ), - @ResponseCode ( code = 500, condition = "Server Error." ) } ) - public List doGetRootChildren( @QueryParam ( "filter" ) String filter, - @QueryParam ( "showHidden" ) Boolean showHidden, - @DefaultValue ( "false" ) @QueryParam ( "includeAcls" ) Boolean includeAcls ) { + @Path( "/children" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the list of child files from root of the repository." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) + public List doGetRootChildren( @QueryParam( "filter" ) String filter, + @QueryParam( "showHidden" ) Boolean showHidden, + @DefaultValue( "false" ) @QueryParam( "includeAcls" ) Boolean includeAcls ) { return fileService.doGetChildren( FileUtils.PATH_SEPARATOR, filter, showHidden, includeAcls ); } @@ -1845,7 +1827,7 @@ public List doGetRootChildren( @QueryParam ( "filter" ) Strin * Retrieve the recursive list of children of the selected repository file. * *

Example Request:
- * GET pentaho/api/repo/files/:public/tree?showHidden=false&filter=*|FILES&_=1389042244670 + * GET pentaho/api/repo/files/:public/tree?showHidden=false&filter=*|FILES&_=1389042244670 *

* * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / @@ -1870,7 +1852,6 @@ public List doGetRootChildren( @QueryParam ( "filter" ) Strin * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. * @param includeAcls Include permission information about the file in the output. - * * @return A RepositoryFileTreeDto object containing the files at the root of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * *

Example Response:

@@ -1896,16 +1877,16 @@ public List doGetRootChildren( @QueryParam ( "filter" ) Strin *
*/ @GET - @Path ( "{pathId : .+}/tree" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the list of files from root of the repository." ), - @ResponseCode ( code = 404, condition = "Invalid parameters." ), - @ResponseCode ( code = 500, condition = "Server Error." ) } ) - public RepositoryFileTreeDto doGetTree( @PathParam ( "pathId" ) String pathId, @QueryParam ( "depth" ) Integer depth, - @QueryParam ( "filter" ) String filter, @QueryParam ( "showHidden" ) Boolean showHidden, - @DefaultValue ( "false" ) @QueryParam ( "includeAcls" ) Boolean includeAcls, - @DefaultValue ( "false" ) @QueryParam ( "includeSysDirs" ) Boolean includeSystemFolders ) { + @Path( "{pathId : .+}/tree" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the list of files from root of the repository." ), + @ResponseCode( code = 404, condition = "Invalid parameters." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) + public RepositoryFileTreeDto doGetTree( @PathParam( "pathId" ) String pathId, @QueryParam( "depth" ) Integer depth, + @QueryParam( "filter" ) String filter, @QueryParam( "showHidden" ) Boolean showHidden, + @DefaultValue( "false" ) @QueryParam( "includeAcls" ) Boolean includeAcls, + @DefaultValue( "false" ) @QueryParam( "includeSysDirs" ) Boolean includeSystemFolders ) { return fileService.doGetTree( pathId, depth, filter, showHidden, includeAcls, includeSystemFolders ); } @@ -1913,7 +1894,7 @@ public RepositoryFileTreeDto doGetTree( @PathParam ( "pathId" ) String pathId, @ * Retrieve a list of child files from the selected repository path of the repository. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test/children + * GET pentaho/api/repo/files/:jmeter-test/children *

* * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / @@ -1937,7 +1918,6 @@ public RepositoryFileTreeDto doGetTree( @PathParam ( "pathId" ) String pathId, @ * excludeMembers= clause in the same service call. * @param showHidden Include or exclude hidden files from the file list. * @param includeAcls Include permission information about the file in the output. - * * @return A RepositoryFileTreeDto object containing the files at the selected repository path of the repository. Will return files but not folders under the "/" folder. The fields returned will include the name, filesize, description, id and title. * *

Example Response:

@@ -1963,15 +1943,15 @@ public RepositoryFileTreeDto doGetTree( @PathParam ( "pathId" ) String pathId, @ *
*/ @GET - @Path ( "{pathId : .+}/children" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode( code = 200, - condition = "Successfully retrieved the list of child files from selected repository path of the repository." ), - @ResponseCode( code = 500, condition = "Server Error." ) } ) - public List doGetChildren( @PathParam ( "pathId" ) String pathId, - @QueryParam ( "filter" ) String filter, @QueryParam ( "showHidden" ) Boolean showHidden, - @DefaultValue ( "false" ) @QueryParam ( "includeAcls" ) Boolean includeAcls ) { + @Path( "{pathId : .+}/children" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, + condition = "Successfully retrieved the list of child files from selected repository path of the repository." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) + public List doGetChildren( @PathParam( "pathId" ) String pathId, + @QueryParam( "filter" ) String filter, @QueryParam( "showHidden" ) Boolean showHidden, + @DefaultValue( "false" ) @QueryParam( "includeAcls" ) Boolean includeAcls ) { return fileService.doGetChildren( pathId, filter, showHidden, includeAcls ); } @@ -1980,7 +1960,7 @@ public List doGetChildren( @PathParam ( "pathId" ) String pat * Retrieve the list of files in the user's trash folder. * *

Example Request:
- * GET pentaho/api/repo/files/deleted + * GET pentaho/api/repo/files/deleted *

* * @return A list of RepositoryDto objects containing the files in the trash folder of the repository. @@ -2029,11 +2009,11 @@ public List doGetChildren( @PathParam ( "pathId" ) String pat *
*/ @GET - @Path ( "/deleted" ) - @Produces ( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved the list of files from trash folder of the repository." ), - @ResponseCode ( code = 500, condition = "Server Error." ) } ) + @Path( "/deleted" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved the list of files from trash folder of the repository." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) public List doGetDeletedFiles() { return fileService.doGetDeletedFiles(); } @@ -2043,12 +2023,11 @@ public List doGetDeletedFiles() { * the metadata child, it is considered metadata from PUC and is included in the setMetadata call. * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/metadata + * GET pentaho/api/repo/files/:jmeter-test:test_file_1.xml/metadata *

* * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

@@ -2062,13 +2041,13 @@ public List doGetDeletedFiles() { *
*/ @GET - @Path ( "{pathId : .+}/metadata" ) - @Produces ( { MediaType.APPLICATION_JSON } ) + @Path( "{pathId : .+}/metadata" ) + @Produces( {MediaType.APPLICATION_JSON} ) @StatusCodes( { - @ResponseCode( code = 200, condition = "Successfully retrieved metadata." ), - @ResponseCode( code = 403, condition = "Invalid path." ), - @ResponseCode( code = 500, condition = "Server Error." ) } ) - public List doGetMetadata( @PathParam ( "pathId" ) String pathId ) { + @ResponseCode( code = 200, condition = "Successfully retrieved metadata." ), + @ResponseCode( code = 403, condition = "Invalid path." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) + public List doGetMetadata( @PathParam( "pathId" ) String pathId ) { try { return fileService.doGetMetadata( pathId ); } catch ( FileNotFoundException e ) { @@ -2081,9 +2060,9 @@ public List doGetMetadata( @PathParam ( "pathId" ) Stri * Rename the selected file. * *

Example Request:
- * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/rename?newName=test_file_8 + * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/rename?newName=test_file_8 *
PUT data: - *

+   * 
    *    This PUT body does not contain data.
    *  
*

@@ -2091,22 +2070,21 @@ public List doGetMetadata( @PathParam ( "pathId" ) Stri * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param newName String indicating the new name of the file. - * * @return Response with 200 OK, if the file does not exist to be renamed the response will return 200 OK with the string "File to be renamed does not exist". * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}/rename" ) - @Consumes ( { MediaType.WILDCARD } ) - @Produces ( { MediaType.WILDCARD } ) + @Path( "{pathId : .+}/rename" ) + @Consumes( {MediaType.WILDCARD} ) + @Produces( {MediaType.WILDCARD} ) @StatusCodes( { - @ResponseCode( code = 200, condition = "Successfully renamed file." ), - @ResponseCode( code = 403, condition = "Forbidden." ), - @ResponseCode( code = 404, condition = "File not found." ) } ) + @ResponseCode( code = 200, condition = "Successfully renamed file." ), + @ResponseCode( code = 403, condition = "Forbidden." ), + @ResponseCode( code = 404, condition = "File not found." )} ) public Response doRename( @PathParam( "pathId" ) String pathId, @QueryParam( "newName" ) String newName ) { try { if ( FileUtils.containsControlCharacters( newName ) ) { @@ -2132,9 +2110,9 @@ public Response doRename( @PathParam( "pathId" ) String pathId, @QueryParam( "ne * the metadata child, it is considered metadata from PUC and is included in the setMetadata call. * *

Example Request:
- * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/metadata + * PUT pentaho/api/repo/files/:jmeter-test:test_file_1.xml/metadata *
PUT data: - *

+   * 
    *    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><stringKeyStringValueDtoes><stringKeyStringValueDto><key>metadata.key.1</key><value>metadata.value.1</value></stringKeyStringValueDto></stringKeyStringValueDtoes>
    *  
*

@@ -2142,24 +2120,23 @@ public Response doRename( @PathParam( "pathId" ) String pathId, @QueryParam( "ne * @param pathId The path from the root folder to the root node of the tree to return using colon characters in place of / * or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. * @param metadata A list of StringKeyStringValueDto objects. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}/metadata" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @Consumes ( { MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully retrieved metadata." ), - @ResponseCode ( code = 403, condition = "Invalid path." ), - @ResponseCode ( code = 400, condition = "Invalid payload." ), - @ResponseCode ( code = 500, condition = "Server Error." ) } ) - public Response doSetMetadata( @PathParam ( "pathId" ) String pathId, List metadata ) { + @Path( "{pathId : .+}/metadata" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @Consumes( {MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully retrieved metadata." ), + @ResponseCode( code = 403, condition = "Invalid path." ), + @ResponseCode( code = 400, condition = "Invalid payload." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) + public Response doSetMetadata( @PathParam( "pathId" ) String pathId, List metadata ) { try { fileService.doSetMetadata( pathId, metadata ); return buildOkResponse(); @@ -2174,32 +2151,31 @@ public Response doSetMetadata( @PathParam ( "pathId" ) String pathId, ListExample Request:
- * PUT pentaho/api/repo/files/:public:jmeter-test-dir/createDir + * PUT pentaho/api/repo/files/:public:jmeter-test-dir/createDir *
PUT data: - *
+   * 
    *    This PUT body does not contain data.
    *  
*

* * @param pathId The path from the root folder to the root node of the tree to return using colon characters in * place of / or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file. - * * @return A jax-rs Response object with the appropriate status code, header, and body. * *

Example Response:

- *
+   * 
    *        This response does not contain data.
    *    
*/ @PUT - @Path ( "{pathId : .+}/createDir" ) - @Consumes ( { MediaType.WILDCARD } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Successfully created folder." ), - @ResponseCode ( code = 403, condition = "Forbidden." ), - @ResponseCode ( code = 409, condition = "Path already exists." ), - @ResponseCode ( code = 500, condition = "Server Error." ) } ) - public Response doCreateDirs( @PathParam ( "pathId" ) String pathId ) { + @Path( "{pathId : .+}/createDir" ) + @Consumes( {MediaType.WILDCARD} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully created folder." ), + @ResponseCode( code = 403, condition = "Forbidden." ), + @ResponseCode( code = 409, condition = "Path already exists." ), + @ResponseCode( code = 500, condition = "Server Error." )} ) + public Response doCreateDirs( @PathParam( "pathId" ) String pathId ) { try { if ( fileService.doCreateDirSafe( pathId ) ) { return buildOkResponse(); @@ -2217,44 +2193,42 @@ public Response doCreateDirs( @PathParam ( "pathId" ) String pathId ) { * This method is used to determine whether versioning should be active for the given path * *

Example Request:
- * GET pentaho/api/repo/files/:jmeter-test:test_file_1.ktr/versioningConfiguration - *

+ * GET pentaho/api/repo/files/:jmeter-test:test_file_1.ktr/versioningConfiguration + *
*

* * @param pathId Colon separated path for the repository file. - * * @return The Versioning Configuration applicable to the path submitted * *

Example Response:

- *
+   * 
    * <fileVersioningConfiguration>
-   *   <versionCommentEnabled>true</versionCommentEnabled>
-   *   <versioningEnabled>true</versioningEnabled>
+   * <versionCommentEnabled>true</versionCommentEnabled>
+   * <versioningEnabled>true</versioningEnabled>
    * </fileVersioningConfiguration>
-   *  
+ *
*/ @GET - @Path ( "{pathId : .+}/versioningConfiguration" ) - @Produces ( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } ) - @StatusCodes ( { - @ResponseCode( code = 200, condition = "Successfully returns the versioning configuration" ) } ) + @Path( "{pathId : .+}/versioningConfiguration" ) + @Produces( {MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Successfully returns the versioning configuration" )} ) public FileVersioningConfiguration doVersioningConfiguration( @PathParam( "pathId" ) String pathId ) { IRepositoryVersionManager repositoryVersionManager = PentahoSystem.get( IRepositoryVersionManager.class ); String path = FileUtils.idToPath( pathId ); return new FileVersioningConfiguration( - repositoryVersionManager.isVersioningEnabled( path ), - repositoryVersionManager.isVersionCommentEnabled( path ) ); + repositoryVersionManager.isVersioningEnabled( path ), + repositoryVersionManager.isVersionCommentEnabled( path ) ); } /** * Validates if a current user is authorized to download content from the given dir. * *

Example Request:
- * GET pentaho/api/repo/files/canDownload + * GET pentaho/api/repo/files/canDownload *

* - * @param dirPath to be validated for download action for the current user. - * + * @param dirPath to be validated for download action for the current user. * @return A boolean response based on the current user being authorized to download within the system. * *

Example Response:

@@ -2263,12 +2237,12 @@ public FileVersioningConfiguration doVersioningConfiguration( @PathParam( "pathI *
*/ @GET - @Path ( "/canDownload" ) - @Produces ( { MediaType.TEXT_PLAIN } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Returns a boolean response." ) + @Path( "/canDownload" ) + @Produces( {MediaType.TEXT_PLAIN} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Returns a boolean response." ) } ) - public Response canDownload( @QueryParam ( "dirPath" ) @DefaultValue( "" ) String dirPath ) { + public Response canDownload( @QueryParam( "dirPath" ) @DefaultValue( "" ) String dirPath ) { return Response.ok( ( String.valueOf( SystemUtils.canDownload( dirPath ) ) ) ).build(); } @@ -2276,11 +2250,10 @@ public Response canDownload( @QueryParam ( "dirPath" ) @DefaultValue( "" ) Strin * Validates if a current user is authorized to upload content to the given dir * *

Example Request:
- * GET pentaho/api/repo/files/canUpload + * GET pentaho/api/repo/files/canUpload *

* - * @param dirPath to be validated for upload action for the current user. - * + * @param dirPath to be validated for upload action for the current user. * @return A boolean response based on the current user being authorized to upload to given dir * *

Example Response:

@@ -2289,12 +2262,12 @@ public Response canDownload( @QueryParam ( "dirPath" ) @DefaultValue( "" ) Strin *
*/ @GET - @Path ( "/canUpload" ) - @Produces ( { MediaType.TEXT_PLAIN } ) - @StatusCodes ( { - @ResponseCode ( code = 200, condition = "Returns a boolean response." ) + @Path( "/canUpload" ) + @Produces( {MediaType.TEXT_PLAIN} ) + @StatusCodes( { + @ResponseCode( code = 200, condition = "Returns a boolean response." ) } ) - public Response canUpload( @QueryParam ( "dirPath" ) @DefaultValue( "" ) String dirPath ) { + public Response canUpload( @QueryParam( "dirPath" ) @DefaultValue( "" ) String dirPath ) { return Response.ok( ( String.valueOf( SystemUtils.canUpload( dirPath ) ) ) ).build(); } @@ -2470,7 +2443,7 @@ protected String getUserHomeFolder() { /** * Checks if the given users and roles are valid, i.e. don't contain illegal characters. * Illegal characters may lead to repository corruption. - * + *

* RFC 2253 - The names of security principal objects can contain all Unicode characters except the special LDAP * characters defined in RFC 2253. This list of special characters includes: a leading space; a trailing space; * and any of the following characters: # , + " \ < > ; diff --git a/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/RepositoryImportResource.java b/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/RepositoryImportResource.java index bd25336bcc3..a583160e0ff 100644 --- a/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/RepositoryImportResource.java +++ b/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/RepositoryImportResource.java @@ -50,7 +50,7 @@ import java.util.List; import java.util.stream.Collectors; -@Path ( "/repo/files/import" ) +@Path( "/repo/files/import" ) public class RepositoryImportResource { private static final Logger LOGGER = LogManager.getLogger( RepositoryImportResource.class ); @@ -61,9 +61,9 @@ public class RepositoryImportResource { * Attempts to import all files from the zip archive or single file. A log file is produced at the end of import. * *

Example Request:
- * POST pentaho/api/repo/files/import - *
POST data: - *

+   * POST pentaho/api/repo/files/import
+   * 
POST data: + *
    *      ------WebKitFormBoundaryB9hzsGp4wR5SGAZD
    *      Content-Disposition: form-data; name="importDir"
    *
@@ -115,7 +115,6 @@ public class RepositoryImportResource {
    * @param fileNameOverride        If present and the content represents a single file, this parameter contains the filename to use
    *                                when storing the file in the repository. If not present, the fileInfo.getFileName will be used.
    *                                Note that the later cannot reliably handle foreign character sets.
-   *
    * @return A jax-rs Response object with the appropriate header and body.
    *
    * 

Example Response:

@@ -156,21 +155,21 @@ public class RepositoryImportResource { *
*/ @POST - @Consumes ( MediaType.MULTIPART_FORM_DATA ) - @Produces ( MediaType.TEXT_HTML ) + @Consumes( MediaType.MULTIPART_FORM_DATA ) + @Produces( MediaType.TEXT_HTML ) @Facet( name = "Unsupported" ) - public Response doPostImport( @FormDataParam ( "importDir" ) String importDir, - @FormDataParam ( "fileUpload" ) InputStream fileUpload, - @FormDataParam ( "overwriteFile" ) String overwriteFile, - @FormDataParam ( "overwriteAclPermissions" ) String overwriteAclPermissions, - @FormDataParam ( "applyAclPermissions" ) String applyAclPermission, - @FormDataParam ( "retainOwnership" ) String retainOwnership, - @FormDataParam ( "charSet" ) String charSet, - @FormDataParam ( "logLevel" ) String logLevel, - @FormDataParam ( "fileUpload" ) FormDataContentDisposition fileInfo, - @FormDataParam ( "fileNameOverride" ) String fileNameOverride ) { - return doPostImportCommon( importDir, Arrays.asList( fileUpload ), overwriteFile, overwriteAclPermissions, applyAclPermission, - retainOwnership, charSet, logLevel, fileInfo, fileNameOverride ); + public Response doPostImport( @FormDataParam( "importDir" ) String importDir, + @FormDataParam( "fileUpload" ) InputStream fileUpload, + @FormDataParam( "overwriteFile" ) String overwriteFile, + @FormDataParam( "overwriteAclPermissions" ) String overwriteAclPermissions, + @FormDataParam( "applyAclPermissions" ) String applyAclPermission, + @FormDataParam( "retainOwnership" ) String retainOwnership, + @FormDataParam( "charSet" ) String charSet, + @FormDataParam( "logLevel" ) String logLevel, + @FormDataParam( "fileUpload" ) FormDataContentDisposition fileInfo, + @FormDataParam( "fileNameOverride" ) String fileNameOverride ) { + return doPostImportCommon( importDir, Arrays.asList( fileUpload ), overwriteFile, overwriteAclPermissions, applyAclPermission, + retainOwnership, charSet, logLevel, fileInfo, fileNameOverride ); } protected void validateImportAccess( String importDir ) throws PentahoAccessControlException { @@ -197,25 +196,25 @@ protected void validateImportAccess( String importDir ) throws PentahoAccessCont * @return */ @POST() - @Path ( "/multiple" ) - @Consumes ( MediaType.MULTIPART_FORM_DATA ) - @Produces ( MediaType.TEXT_HTML ) + @Path( "/multiple" ) + @Consumes( MediaType.MULTIPART_FORM_DATA ) + @Produces( MediaType.TEXT_HTML ) @Facet( name = "Unsupported" ) - public Response doPostImport( @FormDataParam ( "importDir" ) String importDir, - @FormDataParam ( "fileUpload" ) List fileParts, - @FormDataParam ( "overwriteFile" ) String overwriteFile, - @FormDataParam ( "overwriteAclPermissions" ) String overwriteAclPermissions, - @FormDataParam ( "applyAclPermissions" ) String applyAclPermission, - @FormDataParam ( "retainOwnership" ) String retainOwnership, - @FormDataParam ( "charSet" ) String charSet, - @FormDataParam ( "logLevel" ) String logLevel, - @FormDataParam ( "fileUpload" ) FormDataContentDisposition fileInfo, - @FormDataParam ( "fileNameOverride" ) String fileNameOverride ) { + public Response doPostImport( @FormDataParam( "importDir" ) String importDir, + @FormDataParam( "fileUpload" ) List fileParts, + @FormDataParam( "overwriteFile" ) String overwriteFile, + @FormDataParam( "overwriteAclPermissions" ) String overwriteAclPermissions, + @FormDataParam( "applyAclPermissions" ) String applyAclPermission, + @FormDataParam( "retainOwnership" ) String retainOwnership, + @FormDataParam( "charSet" ) String charSet, + @FormDataParam( "logLevel" ) String logLevel, + @FormDataParam( "fileUpload" ) FormDataContentDisposition fileInfo, + @FormDataParam( "fileNameOverride" ) String fileNameOverride ) { List fileUploads = fileParts.stream() - .map(part -> part.getValueAs( InputStream.class )) - .collect( Collectors.toList() ); + .map( part -> part.getValueAs( InputStream.class ) ) + .collect( Collectors.toList() ); return doPostImportCommon( importDir, fileUploads, overwriteFile, overwriteAclPermissions, applyAclPermission, - retainOwnership, charSet, logLevel, fileInfo, fileNameOverride ); + retainOwnership, charSet, logLevel, fileInfo, fileNameOverride ); } /** @@ -234,14 +233,14 @@ public Response doPostImport( @FormDataParam ( "importDir" ) String importDir, * @return */ private Response doPostImportCommon( String importDir, List fileUploads, String overwriteFile, - String overwriteAclPermissions, String applyAclPermission, String retainOwnership, - String charSet, String logLevel, FormDataContentDisposition fileInfo, - String fileNameOverride ) { + String overwriteAclPermissions, String applyAclPermission, String retainOwnership, + String charSet, String logLevel, FormDataContentDisposition fileInfo, + String fileNameOverride ) { IRepositoryImportLogger importLogger = null; ByteArrayOutputStream importLoggerStream = new ByteArrayOutputStream(); boolean logJobStarted = false; - if (StringUtils.isBlank( charSet )) { + if ( StringUtils.isBlank( charSet ) ) { charSet = DEFAULT_CHAR_SET; } @@ -272,12 +271,12 @@ private Response doPostImportCommon( String importDir, List fileUpl importLogger = importer.getRepositoryImportLogger(); importLogger.startJob( importLoggerStream, importDir, level ); - List fileNameOverrides = Arrays.asList( fileNameOverride.split(",") ); + List fileNameOverrides = Arrays.asList( fileNameOverride.split( "," ) ); for ( int i = 0; i < fileNameOverrides.size(); i++ ) { - InputStream fileUpload = fileUploads.get(i); + InputStream fileUpload = fileUploads.get( i ); - String fileName = fileNameOverrides.get(i); + String fileName = fileNameOverrides.get( i ); RepositoryFileImportBundle.Builder bundleBuilder = new RepositoryFileImportBundle.Builder(); bundleBuilder.input( fileUpload ); @@ -297,12 +296,13 @@ private Response doPostImportCommon( String importDir, List fileUpl } bundleBuilder.mime( mimeTypeFromFile ); + importer.getRepositoryImportLogger().setPerformingRestore( false ); importer.importFile( bundle ); } // Flush the Mondrian cache to show imported data-sources. IMondrianCatalogService mondrianCatalogService = PentahoSystem.get( IMondrianCatalogService.class, "IMondrianCatalogService", - PentahoSessionHolder.getSession() ); + PentahoSessionHolder.getSession() ); mondrianCatalogService.reInit( PentahoSessionHolder.getSession() ); logJobStarted = true; } catch ( Exception e ) { diff --git a/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/services/FileService.java b/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/services/FileService.java index 9860af02bfc..e2903f583b1 100644 --- a/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/services/FileService.java +++ b/extensions/src/main/java/org/pentaho/platform/web/http/api/resources/services/FileService.java @@ -40,7 +40,9 @@ import org.pentaho.platform.api.repository2.unified.webservices.RepositoryFileDto; import org.pentaho.platform.api.repository2.unified.webservices.RepositoryFileTreeDto; import org.pentaho.platform.api.repository2.unified.webservices.StringKeyStringValueDto; +import org.pentaho.platform.api.importexport.ExportException; import org.pentaho.platform.api.util.IPentahoPlatformExporter; +import org.pentaho.platform.api.util.IRepositoryExportLogger; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.plugin.services.exporter.PentahoPlatformExporter; @@ -49,7 +51,7 @@ import org.pentaho.platform.plugin.services.importer.RepositoryFileImportBundle; import org.pentaho.platform.plugin.services.importexport.BaseExportProcessor; import org.pentaho.platform.plugin.services.importexport.DefaultExportHandler; -import org.pentaho.platform.plugin.services.importexport.ExportException; +import org.pentaho.platform.plugin.services.importexport.RepositoryTextLayout; import org.pentaho.platform.plugin.services.importexport.ExportHandler; import org.pentaho.platform.plugin.services.importexport.IRepositoryImportLogger; import org.pentaho.platform.plugin.services.importexport.ImportSession; @@ -82,6 +84,7 @@ import javax.ws.rs.core.StreamingOutput; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -95,6 +98,8 @@ import java.security.GeneralSecurityException; import java.security.InvalidParameterException; import java.text.Collator; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -131,29 +136,86 @@ public class FileService { private PentahoPlatformExporter backupExporter; - public DownloadFileWrapper systemBackup( String userAgent ) throws IOException, ExportException { + private void validateFilePath( String logFile ) throws IllegalArgumentException { + if ( logFile.contains( ".." ) || logFile.contains( "//" ) || logFile.contains( "\\\\" ) || ( !logFile.endsWith( ".txt" ) && !logFile.endsWith( ".log" ) ) ) { + throw new IllegalArgumentException( Messages.getInstance().getString( "FileService.ERROR_INVALID_LOG_FILENAME", logFile ) ); + } + } + + public DownloadFileWrapper systemBackup( String logFile, String logLevel, String outputFile ) throws IllegalArgumentException, IOException, ExportException { if ( doCanAdminister() ) { - String originalFileName; String encodedFileName; - originalFileName = "SystemBackup.zip"; - encodedFileName = makeEncodedFileName( originalFileName ); - StreamingOutput streamingOutput = getBackupStream(); - final String attachment = HttpMimeTypeListener.buildContentDispositionValue( originalFileName, true ); + encodedFileName = makeEncodedFileName( outputFile ); + IRepositoryExportLogger exportLogger; + Level level = Level.valueOf( logLevel ); + FileOutputStream fileOutputStream = null; + try { + validateFilePath( logFile ); + fileOutputStream = new FileOutputStream( logFile ); + } catch ( FileNotFoundException e ) { + try { + fileOutputStream = retrieveFallbackLogFileLocation( "backup" ); + } catch ( FileNotFoundException fileNotFoundException ) { + throw new ExportException( fileNotFoundException ); + } + } + ByteArrayOutputStream exportLoggerSream = new ByteArrayOutputStream(); + IPentahoPlatformExporter exporter = PentahoSystem.get( IPentahoPlatformExporter.class ); + if ( exporter == null ) { + logger.error( Messages.getInstance().getString( "FileService.ERROR_UNABLE_TO_GET_PLATFORM_EXPORTER" ) ); + throw new ExportException( Messages.getInstance().getString( "FileService.ERROR_UNABLE_TO_GET_PLATFORM_EXPORTER" ) ); + } + exportLogger = exporter.getRepositoryExportLogger(); + if ( exportLogger == null ) { + logger.error( Messages.getInstance().getString( "FileService.ERROR_UNABLE_TO_GET_EXPORT_LOGGER" ) ); + throw new ExportException( Messages.getInstance().getString( "FileService.ERROR_UNABLE_TO_GET_EXPORT_LOGGER" ) ); + } + RepositoryTextLayout stringLayout = new RepositoryTextLayout( level ); + exportLogger.startJob( exportLoggerSream, level, stringLayout ); + StreamingOutput streamingOutput = getBackupStream(); + exportLogger.endJob(); + try { + exportLoggerSream.writeTo( fileOutputStream ); + } catch ( IOException e ) { + logger.error( e.getLocalizedMessage() ); + } + final String attachment = HttpMimeTypeListener.buildContentDispositionValue( outputFile, true ); return new DownloadFileWrapper( streamingOutput, attachment, encodedFileName ); } else { throw new SecurityException(); } } + public FileOutputStream retrieveFallbackLogFileLocation( String filePrefix ) throws FileNotFoundException { + String defaultBaseDir = System.getProperty( "java.io.tmpdir" ); + // Get the current timestamp + SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyyMMdd_HHmmss" ); + String timestamp = dateFormat.format( new Date() ); + String fallbacklogFilePath = defaultBaseDir + File.pathSeparator + filePrefix + "_" + timestamp + ".log"; + return new FileOutputStream( fallbacklogFilePath ); + } + public void systemRestore( final InputStream fileUpload, String overwriteFile, - String applyAclSettings, String overwriteAclSettings ) throws PlatformImportException, SecurityException { + String applyAclSettings, String overwriteAclSettings, String logFile, String logLevel, String backupBundlePath ) throws IllegalArgumentException, PlatformImportException, SecurityException { if ( doCanAdminister() ) { boolean overwriteFileFlag = !"false".equals( overwriteFile ); boolean applyAclSettingsFlag = !"false".equals( applyAclSettings ); boolean overwriteAclSettingsFlag = "true".equals( overwriteAclSettings ); IRepositoryImportLogger importLogger; - Level level = Level.ERROR; + Level level = Level.valueOf( logLevel ); + + FileOutputStream fileOutputStream = null; + try { + validateFilePath( logFile ); + fileOutputStream = new FileOutputStream( logFile ); + } catch ( FileNotFoundException e ) { + try { + fileOutputStream = retrieveFallbackLogFileLocation( "restore" ); + } catch ( FileNotFoundException fileNotFoundException ) { + throw new PlatformImportException( fileNotFoundException.getLocalizedMessage() ); + } + } ByteArrayOutputStream importLoggerStream = new ByteArrayOutputStream(); String importDirectory = "/"; RepositoryFileImportBundle.Builder bundleBuilder = new RepositoryFileImportBundle.Builder(); @@ -163,7 +225,7 @@ public void systemRestore( final InputStream fileUpload, String overwriteFile, bundleBuilder.schedulable( RepositoryFile.SCHEDULABLE_BY_DEFAULT ); bundleBuilder.path( importDirectory ); bundleBuilder.overwriteFile( overwriteFileFlag ); - bundleBuilder.name( "SystemBackup.zip" ); + bundleBuilder.name( backupBundlePath ); bundleBuilder.applyAclSettings( applyAclSettingsFlag ); bundleBuilder.overwriteAclSettings( overwriteAclSettingsFlag ); bundleBuilder.retainOwnership( true ); @@ -173,11 +235,18 @@ public void systemRestore( final InputStream fileUpload, String overwriteFile, IPlatformImporter importer = PentahoSystem.get( IPlatformImporter.class ); importLogger = importer.getRepositoryImportLogger(); - importLogger.startJob( importLoggerStream, importDirectory, level ); + RepositoryTextLayout stringLayout = new RepositoryTextLayout( level ); + importLogger.setPerformingRestore( true ); + importLogger.startJob( importLoggerStream, importDirectory, level, stringLayout ); try { importer.importFile( bundleBuilder.build() ); } finally { importLogger.endJob(); + try { + importLoggerStream.writeTo( fileOutputStream ); + } catch ( IOException e ) { + e.printStackTrace(); + } } } else { throw new SecurityException(); @@ -208,7 +277,7 @@ public void doDeleteFiles( String params ) throws Exception { String[] sourceFileIds = FileUtils.convertCommaSeparatedStringToArray( params ); try { for ( int i = 0; i < sourceFileIds.length; i++ ) { - getRepoWs().deleteFile( sourceFileIds[i], null ); + getRepoWs().deleteFile( sourceFileIds[ i ], null ); } } catch ( Exception e ) { throw e; @@ -259,9 +328,9 @@ public List doGetCanAccessList( String pathId, String permissions ) { ArrayList permMap = new ArrayList(); while ( tokenizer.hasMoreTokens() ) { Integer perm = Integer.valueOf( tokenizer.nextToken() ); - EnumSet permission = EnumSet.of( RepositoryFilePermission.values()[perm] ); + EnumSet permission = EnumSet.of( RepositoryFilePermission.values()[ perm ] ); permMap.add( new Setting( perm.toString(), new Boolean( getRepository() - .hasAccess( idToPath( pathId ), permission ) ).toString() ) ); + .hasAccess( idToPath( pathId ), permission ) ).toString() ) ); } return permMap; } @@ -270,9 +339,9 @@ public List doGetPathsAccessList( StringListWrapper pathsWrapper ) { List pathsPermissonsSettings = new ArrayList(); String permissions = - RepositoryFilePermission.READ.ordinal() + "|" + RepositoryFilePermission.WRITE.ordinal() + "|" - + RepositoryFilePermission.DELETE.ordinal() + "|" + RepositoryFilePermission.ACL_MANAGEMENT.ordinal() + "|" - + RepositoryFilePermission.ALL.ordinal(); + RepositoryFilePermission.READ.ordinal() + "|" + RepositoryFilePermission.WRITE.ordinal() + "|" + + RepositoryFilePermission.DELETE.ordinal() + "|" + RepositoryFilePermission.ACL_MANAGEMENT.ordinal() + "|" + + RepositoryFilePermission.ALL.ordinal(); List paths = pathsWrapper.getStrings(); for ( String path : paths ) { @@ -298,7 +367,7 @@ public List doGetPathsAccessList( StringListWrapper pathsWrapper ) { * @throws IOException */ public void createFile( String charsetName, String pathId, InputStream fileContents ) - throws Exception { + throws Exception { try { if ( FileUtils.containsControlCharacters( pathId ) ) { throw new InvalidNameException(); @@ -323,14 +392,13 @@ public void createFile( String charsetName, String pathId, InputStream fileConte * Moves a list of files from its current location to another, the list should be comma separated. * * @param destPathId colon separated path for the repository file - *
-   *    :path:to:file:id
-   * 
- * @param params comma separated list of files to be moved - *
-   *    path1,path2,...
-   * 
- * + *
+   *                      :path:to:file:id
+   *                   
+ * @param params comma separated list of files to be moved + *
+   *                      path1,path2,...
+   *                   
* @return boolean true if all files were moved correctly or false if the destiny path is * not available * @throws FileNotFoundException @@ -379,13 +447,12 @@ public void doRestoreFiles( String params ) throws InternalError { } /** - * * Restores a list of files from the trash folder to user's home folder, * ignoring files previous locations (with no change of file owner) - * @param params Comma separated list of files to be restored - * @param overwriteMode Default is RENAME (2) which adds a number to the end of the file name. MODE_OVERWRITE (1) - * will just replace existing or MODE_NO_OVERWRITE (3) will not copy if file exist. * + * @param params Comma separated list of files to be restored + * @param overwriteMode Default is RENAME (2) which adds a number to the end of the file name. MODE_OVERWRITE (1) + * will just replace existing or MODE_NO_OVERWRITE (3) will not copy if file exist. */ public boolean doRestoreFilesInHomeDir( String params, int overwriteMode ) { if ( overwriteMode < 1 || overwriteMode > 3 ) { @@ -393,7 +460,7 @@ public boolean doRestoreFilesInHomeDir( String params, int overwriteMode ) { } String userHomeFolderPath = - ClientRepositoryPaths.getUserHomeFolderPath( getSession().getName() ); + ClientRepositoryPaths.getUserHomeFolderPath( getSession().getName() ); String filesToDeletePermanent = null; if ( overwriteMode == MODE_RENAME ) { @@ -473,14 +540,10 @@ public String getFolderFileIdsThatConflictWithSource( String pathToFolder, Strin * Conflict occurs if one of source files has the same * name with any of folder files. * - * @param params - * String with file ids, separated by comma - * @param pathToFolder - * path to folder - * + * @param params String with file ids, separated by comma + * @param pathToFolder path to folder * @return String - * with file ids of not conflict files, separated by comma - * + * with file ids of not conflict files, separated by comma */ protected String getSourceFileIdsThatNotConflictWithFolderFiles( String pathToFolder, String params ) { String[] sourceFileIds = FileUtils.convertCommaSeparatedStringToArray( params ); @@ -510,13 +573,9 @@ protected String getSourceFileIdsThatNotConflictWithFolderFiles( String pathToFo } /** - * - * @param fileIdsList - * List with file ids. - * @return - * - String of file ids, separated by comma - * - Empty String if {@code fileIdList} is null or empty - * + * @param fileIdsList List with file ids. + * @return - String of file ids, separated by comma + * - Empty String if {@code fileIdList} is null or empty */ protected String getCommaSeparatedFileIds( List fileIdsList ) { if ( fileIdsList == null || fileIdsList.size() == 0 ) { @@ -563,11 +622,11 @@ public String getEncodedFileName() { } public DownloadFileWrapper doGetFileOrDirAsDownload( String userAgent, String pathId, String strWithManifest ) - throws Throwable { + throws Throwable { // change file id to path String path = idToPath( pathId ); validateDownloadAccess( path ); - IAuthorizationPolicy policy = getPolicy(); + IAuthorizationPolicy policy = getPolicy(); String originalFileName, encodedFileName = null; @@ -603,7 +662,7 @@ public DownloadFileWrapper doGetFileOrDirAsDownload( String userAgent, String pa StreamingOutput streamingOutput = getDownloadStream( repositoryFile, exportProcessor ); return new DownloadFileWrapper( streamingOutput, HttpMimeTypeListener.buildContentDispositionValue( - originalFileName, true ), encodedFileName ); + originalFileName, true ), encodedFileName ); } private String makeEncodedFileName( String originalFile ) throws UnsupportedEncodingException { @@ -649,7 +708,7 @@ public RepositoryFileToStreamWrapper doGetFileAsInline( String pathId ) throws F try { SimpleRepositoryFileData fileData = - getRepository().getDataForRead( repositoryFile.getId(), SimpleRepositoryFileData.class ); + getRepository().getDataForRead( repositoryFile.getId(), SimpleRepositoryFileData.class ); final InputStream is = fileData.getInputStream(); // copy streaming output @@ -662,7 +721,7 @@ public RepositoryFileToStreamWrapper doGetFileAsInline( String pathId ) throws F return wrapper; } catch ( Exception e ) { logger.error( Messages.getInstance().getString( - "FileResource.EXPORT_FAILED", repositoryFile.getName() + " " + e.getMessage() ), e ); + "FileResource.EXPORT_FAILED", repositoryFile.getName() + " " + e.getMessage() ), e ); throw new InternalError(); } } @@ -699,7 +758,7 @@ public List doGetLocaleProperties( String pathId, Strin * @param properties */ public void doSetLocaleProperties( String pathId, String locale, List properties ) - throws Exception { + throws Exception { RepositoryFileDto file = getRepoWs().getFile( idToPath( pathId ) ); Properties fileProperties = new Properties(); if ( properties != null && !properties.isEmpty() ) { @@ -730,7 +789,7 @@ public void doCopyFiles( String pathId, Integer mode, String params ) { String[] sourceFileIds = FileUtils.convertCommaSeparatedStringToArray( params ); //$NON-NLS-1$ CopyFilesOperation copyFilesOperation = - new CopyFilesOperation( getRepository(), getRepoWs(), Arrays.asList( sourceFileIds ), path, mode ); + new CopyFilesOperation( getRepository(), getRepoWs(), Arrays.asList( sourceFileIds ), path, mode ); copyFilesOperation.execute(); } @@ -779,13 +838,13 @@ public RepositoryFileToStreamWrapper doGetFileOrDir( String pathId ) throws File /** * Save the acls of the selected file to the repository - * + *

* This method is used to update and save the acls of the selected file to the repository * * @param pathId @param pathId colon separated path for the repository file *

-   *               :path:to:file:id
-   *               
+ * :path:to:file:id + *
* @param acl Acl of the repository file RepositoryFileAclDto * @throws FileNotFoundException */ @@ -810,6 +869,7 @@ public void setFileAcls( String pathId, RepositoryFileAclDto acl ) throws FileNo } getRepoWs().updateAcl( acl ); } + /** * Check whether the selected repository folder is visible to the current user * @@ -817,8 +877,8 @@ public void setFileAcls( String pathId, RepositoryFileAclDto acl ) throws FileNo * @return true or false */ public String doGetIsVisible( String pathId ) { - RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); - return repositoryFileDto != null && repositoryFileDto.isHidden() ? "false" : "true"; + RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); + return repositoryFileDto != null && repositoryFileDto.isHidden() ? "false" : "true"; } /** @@ -828,7 +888,7 @@ public String doGetIsVisible( String pathId ) { * @return true or false */ public boolean isFolder( String pathId ) { - RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); + RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); return repositoryFileDto != null && repositoryFileDto.isFolder(); } @@ -839,7 +899,7 @@ public boolean isFolder( String pathId ) { * @return true or false */ public boolean doesExist( String pathId ) { - RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); + RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); return repositoryFileDto != null && repositoryFileDto.getId() != null; } @@ -859,38 +919,38 @@ private boolean isInsideOfAnyHiddenFolder( RepositoryFileDto repositoryFileDto ) } return isInsideOfAnyHiddenFolder( getRepoWs().getFile( idToPath( parentPathId ) ) ); } + /** - * * @param pathId * @return default path to where user can save or open the artifact */ public String doGetDefaultLocation( String pathId ) { - RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); + RepositoryFileDto repositoryFileDto = getRepoWs().getFile( idToPath( pathId ) ); if ( repositoryFileDto == null ) { return ClientRepositoryPaths.getRootFolderPath(); } else if ( isInsideOfAnyHiddenFolder( repositoryFileDto ) ) { String defaultFolder = PentahoSystem.get( ISystemConfig.class ) - .getProperty( PentahoSystem.DEFAULT_FOLDER_WHEN_HOME_FOLDER_IS_HIDDEN_PROPERTY ); + .getProperty( PentahoSystem.DEFAULT_FOLDER_WHEN_HOME_FOLDER_IS_HIDDEN_PROPERTY ); if ( defaultFolder != null && defaultFolder.length() > 0 ) { repositoryFileDto = getRepoWs().getFile( defaultFolder ); if ( repositoryFileDto == null ) { return ClientRepositoryPaths.getRootFolderPath(); } else if ( isInsideOfAnyHiddenFolder( repositoryFileDto ) ) { - repositoryFileDto = getRepoWs().getFile( ClientRepositoryPaths.getPublicFolderPath() ); + repositoryFileDto = getRepoWs().getFile( ClientRepositoryPaths.getPublicFolderPath() ); if ( isInsideOfAnyHiddenFolder( repositoryFileDto ) ) { return ClientRepositoryPaths.getRootFolderPath(); } else { - return ClientRepositoryPaths.getPublicFolderPath(); + return ClientRepositoryPaths.getPublicFolderPath(); } } else { return defaultFolder; } } else { - repositoryFileDto = getRepoWs().getFile( ClientRepositoryPaths.getPublicFolderPath() ); + repositoryFileDto = getRepoWs().getFile( ClientRepositoryPaths.getPublicFolderPath() ); if ( isInsideOfAnyHiddenFolder( repositoryFileDto ) ) { return ClientRepositoryPaths.getRootFolderPath(); } else { - return ClientRepositoryPaths.getPublicFolderPath(); + return ClientRepositoryPaths.getPublicFolderPath(); } } } else { @@ -975,8 +1035,8 @@ public RepositoryFileDto doGetRootProperties() { * * @param pathId @param pathId colon separated path for the repository file *
-   *               :path:to:file:id
-   *               
+ * :path:to:file:id + *
* @return file properties object RepositoryFileDto * @throws FileNotFoundException */ @@ -987,6 +1047,7 @@ public RepositoryFileDto doGetProperties( String pathId ) throws FileNotFoundExc } return file; } + /** * Gets the permission for whether or not a user can edit files * @@ -994,7 +1055,7 @@ public RepositoryFileDto doGetProperties( String pathId ) throws FileNotFoundExc */ public String doGetCanEdit() { String editPermission = PentahoSystem.getSystemSetting( "edit-permission", "" ); - if( editPermission != null && editPermission.length() > 0 ) { + if ( editPermission != null && editPermission.length() > 0 ) { return getPolicy().isAllowed( editPermission ) ? "true" : "false"; } else { return "true"; @@ -1095,10 +1156,10 @@ public void doSetMetadata( String pathId, List metadata RepositoryFileAclDto fileAcl = getRepoWs().getAcl( file.getId() ); boolean canManage = - getSession().getName().equals( fileAcl.getOwner() ) - || ( getPolicy().isAllowed( RepositoryReadAction.NAME ) - && getPolicy().isAllowed( RepositoryCreateAction.NAME ) && getPolicy().isAllowed( - AdministerSecurityAction.NAME ) ); + getSession().getName().equals( fileAcl.getOwner() ) + || ( getPolicy().isAllowed( RepositoryReadAction.NAME ) + && getPolicy().isAllowed( RepositoryCreateAction.NAME ) && getPolicy().isAllowed( + AdministerSecurityAction.NAME ) ); if ( !canManage ) { @@ -1111,7 +1172,7 @@ && getPolicy().isAllowed( RepositoryCreateAction.NAME ) && getPolicy().isAllowed RepositoryFileAclAceDto acl = fileAcl.getAces().get( i ); if ( acl.getRecipient().equals( getSession().getName() ) ) { if ( acl.getPermissions().contains( RepositoryFilePermission.ACL_MANAGEMENT.ordinal() ) - || acl.getPermissions().contains( RepositoryFilePermission.ALL.ordinal() ) ) { + || acl.getPermissions().contains( RepositoryFilePermission.ALL.ordinal() ) ) { canManage = true; break; } @@ -1203,16 +1264,11 @@ public boolean isPath( String pathId ) { } /** - * - * @param params - * id of files, separated by ',' - * + * @param params id of files, separated by ',' * @return false if homeFolder has files - * with names and extension equal to passed files - * true otherwise - * - * @throws IllegalArgumentException - * if {@code params} is null + * with names and extension equal to passed files + * true otherwise + * @throws IllegalArgumentException if {@code params} is null */ public boolean canRestoreToFolderWithNoConflicts( String pathToFolder, String params ) { if ( params == null ) { @@ -1242,54 +1298,54 @@ public IAuthorizationPolicy getPolicy() { /** * Store content creator of the selected repository file * - * @param pathId colon separated path for the repository file - *
-   *    :path:to:file:id
-   * 
+ * @param pathId colon separated path for the repository file + *
+   *                          :path:to:file:id
+   *                       
* @param contentCreator repository file - *
-   *   
-   *     <repositoryFileDto>
-   *     <createdDate>1402911997019</createdDate>
-   *     <fileSize>3461</fileSize>
-   *     <folder>false</folder>
-   *     <hidden>false</hidden>
-   *     <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id>
-   *     <lastModifiedDate>1406647160536</lastModifiedDate>
-   *     <locale>en</locale>
-   *     <localePropertiesMapEntries>
-   *       <localeMapDto>
-   *         <locale>default</locale>
-   *         <properties>
-   *           <stringKeyStringValueDto>
-   *             <key>file.title</key>
-   *             <value>myFile</value>
-   *           </stringKeyStringValueDto>
-   *           <stringKeyStringValueDto>
-   *             <key>jcr:primaryType</key>
-   *             <value>nt:unstructured</value>
-   *           </stringKeyStringValueDto>
-   *           <stringKeyStringValueDto>
-   *             <key>title</key>
-   *             <value>myFile</value>
-   *           </stringKeyStringValueDto>
-   *           <stringKeyStringValueDto>
-   *             <key>file.description</key>
-   *             <value>myFile Description</value>
-   *           </stringKeyStringValueDto>
-   *         </properties>
-   *       </localeMapDto>
-   *     </localePropertiesMapEntries>
-   *     <locked>false</locked>
-   *     <name>myFile.prpt</name></name>
-   *     <originalParentFolderPath>/public/admin</originalParentFolderPath>
-   *     <ownerType>-1</ownerType>
-   *     <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path>
-   *     <title>myFile</title>
-   *     <versionId>1.9</versionId>
-   *     <versioned>true</versioned>
-   *   </repositoryFileAclDto>
-   * 
+ *
+   *                         
+   *                           <repositoryFileDto>
+   *                           <createdDate>1402911997019</createdDate>
+   *                           <fileSize>3461</fileSize>
+   *                           <folder>false</folder>
+   *                           <hidden>false</hidden>
+   *                           <id>ff11ac89-7eda-4c03-aab1-e27f9048fd38</id>
+   *                           <lastModifiedDate>1406647160536</lastModifiedDate>
+   *                           <locale>en</locale>
+   *                           <localePropertiesMapEntries>
+   *                             <localeMapDto>
+   *                               <locale>default</locale>
+   *                               <properties>
+   *                                 <stringKeyStringValueDto>
+   *                                   <key>file.title</key>
+   *                                   <value>myFile</value>
+   *                                 </stringKeyStringValueDto>
+   *                                 <stringKeyStringValueDto>
+   *                                   <key>jcr:primaryType</key>
+   *                                   <value>nt:unstructured</value>
+   *                                 </stringKeyStringValueDto>
+   *                                 <stringKeyStringValueDto>
+   *                                   <key>title</key>
+   *                                   <value>myFile</value>
+   *                                 </stringKeyStringValueDto>
+   *                                 <stringKeyStringValueDto>
+   *                                   <key>file.description</key>
+   *                                   <value>myFile Description</value>
+   *                                 </stringKeyStringValueDto>
+   *                               </properties>
+   *                             </localeMapDto>
+   *                           </localePropertiesMapEntries>
+   *                           <locked>false</locked>
+   *                           <name>myFile.prpt</name></name>
+   *                           <originalParentFolderPath>/public/admin</originalParentFolderPath>
+   *                           <ownerType>-1</ownerType>
+   *                           <path>/public/admin/ff11ac89-7eda-4c03-aab1-e27f9048fd38</path>
+   *                           <title>myFile</title>
+   *                           <versionId>1.9</versionId>
+   *                           <versioned>true</versioned>
+   *                         </repositoryFileAclDto>
+   *                       
* @throws FileNotFoundException */ public void doSetContentCreator( String pathId, RepositoryFileDto contentCreator ) throws FileNotFoundException { @@ -1310,11 +1366,11 @@ public void doSetContentCreator( String pathId, RepositoryFileDto contentCreator * Retrieves the list of locale map for the selected repository file. The list will be empty if a problem occurs. * * @param pathId colon separated path for the repository file - *
-   *    :path:to:file:id
-   * 
+ *
+   *                  :path:to:file:id
+   *               
* @return List the list of locales - *
+   * 
    *           
    *           <localePropertiesMapEntries>
    *             <localeMapDto>
@@ -1372,8 +1428,8 @@ public boolean doCanAdminister() {
     boolean status = false;
     try {
       status = getPolicy().isAllowed( RepositoryReadAction.NAME )
-        && getPolicy().isAllowed( RepositoryCreateAction.NAME )
-        && getPolicy().isAllowed( AdministerSecurityAction.NAME );
+          && getPolicy().isAllowed( RepositoryCreateAction.NAME )
+          && getPolicy().isAllowed( AdministerSecurityAction.NAME );
     } catch ( Exception e ) {
       logger.error( Messages.getInstance().getString( "SystemResource.CAN_ADMINISTER" ), e );
     }
@@ -1391,7 +1447,7 @@ public RepositoryFileAclDto doGetFileAcl( String pathId ) {
     RepositoryFileAclDto fileAcl = getRepoWs().getAcl( file.getId() );
     if ( fileAcl.isEntriesInheriting() ) {
       List aces =
-        getRepoWs().getEffectiveAcesWithForceFlag( file.getId(), fileAcl.isEntriesInheriting() );
+          getRepoWs().getEffectiveAcesWithForceFlag( file.getId(), fileAcl.isEntriesInheriting() );
       fileAcl.setAces( aces, fileAcl.isEntriesInheriting() );
     }
     addAdminRole( fileAcl );
@@ -1400,7 +1456,7 @@ public RepositoryFileAclDto doGetFileAcl( String pathId ) {
 
   protected void addAdminRole( RepositoryFileAclDto fileAcl ) {
     String adminRoleName =
-      PentahoSystem.get( String.class, "singleTenantAdminAuthorityName", PentahoSessionHolder.getSession() );
+        PentahoSystem.get( String.class, "singleTenantAdminAuthorityName", PentahoSessionHolder.getSession() );
     if ( fileAcl.getAces() == null ) {
       fileAcl.setAces( new LinkedList() );
     }
@@ -1445,7 +1501,7 @@ public RepositoryFileTreeDto doGetTree( String pathId, Integer depth, String fil
     }
 
     //translating /home and /public folders titles
-    for ( RepositoryFileTreeDto dto : tree.getChildren( ) ) {
+    for ( RepositoryFileTreeDto dto : tree.getChildren() ) {
       if ( dto.getFile().getName().equals( ClientRepositoryPaths.getHomeFolderName() ) && dto.getFile().getPath().equals( ClientRepositoryPaths.getHomeFolderPath() ) ) {
         dto.getFile().setTitle( Messages.getInstance().getString( "FileResource.HOME_FOLDER_DISPLAY_TITLE" ) );
       } else if ( dto.getFile().getName().equals( ClientRepositoryPaths.getPublicFolderName() ) && dto.getFile().getPath().equals( ClientRepositoryPaths.getPublicFolderPath() ) ) {
@@ -1521,7 +1577,7 @@ public List doGetGeneratedContent( String pathId, String user
    * @private
    */
   private List doGetGeneratedContentForUser( String pathId, String userDir )
-    throws FileNotFoundException {
+      throws FileNotFoundException {
     RepositoryFileDto targetFile = doGetProperties( pathId );
     if ( targetFile != null ) {
       String targetFileId = targetFile.getId();
@@ -1542,7 +1598,7 @@ private List doGetGeneratedContentForUser( String pathId, Str
    */
   public List searchGeneratedContent( String userDir, String targetComparator,
                                                          String metadataConstant )
-    throws FileNotFoundException {
+      throws FileNotFoundException {
     List content = new ArrayList();
 
     RepositoryFile workspaceFolder = getRepository().getFile( userDir );
@@ -1600,7 +1656,7 @@ public boolean doRename( String pathId, String newName ) throws Exception {
     // If destination already exists throw
     if ( repository.getFile( buf.toString() ) != null ) {
       throw new IllegalArgumentException( org.pentaho.platform.repository2.messages.Messages.getInstance().getString(
-        "JcrRepositoryFileDao.ERROR_0003_ILLEGAL_DEST_PATH" ) );
+          "JcrRepositoryFileDao.ERROR_0003_ILLEGAL_DEST_PATH" ) );
     }
     repository.moveFile( fileToBeRenamed.getId(), buf.toString(), "Renaming the file" );
     RepositoryFile movedFile = repository.getFileById( fileToBeRenamed.getId() );
@@ -1625,8 +1681,8 @@ public boolean doRename( String pathId, String newName ) throws Exception {
           }
         }
         RepositoryFile updatedFile =
-          new RepositoryFile.Builder( movedFile ).localePropertiesMap( localePropertiesMap ).name( newName ).title(
-            newName ).build();
+            new RepositoryFile.Builder( movedFile ).localePropertiesMap( localePropertiesMap ).name( newName ).title(
+                newName ).build();
         repository.updateFile( updatedFile, RepositoryFileHelper.getFileData( movedFile ), "Updating the file" );
       }
       return true;
@@ -1639,12 +1695,12 @@ public boolean doRename( String pathId, String newName ) throws Exception {
   /**
    * Creates a new folder with the specified name
    *
-   * @param pathId      The path from the root folder to the root node of the tree to return using colon characters in
-   *                    place of / or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file
-   *                    
-   *                      :path:to:file
-   *                    
- * @return A jax-rs Response object with the appropriate status code, header, and body. + * @param pathId The path from the root folder to the root node of the tree to return using colon characters in + * place of / or \ characters. To clarify /path/to/file, the encoded pathId would be :path:to:file + *
+   *                                    :path:to:file
+   *                                  
+ * @return A jax-rs Response object with the appropriate status code, header, and body. * @deprecated use {@link #doCreateDirSafe(String)} instead */ @Deprecated @@ -1711,7 +1767,7 @@ public boolean isValidFolderName( String path ) { * [pentaho-commons-gwt-modules] org.pentaho.gwt.widgets.client.utils.NameUtils#isValidFolderName */ if ( FileUtils.containsReservedCharacter( path, doGetReservedChars().toString().toCharArray() ) - || FileUtils.containsControlCharacters( path ) ) { + || FileUtils.containsControlCharacters( path ) ) { return false; } @@ -1731,11 +1787,11 @@ public boolean isValidFileName( final String name ) { * [pentaho-commons-gwt-modules] org.pentaho.gwt.widgets.client.utils.NameUtils#isValidFileName */ return !( - StringUtils.isEmpty( name ) || // not null, not empty and not all whitespace - !name.trim().equals( name ) || !decode( name ).trim().equals( decode( name ) ) || // no leading or trailing whitespace - FileUtils.containsReservedCharacter( name, doGetReservedChars().toString().toCharArray() ) || // no reserved characters - FileUtils.containsControlCharacters( name ) || FileUtils.containsControlCharacters( decode( name ) ) // control characters - ); + StringUtils.isEmpty( name ) || // not null, not empty and not all whitespace + !name.trim().equals( name ) || !decode( name ).trim().equals( decode( name ) ) || // no leading or trailing whitespace + FileUtils.containsReservedCharacter( name, doGetReservedChars().toString().toCharArray() ) || // no reserved characters + FileUtils.containsControlCharacters( name ) || FileUtils.containsControlCharacters( decode( name ) ) // control characters + ); } private String getParentPath( final String path ) { @@ -1766,7 +1822,7 @@ public RepositoryFileOutputStream getRepositoryFileOutputStream( String path ) { } public RepositoryFileInputStream getRepositoryFileInputStream( RepositoryFile repositoryFile ) - throws FileNotFoundException { + throws FileNotFoundException { return new RepositoryFileInputStream( repositoryFile ); } @@ -1811,7 +1867,7 @@ protected ExportHandler getDownloadExportHandler() { } protected StreamingOutput getDownloadStream( RepositoryFile repositoryFile, BaseExportProcessor exportProcessor ) - throws ExportException, IOException { + throws ExportException, IOException { File zipFile = exportProcessor.performExport( repositoryFile ); final FileInputStream is = new FileInputStream( zipFile ); // copy streaming output @@ -1823,7 +1879,7 @@ public void write( OutputStream output ) throws IOException { }; } - protected RepositoryRequest getRepositoryRequest( String path, Boolean showHidden, Integer depth, String filter ) { + protected RepositoryRequest getRepositoryRequest( String path, Boolean showHidden, Integer depth, String filter ) { return new RepositoryRequest( path, showHidden, depth, filter ); } @@ -1886,7 +1942,7 @@ public boolean isShowingTitle( RepositoryRequest repositoryRequest ) { return false; } } else if ( repositoryRequest.getIncludeMemberSet() != null - && !repositoryRequest.getIncludeMemberSet().contains( "title" ) ) { + && !repositoryRequest.getIncludeMemberSet().contains( "title" ) ) { return false; } return true; @@ -1929,7 +1985,7 @@ protected Collator getCollator( int strength ) { private PentahoPlatformExporter getBackupExporter() { if ( backupExporter == null ) { backupExporter = - (PentahoPlatformExporter) PentahoSystem.get( IPentahoPlatformExporter.class, "IPentahoPlatformExporter", null ); + (PentahoPlatformExporter) PentahoSystem.get( IPentahoPlatformExporter.class, "IPentahoPlatformExporter", null ); } return backupExporter; diff --git a/extensions/src/main/resources/org/pentaho/platform/plugin/services/messages/messages.properties b/extensions/src/main/resources/org/pentaho/platform/plugin/services/messages/messages.properties index db771ce9548..928cfe6bb41 100644 --- a/extensions/src/main/resources/org/pentaho/platform/plugin/services/messages/messages.properties +++ b/extensions/src/main/resources/org/pentaho/platform/plugin/services/messages/messages.properties @@ -194,7 +194,8 @@ PentahoPlatformImporter.ERROR_0008_PUBLISH_JOB_OR_TRANS_WITH_MISSING_PLUGINS=Cou CommandLineProcessor.INFO_IMPORT_SUCCESSFUL=Import was successful CommandLineProcessor.INFO_EXPORT_SUCCESSFUL=Export was successful -CommandLineProcessor.INFO_RESTORE_SUCCESSFUL=Restore was successful +CommandLineProcessor.INFO_RESTORE_SUCCESSFUL=Restore complete +CommandLineProcessor.INFO_RESTORE_SUCCESSFUL=Restore complete CommandLineProcessor.ERROR_0001_MISSING_ARG=Missing Arguments: {0} CommandLineProcessor.ERROR_0002_INVALID_RESPONSE=Invalid ClientResponse received in performREST() @@ -204,6 +205,7 @@ CommandLineProcessor.ERROR_0005_INVALID_FILE_PATH=Invalid file-path: {0} CommandLineProcessor.ERROR_0006_NON_ADMIN_CREDENTIALS=Non admin credentials entered CommandLineProcessor.ERROR_0007_FORBIDDEN=User is not allowed to perform this operation: {0} CommandLineProcessor.ERROR_0008_INVALID_PARAMETER=Invalid parameter syntax: "{0}" +CommandLineProcessor.ERROR_0009_INVALID_LOG_FILE_PATH=Invalid log file path: "{0}" CommandLineProcessor.INFO_OPTION_HELP_DESCRIPTION=print this message CommandLineProcessor.INFO_OPTION_IMPORT_DESCRIPTION=import @@ -216,6 +218,7 @@ CommandLineProcessor.INFO_OPTION_URL_DESCRIPTION=url of repository (e.g. http:// CommandLineProcessor.INFO_OPTION_FILEPATH_DESCRIPTION=Path to directory of files for import, or path to .zip file for export CommandLineProcessor.INFO_OPTION_CHARSET_DESCRIPTION=charset to use for the repository (characters from external systems converted to this charset) CommandLineProcessor.INFO_OPTION_LOGFILE_DESCRIPTION=full path and filename of logfile messages +CommandLineProcessor.INFO_OPTION_LOGLEVEL_DESCRIPTION=Log Level CommandLineProcessor.INFO_OPTION_PATH_DESCRIPTION=repository path to which to add imported files, or to export from (e.g. /public) CommandLineProcessor.INFO_OPTION_OVERWRITE_DESCRIPTION=overwrite files (import only) CommandLineProcessor.INFO_OPTION_PERMISSION_DESCRIPTION=apply ACL manifest permissions to files and folders (import only) @@ -232,6 +235,8 @@ CommandLineProcessor.INFO_REST_RESPONSE_RECEIVED=done response = {0} CommandLineProcessor.INFO_EXPORT_COMPLETED=Export Completed CommandLineProcessor.INFO_EXPORT_WRITTEN_TO=Export written to: {0} CommandLineProcessor.INFO_RESPONSE_STATUS=Response Status: {0} +CommandLineProcessor.INFO_BACKUP_COMPLETED=Backup Completed +CommandLineProcessor.INFO_BACKUP_WRITTEN_TO=Backup written to: {0} CommandLineProcessor.INFO_PRINTHELP_CMDLINE=importexport CommandLineProcessor.INFO_PRINTHELP_HEADER=Unified repository command line import/export tool @@ -302,23 +307,100 @@ SolutionImportHandler.SkipLocaleFile=Skipping [{0}], it is a locale property fil SolutionImportHandler.ConnectionWithoutDatabaseType=Can't import connection [{0}] because it doesn't have a databaseType. SolutionImportHandler.SchedulesWithSpaces=Could not import schedule, attempting to replace spaces with underscores and retrying: {0} + +SolutionImportHandler.INFO_START_IMPORT_PROCESS=Starting the restore process +SolutionImportHandler.INFO_START_IMPORT_FILEFOLDER=*********************** [ Start: Restore File/Folder(s) ] ************************************** +SolutionImportHandler.INFO_COUNT_FILEFOLDER=Found [ {0} ] repository file(s)/folder(s) to restore +SolutionImportHandler.ERROR_IMPORTING_REPOSITORY_OBJECT=Attempting to restore repository object with path [ {0} ] from the cache. Cause [ {1} ] +SolutionImportHandler.INFO_SUCCESSFUL_REPOSITORY_IMPORT_COUNT=Successfully restored [ {0} ] out of [ {1} ] repository file(s)/folder(s) +SolutionImportHandler.INFO_START_IMPORT_LOCALEFILE=****************************[ Start: Restore Locale File(s) ] ********************************** +SolutionImportHandler.ERROR_IMPORTING_LOCALE_FILE=Error performing restore of locale files. Cause [ {0} ] +SolutionImportHandler.INFO_END_IMPORT_LOCALEFILE=****************************[ End: Restore Locale File(s) ] ********************************** +SolutionImportHandler.INFO_END_IMPORT_FILEFOLDER=*********************** [ End: Restore File/Folder(s) ] *********************************** +SolutionImportHandler.INFO_START_IMPORT_DATASOURCE=****************************[ Start: Restore DataSource(s) ] ********************************** +SolutionImportHandler.INFO_COUNT_DATASOURCE=Found [ {0}} ] DataSource(s) to restore +SolutionImportHandler.ERROR_IMPORTING_JDBC_DATASOURCE=Error while attempting to restore JDBC DataSource [ {0} ]. Cause [ {1} ] +SolutionImportHandler.INFO_END_IMPORT_DATASOURCE=****************************[ End: Restore DataSource(s) ] ********************************** +SolutionImportHandler.INFO_SUCCESSFUL_DATASOURCE_IMPORT_COUNT=Successfully restored [ {0} ] out of [ {1} ] +SolutionImportHandler.INFO_START_IMPORT_SCHEDULE=*********************** [ Start: Restore Schedule(s) ] ************************************** +SolutionImportHandler.INFO_END_IMPORT_SCHEDULE=*********************** [ End: Restore Schedule(s) ] ************************************** +SolutionImportHandler.INFO_COUNT_SCHEDULUE=Found {0} schedules in the manifest to restore +SolutionImportHandler.ERROR_IMPORTING_SCHEDULE=Unable to restore schedule [ {0} ] cause [ {1} ] +SolutionImportHandler.INFO_SUCCESSFUL_SCHEDULE_IMPORT_COUNT=Successfully restored [ {0} ] out of [ {1} ] +SolutionImportHandler.INFO_START_IMPORT_METASTORE=********************** [ Start: Restore MetaStore ] ****************************************** +SolutionImportHandler.INFO_END_IMPORT_METASTORE=********************** [ End: Restore MetaStore ] ****************************************** +SolutionImportHandler.INFO_SUCCESSFUL_IMPORT_METASTORE=Successfully restore metastore +SolutionImportHandler.INFO_START_IMPORT_USER=******************************* [Start: Restore User(s)] *************************** +SolutionImportHandler.INFO_COUNT_USER=Found [ {0} ] users to restore +SolutionImportHandler.INFO_SUCCESSFUL_USER_COUNT=Successfully restored [ {0} ] out of [ {1} ] user(s) +SolutionImportHandler.INFO_END_IMPORT_USER=****************************** [End Restore User(s)] *************************** +SolutionImportHandler.INFO_START_IMPORT_USER_SETTING=************************[ Start: Restore user specific settings] ************************* +SolutionImportHandler.INFO_COUNT_USER_SETTING=Found [ {0} ] user specific settings for user [ {1} ] +SolutionImportHandler.INFO_SUCCESSFUL_USER_SETTING_IMPORT_COUNT=Successfully restored [ {0} ] out of [ {1} ] user specific settings +SolutionImportHandler.INFO_END_IMPORT_USER_SETTING=************************[ End: Restore user specific settings] ************************* +SolutionImportHandler.INFO_COUNT_ROLE=Found [ {0} ] roles to restore +SolutionImportHandler.INFO_SUCCESSFUL_ROLE_COUNT=Successfully restored [ {0} ] out of [ {1} ] roles +SolutionImportHandler.INFO_START_IMPORT_ROLE=*********************** [ Start: Restore Role(s) ] *************************************** +SolutionImportHandler.INFO_END_IMPORT_ROLE=*********************** [ End: Restore Role(s) ] *************************************** +SolutionImportHandler.INFO_START_IMPORT_METADATA_DATASOURCE=*********************** [ Start: Restore Metadata DataSource(s) ] ***************************** +SolutionImportHandler.INFO_COUNT_METADATA_DATASOURCE=Found [ {0} ] metadata models to restore +SolutionImportHandler.INFO_SUCCESSFUL_METDATA_DATASOURCE_COUNT=Successfully restored [ {0} ] out of [ {1} ] metadata models +SolutionImportHandler.INFO_END_IMPORT_METADATA_DATASOURCE=*********************** [ End: Restore Metadata DataSource(s) ] ***************************** +SolutionImportHandler.INFO_START_IMPORT_MONDRIAN_DATASOURCE=*********************** [ Start: Restore Mondrian DataSource(s) ] ***************************** +SolutionImportHandler.INFO_COUNT_MONDRIAN_DATASOURCE=Found [ {0} ] mondrian schemas to restore +SolutionImportHandler.INFO_SUCCESSFUL_MONDRIAN_DATASOURCE_IMPORT_COUNT=Successfully restored [ {0} ] out of [ {1} ] DataSource(s) +SolutionImportHandler.INFO_END_IMPORT_MONDRIAN_DATASOURCE=*********************** [ End: Restore Mondrian DataSource(s) ] ***************************** +SolutionImportHandler.INFO_START_IMPORT_REPOSITORY_OBJECT=****************************** [ Start: Restore Repository File/Folder(s) ] ********************************** +SolutionImportHandler.INFO_END_IMPORT_REPOSITORY_OBJECT=****************************** [ End: Restore Repository File/Folder(s) ] ********************************** +SolutionImportHandler.ERROR_NOT_=This not a valid file name. Failing the restore PentahoPlatformExporter.UNSUPPORTED_JobTrigger=Unsupported JobTrigger encountered during export, skipping it: {0} PentahoPlatformExporter.ERROR_EXPORTING_JOBS=There was an error while exporting scheduled jobs ScheduleExportUtil.JOB_MUST_NOT_BE_NULL=Job can not be null - +PentahoPlatformExporter.INFO_START_EXPORT_JDBC_DATASOURCE=*************************** [ Start: Backup JDBC Datasource(s) ] ******************************* +PentahoPlatformExporter.INFO_COUNT_JDBC_DATASOURCE_TO_EXPORT=Found [ {0} ] JDBC DataSource(s) to backup +PentahoPlatformExporter.INFO_SUCCESSFUL_JDBC_DATASOURCE_EXPORT_COUNT=Successfully perform backup of[ {0} ] out of [ {1} ] JDBC DataSource(s) +PentahoPlatformExporter.INFO_END_EXPORT_JDBC_DATASOURCE=*************************** [ End: Backup JDBC Datasource(s) ] ******************************* +PentahoPlatformExporter.INFO_START_EXPORT_REPOSITORY_OBJECT=********************************* [ Start: Backup repository File(s)/Folder(s) ] ******************************* +PentahoPlatformExporter.INFO_END_EXPORT_REPOSITORY_OBJECT=********************************* [ End: Backup repository File(s)/Folder(s) ] ******************************* +PentahoPlatformExporter.ERROR_EXPORT_REPOSITORY_OBJECT=Error while performing backup of a file [ {0} ] +PentahoPlatformExporter.INFO_START_EXPORT_USER=********************************* [ Start: Backup User(s) ] ******************************* +PentahoPlatformExporter.INFO_COUNT_USER_TO_EXPORT=Found [ {0} ] User(s) to backup +PentahoPlatformExporter.INFO_SUCCESSFUL_USER_EXPORT_COUNT=Successfully perform backup of [ {0} ] out of [ {1} ] User(s) +PentahoPlatformExporter.INFO_END_EXPORT_USER=********************************* [ End: Backup User(s) ] ******************************* +PentahoPlatformExporter.INFO_START_EXPORT_ROLE=********************************* [ Start: Backup Role(s) ] ******************************* +PentahoPlatformExporter.INFO_COUNT_ROLE_TO_EXPORT=Found [ {0} ] Role(s) to backup +PentahoPlatformExporter.INFO_SUCCESSFUL_ROLE_EXPORT_COUNT=Successfully perform backup of [ {0} ] out of [ {1} ] Role(s) +PentahoPlatformExporter.INFO_END_EXPORT_ROLE=********************************* [ End: Backup Role(s) ] ******************************* +PentahoPlatformExporter.INFO_START_EXPORT_METASTORE=********************************* [ Start: Backup Metastore ] ******************************* +PentahoPlatformExporter.INFO_END_EXPORT_METASTORE=********************************* [ End: Backup Metastore ] ******************************* +PentahoPlatformExporter.INFO_SUCCESSFUL_EXPORT_METASTORE=Finished adding the metastore to the backup manifest +PentahoPlatformExporter.INFO_START_EXPORT_MONDRIAN_DATASOURCE=********************************* [ Start: Backup Mondrian datasource(s) ] ******************************* +PentahoPlatformExporter.INFO_COUNT_MONDRIAN_DATASOURCE_TO_EXPORT=Found [ {0} ] Role(s) to backup +PentahoPlatformExporter.INFO_SUCCESSFUL_MONDRIAN_DATASOURCE_EXPORT_COUNT=Successfully perform backup of [ {0} ] out of [ {1} ] Role(s) +PentahoPlatformExporter.ERROR_MONDRIAN_DATASOURCE_EXPORT=Error performing backup of Mondrian DataSource. Cause [ {0} ] +PentahoPlatformExporter.INFO_END_EXPORT_MONDRIAN_DATASOURCE=********************************* [ End: Backup Mondrian datasource(s) ] ******************************* +PentahoPlatformExporter.INFO_START_EXPORT_METADATA=********************************* [ Start: Backup Metadata datasource(s) ] ******************************* +PentahoPlatformExporter.INFO_COUNT_METADATA_DATASOURCE_TO_EXPORT=Found [ {0} ] Metadata DataSource(s) to backup +PentahoPlatformExporter.INFO_SUCCESSFUL_METADATA_DATASOURCE_EXPORT_COUNT=Successfully perform backup of [ {0} ] out of [ {1} ] Metadata DataSource(s) +PentahoPlatformExporter.ERROR_METADATA_DATASOURCE_EXPORT=Error performing backup of Mondrian DataSource. Cause [ {0} ] +PentahoPlatformExporter.INFO_END_EXPORT_METADATA=*********************** [ End: Backup metadata datasource(s) ]************************* +PentahoPlatformExporter.ERROR_EXPORT_FILE_CONTENT=Error while performing backup of file content. Cause {0} +PentahoPlatformExporter.ERROR_GENERATING_EXPORT_XML=Error generating export XML +PentahoPlatformExporter.INFO_END_EXPORT_PROCESS=End: Backup process +PentahoPlatformExporter.INFO_START_EXPORT_PROCESS=Start: Backup process ERROR.Encrypting_Password=Could not encrypt password for user {0} ERROR.Restoring_Password=Could restore password for user {0}. Setting a temporary password. ERROR.CreatingUser=Could not create user {0}. ERROR.OverridingExistingUser=Failed to set roles or password for existing user [{0}]. ROLE.Already.Exists=Role {0} already exists, could not create it. -ROLE.importing=Importing role: {0} +ROLE.importing=Performing backup of role: {0} USER.Already.Exists=User {0} already exists, could not create it. -USER.importing=Importing user: {0} +USER.importing=Performing backup of user: {0} ERROR.ScheduledWithoutPermission=File [{0}] doesn't have schedulable permission (isSchedulable=false) but there are some schedule(s) in import bundle which refers the file SCHEDULE.AssigningPermission=Assigning 'isSchedulable=true' permission for file [{0}]. -ERROR.SettingRolePermissions=Could not set permissions for role {0} during import. -PentahoPlatformExporter.ERROR.ExportingMetaStore=Error exporting the MetaStore -ERROR.ImportingUserSetting=Could not import user settings for user {0}. +ERROR.SettingRolePermissions=Could not set permissions for role {0} during backup process. +PentahoPlatformExporter.ERROR.ExportingMetaStore=Error performing backup the MetaStore +ERROR.ImportingUserSetting=Could not backup user settings for user {0}. ZIPFILE.ProcessingEntry=Processing [{0}] ZIPFILE.ExceptionOccurred=Exception occurred when processing Zip: @@ -329,7 +411,7 @@ UserRoleDaoService.PassValidationError_ReadingSecProperties=There was an error r RepositoryFileImportFileHandler.ProcessingFile=Processing [{0}] RepositoryFileImportFileHandler.SkippingImplicitlyCreatedFolder=Skipping entry for folder [{0}]. It was already processed implicitly. -RepositoryFileImportFileHandler.SkippingExistingFile=Not importing existing file [{0}] +RepositoryFileImportFileHandler.SkippingExistingFile=Not performing backup of existing file [{0}] RepositoryFileImportFileHandler.ExistingFolder=Existing folder [{0}] RepositoryFileImportFileHandler.CreatingFolder=Creating folder [{0}] RepositoryFileImportFileHandler.CreatingImpliedFolder=Creating implied folder [{0}] diff --git a/extensions/src/main/resources/org/pentaho/platform/web/http/messages/messages.properties b/extensions/src/main/resources/org/pentaho/platform/web/http/messages/messages.properties index e14d2b9bc4d..2dd0aaf56cf 100644 --- a/extensions/src/main/resources/org/pentaho/platform/web/http/messages/messages.properties +++ b/extensions/src/main/resources/org/pentaho/platform/web/http/messages/messages.properties @@ -152,4 +152,7 @@ FileResource.INCORRECT_EXTENSION={0} has incorrect extension. FileResource.HOME_FOLDER_DISPLAY_TITLE=Home FileResource.PUBLIC_FOLDER_DISPLAY_TITLE=Public -RepositoryResource.USER_NOT_AUTHORIZED_TO_EDIT=User is not authorized to edit the content. Please contact your system administrator. \ No newline at end of file +RepositoryResource.USER_NOT_AUTHORIZED_TO_EDIT=User is not authorized to edit the content. Please contact your system administrator. +FileService.ERROR_INVALID_LOG_FILENAME=Invalid log file name {0} +FileService.ERROR_UNABLE_TO_GET_PLATFORM_EXPORTER=Unable to get platform exporter from the system. Platform exporter has not been configured +FileService.ERROR_UNABLE_TO_GET_EXPORT_LOGGER=Unable to get export logger from the platform exporter. Export logger is null" \ No newline at end of file diff --git a/extensions/src/test/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporterTest.java b/extensions/src/test/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporterTest.java index 65ca89a6fbd..65969dff0b7 100644 --- a/extensions/src/test/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporterTest.java +++ b/extensions/src/test/java/org/pentaho/platform/plugin/services/exporter/PentahoPlatformExporterTest.java @@ -13,6 +13,7 @@ package org.pentaho.platform.plugin.services.exporter; +import org.apache.logging.log4j.Level; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -29,13 +30,12 @@ import org.pentaho.platform.api.scheduler2.IScheduler; import org.pentaho.platform.api.usersettings.IAnyUserSettingService; import org.pentaho.platform.api.usersettings.pojo.IUserSetting; +import org.pentaho.platform.api.util.IRepositoryExportLogger; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.plugin.action.mondrian.catalog.IMondrianCatalogService; import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalog; -import org.pentaho.platform.plugin.services.importexport.ExportManifestUserSetting; -import org.pentaho.platform.plugin.services.importexport.RoleExport; -import org.pentaho.platform.plugin.services.importexport.UserExport; +import org.pentaho.platform.plugin.services.importexport.*; import org.pentaho.platform.plugin.services.importexport.exportManifest.ExportManifest; import org.pentaho.platform.plugin.services.importexport.exportManifest.bindings.DatabaseConnection; import org.pentaho.platform.plugin.services.importexport.exportManifest.bindings.ExportManifestMetaStore; @@ -48,6 +48,7 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; +import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.IOException; import java.util.ArrayList; @@ -98,6 +99,9 @@ public void setUp() throws Exception { doReturn( "session name" ).when( session ).getName(); exporter = new PentahoPlatformExporter( repo ); + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + exporter.setRepositoryExportLogger( exportLogger ); } @After @@ -154,7 +158,13 @@ public void testExportUsersAndRoles() { UserDetails userDetails = new User( "testUser", "testPassword", true, true, true, true, authList ); when( userDetailsService.loadUserByUsername( nullable( String.class ) ) ).thenReturn( userDetails ); + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + exporter.setRepositoryExportLogger( exportLogger ); exporter.exportUsersAndRoles(); + exportLogger.endJob(); verify( manifest ).addUserExport( userCaptor.capture() ); verify( manifest ).addRoleExport( roleCaptor.capture() ); @@ -172,8 +182,13 @@ public void testExportUsersAndRoles() { public void testExportMetadata_noModels() throws Exception { IMetadataDomainRepository mdr = mock( IMetadataDomainRepository.class ); exporter.setMetadataDomainRepository( mdr ); - + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + exporter.setRepositoryExportLogger( exportLogger ); exporter.exportMetadataModels(); + exportLogger.endJob(); assertEquals( 0, exporter.getExportManifest().getMetadataList().size() ); } @@ -194,13 +209,18 @@ public void testExportMetadata() throws Exception { inputMap.put( "test1", is ); doReturn( inputMap ).when( exporterSpy ).getDomainFilesData( "test1" ); - + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + exporterSpy.setRepositoryExportLogger( exportLogger ); exporterSpy.exportMetadataModels(); + exportLogger.endJob(); assertEquals( 1, exporterSpy.getExportManifest().getMetadataList().size() ); assertEquals( "test1", exporterSpy.getExportManifest().getMetadataList().get( 0 ).getDomainId() ); assertEquals( PentahoPlatformExporter.METADATA_PATH_IN_ZIP + "test1.xmi", - exporterSpy.getExportManifest().getMetadataList().get( 0 ).getFile() ); + exporterSpy.getExportManifest().getMetadataList().get( 0 ).getFile() ); } @Test @@ -217,8 +237,13 @@ public void testExportDatasources() throws Exception { datasources.add( icon ); when( svc.getDatasources() ).thenReturn( datasources ); - + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + exporterSpy.setRepositoryExportLogger( exportLogger ); exporterSpy.exportDatasources(); + exportLogger.endJob(); assertEquals( 1, exporterSpy.getExportManifest().getDatasourceList().size() ); DatabaseConnection exportedDatabaseConnection = exporterSpy.getExportManifest().getDatasourceList().get( 0 ); @@ -244,9 +269,13 @@ public void testParseXmlaEnabled() throws Exception { public void testExportMondrianSchemas_noCatalogs() throws Exception { PentahoSystem.registerObject( mondrianCatalogService ); exporterSpy.setMondrianCatalogRepositoryHelper( mondrianCatalogRepositoryHelper ); - + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + exporterSpy.setRepositoryExportLogger( exportLogger ); exporterSpy.exportMondrianSchemas(); - + exportLogger.endJob(); verify( exportManifest, never() ).addMondrian( ArgumentMatchers.any( ExportManifestMondrian.class ) ); verify( mondrianCatalogRepositoryHelper, never() ).getModrianSchemaFiles( nullable( String.class ) ); } @@ -284,7 +313,7 @@ public void testExportMondrianSchemas_AdditionalParametersSaved() throws Excepti public void testPerformExportMondrianSchemas_XmlUnsafeDataSourceInfoSaved() throws IOException { final String dataSourceInfo = "DataSource=\""DS "Test's" & <Fun>"\";" - + "DynamicSchemaProcessor=\""DSP's & "Other" <stuff>"\";"; + + "DynamicSchemaProcessor=\""DSP's & "Other" <stuff>"\";"; final String dataSourceExpectedValue = "\"DS \"Test's\" & \""; final String dynamicSchemaProcessorExpectedValue = "\"DSP's & \"Other\" \""; @@ -316,8 +345,13 @@ private void executeExportMondrianSchemasForDataSourceInfo( String catalogName, inputMap.put( catalogName, is ); when( mondrianCatalogRepositoryHelper.getModrianSchemaFiles( catalogName ) ).thenReturn( inputMap ); exporterSpy.zos = mock( ZipOutputStream.class ); - + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + exporterSpy.setRepositoryExportLogger( exportLogger ); exporterSpy.exportMondrianSchemas(); + exportLogger.endJob(); } @Test @@ -327,8 +361,13 @@ public void testExportMetaStore() throws Exception { exporterSpy.setRepoMetaStore( metastore ); ExportManifest manifest = mock( ExportManifest.class ); exporterSpy.setExportManifest( manifest ); - + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + exporterSpy.setRepositoryExportLogger( exportLogger ); exporterSpy.exportMetastore(); + exportLogger.endJob(); verify( exporterSpy.zos ).putNextEntry( ArgumentMatchers.any( ZipEntry.class ) ); verify( manifest ).setMetaStore( ArgumentMatchers.any( ExportManifestMetaStore.class ) ); } diff --git a/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessorTest.java b/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessorTest.java index ffb6ae36a1d..0fb2e72575c 100644 --- a/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessorTest.java +++ b/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleFilesProcessorTest.java @@ -73,21 +73,22 @@ public void testProcessLocaleFilesIgnoreProperties() throws Exception { importer.setRepositoryImportLogger( new Log4JRepositoryImportLogger() ); ByteArrayInputStream localePropertiesContent = new ByteArrayInputStream( - ("description=This runs a simple Kettle transformation filtering records from the Quandrant_Actuals sample data " - + "table, and sending a Hello message to each position.\nname=1. Hello ETL") - .getBytes() ); + ( "description=This runs a simple Kettle transformation filtering records from the Quandrant_Actuals sample data " + + "table, and sending a Hello message to each position.\nname=1. Hello ETL" ) + .getBytes() ); ByteArrayInputStream localeContent = - new ByteArrayInputStream( "file.title=fileTitle\ntitle=SampleTransformation\nfile.description=".getBytes() ); + new ByteArrayInputStream( "file.title=fileTitle\ntitle=SampleTransformation\nfile.description=".getBytes() ); localeFilesProcessor = spy( new LocaleFilesProcessor() ); localeFilesProcessor.createLocaleEntry( "/", "file1.properties", null, "description", null, localePropertiesContent, 0 ); localeFilesProcessor.createLocaleEntry( "/", "file1.locale", null, "description", null, localeContent, 0 ); - localeFilesProcessor.processLocaleFiles( importer ); + int count = localeFilesProcessor.processLocaleFiles( importer ); + System.out.println( count ); Mockito.verify( localeFilesProcessor, times( 1 ) ) - .proceed( any( IPlatformImporter.class ), any( RepositoryFileImportBundle.Builder.class ), nullable( String.class ), - any( LocaleFileDescriptor.class ) ); + .proceed( any( IPlatformImporter.class ), any( RepositoryFileImportBundle.Builder.class ), nullable( String.class ), + any( LocaleFileDescriptor.class ) ); } @Test @@ -103,23 +104,24 @@ public void testProcessLocaleFilesDontIgnoreProperties() throws Exception { importer.setRepositoryImportLogger( new Log4JRepositoryImportLogger() ); ByteArrayInputStream localePropertiesContent = new ByteArrayInputStream( - ("description=This runs a simple Kettle transformation filtering records from the Quandrant_Actuals sample data " - + "table, and sending a Hello message to each position.\nname=1. Hello ETL") - .getBytes() ); + ( "description=This runs a simple Kettle transformation filtering records from the Quandrant_Actuals sample data " + + "table, and sending a Hello message to each position.\nname=1. Hello ETL" ) + .getBytes() ); localeFilesProcessor = spy( new LocaleFilesProcessor() ); localeFilesProcessor.createLocaleEntry( "/", "file1.properties", null, "description", null, localePropertiesContent, 0 ); - localeFilesProcessor.processLocaleFiles( importer ); + int count = localeFilesProcessor.processLocaleFiles( importer ); + System.out.println( count ); Mockito.verify( localeFilesProcessor, times( 1 ) ) - .proceed( any( IPlatformImporter.class ), any( RepositoryFileImportBundle.Builder.class ), nullable( String.class ), - any( LocaleFileDescriptor.class ) ); + .proceed( any( IPlatformImporter.class ), any( RepositoryFileImportBundle.Builder.class ), nullable( String.class ), + any( LocaleFileDescriptor.class ) ); } @Test public void testProcessLocaleFilesTwoLocaleFiles() throws Exception { IRepositoryContentConverterHandler converterHandler = - new DefaultRepositoryContentConverterHandler( new HashMap() ); + new DefaultRepositoryContentConverterHandler( new HashMap() ); List localeMimeList = new ArrayList(); localeMimeList.add( new MimeType( "text/locale", "locale" ) ); @@ -140,8 +142,8 @@ public void testProcessLocaleFilesTwoLocaleFiles() throws Exception { StringBuffer localePropertiesContent = new StringBuffer(); localePropertiesContent.append( - "description=This runs a simple Kettle transformation filtering records from the Quandrant_Actuals sample data " - + "table, and sending a Hello message to each position.\n" ); + "description=This runs a simple Kettle transformation filtering records from the Quandrant_Actuals sample data " + + "table, and sending a Hello message to each position.\n" ); localePropertiesContent.append( "name=1. Hello ETL" ); assertTrue( processIsLocalFile( "SampleTransformation.properties", localePropertiesContent ) ); @@ -153,8 +155,8 @@ public void testProcessLocaleFilesTwoLocaleFiles() throws Exception { assertTrue( processIsLocalFile( "SampleTransformation.xaction.locale", localeContent ) ); - localeFilesProcessor.processLocaleFiles( importer ); - + int count = localeFilesProcessor.processLocaleFiles( importer ); + System.out.println( count ); //verify that in case of both .properties and .locale files are at input the only one proceeded is .locale Mockito.verify( localeImportHandlerSpy, times( 1 ) ).importFile( any( IPlatformImportBundle.class ) ); ArgumentCaptor argument = ArgumentCaptor.forClass( IPlatformImportBundle.class ); @@ -165,10 +167,10 @@ public void testProcessLocaleFilesTwoLocaleFiles() throws Exception { @Test public void isXMLLocaleTest() { String xml = "\n" - + "" - + "the name" - + "the description" - + ""; + + "" + + "the name" + + "the description" + + ""; localeFilesProcessor = new LocaleFilesProcessor(); assertTrue( localeFilesProcessor.isXMLlocale( new ByteArrayInputStream( xml.getBytes() ) ) ); } @@ -176,8 +178,8 @@ public void isXMLLocaleTest() { @Test public void isXMLLocaleWrongFormatTest() { String xml = "\n" - + "the name" - + "the description"; + + "the name" + + "the description"; localeFilesProcessor = new LocaleFilesProcessor(); assertFalse( localeFilesProcessor.isXMLlocale( new ByteArrayInputStream( xml.getBytes() ) ) ); } @@ -185,10 +187,10 @@ public void isXMLLocaleWrongFormatTest() { @Test public void isXMLLocaleEmptyValuesTest() { String xml = "\n" - + "" - + "" - + "" - + ""; + + "" + + "" + + "" + + ""; localeFilesProcessor = new LocaleFilesProcessor(); assertFalse( localeFilesProcessor.isXMLlocale( new ByteArrayInputStream( xml.getBytes() ) ) ); } @@ -196,7 +198,7 @@ public void isXMLLocaleEmptyValuesTest() { private boolean processIsLocalFile( String fileName, StringBuffer localeContent ) throws Exception { RepositoryFile file = new RepositoryFile.Builder( fileName ).build(); RepositoryFileBundle repoFileBundle = - new RepositoryFileBundle( file, null, StringUtils.EMPTY, null, DEFAULT_ENCODING, null ); + new RepositoryFileBundle( file, null, StringUtils.EMPTY, null, DEFAULT_ENCODING, null ); return localeFilesProcessor.isLocaleFile( repoFileBundle, "/", localeContent.toString().getBytes() ); } diff --git a/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleImportHandlerTest.java b/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleImportHandlerTest.java index 6900c23b641..8fa7ba87e4a 100644 --- a/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleImportHandlerTest.java +++ b/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/LocaleImportHandlerTest.java @@ -36,6 +36,7 @@ import org.pentaho.platform.util.messages.LocaleHelper; import org.springframework.test.util.ReflectionTestUtils; import org.xml.sax.SAXException; + import javax.xml.parsers.ParserConfigurationException; import java.io.ByteArrayInputStream; import java.io.File; @@ -149,7 +150,8 @@ public void testImportLocaleFiles() throws Exception { localeContent = new StringBuffer( "bla bla" ); assertFalse( processIsLocalFile( "test.properties", localeContent ) ); - localeFilesProcessor.processLocaleFiles( importer ); + int count = localeFilesProcessor.processLocaleFiles( importer ); + System.out.println( count ); } @Test @@ -163,12 +165,12 @@ public void testImportDefaultPropertiesFiles() { when( mockLocale.getFile().getName() ).thenReturn( "someFile.properties" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "someFile.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle.getFile() ); when( mockUnifiedRepository.getChildren( nullable( Integer.class ) ) ).thenReturn( localeFolderChildren ); @@ -194,12 +196,12 @@ public void testImportLocalizedPropertiesFiles_fr() { when( mockLocale.getFile().getName() ).thenReturn( "someFile_fr.properties" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "someFile.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle.getFile() ); when( mockUnifiedRepository.getChildren( nullable( Integer.class ) ) ).thenReturn( localeFolderChildren ); @@ -225,12 +227,12 @@ public void testImportLocalizedPropertiesFiles_en_us() { when( mockLocale.getFile().getName() ).thenReturn( "someFile_en_US.properties" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "someFile.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle.getFile() ); when( mockUnifiedRepository.getChildren( nullable( Integer.class ) ) ).thenReturn( localeFolderChildren ); @@ -255,8 +257,8 @@ public void testImportLocalizedPropertiesFiles_en_gb() { when( mockLocale.getFile().getName() ).thenReturn( "someFile_en_GB.properties" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "someFile.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); @@ -283,12 +285,12 @@ public void testImportDefaultWithFileExtensionPropertiesFiles() { when( mockLocale.getFile().getName() ).thenReturn( "someFile.xaction.properties" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "someFile.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle.getFile() ); when( mockUnifiedRepository.getChildren( nullable( Integer.class ) ) ).thenReturn( localeFolderChildren ); @@ -312,12 +314,12 @@ public void testImportLocalizedWithFileExtensionPropertiesFiles_fr() { when( mockLocale.getFile().getName() ).thenReturn( "some_File.xaction_fr.locale" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "some_File.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle.getFile() ); when( mockUnifiedRepository.getChildren( nullable( Integer.class ) ) ).thenReturn( localeFolderChildren ); @@ -341,12 +343,12 @@ public void testImportLocalizedWithFileExtensionPropertiesFiles_en_us() { when( mockLocale.getFile().getName() ).thenReturn( "someFile.xaction_en_US.locale" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "someFile.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle.getFile() ); when( mockUnifiedRepository.getChildren( nullable( Integer.class ) ) ).thenReturn( localeFolderChildren ); @@ -372,12 +374,12 @@ public void testImportLocalizedWithFileExtensionPropertiesFiles_en_gb() { when( mockLocale.getFile().getName() ).thenReturn( "someFile.xaction_en_GB.properties" ); String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle = createBundle( propertiesContent, "someFile.xaction" ); when( mockUnifiedRepository.getFile( nullable( String.class ) ) ).thenReturn( importBundle.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle.getFile() ); when( mockUnifiedRepository.getChildren( nullable( Integer.class ) ) ).thenReturn( localeFolderChildren ); @@ -462,8 +464,8 @@ public void testImportLocaleFolderChild() { String propertyFile = "someFile_rf.xaction.properties"; String propertiesContent = - "description=Some Description\n" - + "title=Some Title"; + "description=Some Description\n" + + "title=Some Title"; RepositoryFileImportBundle importBundle1 = createBundle( propertiesContent, someFile1 ); when( mockUnifiedRepository.getFile( FILE_BUNDLE_PATH + someFile1 ) ).thenReturn( importBundle1.getFile() ); RepositoryFileImportBundle importBundle2 = createBundle( propertiesContent, someFile2 ); @@ -473,7 +475,7 @@ public void testImportLocaleFolderChild() { RepositoryFileImportBundle importProperties = createBundle( propertiesContent, propertyFile ); when( mockUnifiedRepository.getFile( FILE_BUNDLE_PATH + propertyFile ) ).thenReturn( importProperties.getFile() ); - List localeFolderChildren = new ArrayList<>( ); + List localeFolderChildren = new ArrayList<>(); localeFolderChildren.add( importBundle1.getFile() ); localeFolderChildren.add( importBundle2.getFile() ); localeFolderChildren.add( importBundle3.getFile() ); @@ -549,8 +551,8 @@ public void shouldNotFailAndReturnNullWhenMaliciousXmlIsGiven() throws IOExcepti @Test public void shouldNotFailAndReturnNotNullWhenLegalXmlIsGiven() throws Exception { String xml = "\n" - + "" - + ""; + + "" + + ""; LocaleImportHandler lih = new LocaleImportHandler( Collections.emptyList(), null ); assertNotNull( lih.getLocalBundleDocument( new StringBufferInputStream( xml ) ) ); @@ -563,10 +565,10 @@ public void loadPropertiesByXmlTest() throws Exception { when( repFileBundleMock.getFile() ).thenReturn( repFileMock ); when( repFileMock.getName() ).thenReturn( "index.xml" ); String xml = "\n" - + "" - + "the name" - + "the description" - + ""; + + "" + + "the name" + + "the description" + + ""; when( repFileBundleMock.getInputStream() ).thenReturn( new ByteArrayInputStream( xml.getBytes() ) ); assertEquals( localeImportHandler.loadPropertiesByXml( repFileBundleMock ).size(), 2 ); } @@ -578,10 +580,10 @@ public void loadPropertiesByXmlReferenceToVariableInNameTest() throws Exception when( repFileBundleMock.getFile() ).thenReturn( repFileMock ); when( repFileMock.getName() ).thenReturn( "index.xml" ); String xml = "\n" - + "" - + "%name" - + "the description" - + ""; + + "" + + "%name" + + "the description" + + ""; when( repFileBundleMock.getInputStream() ).thenReturn( new ByteArrayInputStream( xml.getBytes() ) ); assertEquals( localeImportHandler.loadPropertiesByXml( repFileBundleMock ).size(), 1 ); } @@ -593,10 +595,10 @@ public void loadPropertiesByXmlReferenceToVariableInDescriptionTest() throws Exc when( repFileBundleMock.getFile() ).thenReturn( repFileMock ); when( repFileMock.getName() ).thenReturn( "index.xml" ); String xml = "\n" - + "" - + "the name" - + "%description" - + ""; + + "" + + "the name" + + "%description" + + ""; when( repFileBundleMock.getInputStream() ).thenReturn( new ByteArrayInputStream( xml.getBytes() ) ); assertEquals( localeImportHandler.loadPropertiesByXml( repFileBundleMock ).size(), 1 ); } @@ -608,10 +610,10 @@ public void loadPropertiesByXmlReferenceToVariablesTest() throws Exception { when( repFileBundleMock.getFile() ).thenReturn( repFileMock ); when( repFileMock.getName() ).thenReturn( "index.xml" ); String xml = "\n" - + "" - + "%name" - + "%description" - + ""; + + "" + + "%name" + + "%description" + + ""; when( repFileBundleMock.getInputStream() ).thenReturn( new ByteArrayInputStream( xml.getBytes() ) ); assertEquals( localeImportHandler.loadPropertiesByXml( repFileBundleMock ).size(), 0 ); } @@ -628,7 +630,7 @@ public void loadPropertiesByXmlWrongFormatTest() { } @Test - public void loadPropertiesByXmlInputStreamExceptionTest() throws Exception { + public void loadPropertiesByXmlInputStreamExceptionTest() throws Exception { RepositoryFileImportBundle repFileBundleMock = mock( RepositoryFileImportBundle.class ); RepositoryFile repFileMock = mock( RepositoryFile.class ); IPlatformImporter platformImporterMock = mock( IPlatformImporter.class ); diff --git a/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/PlatformImporterTest.java b/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/PlatformImporterTest.java index 026d4165f12..a5dc07c5ae6 100644 --- a/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/PlatformImporterTest.java +++ b/extensions/src/test/java/org/pentaho/platform/plugin/services/importer/PlatformImporterTest.java @@ -71,6 +71,7 @@ public void testNoMatchingMime() throws Exception { try { importer.setRepositoryImportLogger( importLogger ); + importer.getRepositoryImportLogger().setPerformingRestore( false ); importer.importFile( bundle1 ); String result = new String( outputStream.toByteArray() ); assertTrue( result.contains( "Start Import Job" ) ); // Logged at INFO level @@ -111,10 +112,10 @@ public void testMatchingMimeAndHandler() throws Exception { "parameterized-domain-id" ) ).build(); importer.importFile( bundle1 ); - + verify( mockImportHandler, times( 1 ) ).importFile( bundle1 ); } - + @Test public void testUseDefaultHandler() throws Exception { @@ -133,7 +134,7 @@ public void testUseDefaultHandler() throws Exception { new PentahoPlatformImporter( handlers, new DefaultRepositoryContentConverterHandler( new HashMap() ) ); - + IPlatformImportHandler mockDefaultImportHandler = mock( IPlatformImportHandler.class ); importer.setDefaultHandler( mockDefaultImportHandler ); importer.setRepositoryImportLogger( importLogger ); @@ -147,7 +148,7 @@ public void testUseDefaultHandler() throws Exception { "parameterized-domain-id" ) ).build(); importer.importFile( bundle1 ); - + verify( mockDefaultImportHandler, times( 1 ) ).importFile( bundle1 ); } } diff --git a/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessorTest.java b/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessorTest.java index 896ae97029b..d45c11c4a9c 100644 --- a/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessorTest.java +++ b/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/BaseExportProcessorTest.java @@ -33,6 +33,7 @@ import org.junit.Before; import org.junit.Test; import org.pentaho.platform.api.repository2.unified.RepositoryFile; +import org.pentaho.platform.api.importexport.ExportException; import java.io.File; import java.io.IOException; @@ -56,13 +57,13 @@ public File performExport( RepositoryFile exportRepositoryFile ) throws ExportEx @Override public void exportDirectory( RepositoryFile repositoryDir, OutputStream outputStream, String filePath ) - throws ExportException, IOException { + throws ExportException, IOException { // To change body of implemented methods use File | Settings | File Templates. } @Override public void exportFile( RepositoryFile repositoryFile, OutputStream outputStream, String filePath ) - throws ExportException, IOException { + throws ExportException, IOException { // To change body of implemented methods use File | Settings | File Templates. } } diff --git a/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessorTest.java b/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessorTest.java index ceeb44abef3..2d3865c546e 100644 --- a/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessorTest.java +++ b/extensions/src/test/java/org/pentaho/platform/plugin/services/importexport/ZipExportProcessorTest.java @@ -28,6 +28,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.Serializable; +import java.io.ByteArrayOutputStream; + import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -40,6 +42,7 @@ import java.util.zip.ZipInputStream; import org.apache.commons.io.FileUtils; +import org.apache.logging.log4j.Level; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -63,6 +66,7 @@ import org.pentaho.platform.api.repository2.unified.RepositoryFileSid.Type; import org.pentaho.platform.api.repository2.unified.RepositoryRequest; import org.pentaho.platform.api.repository2.unified.data.simple.SimpleRepositoryFileData; +import org.pentaho.platform.api.util.IRepositoryExportLogger; import org.pentaho.platform.core.mimetype.MimeType; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; @@ -101,7 +105,7 @@ public static void afterClass() throws IOException { @Before public void init() throws IOException, PlatformInitializationException, DomainIdNullException, - DomainAlreadyExistsException, DomainStorageException { + DomainAlreadyExistsException, DomainStorageException { List availableLocales = java.util.Collections.singletonList( LOCALE_DEFAULT ); Properties localePropertries = new Properties(); @@ -119,7 +123,7 @@ public void init() throws IOException, PlatformInitializationException, DomainId final RepositoryFile fileX = new RepositoryFile.Builder( "eval (+)%.prpt" ).path( "/home/test user/two words/eval (+)%.prpt" ).id( "/home/test user/two words/eval (+)%.prpt" ).folder( false ).build(); - final RepositoryFile[] repoFiles = new RepositoryFile[] { file0, file1, file2, file3, fileX }; + final RepositoryFile[] repoFiles = new RepositoryFile[] {file0, file1, file2, file3, fileX}; final Map repoFilesMap = new HashMap(); for ( RepositoryFile f : repoFiles ) { repoFilesMap.put( f.getId(), f ); @@ -130,7 +134,7 @@ public void init() throws IOException, PlatformInitializationException, DomainId @Override public RepositoryFile answer( InvocationOnMock invocation ) throws Throwable { Object[] args = invocation.getArguments(); - final Object fileId = args[0]; + final Object fileId = args[ 0 ]; return getRepoFile( repoFilesMap, fileId ); } @@ -152,16 +156,16 @@ public RepositoryFile answer( InvocationOnMock invocation ) throws Throwable { @Override public List answer( InvocationOnMock invocation ) throws Throwable { // returns the following item from - RepositoryRequest r = (RepositoryRequest) invocation.getArguments()[0]; + RepositoryRequest r = (RepositoryRequest) invocation.getArguments()[ 0 ]; String path = r.getPath(); RepositoryFile thisFile = getRepoFile( repoFilesMap, path ); if ( thisFile == null || !thisFile.isFolder() ) { return Collections.emptyList(); } for ( int i = 0, n = repoFiles.length - 1; i < n; i++ ) { - RepositoryFile iFile = repoFiles[i]; + RepositoryFile iFile = repoFiles[ i ]; if ( iFile == thisFile || iFile.getId().equals( thisFile.getId() ) ) { - return Collections.singletonList( repoFiles[i + 1] ); + return Collections.singletonList( repoFiles[ i + 1 ] ); } } return Collections.emptyList(); @@ -185,10 +189,10 @@ public List answer( InvocationOnMock invocation ) throws Throwab Answer answerGetDataForRead = new Answer() { @Override public IRepositoryFileData answer( InvocationOnMock invocation ) throws Throwable { - Serializable id = (Serializable) invocation.getArguments()[0]; + Serializable id = (Serializable) invocation.getArguments()[ 0 ]; RepositoryFile file = getRepoFile( repoFilesMap, id ); if ( !file.isFolder() ) { - return new SimpleRepositoryFileData( new ByteArrayInputStream( new byte[0] ), "UTF-8", MIME_PRPT.getName() ); + return new SimpleRepositoryFileData( new ByteArrayInputStream( new byte[ 0 ] ), "UTF-8", MIME_PRPT.getName() ); } return null; } @@ -300,11 +304,16 @@ public void testPerformExport_withoutManifest() throws Exception { RepositoryFile expFolder = repo.getFile( expFolderPath ); assertNotNull( expFolder ); + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + zipNoMF.setRepositoryExportLogger( exportLogger ); File result = zipNoMF.performExport( repo.getFile( expFolderPath ) ); - + exportLogger.endJob(); Set zipEntriesFiles = extractZipEntries( result ); final String[] expectedEntries = - new String[] { "two words/eval (+)%.prpt", "two words/eval (+)%.prpt_en.locale", "two words/index_en.locale" }; + new String[] {"two words/eval (+)%.prpt", "two words/eval (+)%.prpt_en.locale", "two words/index_en.locale"}; for ( String e : expectedEntries ) { assertTrue( "expected entry: [" + e + "]", zipEntriesFiles.contains( e ) ); } @@ -321,13 +330,18 @@ public void testPerformExport_withManifest() throws Exception { RepositoryFile expFolder = repo.getFile( expFolderPath ); assertNotNull( expFolder ); - + // mock logger to prevent npe + IRepositoryExportLogger exportLogger = new Log4JRepositoryExportLogger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + exportLogger.startJob( outputStream, Level.INFO, new RepositoryTextLayout( Level.INFO ) ); + zipMF.setRepositoryExportLogger( exportLogger ); + exportLogger.endJob(); File result = zipMF.performExport( repo.getFile( expFolderPath ) ); Set zipEntriesFiles = extractZipEntries( result ); final String[] expectedEntries = - new String[] { "two+words/eval+%28%2B%29%25.prpt", "two+words/eval+%28%2B%29%25.prpt_en.locale", - "two+words/index_en.locale", "exportManifest.xml" }; + new String[] {"two+words/eval+%28%2B%29%25.prpt", "two+words/eval+%28%2B%29%25.prpt_en.locale", + "two+words/index_en.locale", "exportManifest.xml"}; for ( String e : expectedEntries ) { assertTrue( "expected entry: [" + e + "]", zipEntriesFiles.contains( e ) ); }