/*! ******************************************************************************
*
* 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 java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.pentaho.di.cluster.SlaveServer;
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.plugins.JobEntryPluginType;
import org.pentaho.di.core.plugins.PluginInterface;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.row.RowMetaInterface;
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.job.JobMeta;
import org.pentaho.di.job.entries.missing.MissingEntry;
import org.pentaho.di.job.entry.JobEntryBase;
import org.pentaho.di.job.entry.JobEntryCopy;
import org.pentaho.di.job.entry.JobEntryInterface;
import org.pentaho.di.repository.LongObjectId;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.repository.kdr.KettleDatabaseRepository;
import org.pentaho.di.repository.kdr.delegates.metastore.KettleDatabaseRepositoryMetaStore;
public class KettleDatabaseRepositoryJobEntryDelegate extends KettleDatabaseRepositoryBaseDelegate {
// private static Class<?> PKG = JobEntryCopy.class; // for i18n purposes, needed by Translator2!!
public static final String JOBENTRY_ATTRIBUTE_PREFIX = "_ATTR_" + '\t';
public KettleDatabaseRepositoryJobEntryDelegate( KettleDatabaseRepository repository ) {
super( repository );
}
public RowMetaAndData getJobEntry( ObjectId id_jobentry ) throws KettleException {
return repository.connectionDelegate.getOneRow(
quoteTable( KettleDatabaseRepository.TABLE_R_JOBENTRY ),
quote( KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOBENTRY ), id_jobentry );
}
public RowMetaAndData getJobEntryCopy( ObjectId id_jobentry_copy ) throws KettleException {
return repository.connectionDelegate.getOneRow(
quoteTable( KettleDatabaseRepository.TABLE_R_JOBENTRY_COPY ),
quote( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_ID_JOBENTRY_COPY ), id_jobentry_copy );
}
public RowMetaAndData getJobEntryType( ObjectId id_jobentry_type ) throws KettleException {
return repository.connectionDelegate.getOneRow(
quoteTable( KettleDatabaseRepository.TABLE_R_JOBENTRY_TYPE ),
quote( KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOBENTRY_TYPE ), id_jobentry_type );
}
public synchronized ObjectId getJobEntryID( String name, ObjectId id_job ) throws KettleException {
return repository.connectionDelegate.getIDWithValue(
quoteTable( KettleDatabaseRepository.TABLE_R_JOBENTRY ),
quote( KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOBENTRY ),
quote( KettleDatabaseRepository.FIELD_JOBENTRY_NAME ), name,
quote( KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOB ), id_job );
}
public synchronized ObjectId getJobEntryTypeID( String code ) throws KettleException {
return repository.connectionDelegate.getIDWithValue(
quoteTable( KettleDatabaseRepository.TABLE_R_JOBENTRY_TYPE ),
quote( KettleDatabaseRepository.FIELD_JOBENTRY_TYPE_ID_JOBENTRY_TYPE ),
quote( KettleDatabaseRepository.FIELD_JOBENTRY_TYPE_CODE ), code );
}
/**
* Load the chef graphical entry from repository We load type, name & description if no entry can be found.
*
* @param log
* the logging channel
* @param rep
* the Repository
* @param jobId
* The job ID
* @param jobEntryCopyId
* The jobentry copy ID
* @param jobentries
* A list with all jobentries
* @param databases
* A list with all defined databases
*/
public JobEntryCopy loadJobEntryCopy( ObjectId jobId, ObjectId jobEntryCopyId,
List<JobEntryInterface> jobentries, List<DatabaseMeta> databases, List<SlaveServer> slaveServers, String jobname )
throws KettleException {
JobEntryCopy jobEntryCopy = new JobEntryCopy();
try {
jobEntryCopy.setObjectId( jobEntryCopyId );
// Handle GUI information: nr, location, ...
RowMetaAndData r = getJobEntryCopy( jobEntryCopyId );
if ( r != null ) {
// These are the jobentry_copy fields...
//
ObjectId jobEntryId =
new LongObjectId( r.getInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_ID_JOBENTRY, 0 ) );
ObjectId jobEntryTypeId =
new LongObjectId( r.getInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_ID_JOBENTRY_TYPE, 0 ) );
jobEntryCopy.setNr( (int) r.getInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_NR, 0 ) );
int locx = (int) r.getInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_GUI_LOCATION_X, 0 );
int locy = (int) r.getInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_GUI_LOCATION_Y, 0 );
boolean isdrawn = r.getBoolean( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_GUI_DRAW, false );
boolean isparallel = r.getBoolean( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_PARALLEL, false );
// Do we have the jobentry already?
//
jobEntryCopy.setEntry( JobMeta.findJobEntry( jobentries, jobEntryId ) );
if ( jobEntryCopy.getEntry() == null ) {
// What type of jobentry do we load now?
// Get the jobentry type code
//
RowMetaAndData rt = getJobEntryType( new LongObjectId( jobEntryTypeId ) );
if ( rt != null ) {
String jet_code = rt.getString( KettleDatabaseRepository.FIELD_JOBENTRY_TYPE_CODE, null );
JobEntryInterface jobEntry = null;
PluginRegistry registry = PluginRegistry.getInstance();
PluginInterface jobPlugin = registry.findPluginWithId( JobEntryPluginType.class, jet_code );
if ( jobPlugin == null ) {
jobEntry = new MissingEntry( jobname, jet_code );
} else {
jobEntry = (JobEntryInterface) registry.loadClass( jobPlugin );
}
if ( jobEntry != null ) {
jobEntryCopy.setEntry( jobEntry );
// Load the attributes for that jobentry
//
// THIS IS THE PLUGIN/JOB-ENTRY BEING LOADED!
//
// If you extended the JobEntryBase class, you're fine.
// Otherwise you're on your own.
//
if ( jobEntry instanceof JobEntryBase ) {
loadJobEntryBase( (JobEntryBase) jobEntry, jobEntryId, databases, slaveServers );
( (JobEntryBase) jobEntry ).setAttributesMap( loadJobEntryAttributesMap( jobId, jobEntryId ) );
}
compatibleJobEntryLoadRep( jobEntry, repository, jobEntryTypeId, databases, slaveServers );
jobEntry.loadRep( repository, repository.metaStore, jobEntryId, databases, slaveServers );
jobEntryCopy.getEntry().setObjectId( jobEntryId );
jobentries.add( jobEntryCopy.getEntry() );
} else {
throw new KettleException( "JobEntryLoader was unable to find Job Entry Plugin with description ["
+ jet_code + "]." );
}
} else {
throw new KettleException( "Unable to find Job Entry Type with id="
+ jobEntryTypeId + " in the repository" );
}
}
jobEntryCopy.setLocation( locx, locy );
jobEntryCopy.setDrawn( isdrawn );
jobEntryCopy.setLaunchingInParallel( isparallel );
return jobEntryCopy;
} else {
throw new KettleException( "Unable to find job entry copy in repository with id_jobentry_copy="
+ jobEntryCopyId );
}
} catch ( KettleDatabaseException dbe ) {
throw new KettleException( "Unable to load job entry copy from repository with id_jobentry_copy="
+ jobEntryCopyId, dbe );
}
}
@SuppressWarnings( "deprecation" )
private void compatibleJobEntryLoadRep( JobEntryInterface jobEntry, KettleDatabaseRepository repository,
ObjectId id_jobentry_type, List<DatabaseMeta> databases, List<SlaveServer> slaveServers ) throws KettleException {
jobEntry.loadRep( repository, id_jobentry_type, databases, slaveServers );
}
public void saveJobEntryCopy( JobEntryCopy copy, ObjectId id_job, KettleDatabaseRepositoryMetaStore metaStore ) throws KettleException {
try {
JobEntryInterface entry = copy.getEntry();
/*
* --1-- Save the JobEntryCopy details... --2-- If we don't find a id_jobentry, save the jobentry (meaning: only
* once)
*/
// See if an entry with the same name is already available...
ObjectId id_jobentry = getJobEntryID( copy.getName(), id_job );
if ( id_jobentry == null ) {
insertJobEntry( id_job, (JobEntryBase) entry );
// THIS IS THE PLUGIN/JOB-ENTRY BEING SAVED!
//
entry.saveRep( repository, metaStore, id_job );
compatibleEntrySaveRep( entry, repository, id_job );
// Save the attribute groups map
//
if ( entry instanceof JobEntryBase ) {
saveAttributesMap( id_job, copy.getObjectId(), ( (JobEntryBase) entry ).getAttributesMap() );
}
id_jobentry = entry.getObjectId();
}
// OK, the entry is saved.
// Get the entry type...
//
ObjectId id_jobentry_type = getJobEntryTypeID( entry.getPluginId() );
// Oops, not found: update the repository!
if ( id_jobentry_type == null ) {
repository.updateJobEntryTypes();
// Try again!
id_jobentry_type = getJobEntryTypeID( entry.getPluginId() );
}
// Save the entry copy..
//
copy.setObjectId( insertJobEntryCopy( id_job, id_jobentry, id_jobentry_type, copy.getNr(), copy
.getLocation().x, copy.getLocation().y, copy.isDrawn(), copy.isLaunchingInParallel() ) );
} catch ( KettleDatabaseException dbe ) {
throw new KettleException( "Unable to save job entry copy to the repository, id_job=" + id_job, dbe );
}
}
@SuppressWarnings( "deprecation" )
private void compatibleEntrySaveRep( JobEntryInterface entry, Repository repository, ObjectId id_job ) throws KettleException {
entry.saveRep( repository, id_job );
}
public synchronized ObjectId insertJobEntry( ObjectId id_job, JobEntryBase jobEntryBase ) throws KettleException {
ObjectId id = repository.connectionDelegate.getNextJobEntryID();
ObjectId id_jobentry_type = getJobEntryTypeID( jobEntryBase.getPluginId() );
log.logDebug( "ID_JobEntry_type = " + id_jobentry_type + " for type = [" + jobEntryBase.getPluginId() + "]" );
RowMetaAndData table = new RowMetaAndData();
table.addValue( new ValueMetaInteger(
KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOBENTRY ), id );
table.addValue(
new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOB ), id_job );
table
.addValue(
new ValueMetaInteger(
KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOBENTRY_TYPE ),
id_jobentry_type );
table.addValue(
new ValueMetaString( KettleDatabaseRepository.FIELD_JOBENTRY_NAME ),
jobEntryBase.getName() );
table.addValue( new ValueMetaString(
KettleDatabaseRepository.FIELD_JOBENTRY_DESCRIPTION ), jobEntryBase
.getDescription() );
repository.connectionDelegate.getDatabase().prepareInsert(
table.getRowMeta(), KettleDatabaseRepository.TABLE_R_JOBENTRY );
repository.connectionDelegate.getDatabase().setValuesInsert( table );
repository.connectionDelegate.getDatabase().insertRow();
repository.connectionDelegate.getDatabase().closeInsert();
jobEntryBase.setObjectId( id );
return id;
}
public synchronized ObjectId insertJobEntryCopy( ObjectId id_job, ObjectId id_jobentry,
ObjectId id_jobentry_type, int nr, long gui_location_x, long gui_location_y, boolean gui_draw,
boolean parallel ) throws KettleException {
ObjectId id = repository.connectionDelegate.getNextJobEntryCopyID();
RowMetaAndData table = new RowMetaAndData();
//CHECKSTYLE:LineLength:OFF
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_ID_JOBENTRY_COPY ), id );
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_ID_JOBENTRY ), id_jobentry );
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_ID_JOB ), id_job );
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_ID_JOBENTRY_TYPE ), id_jobentry_type );
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_NR ), new Long( nr ) );
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_GUI_LOCATION_X ), new Long( gui_location_x ) );
table.addValue( new ValueMetaInteger( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_GUI_LOCATION_Y ), new Long( gui_location_y ) );
table.addValue( new ValueMetaBoolean( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_GUI_DRAW ), Boolean.valueOf( gui_draw ) );
table.addValue( new ValueMetaBoolean( KettleDatabaseRepository.FIELD_JOBENTRY_COPY_PARALLEL ), Boolean.valueOf( parallel ) );
repository.connectionDelegate.getDatabase().prepareInsert( table.getRowMeta(), KettleDatabaseRepository.TABLE_R_JOBENTRY_COPY );
repository.connectionDelegate.getDatabase().setValuesInsert( table );
repository.connectionDelegate.getDatabase().insertRow();
repository.connectionDelegate.getDatabase().closeInsert();
return id;
}
public synchronized int getNrJobEntries( ObjectId id_job ) throws KettleException {
int retval = 0;
RowMetaAndData par = repository.connectionDelegate.getParameterMetaData( id_job );
String sql =
"SELECT COUNT(*) FROM "
+ quoteTable( KettleDatabaseRepository.TABLE_R_JOBENTRY ) + " WHERE "
+ quote( KettleDatabaseRepository.FIELD_JOBENTRY_ID_JOB ) + " = ? ";
RowMetaAndData r = repository.connectionDelegate.getOneRow( sql, par.getRowMeta(), par.getData() );
if ( r != null ) {
retval = (int) r.getInteger( 0, 0L );
}
return retval;
}
public void loadJobEntryBase( JobEntryBase jobEntryBase, ObjectId id_jobentry, List<DatabaseMeta> databases,
List<SlaveServer> slaveServers ) throws KettleException {
try {
RowMetaAndData r = getJobEntry( id_jobentry );
if ( r != null ) {
jobEntryBase.setName( r.getString( "NAME", null ) );
jobEntryBase.setDescription( r.getString( "DESCRIPTION", null ) );
long id_jobentry_type = r.getInteger( "ID_JOBENTRY_TYPE", 0 );
RowMetaAndData jetrow = getJobEntryType( new LongObjectId( id_jobentry_type ) );
if ( jetrow != null ) {
jobEntryBase.setPluginId( jetrow.getString( "CODE", null ) );
}
}
} catch ( KettleDatabaseException dbe ) {
throw new KettleException( "Unable to load base job entry information from the repository for id_jobentry="
+ id_jobentry, dbe );
}
}
private void saveAttributesMap( ObjectId jobId, ObjectId entryId, Map<String, Map<String, String>> attributesMap ) throws KettleException {
for ( final String groupName : attributesMap.keySet() ) {
Map<String, String> attributes = attributesMap.get( groupName );
for ( final String key : attributes.keySet() ) {
final String value = attributes.get( key );
if ( key != null && value != null ) {
repository.connectionDelegate.insertJobEntryAttribute( jobId, entryId, 0, JOBENTRY_ATTRIBUTE_PREFIX
+ groupName + '\t' + value, 0, value );
}
}
}
}
private Map<String, Map<String, String>> loadJobEntryAttributesMap( ObjectId jobId, Object jobEntryId ) throws KettleException {
Map<String, Map<String, String>> attributesMap = new HashMap<String, Map<String, String>>();
List<Object[]> attributeRows =
repository.connectionDelegate.getJobEntryAttributesWithPrefix( jobId, jobId, JOBENTRY_ATTRIBUTE_PREFIX );
RowMetaInterface rowMeta = repository.connectionDelegate.getReturnRowMeta();
for ( Object[] attributeRow : attributeRows ) {
String code = rowMeta.getString( attributeRow, KettleDatabaseRepository.FIELD_JOBENTRY_ATTRIBUTE_CODE, null );
String value =
rowMeta.getString( attributeRow, KettleDatabaseRepository.FIELD_JOBENTRY_ATTRIBUTE_VALUE_STR, null );
if ( code != null && value != null ) {
code = code.substring( JOBENTRY_ATTRIBUTE_PREFIX.length() );
int tabIndex = code.indexOf( '\t' );
if ( tabIndex > 0 ) {
String groupName = code.substring( 0, tabIndex );
String key = code.substring( tabIndex + 1 );
Map<String, String> attributes = attributesMap.get( groupName );
if ( attributes == null ) {
attributes = new HashMap<String, String>();
attributesMap.put( groupName, attributes );
}
attributes.put( key, value );
}
}
}
return attributesMap;
}
}