/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 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 org.pentaho.di.core.Const;
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.exception.KettleDependencyException;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleObjectExistsException;
import org.pentaho.di.core.row.value.ValueMetaBoolean;
import org.pentaho.di.core.row.value.ValueMetaInteger;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.partition.PartitionSchema;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.kdr.KettleDatabaseRepository;
public class KettleDatabaseRepositoryPartitionSchemaDelegate extends KettleDatabaseRepositoryBaseDelegate {
// private static Class<?> PKG = PartitionSchema.class; // for i18n purposes, needed by Translator2!!
public KettleDatabaseRepositoryPartitionSchemaDelegate( KettleDatabaseRepository repository ) {
super( repository );
}
public RowMetaAndData getPartitionSchema( ObjectId id_partition_schema ) throws KettleException {
return repository.connectionDelegate.getOneRow(
quoteTable( KettleDatabaseRepository.TABLE_R_PARTITION_SCHEMA ),
quote( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_ID_PARTITION_SCHEMA ), id_partition_schema );
}
public RowMetaAndData getPartition( ObjectId id_partition ) throws KettleException {
return repository.connectionDelegate.getOneRow(
quoteTable( KettleDatabaseRepository.TABLE_R_PARTITION ),
quote( KettleDatabaseRepository.FIELD_PARTITION_ID_PARTITION ), id_partition );
}
public synchronized ObjectId getPartitionSchemaID( String name ) throws KettleException {
return repository.connectionDelegate.getIDWithValue(
quoteTable( KettleDatabaseRepository.TABLE_R_PARTITION_SCHEMA ),
quote( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_ID_PARTITION_SCHEMA ),
quote( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_NAME ), name );
}
public void savePartitionSchema( PartitionSchema partitionSchema ) throws KettleException {
savePartitionSchema( partitionSchema, null, false );
}
public void savePartitionSchema( PartitionSchema partitionSchema, ObjectId id_transformation,
boolean isUsedByTransformation ) throws KettleException {
try {
savePartitionSchema( partitionSchema, id_transformation, isUsedByTransformation, false );
} catch ( KettleObjectExistsException e ) {
// This is an expected possibility here. Common objects are not going to overwrite database objects
log.logBasic( e.getMessage() );
}
}
public void savePartitionSchema( PartitionSchema partitionSchema, ObjectId id_transformation,
boolean isUsedByTransformation, boolean overwrite ) throws KettleException {
// Look up the ID again (import scenario!)
//
if ( partitionSchema.getObjectId() == null ) {
partitionSchema.setObjectId( getPartitionSchemaID( partitionSchema.getName() ) );
}
if ( partitionSchema.getObjectId() == null ) {
// New Slave Server
partitionSchema.setObjectId( insertPartitionSchema( partitionSchema ) );
} else {
ObjectId existingPartitionSchemaId = partitionSchema.getObjectId();
// If we received a partitionSchemaId and it is different from the partition schema we are working with...
if ( existingPartitionSchemaId != null && !partitionSchema.getObjectId().equals( existingPartitionSchemaId ) ) {
// A partition with this name already exists
if ( overwrite ) {
// Proceed with save, removing the original version from the repository first
repository.deletePartitionSchema( existingPartitionSchemaId );
updatePartitionSchema( partitionSchema );
repository.delPartitions( partitionSchema.getObjectId() );
} else {
throw new KettleObjectExistsException( "Failed to save object to repository. Object ["
+ partitionSchema.getName() + "] already exists." );
}
} else {
// There are no naming collisions (either it is the same object or the name is unique)
updatePartitionSchema( partitionSchema );
repository.delPartitions( partitionSchema.getObjectId() );
}
}
// Save the partitionschema-partition relationships
//
for ( int i = 0; i < partitionSchema.getPartitionIDs().size(); i++ ) {
insertPartition( partitionSchema.getObjectId(), partitionSchema.getPartitionIDs().get( i ) );
}
// Save a link to the transformation to keep track of the use of this partition schema
// Otherwise, we shouldn't bother with this
//
if ( isUsedByTransformation ) {
repository.insertTransformationPartitionSchema( id_transformation, partitionSchema.getObjectId() );
}
}
public PartitionSchema loadPartitionSchema( ObjectId id_partition_schema ) throws KettleException {
PartitionSchema partitionSchema = new PartitionSchema();
partitionSchema.setObjectId( id_partition_schema );
RowMetaAndData row = getPartitionSchema( id_partition_schema );
partitionSchema.setName( row.getString( "NAME", null ) );
ObjectId[] pids = repository.getPartitionIDs( id_partition_schema );
for ( int i = 0; i < pids.length; i++ ) {
partitionSchema.getPartitionIDs().add( getPartition( pids[i] ).getString( "PARTITION_ID", null ) );
}
partitionSchema.setDynamicallyDefined( row.getBoolean( "DYNAMIC_DEFINITION", false ) );
partitionSchema.setNumberOfPartitionsPerSlave( row.getString( "PARTITIONS_PER_SLAVE", null ) );
return partitionSchema;
}
public synchronized ObjectId insertPartitionSchema( PartitionSchema partitionSchema ) throws KettleException {
if ( getPartitionSchemaID( partitionSchema.getName() ) != null ) {
// This partition schema name is already in use. Throw an exception.
throw new KettleObjectExistsException( "Failed to create object in repository. Object ["
+ partitionSchema.getName() + "] already exists." );
}
ObjectId id = repository.connectionDelegate.getNextPartitionSchemaID();
RowMetaAndData table = new RowMetaAndData();
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_ID_PARTITION_SCHEMA ), id );
table.addValue( new ValueMetaString( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_NAME ),
partitionSchema.getName() );
table.addValue( new ValueMetaBoolean( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_DYNAMIC_DEFINITION ),
partitionSchema.isDynamicallyDefined() );
table.addValue( new ValueMetaString( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_PARTITIONS_PER_SLAVE ),
partitionSchema.getNumberOfPartitionsPerSlave() );
repository.connectionDelegate.getDatabase().prepareInsert(
table.getRowMeta(), KettleDatabaseRepository.TABLE_R_PARTITION_SCHEMA );
repository.connectionDelegate.getDatabase().setValuesInsert( table );
repository.connectionDelegate.getDatabase().insertRow();
repository.connectionDelegate.getDatabase().closeInsert();
return id;
}
public synchronized void updatePartitionSchema( PartitionSchema partitionSchema ) throws KettleException {
RowMetaAndData table = new RowMetaAndData();
table.addValue( new ValueMetaString( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_NAME ),
partitionSchema.getName() );
table.addValue( new ValueMetaBoolean( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_DYNAMIC_DEFINITION ),
partitionSchema.isDynamicallyDefined() );
table.addValue( new ValueMetaString( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_PARTITIONS_PER_SLAVE ),
partitionSchema.getNumberOfPartitionsPerSlave() );
repository.connectionDelegate.updateTableRow(
KettleDatabaseRepository.TABLE_R_PARTITION_SCHEMA,
KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_ID_PARTITION_SCHEMA, table, partitionSchema.getObjectId() );
}
public synchronized ObjectId insertPartition( ObjectId id_partition_schema, String partition_id ) throws KettleException {
ObjectId id = repository.connectionDelegate.getNextPartitionID();
RowMetaAndData table = new RowMetaAndData();
table.addValue( new ValueMetaInteger(
KettleDatabaseRepository.FIELD_PARTITION_ID_PARTITION ), id );
table.addValue(
new ValueMetaInteger(
KettleDatabaseRepository.FIELD_PARTITION_ID_PARTITION_SCHEMA ),
id_partition_schema );
table.addValue( new ValueMetaString(
KettleDatabaseRepository.FIELD_PARTITION_PARTITION_ID ), partition_id );
repository.connectionDelegate.getDatabase().prepareInsert(
table.getRowMeta(), KettleDatabaseRepository.TABLE_R_PARTITION );
repository.connectionDelegate.getDatabase().setValuesInsert( table );
repository.connectionDelegate.getDatabase().insertRow();
repository.connectionDelegate.getDatabase().closeInsert();
return id;
}
public synchronized void delPartitionSchema( ObjectId id_partition_schema ) throws KettleException {
// First, see if the schema is still used by other objects...
// If so, generate an error!!
//
// We look in table R_TRANS_PARTITION_SCHEMA to see if there are any transformations using this schema.
String[] transList = repository.getTransformationsUsingPartitionSchema( id_partition_schema );
if ( transList.length == 0 ) {
repository.connectionDelegate.performDelete( "DELETE FROM "
+ quoteTable( KettleDatabaseRepository.TABLE_R_PARTITION ) + " WHERE "
+ quote( KettleDatabaseRepository.FIELD_PARTITION_ID_PARTITION_SCHEMA ) + " = ? ", id_partition_schema );
repository.connectionDelegate.performDelete(
"DELETE FROM "
+ quoteTable( KettleDatabaseRepository.TABLE_R_PARTITION_SCHEMA ) + " WHERE "
+ quote( KettleDatabaseRepository.FIELD_PARTITION_SCHEMA_ID_PARTITION_SCHEMA ) + " = ? ",
id_partition_schema );
} else {
StringBuilder message = new StringBuilder( 100 );
message.append( "The partition schema is used by the following transformations:" ).append( Const.CR );
for ( int i = 0; i < transList.length; i++ ) {
message.append( " " ).append( transList[i] ).append( Const.CR );
}
message.append( Const.CR );
KettleDependencyException e = new KettleDependencyException( message.toString() );
throw new KettleDependencyException(
"This partition schema is still in use by one or more transformations (" + transList.length + ") :", e );
}
}
}