/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* Copyright 2006 - 2016 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.platform.web.http.api.resources.operations;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.repository2.unified.IRepositoryFileData;
import org.pentaho.platform.api.repository2.unified.IUnifiedRepository;
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.repository2.unified.UnifiedRepositoryAccessDeniedException;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.repository2.unified.webservices.DefaultUnifiedRepositoryWebService;
import org.pentaho.platform.repository2.unified.webservices.RepositoryFileAdapter;
import org.pentaho.platform.repository2.unified.webservices.RepositoryFileDto;
import org.pentaho.platform.web.http.api.resources.services.FileService;
import org.pentaho.platform.web.http.api.resources.utils.FileUtils;
import org.pentaho.platform.web.http.api.resources.utils.RepositoryFileHelper;
import org.pentaho.platform.web.http.messages.Messages;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class CopyFilesOperation {
private RepositoryFile destDir;
private List<String> sourceFileIds;
private String path;
private int mode;
private IUnifiedRepository repository;
private DefaultUnifiedRepositoryWebService defaultUnifiedRepositoryWebService;
private static final Log logger = LogFactory.getLog( FileService.class );
public static final Integer DEFAULT_DEEPNESS = 10;
public CopyFilesOperation( List<String> sourceFileIds, String destDirPath, int overrideMode ) {
this( PentahoSystem.get( IUnifiedRepository.class ), new DefaultUnifiedRepositoryWebService(), sourceFileIds,
destDirPath, overrideMode );
}
public CopyFilesOperation( IUnifiedRepository repository,
DefaultUnifiedRepositoryWebService defaultUnifiedRepositoryWebService,
List<String> sourceFileIds, String destDirPath, int overrideMode ) {
if ( repository == null ) {
throw new IllegalArgumentException( "repository cannot be null" );
}
this.repository = repository;
if ( defaultUnifiedRepositoryWebService == null ) {
throw new IllegalArgumentException( "defaultUnifiedRepositoryWebService cannot be null" );
}
this.defaultUnifiedRepositoryWebService = defaultUnifiedRepositoryWebService;
if ( sourceFileIds == null ) {
throw new IllegalArgumentException( "sourceFileIds cannot be null" );
}
if ( sourceFileIds.isEmpty() ) {
throw new IllegalArgumentException( "Nothing to copy, list of files shouldn't be empty" );
}
this.sourceFileIds = sourceFileIds;
if ( destDirPath == null ) {
throw new IllegalArgumentException( "destDirPath cannot be null" );
}
destDir = getRepository().getFile( destDirPath );
if ( destDir == null ) {
throw new IllegalArgumentException( "Directory with destPath: " + destDirPath + " doesn't exist" );
}
if ( !destDir.isFolder() ) {
throw new IllegalArgumentException( destDirPath + " should be a folder" );
}
this.mode = overrideMode;
this.path = destDirPath;
}
public void execute() {
for ( String sourceFileId : getSourceFileIds() ) {
RepositoryFile sourceFile = getRepository().getFileById( sourceFileId );
if ( sourceFile == null ) {
logger.warn( "File with id: " + sourceFileId + " is not found" );
continue;
}
if ( mode == FileService.MODE_OVERWRITE ) {
copyOverrideMode( sourceFile );
} else if ( mode == FileService.MODE_NO_OVERWRITE ) {
copyNoOverrideMode( sourceFile );
} else {
copyRenameMode( sourceFile );
}
}
}
private void copyOverrideMode( RepositoryFile file ) {
if ( sourceAndDestDirAreSame( file.getPath() ) ) {
return;
}
RepositoryFileAcl acl = getRepository().getAcl( file.getId() );
RepositoryFile destFile = getRepository()
.getFile( destDir.getPath() + FileUtils.PATH_SEPARATOR + file.getName() );
if ( destFile == null ) {
// destFile doesn't exist so we'll create it.
RepositoryFile duplicateFile =
new RepositoryFile.Builder( file.getName() ).hidden( file.isHidden() ).versioned(
file.isVersioned() ).build();
final RepositoryFile repositoryFile =
getRepository()
.createFile( destDir.getId(), duplicateFile, RepositoryFileHelper.getFileData( file ), acl,
null );
getRepository()
.setFileMetadata( repositoryFile.getId(), getRepository().getFileMetadata( file.getId() ) );
return;
}
RepositoryFileDto destFileDto = toFileDto( destFile, null, false );
destFileDto.setHidden( file.isHidden() );
destFile = toFile( destFileDto );
final RepositoryFile repositoryFile = getRepository().updateFile( destFile, RepositoryFileHelper.getFileData( file ), null );
getRepository().updateAcl( acl );
getRepository()
.setFileMetadata( repositoryFile.getId(), getRepository().getFileMetadata( file.getId() ) );
}
private void copyNoOverrideMode( RepositoryFile repoFile ) {
if ( sourceAndDestDirAreSame( repoFile.getPath() ) ) {
return;
}
RepositoryFile destFile =
getRepository().getFile( destDir.getPath() + FileUtils.PATH_SEPARATOR + repoFile.getName() );
if ( destFile != null ) {
// file exists already
return;
}
final RepositoryFile repositoryFile;
final RepositoryFile duplicateFile;
if ( repoFile.isFolder() ) {
duplicateFile = repoFile.clone();
repositoryFile = getRepository()
.createFolder( destDir.getId(), duplicateFile, getRepository().getAcl( repoFile.getId() ), null );
performFolderDeepCopy( repoFile, repositoryFile, DEFAULT_DEEPNESS );
} else {
duplicateFile = new RepositoryFile.
Builder( repoFile.getName() )
.hidden( repoFile.isHidden() )
.folder( repoFile.isFolder() )
.versioned( repoFile.isVersioned() )
.build();
repositoryFile = getRepository()
.createFile( destDir.getId(), duplicateFile, RepositoryFileHelper.getFileData( repoFile ),
getRepository().getAcl( repoFile.getId() ),
null );
}
getRepository()
.setFileMetadata( repositoryFile.getId(), getRepository().getFileMetadata( repoFile.getId() ) );
}
private void copyRenameMode( RepositoryFile repoFile ) {
// First try to see if regular name is available
String repoFileName = repoFile.getName();
String copyText = "";
String rootCopyText = "";
String nameNoExtension = repoFileName;
String extension = "";
int indexOfDot = repoFileName.lastIndexOf( '.' );
if ( !( indexOfDot == -1 ) ) {
nameNoExtension = repoFileName.substring( 0, indexOfDot );
extension = repoFileName.substring( indexOfDot );
}
RepositoryFileDto
testFile =
getRepoWs().getFile( path + FileUtils.PATH_SEPARATOR + nameNoExtension + extension ); //$NON-NLS-1$
if ( testFile != null ) {
// Second try COPY_PREFIX, If the name already ends with a COPY_PREFIX don't append twice
if ( !nameNoExtension
.endsWith( Messages.getInstance().getString( "FileResource.COPY_PREFIX" ) ) ) { //$NON-NLS-1$
copyText = rootCopyText = Messages.getInstance().getString( "FileResource.COPY_PREFIX" );
repoFileName = nameNoExtension + copyText + extension;
testFile = getRepoWs().getFile( path + FileUtils.PATH_SEPARATOR + repoFileName );
}
}
// Third try COPY_PREFIX + DUPLICATE_INDICATOR
Integer nameCount = 1;
while ( testFile != null ) {
nameCount++;
copyText =
rootCopyText + Messages.getInstance().getString( "FileResource.DUPLICATE_INDICATOR", nameCount );
repoFileName = nameNoExtension + copyText + extension;
testFile = getRepoWs().getFile( path + FileUtils.PATH_SEPARATOR + repoFileName );
}
IRepositoryFileData data = RepositoryFileHelper.getFileData( repoFile );
RepositoryFileAcl acl = getRepository().getAcl( repoFile.getId() );
RepositoryFile duplicateFile = null;
final RepositoryFile repositoryFile;
if ( repoFile.isFolder() ) {
// If the title is different than the source file, copy it separately
if ( !repoFile.getName().equals( repoFile.getTitle() ) ) {
duplicateFile =
new RepositoryFile.Builder( repoFileName ).title( RepositoryFile.DEFAULT_LOCALE,
repoFile.getTitle() + copyText ).hidden( repoFile.isHidden() ).versioned(
repoFile.isVersioned() ).folder( true ).build();
} else {
duplicateFile = new RepositoryFile.Builder( repoFileName ).hidden( repoFile.isHidden() ).folder( true ).build();
}
repositoryFile = getRepository()
.createFolder( destDir.getId(), duplicateFile, acl, null );
performFolderDeepCopy( repoFile, repositoryFile, DEFAULT_DEEPNESS );
} else {
// If the title is different than the source file, copy it separately
if ( !repoFile.getName().equals( repoFile.getTitle() ) ) {
duplicateFile =
new RepositoryFile.Builder( repoFileName ).title( RepositoryFile.DEFAULT_LOCALE,
repoFile.getTitle() + copyText ).hidden( repoFile.isHidden() ).versioned(
repoFile.isVersioned() ).build();
} else {
duplicateFile = new RepositoryFile.Builder( repoFileName ).hidden( repoFile.isHidden() ).build();
}
repositoryFile =
getRepository().createFile( destDir.getId(), duplicateFile, data, acl, null );
}
if ( repositoryFile == null ) {
throw new UnifiedRepositoryAccessDeniedException( Messages.getInstance().getString(
"JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED_CREATE", destDir.getId() ) );
}
getRepository().setFileMetadata( repositoryFile.getId(), getRepository().getFileMetadata( repoFile.getId() ) );
}
private boolean sourceAndDestDirAreSame( String path ) {
String pathWithoutFileName =
path.substring( 0, path.lastIndexOf( FileUtils.PATH_SEPARATOR ) );
return pathWithoutFileName.equals( destDir.getPath() );
}
/**
* @param from folder, from witch we will copy content
* @param to folder, in witch we will copy content
* @param deepness deepness of child entries in each folder
*/
protected void performFolderDeepCopy( RepositoryFile from, RepositoryFile to, Integer deepness ) {
if ( from == null || to == null ) {
throw new IllegalArgumentException( "Folder should not be null" );
}
if ( !from.isFolder() ) {
throw new IllegalArgumentException( from.getPath() + " is not a folder" );
}
if ( !to.isFolder() ) {
throw new IllegalArgumentException( to.getPath() + " is not a folder" );
}
if ( deepness == null || deepness < 0 ) {
deepness = DEFAULT_DEEPNESS;
}
List<RepositoryFile> children =
getRepository().getChildren( createRepoRequest( from, deepness ) );
for ( RepositoryFile repoFile : children ) {
if ( repoFile.isFolder() ) {
RepositoryFile childFolder =
getRepository().createFolder( to.getId(), repoFile, getRepository().getAcl( repoFile.getId() ), null );
performFolderDeepCopy( repoFile, childFolder, deepness );
} else {
getRepository().createFile( to.getId(), repoFile, RepositoryFileHelper.getFileData( repoFile ), null );
}
}
}
protected IUnifiedRepository getRepository() {
if ( repository == null ) {
repository = PentahoSystem.get( IUnifiedRepository.class );
}
return repository;
}
protected DefaultUnifiedRepositoryWebService getRepoWs() {
if ( defaultUnifiedRepositoryWebService == null ) {
defaultUnifiedRepositoryWebService = new DefaultUnifiedRepositoryWebService();
}
return defaultUnifiedRepositoryWebService;
}
public List<String> getSourceFileIds() {
return new ArrayList<>( sourceFileIds );
}
/**
* For testing
*/
protected RepositoryRequest createRepoRequest( RepositoryFile repoFile, int deepness ) {
return new RepositoryRequest( String.valueOf( repoFile.getId() ), true, deepness, null );
}
/**
* For testing
*/
protected RepositoryFileDto toFileDto( RepositoryFile repositoryFile, Set<String> memberSet, boolean exclude ) {
return RepositoryFileAdapter.toFileDto( repositoryFile, memberSet, exclude );
}
/**
* For testing
*/
protected RepositoryFile toFile( RepositoryFileDto repositoryFileDto ) {
return RepositoryFileAdapter.toFile( repositoryFileDto );
}
}