/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.pentaho.di.repository.kdr.delegates;
import java.util.ArrayList;
import java.util.List;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.row.value.ValueMetaInteger;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.LongObjectId;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.RepositoryDirectory;
import org.pentaho.di.repository.RepositoryDirectoryInterface;
import org.pentaho.di.repository.kdr.KettleDatabaseRepository;
public class KettleDatabaseRepositoryDirectoryDelegate extends KettleDatabaseRepositoryBaseDelegate {
private static Class<?> PKG = RepositoryDirectory.class; // for i18n purposes, needed by Translator2!!
public KettleDatabaseRepositoryDirectoryDelegate( KettleDatabaseRepository repository ) {
super( repository );
}
public RowMetaAndData getDirectory( ObjectId id_directory ) throws KettleException {
return repository.connectionDelegate.getOneRow(
quoteTable( KettleDatabaseRepository.TABLE_R_DIRECTORY ),
quote( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY ), id_directory );
}
public RepositoryDirectoryInterface loadPathToRoot( ObjectId id_directory ) throws KettleException {
List<RepositoryDirectory> path = new ArrayList<>();
ObjectId directoryId = id_directory;
RowMetaAndData directoryRow = getDirectory( directoryId );
Long parentId = directoryRow.getInteger( 1 );
// Do not load root itself, it doesn't exist.
//
while ( parentId != null && parentId >= 0 ) {
RepositoryDirectory directory = new RepositoryDirectory();
directory.setName( directoryRow.getString( 2, null ) ); // Name of the directory
directory.setObjectId( directoryId );
path.add( directory );
// System.out.println( "+ dir '" + directory.getName() + "'" );
directoryId = new LongObjectId( parentId );
directoryRow = getDirectory( directoryId );
parentId = directoryRow.getInteger( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY_PARENT );
}
RepositoryDirectory root = new RepositoryDirectory();
root.setObjectId( new LongObjectId( 0 ) );
path.add( root );
// Connect the directories to each other.
//
for ( int i = 0; i < path.size() - 1; i++ ) {
RepositoryDirectory item = path.get( i );
RepositoryDirectory parent = path.get( i + 1 );
item.setParent( parent );
parent.addSubdirectory( item );
}
RepositoryDirectory repositoryDirectory = path.get( 0 );
return repositoryDirectory;
}
public RepositoryDirectoryInterface loadRepositoryDirectoryTree( RepositoryDirectoryInterface root ) throws KettleException {
try {
synchronized ( repository ) {
root.clear();
ObjectId[] subids = repository.getSubDirectoryIDs( root.getObjectId() );
for ( int i = 0; i < subids.length; i++ ) {
RepositoryDirectory subdir = new RepositoryDirectory();
loadRepositoryDirectory( subdir, subids[i] );
root.addSubdirectory( subdir );
}
}
return root;
} catch ( Exception e ) {
throw new KettleException( "An error occured loading the directory tree from the repository", e );
}
}
public void loadRepositoryDirectory( RepositoryDirectory repositoryDirectory, ObjectId id_directory ) throws KettleException {
if ( id_directory == null ) {
// This is the root directory, id = OL
id_directory = new LongObjectId( 0L );
}
try {
RowMetaAndData row = getDirectory( id_directory );
if ( row != null ) {
repositoryDirectory.setObjectId( id_directory );
// Content?
//
repositoryDirectory.setName( row.getString( "DIRECTORY_NAME", null ) );
// The sub-directories?
//
ObjectId[] subids = repository.getSubDirectoryIDs( repositoryDirectory.getObjectId() );
for ( int i = 0; i < subids.length; i++ ) {
RepositoryDirectory subdir = new RepositoryDirectory();
loadRepositoryDirectory( subdir, subids[i] );
repositoryDirectory.addSubdirectory( subdir );
}
}
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString(
PKG, "Repository.LoadRepositoryDirectory.ErrorLoading.Exception" ), e );
}
}
/*
* public synchronized RepositoryDirectory refreshRepositoryDirectoryTree() throws KettleException { try {
* RepositoryDirectory tree = new RepositoryDirectory(); loadRepositoryDirectory(tree, tree.getID());
* repository.setDirectoryTree(tree); return tree; } catch (KettleException e) { repository.setDirectoryTree( new
* RepositoryDirectory() ); throw new KettleException("Unable to read the directory tree from the repository!", e); }
* }
*/
private synchronized ObjectId insertDirectory( ObjectId id_directory_parent, RepositoryDirectoryInterface dir ) throws KettleException {
ObjectId id = repository.connectionDelegate.getNextDirectoryID();
String tablename = KettleDatabaseRepository.TABLE_R_DIRECTORY;
RowMetaAndData table = new RowMetaAndData();
table.addValue( new ValueMetaInteger(
KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY ), id );
table.addValue(
new ValueMetaInteger(
KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY_PARENT ),
id_directory_parent );
table.addValue( new ValueMetaString(
KettleDatabaseRepository.FIELD_DIRECTORY_DIRECTORY_NAME ), dir.getName() );
repository.connectionDelegate.getDatabase().prepareInsert( table.getRowMeta(), tablename );
repository.connectionDelegate.getDatabase().setValuesInsert( table );
repository.connectionDelegate.getDatabase().insertRow();
repository.connectionDelegate.getDatabase().closeInsert();
return id;
}
public synchronized void deleteDirectory( ObjectId id_directory ) throws KettleException {
repository.connectionDelegate.performDelete( "DELETE FROM "
+ quoteTable( KettleDatabaseRepository.TABLE_R_DIRECTORY ) + " WHERE "
+ quote( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY ) + " = ? ", id_directory );
}
public synchronized void deleteDirectory( RepositoryDirectoryInterface dir ) throws KettleException {
String[] trans = repository.getTransformationNames( dir.getObjectId(), false ); // TODO : include or exclude deleted
// objects?
String[] jobs = repository.getJobNames( dir.getObjectId(), false ); // TODO : include or exclude deleted objects?
ObjectId[] subDirectories = repository.getSubDirectoryIDs( dir.getObjectId() );
if ( trans.length == 0 && jobs.length == 0 && subDirectories.length == 0 ) {
repository.directoryDelegate.deleteDirectory( dir.getObjectId() );
} else {
deleteDirectoryRecursively( dir );
}
}
private synchronized void deleteDirectoryRecursively( RepositoryDirectoryInterface dir ) throws KettleException {
String[] trans = repository.getTransformationNames( dir.getObjectId(), false ); // TODO : include or exclude deleted
// objects?
String[] jobs = repository.getJobNames( dir.getObjectId(), false ); // TODO : include or exclude deleted objects?
for ( String transformation : trans ) {
ObjectId id = repository.getTransformationID( transformation, dir );
repository.deleteTransformation( id );
}
for ( String job : jobs ) {
ObjectId id = repository.getJobId( job, dir );
repository.deleteJob( id );
}
for ( RepositoryDirectoryInterface subDir : dir.getChildren() ) {
deleteDirectoryRecursively( subDir );
}
repository.directoryDelegate.deleteDirectory( dir.getObjectId() );
}
/**
* Move / rename a directory in the repository
*
* @param id_directory
* Id of the directory to be moved/renamed
* @param id_directory_parent
* Id of the new parent directory (null if the parent does not change)
* @param newName
* New name for this directory (null if the name does not change)
* @throws KettleException
*/
public synchronized void renameDirectory( ObjectId id_directory, ObjectId id_directory_parent, String newName ) throws KettleException {
if ( id_directory.equals( id_directory_parent ) ) {
// Make sure the directory cannot become its own parent
throw new KettleException( "Failed to copy directory into itself" );
} else {
// Make sure the directory does not become a descendant of itself
RepositoryDirectory rd = new RepositoryDirectory();
loadRepositoryDirectory( rd, id_directory );
if ( rd.findDirectory( id_directory_parent ) != null ) {
// The parent directory is a child of this directory. Do not proceed
throw new KettleException( "Directory cannot become a child to itself" );
} else {
// Check for duplication
RepositoryDirectory newParent = new RepositoryDirectory();
loadRepositoryDirectory( newParent, id_directory_parent );
RepositoryDirectory child = newParent.findChild( newName == null ? rd.getName() : newName );
if ( child != null ) {
throw new KettleException( "Destination directory already contains a diectory with requested name" );
}
}
}
if ( id_directory_parent != null || newName != null ) {
RowMetaAndData r = new RowMetaAndData();
String sql = "UPDATE " + quoteTable( KettleDatabaseRepository.TABLE_R_DIRECTORY ) + " SET ";
boolean additionalParameter = false;
if ( newName != null ) {
additionalParameter = true;
sql += quote( KettleDatabaseRepository.FIELD_DIRECTORY_DIRECTORY_NAME ) + " = ?";
r.addValue( new ValueMetaString(
KettleDatabaseRepository.FIELD_DIRECTORY_DIRECTORY_NAME ), newName );
}
if ( id_directory_parent != null ) {
// Add a parameter separator if the first parm was added
if ( additionalParameter ) {
sql += ", ";
}
sql += quote( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY_PARENT ) + " = ?";
r.addValue(
new ValueMetaInteger(
KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY_PARENT ),
id_directory_parent );
}
sql += " WHERE " + quote( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY ) + " = ? ";
r.addValue( new ValueMetaInteger( "id_directory" ), Long.valueOf( id_directory
.toString() ) );
repository.connectionDelegate.getDatabase().execStatement( sql, r.getRowMeta(), r.getData() );
}
}
public synchronized int getNrSubDirectories( ObjectId id_directory ) throws KettleException {
int retval = 0;
RowMetaAndData dirParRow = repository.connectionDelegate.getParameterMetaData( id_directory );
String sql =
"SELECT COUNT(*) FROM "
+ quoteTable( KettleDatabaseRepository.TABLE_R_DIRECTORY ) + " WHERE "
+ quote( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY_PARENT ) + " = ? ";
RowMetaAndData r = repository.connectionDelegate.getOneRow( sql, dirParRow.getRowMeta(), dirParRow.getData() );
if ( r != null ) {
retval = (int) r.getInteger( 0, 0 );
}
return retval;
}
public synchronized ObjectId[] getSubDirectoryIDs( ObjectId id_directory ) throws KettleException {
return repository.connectionDelegate.getIDs( "SELECT "
+ quote( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY ) + " FROM "
+ quoteTable( KettleDatabaseRepository.TABLE_R_DIRECTORY ) + " WHERE "
+ quote( KettleDatabaseRepository.FIELD_DIRECTORY_ID_DIRECTORY_PARENT ) + " = ? ORDER BY "
+ quote( KettleDatabaseRepository.FIELD_DIRECTORY_DIRECTORY_NAME ), id_directory );
}
public void saveRepositoryDirectory( RepositoryDirectoryInterface dir ) throws KettleException {
try {
ObjectId id_directory_parent = null;
if ( dir.getParent() != null ) {
id_directory_parent = dir.getParent().getObjectId();
}
dir.setObjectId( insertDirectory( id_directory_parent, dir ) );
log.logDetailed( "New id of directory = " + dir.getObjectId() );
repository.commit();
} catch ( Exception e ) {
throw new KettleException( "Unable to save directory [" + dir + "] in the repository", e );
}
}
public void delRepositoryDirectory( RepositoryDirectoryInterface dir, boolean deleteNonEmptyFolder ) throws KettleException {
try {
if ( !deleteNonEmptyFolder ) {
String[] trans = repository.getTransformationNames( dir.getObjectId(), false ); // TODO : include or exclude
// deleted objects?
String[] jobs = repository.getJobNames( dir.getObjectId(), false ); // TODO : include or exclude deleted
// objects?
ObjectId[] subDirectories = repository.getSubDirectoryIDs( dir.getObjectId() );
if ( trans.length == 0 && jobs.length == 0 && subDirectories.length == 0 ) {
repository.directoryDelegate.deleteDirectory( dir.getObjectId() );
repository.commit();
} else {
throw new KettleException( "This directory is not empty!" );
}
} else {
repository.directoryDelegate.deleteDirectory( dir );
repository.commit();
}
} catch ( Exception e ) {
throw new KettleException( "Unexpected error deleting repository directory:", e );
}
}
/**
* @deprecated use {@link #renameRepositoryDirectory(ObjectId, RepositoryDirectoryInterface, String)}
*
* @param dir
* @return
* @throws KettleException
*/
@Deprecated
public ObjectId renameRepositoryDirectory( RepositoryDirectory dir ) throws KettleException {
try {
renameDirectory( dir.getObjectId(), null, dir.getName() );
return dir.getObjectId(); // doesn't change in this specific case.
} catch ( Exception e ) {
throw new KettleException( "Unable to rename the specified repository directory [" + dir + "]", e );
}
}
public ObjectId renameRepositoryDirectory( ObjectId id, RepositoryDirectoryInterface newParentDir, String newName ) throws KettleException {
ObjectId parentId = null;
if ( newParentDir != null ) {
parentId = newParentDir.getObjectId();
}
try {
renameDirectory( id, parentId, newName );
return id; // doesn't change in this specific case.
} catch ( Exception e ) {
throw new KettleException( "Unable to rename the specified repository directory [" + id + "]", e );
}
}
/**
* Create a new directory, possibly by creating several sub-directies of / at the same time.
*
* @param parentDirectory
* the parent directory
* @param directoryPath
* The path to the new Repository Directory, to be created.
* @return The created sub-directory
* @throws KettleException
* In case something goes wrong
*/
public RepositoryDirectoryInterface createRepositoryDirectory( RepositoryDirectoryInterface parentDirectory,
String directoryPath ) throws KettleException {
// RepositoryDirectoryInterface refreshedParentDir =
// repository.loadRepositoryDirectoryTree().findDirectory(parentDirectory.getPath());
RepositoryDirectoryInterface refreshedParentDir = parentDirectory;
String[] path = Const.splitPath( directoryPath, RepositoryDirectory.DIRECTORY_SEPARATOR );
RepositoryDirectoryInterface parent = refreshedParentDir;
for ( int level = 0; level < path.length; level++ ) {
RepositoryDirectoryInterface rd = parent.findChild( path[level] );
if ( rd == null ) {
// This child directory doesn't exists, let's add it!
//
rd = new RepositoryDirectory( parent, path[level] );
saveRepositoryDirectory( rd );
// Don't forget to add this directory to the tree!
//
parent.addSubdirectory( rd );
parent = rd;
} else {
parent = rd;
}
}
return parent;
}
}