/*! ****************************************************************************** * * 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.trans.steps.metainject; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.ObjectLocationSpecificationMethod; import org.pentaho.di.core.annotations.Step; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettlePluginException; import org.pentaho.di.core.exception.KettleStepException; import org.pentaho.di.core.exception.KettleXMLException; import org.pentaho.di.core.injection.Injection; import org.pentaho.di.core.injection.InjectionDeep; import org.pentaho.di.core.injection.InjectionSupported; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.value.ValueMetaFactory; import org.pentaho.di.core.util.CurrentDirectoryResolver; import org.pentaho.di.core.variables.VariableSpace; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.Repository; import org.pentaho.di.repository.RepositoryDirectory; import org.pentaho.di.repository.RepositoryDirectoryInterface; import org.pentaho.di.repository.StringObjectId; import org.pentaho.di.resource.ResourceDefinition; import org.pentaho.di.resource.ResourceEntry; import org.pentaho.di.resource.ResourceEntry.ResourceType; import org.pentaho.di.resource.ResourceNamingInterface; import org.pentaho.di.resource.ResourceReference; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransHopMeta; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.step.BaseStepMeta; import org.pentaho.di.trans.step.StepDataInterface; import org.pentaho.di.trans.step.StepInterface; import org.pentaho.di.trans.step.StepMeta; import org.pentaho.di.trans.step.StepMetaChangeListenerInterface; import org.pentaho.di.trans.step.StepMetaInterface; import org.pentaho.metastore.api.IMetaStore; import org.w3c.dom.Node; /** * @author matt * @version 3.0 * @since 2007-07-05 */ @Step( id = "MetaInject", image = "org/pentaho/di/ui/trans/steps/metainject/img/GenericTransform.svg", name = "i18n:org.pentaho.di.trans.step:BaseStep.TypeLongDesc.MetaInject", categoryDescription = "i18n:org.pentaho.di.trans.step:BaseStep.Category.Flow", documentationUrl = "0L0/0Y0/0K0/ETL_Metadata_Injection" ) @InjectionSupported( localizationPrefix = "MetaInject.Injection.", groups = { "SOURCE_OUTPUT_FIELDS", "MAPPING_FIELDS" } ) public class MetaInjectMeta extends BaseStepMeta implements StepMetaInterface, StepMetaChangeListenerInterface { private static Class<?> PKG = MetaInjectMeta.class; // for i18n purposes, needed by Translator2!! private static final String MAPPINGS = "mappings"; private static final String MAPPING = "mapping"; private static final String SPECIFICATION_METHOD = "specification_method"; private static final String TRANS_OBJECT_ID = "trans_object_id"; private static final String TRANS_NAME = "trans_name"; private static final String FILENAME = "filename"; private static final String DIRECTORY_PATH = "directory_path"; private static final String TARGET_FILE = "target_file"; private static final String NO_EXECUTION = "no_execution"; private static final String SOURCE_STEP = "source_step"; private static final String STREAM_SOURCE_STEP = "stream_source_step"; private static final String STREAM_TARGET_STEP = "stream_target_step"; private static final String TARGET_STEP_NAME = "target_step_name"; private static final String TARGET_ATTRIBUTE_KEY = "target_attribute_key"; private static final String TARGET_DETAIL = "target_detail"; private static final String SOURCE_FIELD = "source_field"; private static final String SOURCE_OUTPUT_FIELDS = "source_output_fields"; private static final String SOURCE_OUTPUT_FIELD = "source_output_field"; private static final String SOURCE_OUTPUT_FIELD_NAME = "source_output_field_name"; private static final String SOURCE_OUTPUT_FIELD_TYPE = "source_output_field_type"; private static final String SOURCE_OUTPUT_FIELD_LENGTH = "source_output_field_length"; private static final String SOURCE_OUTPUT_FIELD_PRECISION = "source_output_field_precision"; private static final String MAPPING_SOURCE_FIELD = "mapping_source_field"; private static final String MAPPING_SOURCE_STEP = "mapping_source_step"; private static final String MAPPING_TARGET_DETAIL = "mapping_target_detail"; private static final String MAPPING_TARGET_ATTRIBUTE_KEY = "mapping_target_attribute_key"; private static final String MAPPING_TARGET_STEP_NAME = "mapping_target_step_name"; private static final String GROUP_AND_NAME_DELIMITER = "."; // description of the transformation to execute... // @Injection( name = "TRANS_NAME" ) private String transName; @Injection( name = "FILE_NAME" ) private String fileName; @Injection( name = "DIRECTORY_PATH" ) private String directoryPath; private ObjectId transObjectId; @Injection( name = "TRANS_SEPECIFICATION_METHOD" ) private ObjectLocationSpecificationMethod specificationMethod; @Injection( name = "SOURCE_STEP_NAME" ) private String sourceStepName; @InjectionDeep private List<MetaInjectOutputField> sourceOutputFields; private Map<TargetStepAttribute, SourceStepField> targetSourceMapping; @InjectionDeep private List<MetaInjectMapping> metaInjectMapping; @Injection( name = "TARGET_FILE" ) private String targetFile; @Injection( name = "NO_EXECUTION" ) private boolean noExecution; @Injection( name = "STREAMING_SOURCE_STEP" ) private String streamSourceStepname; private StepMeta streamSourceStep; @Injection( name = "STREAMING_TARGET_STEP" ) private String streamTargetStepname; public MetaInjectMeta() { super(); // allocate BaseStepMeta specificationMethod = ObjectLocationSpecificationMethod.FILENAME; targetSourceMapping = new HashMap<TargetStepAttribute, SourceStepField>(); sourceOutputFields = new ArrayList<MetaInjectOutputField>(); } // TODO: deep copy @Override public Object clone() { Object retval = super.clone(); return retval; } @Override public void setDefault() { } @Override public String getXML() { actualizeMetaInjectMapping(); StringBuilder retval = new StringBuilder( 500 ); retval.append( " " ).append( XMLHandler.addTagValue( SPECIFICATION_METHOD, specificationMethod == null ? null : specificationMethod.getCode() ) ); retval.append( " " ).append( XMLHandler.addTagValue( TRANS_OBJECT_ID, transObjectId == null ? null : transObjectId.toString() ) ); retval.append( " " ).append( XMLHandler.addTagValue( TRANS_NAME, transName ) ); retval.append( " " ).append( XMLHandler.addTagValue( FILENAME, fileName ) ); retval.append( " " ).append( XMLHandler.addTagValue( DIRECTORY_PATH, directoryPath ) ); retval.append( " " ).append( XMLHandler.addTagValue( SOURCE_STEP, sourceStepName ) ); retval.append( " " ).append( XMLHandler.openTag( SOURCE_OUTPUT_FIELDS ) ); for ( MetaInjectOutputField field : sourceOutputFields ) { retval.append( " " ).append( XMLHandler.openTag( SOURCE_OUTPUT_FIELD ) ); retval.append( " " ).append( XMLHandler.addTagValue( SOURCE_OUTPUT_FIELD_NAME, field.getName() ) ); retval.append( " " ).append( XMLHandler.addTagValue( SOURCE_OUTPUT_FIELD_TYPE, field .getTypeDescription() ) ); retval.append( " " ).append( XMLHandler.addTagValue( SOURCE_OUTPUT_FIELD_LENGTH, field.getLength() ) ); retval.append( " " ).append( XMLHandler.addTagValue( SOURCE_OUTPUT_FIELD_PRECISION, field .getPrecision() ) ); retval.append( " " ).append( XMLHandler.closeTag( SOURCE_OUTPUT_FIELD ) ); } retval.append( " " ).append( XMLHandler.closeTag( SOURCE_OUTPUT_FIELDS ) ); retval.append( " " ).append( XMLHandler.addTagValue( TARGET_FILE, targetFile ) ); retval.append( " " ).append( XMLHandler.addTagValue( NO_EXECUTION, noExecution ) ); if ( ( streamSourceStepname == null ) && ( streamSourceStep != null ) ) { streamSourceStepname = streamSourceStep.getName(); } retval.append( " " ).append( XMLHandler.addTagValue( STREAM_SOURCE_STEP, streamSourceStepname ) ); retval.append( " " ).append( XMLHandler.addTagValue( STREAM_TARGET_STEP, streamTargetStepname ) ); retval.append( " " ).append( XMLHandler.openTag( MAPPINGS ) ); for ( TargetStepAttribute target : targetSourceMapping.keySet() ) { retval.append( " " ).append( XMLHandler.openTag( MAPPING ) ); SourceStepField source = targetSourceMapping.get( target ); retval.append( " " ).append( XMLHandler.addTagValue( TARGET_STEP_NAME, target.getStepname() ) ); retval.append( " " ).append( XMLHandler.addTagValue( TARGET_ATTRIBUTE_KEY, target.getAttributeKey() ) ); retval.append( " " ).append( XMLHandler.addTagValue( TARGET_DETAIL, target.isDetail() ) ); retval.append( " " ).append( XMLHandler.addTagValue( SOURCE_STEP, source.getStepname() ) ); retval.append( " " ).append( XMLHandler.addTagValue( SOURCE_FIELD, source.getField() ) ); retval.append( " " ).append( XMLHandler.closeTag( MAPPING ) ); } retval.append( " " ).append( XMLHandler.closeTag( MAPPINGS ) ); return retval.toString(); } @Override public void loadXML( Node stepnode, List<DatabaseMeta> databases, IMetaStore metaStore ) throws KettleXMLException { try { String method = XMLHandler.getTagValue( stepnode, SPECIFICATION_METHOD ); specificationMethod = ObjectLocationSpecificationMethod.getSpecificationMethodByCode( method ); String transId = XMLHandler.getTagValue( stepnode, TRANS_OBJECT_ID ); transObjectId = Utils.isEmpty( transId ) ? null : new StringObjectId( transId ); transName = XMLHandler.getTagValue( stepnode, TRANS_NAME ); fileName = XMLHandler.getTagValue( stepnode, FILENAME ); directoryPath = XMLHandler.getTagValue( stepnode, DIRECTORY_PATH ); sourceStepName = XMLHandler.getTagValue( stepnode, SOURCE_STEP ); Node outputFieldsNode = XMLHandler.getSubNode( stepnode, SOURCE_OUTPUT_FIELDS ); List<Node> outputFieldNodes = XMLHandler.getNodes( outputFieldsNode, SOURCE_OUTPUT_FIELD ); sourceOutputFields = new ArrayList<MetaInjectOutputField>(); for ( Node outputFieldNode : outputFieldNodes ) { String name = XMLHandler.getTagValue( outputFieldNode, SOURCE_OUTPUT_FIELD_NAME ); String typeName = XMLHandler.getTagValue( outputFieldNode, SOURCE_OUTPUT_FIELD_TYPE ); int length = Const.toInt( XMLHandler.getTagValue( outputFieldNode, SOURCE_OUTPUT_FIELD_LENGTH ), -1 ); int precision = Const.toInt( XMLHandler.getTagValue( outputFieldNode, SOURCE_OUTPUT_FIELD_PRECISION ), -1 ); int type = ValueMetaFactory.getIdForValueMeta( typeName ); sourceOutputFields.add( new MetaInjectOutputField( name, type, length, precision ) ); } targetFile = XMLHandler.getTagValue( stepnode, TARGET_FILE ); noExecution = "Y".equalsIgnoreCase( XMLHandler.getTagValue( stepnode, NO_EXECUTION ) ); streamSourceStepname = XMLHandler.getTagValue( stepnode, STREAM_SOURCE_STEP ); streamTargetStepname = XMLHandler.getTagValue( stepnode, STREAM_TARGET_STEP ); Node mappingsNode = XMLHandler.getSubNode( stepnode, MAPPINGS ); int nrMappings = XMLHandler.countNodes( mappingsNode, MAPPING ); for ( int i = 0; i < nrMappings; i++ ) { Node mappingNode = XMLHandler.getSubNodeByNr( mappingsNode, MAPPING, i ); String targetStepname = XMLHandler.getTagValue( mappingNode, TARGET_STEP_NAME ); String targetAttributeKey = XMLHandler.getTagValue( mappingNode, TARGET_ATTRIBUTE_KEY ); boolean targetDetail = "Y".equalsIgnoreCase( XMLHandler.getTagValue( mappingNode, TARGET_DETAIL ) ); String sourceStepname = XMLHandler.getTagValue( mappingNode, SOURCE_STEP ); String sourceField = XMLHandler.getTagValue( mappingNode, SOURCE_FIELD ); TargetStepAttribute target = new TargetStepAttribute( targetStepname, targetAttributeKey, targetDetail ); SourceStepField source = new SourceStepField( sourceStepname, sourceField ); targetSourceMapping.put( target, source ); } MetaInjectMigration.migrateFrom70( targetSourceMapping ); } catch ( Exception e ) { throw new KettleXMLException( "Unable to load step info from XML", e ); } } @Override public void readRep( Repository rep, IMetaStore metaStore, ObjectId id_step, List<DatabaseMeta> databases ) throws KettleException { try { String method = rep.getStepAttributeString( id_step, SPECIFICATION_METHOD ); specificationMethod = ObjectLocationSpecificationMethod.getSpecificationMethodByCode( method ); String transId = rep.getStepAttributeString( id_step, TRANS_OBJECT_ID ); transObjectId = Utils.isEmpty( transId ) ? null : new StringObjectId( transId ); transName = rep.getStepAttributeString( id_step, TRANS_NAME ); fileName = rep.getStepAttributeString( id_step, FILENAME ); directoryPath = rep.getStepAttributeString( id_step, DIRECTORY_PATH ); sourceStepName = rep.getStepAttributeString( id_step, SOURCE_STEP ); streamSourceStepname = rep.getStepAttributeString( id_step, STREAM_SOURCE_STEP ); streamTargetStepname = rep.getStepAttributeString( id_step, STREAM_TARGET_STEP ); sourceOutputFields = new ArrayList<MetaInjectOutputField>(); int nrSourceOutputFields = rep.countNrStepAttributes( id_step, SOURCE_OUTPUT_FIELD_NAME ); for ( int i = 0; i < nrSourceOutputFields; i++ ) { String name = rep.getStepAttributeString( id_step, i, SOURCE_OUTPUT_FIELD_NAME ); String typeName = rep.getStepAttributeString( id_step, i, SOURCE_OUTPUT_FIELD_TYPE ); int length = (int) rep.getStepAttributeInteger( id_step, i, SOURCE_OUTPUT_FIELD_LENGTH ); int precision = (int) rep.getStepAttributeInteger( id_step, i, SOURCE_OUTPUT_FIELD_PRECISION ); int type = ValueMetaFactory.getIdForValueMeta( typeName ); sourceOutputFields.add( new MetaInjectOutputField( name, type, length, precision ) ); } targetFile = rep.getStepAttributeString( id_step, TARGET_FILE ); noExecution = rep.getStepAttributeBoolean( id_step, NO_EXECUTION ); int nrMappings = rep.countNrStepAttributes( id_step, MAPPING_TARGET_STEP_NAME ); for ( int i = 0; i < nrMappings; i++ ) { String targetStepname = rep.getStepAttributeString( id_step, i, MAPPING_TARGET_STEP_NAME ); String targetAttributeKey = rep.getStepAttributeString( id_step, i, MAPPING_TARGET_ATTRIBUTE_KEY ); boolean targetDetail = rep.getStepAttributeBoolean( id_step, i, MAPPING_TARGET_DETAIL ); String sourceStepname = rep.getStepAttributeString( id_step, i, MAPPING_SOURCE_STEP ); String sourceField = rep.getStepAttributeString( id_step, i, MAPPING_SOURCE_FIELD ); TargetStepAttribute target = new TargetStepAttribute( targetStepname, targetAttributeKey, targetDetail ); SourceStepField source = new SourceStepField( sourceStepname, sourceField ); targetSourceMapping.put( target, source ); } MetaInjectMigration.migrateFrom70( targetSourceMapping ); } catch ( Exception e ) { throw new KettleException( "Unexpected error reading step information from the repository", e ); } } @Override public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_transformation, ObjectId id_step ) throws KettleException { try { rep.saveStepAttribute( id_transformation, id_step, SPECIFICATION_METHOD, specificationMethod == null ? null : specificationMethod.getCode() ); rep.saveStepAttribute( id_transformation, id_step, TRANS_OBJECT_ID, transObjectId == null ? null : transObjectId .toString() ); rep.saveStepAttribute( id_transformation, id_step, FILENAME, fileName ); rep.saveStepAttribute( id_transformation, id_step, TRANS_NAME, transName ); rep.saveStepAttribute( id_transformation, id_step, DIRECTORY_PATH, directoryPath ); rep.saveStepAttribute( id_transformation, id_step, SOURCE_STEP, sourceStepName ); rep.saveStepAttribute( id_transformation, id_step, STREAM_SOURCE_STEP, streamSourceStepname ); rep.saveStepAttribute( id_transformation, id_step, STREAM_TARGET_STEP, streamTargetStepname ); MetaInjectOutputField aField = null; for ( int i = 0; i < sourceOutputFields.size(); i++ ) { aField = sourceOutputFields.get( i ); rep.saveStepAttribute( id_transformation, id_step, i, SOURCE_OUTPUT_FIELD_NAME, aField.getName() ); rep.saveStepAttribute( id_transformation, id_step, i, SOURCE_OUTPUT_FIELD_TYPE, aField.getTypeDescription() ); rep.saveStepAttribute( id_transformation, id_step, i, SOURCE_OUTPUT_FIELD_LENGTH, aField.getLength() ); rep.saveStepAttribute( id_transformation, id_step, i, SOURCE_OUTPUT_FIELD_PRECISION, aField.getPrecision() ); } rep.saveStepAttribute( id_transformation, id_step, TARGET_FILE, targetFile ); rep.saveStepAttribute( id_transformation, id_step, NO_EXECUTION, noExecution ); List<TargetStepAttribute> keySet = new ArrayList<TargetStepAttribute>( targetSourceMapping.keySet() ); for ( int i = 0; i < keySet.size(); i++ ) { TargetStepAttribute target = keySet.get( i ); SourceStepField source = targetSourceMapping.get( target ); rep.saveStepAttribute( id_transformation, id_step, i, MAPPING_TARGET_STEP_NAME, target.getStepname() ); rep.saveStepAttribute( id_transformation, id_step, i, MAPPING_TARGET_ATTRIBUTE_KEY, target.getAttributeKey() ); rep.saveStepAttribute( id_transformation, id_step, i, MAPPING_TARGET_DETAIL, target.isDetail() ); rep.saveStepAttribute( id_transformation, id_step, i, MAPPING_SOURCE_STEP, source.getStepname() ); rep.saveStepAttribute( id_transformation, id_step, i, MAPPING_SOURCE_FIELD, source.getField() ); } } catch ( Exception e ) { throw new KettleException( "Unable to save step information to the repository for id_step=" + id_step, e ); } } @Override public void getFields( RowMetaInterface rowMeta, String origin, RowMetaInterface[] info, StepMeta nextStep, VariableSpace space, Repository repository, IMetaStore metaStore ) throws KettleStepException { rowMeta.clear(); // No defined output is expected from this step. if ( !Utils.isEmpty( sourceStepName ) ) { for ( MetaInjectOutputField field : sourceOutputFields ) { try { rowMeta.addValueMeta( field.createValueMeta() ); } catch ( KettlePluginException e ) { throw new KettleStepException( "Error creating value meta for output field '" + field.getName() + "'", e ); } } } } @Override public StepInterface getStep( StepMeta stepMeta, StepDataInterface stepDataInterface, int cnr, TransMeta tr, Trans trans ) { return new MetaInject( stepMeta, stepDataInterface, cnr, tr, trans ); } @Override public StepDataInterface getStepData() { return new MetaInjectData(); } public Map<TargetStepAttribute, SourceStepField> getTargetSourceMapping() { return targetSourceMapping; } public void setTargetSourceMapping( Map<TargetStepAttribute, SourceStepField> targetSourceMapping ) { this.targetSourceMapping = targetSourceMapping; } /** * @return the transName */ public String getTransName() { return transName; } /** * @param transName the transName to set */ public void setTransName( String transName ) { this.transName = transName; } /** * @return the fileName */ public String getFileName() { return fileName; } /** * @param fileName the fileName to set */ public void setFileName( String fileName ) { this.fileName = fileName; } /** * @return the directoryPath */ public String getDirectoryPath() { return directoryPath; } /** * @param directoryPath the directoryPath to set */ public void setDirectoryPath( String directoryPath ) { this.directoryPath = directoryPath; } /** * @return the transObjectId */ public ObjectId getTransObjectId() { return transObjectId; } /** * @param transObjectId the transObjectId to set */ public void setTransObjectId( ObjectId transObjectId ) { this.transObjectId = transObjectId; } @Injection( name = "TRANS_OBJECT_ID" ) public void setTransStringObjectId( String transStringObjectId ) { this.transObjectId = new StringObjectId( transStringObjectId ); } /** * @return the specificationMethod */ public ObjectLocationSpecificationMethod getSpecificationMethod() { return specificationMethod; } /** * @param specificationMethod the specificationMethod to set */ public void setSpecificationMethod( ObjectLocationSpecificationMethod specificationMethod ) { this.specificationMethod = specificationMethod; } @Deprecated public static final synchronized TransMeta loadTransformationMeta( MetaInjectMeta mappingMeta, Repository rep, VariableSpace space ) throws KettleException { return loadTransformationMeta( mappingMeta, rep, null, space ); } public static final synchronized TransMeta loadTransformationMeta( MetaInjectMeta injectMeta, Repository rep, IMetaStore metaStore, VariableSpace space ) throws KettleException { TransMeta mappingTransMeta = null; CurrentDirectoryResolver resolver = new CurrentDirectoryResolver(); VariableSpace tmpSpace = resolver.resolveCurrentDirectory( injectMeta.getSpecificationMethod(), space, rep, injectMeta .getParentStepMeta(), injectMeta.getFileName() ); switch ( injectMeta.getSpecificationMethod() ) { case FILENAME: String realFilename = tmpSpace.environmentSubstitute( injectMeta.getFileName() ); try { // OK, load the meta-data from file... // // Don't set internal variables: they belong to the parent thread! // mappingTransMeta = new TransMeta( realFilename, metaStore, rep, false, tmpSpace, null ); mappingTransMeta.getLogChannel().logDetailed( "Loading Mapping from repository", "Mapping transformation was loaded from XML file [" + realFilename + "]" ); } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "MetaInjectMeta.Exception.UnableToLoadTransformationFromFile", realFilename ), e ); } break; case REPOSITORY_BY_NAME: String realTransname = tmpSpace.environmentSubstitute( injectMeta.getTransName() ); String realDirectory = tmpSpace.environmentSubstitute( injectMeta.getDirectoryPath() ); if ( !Utils.isEmpty( realTransname ) && !Utils.isEmpty( realDirectory ) && rep != null ) { RepositoryDirectoryInterface repdir = rep.findDirectory( realDirectory ); if ( repdir != null ) { try { // reads the last revision in the repository... // // TODO: FIXME: see if we need to pass external MetaStore references to the repository? // mappingTransMeta = rep.loadTransformation( realTransname, repdir, null, true, null ); mappingTransMeta.getLogChannel().logDetailed( "Loading Mapping from repository", "Mapping transformation [" + realTransname + "] was loaded from the repository" ); } catch ( Exception e ) { throw new KettleException( "Unable to load transformation [" + realTransname + "]", e ); } } else { throw new KettleException( BaseMessages.getString( PKG, "MetaInjectMeta.Exception.UnableToLoadTransformationFromRepository", realTransname, realDirectory ) ); } } break; case REPOSITORY_BY_REFERENCE: // Read the last revision by reference... mappingTransMeta = rep.loadTransformation( injectMeta.getTransObjectId(), null ); break; default: break; } // Pass some important information to the mapping transformation metadata: // mappingTransMeta.copyVariablesFrom( space ); mappingTransMeta.setRepository( rep ); mappingTransMeta.setFilename( mappingTransMeta.getFilename() ); return mappingTransMeta; } /** * package-local visibility for testing purposes */ TransMeta loadTransformationMeta( Repository rep, VariableSpace space ) throws KettleException { return MetaInjectMeta.loadTransformationMeta( this, rep, null, space ); } @Override public List<ResourceReference> getResourceDependencies( TransMeta transMeta, StepMeta stepInfo ) { List<ResourceReference> references = new ArrayList<ResourceReference>( 5 ); String realFilename = transMeta.environmentSubstitute( fileName ); String realTransname = transMeta.environmentSubstitute( transName ); ResourceReference reference = new ResourceReference( stepInfo ); references.add( reference ); if ( !Utils.isEmpty( realFilename ) ) { // Add the filename to the references, including a reference to this step // meta data. // reference.getEntries().add( new ResourceEntry( realFilename, ResourceType.ACTIONFILE ) ); } else if ( !Utils.isEmpty( realTransname ) ) { // Add the filename to the references, including a reference to this step // meta data. // reference.getEntries().add( new ResourceEntry( realTransname, ResourceType.ACTIONFILE ) ); } return references; } @Override public String exportResources( VariableSpace space, Map<String, ResourceDefinition> definitions, ResourceNamingInterface resourceNamingInterface, Repository repository, IMetaStore metaStore ) throws KettleException { try { // Try to load the transformation from repository or file. // Modify this recursively too... // // NOTE: there is no need to clone this step because the caller is // responsible for this. // // First load the executor transformation metadata... // TransMeta executorTransMeta = loadTransformationMeta( repository, space ); // Also go down into the mapping transformation and export the files // there. (mapping recursively down) // String proposedNewFilename = executorTransMeta.exportResources( executorTransMeta, definitions, resourceNamingInterface, repository, metaStore ); // To get a relative path to it, we inject // ${Internal.Transformation.Filename.Directory} // String newFilename = "${" + Const.INTERNAL_VARIABLE_TRANSFORMATION_FILENAME_DIRECTORY + "}/" + proposedNewFilename; // Set the correct filename inside the XML. // executorTransMeta.setFilename( newFilename ); // exports always reside in the root directory, in case we want to turn // this into a file repository... // executorTransMeta.setRepositoryDirectory( new RepositoryDirectory() ); // change it in the entry // fileName = newFilename; return proposedNewFilename; } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "MetaInjectMeta.Exception.UnableToLoadTrans", fileName ) ); } } @Override public boolean excludeFromCopyDistributeVerification() { return true; } @Override public boolean excludeFromRowLayoutVerification() { return true; } /** * @return the sourceStepName */ public String getSourceStepName() { return sourceStepName; } /** * @param sourceStepName the sourceStepName to set */ public void setSourceStepName( String sourceStepName ) { this.sourceStepName = sourceStepName; } /** * @return the targetFile */ public String getTargetFile() { return targetFile; } /** * @param targetFile the targetFile to set */ public void setTargetFile( String targetFile ) { this.targetFile = targetFile; } /** * @return the noExecution */ public boolean isNoExecution() { return noExecution; } /** * @param noExecution the noExecution to set */ public void setNoExecution( boolean noExecution ) { this.noExecution = noExecution; } /** * @return The objects referenced in the step, like a mapping, a transformation, a job, ... */ @Override public String[] getReferencedObjectDescriptions() { return new String[] { BaseMessages.getString( PKG, "MetaInjectMeta.ReferencedObject.Description" ), }; } private boolean isTransformationDefined() { return !Utils.isEmpty( fileName ) || transObjectId != null || ( !Utils.isEmpty( this.directoryPath ) && !Const .isEmpty( transName ) ); } @Override public boolean[] isReferencedObjectEnabled() { return new boolean[] { isTransformationDefined(), }; } @Override public String getActiveReferencedObjectDescription() { return BaseMessages.getString( PKG, "MetaInjectMeta.ReferencedObjectAfterInjection.Description" ); } @Override @Deprecated public Object loadReferencedObject( int index, Repository rep, VariableSpace space ) throws KettleException { return loadReferencedObject( index, rep, null, space ); } /** * Load the referenced object * * @param meta The metadata that references * @param index the object index to load * @param rep the repository * @param metaStore metaStore * @param space the variable space to use * @return the referenced object once loaded * @throws KettleException */ @Override public Object loadReferencedObject( int index, Repository rep, IMetaStore metaStore, VariableSpace space ) throws KettleException { return loadTransformationMeta( this, rep, metaStore, space ); } public String getStreamSourceStepname() { return streamSourceStepname; } public void setStreamSourceStepname( String streamSourceStepname ) { this.streamSourceStepname = streamSourceStepname; } public StepMeta getStreamSourceStep() { return streamSourceStep; } public void setStreamSourceStep( StepMeta streamSourceStep ) { this.streamSourceStep = streamSourceStep; } public String getStreamTargetStepname() { return streamTargetStepname; } public void setStreamTargetStepname( String streamTargetStepname ) { this.streamTargetStepname = streamTargetStepname; } @Override public void searchInfoAndTargetSteps( List<StepMeta> steps ) { streamSourceStep = StepMeta.findStep( steps, streamSourceStepname ); } public List<MetaInjectOutputField> getSourceOutputFields() { return sourceOutputFields; } public void setSourceOutputFields( List<MetaInjectOutputField> sourceOutputFields ) { this.sourceOutputFields = sourceOutputFields; } public List<MetaInjectMapping> getMetaInjectMapping() { return metaInjectMapping; } public void setMetaInjectMapping( List<MetaInjectMapping> metaInjectMapping ) { this.metaInjectMapping = metaInjectMapping; } public void actualizeMetaInjectMapping() { if ( metaInjectMapping == null || metaInjectMapping.isEmpty() ) { return; } Map<TargetStepAttribute, SourceStepField> targetToSourceMap = convertToMap( metaInjectMapping ); setTargetSourceMapping( targetToSourceMap ); } /** * package-local visibility for testing purposes */ static Map<TargetStepAttribute, SourceStepField> convertToMap( List<MetaInjectMapping> metaInjectMapping ) { Map<TargetStepAttribute, SourceStepField> targetToSourceMap = new HashMap<TargetStepAttribute, SourceStepField>(); for ( MetaInjectMapping mappingEntry : metaInjectMapping ) { if ( !isMappingEntryFilled( mappingEntry ) ) { continue; } TargetStepAttribute targetStepAttribute = createTargetStepAttribute( mappingEntry ); SourceStepField sourceStepField = createSourceStepField( mappingEntry ); targetToSourceMap.put( targetStepAttribute, sourceStepField ); } return targetToSourceMap; } private static TargetStepAttribute createTargetStepAttribute( MetaInjectMapping mappingEntry ) { String targetFieldName = mappingEntry.getTargetField(); if ( targetFieldName.contains( GROUP_AND_NAME_DELIMITER ) ) { String[] targetFieldGroupAndName = targetFieldName.split( "\\" + GROUP_AND_NAME_DELIMITER ); return new TargetStepAttribute( mappingEntry.getTargetStep(), targetFieldGroupAndName[ 1 ], true ); } return new TargetStepAttribute( mappingEntry.getTargetStep(), mappingEntry.getTargetField(), false ); } private static boolean isMappingEntryFilled( MetaInjectMapping mappingEntry ) { if ( mappingEntry.getSourceStep() == null || mappingEntry.getSourceField() == null || mappingEntry .getTargetStep() == null || mappingEntry.getTargetField() == null ) { return false; } return true; } private static SourceStepField createSourceStepField( MetaInjectMapping mappingEntry ) { return new SourceStepField( mappingEntry.getSourceStep(), mappingEntry.getSourceField() ); } @Override public void onStepChange( TransMeta transMeta, StepMeta oldMeta, StepMeta newMeta ) { for ( int i = 0; i < transMeta.nrTransHops(); i++ ) { TransHopMeta hopMeta = transMeta.getTransHop( i ); if ( hopMeta.getFromStep().equals( oldMeta ) ) { StepMeta toStepMeta = hopMeta.getToStep(); if ( ( toStepMeta.getStepMetaInterface() instanceof MetaInjectMeta ) && ( toStepMeta.equals( this .getParentStepMeta() ) ) ) { MetaInjectMeta toMeta = (MetaInjectMeta) toStepMeta.getStepMetaInterface(); Map<TargetStepAttribute, SourceStepField> sourceMapping = toMeta.getTargetSourceMapping(); for ( Entry<TargetStepAttribute, SourceStepField> entry : sourceMapping.entrySet() ) { SourceStepField value = entry.getValue(); if ( value.getStepname().equals( oldMeta.getName() ) ) { value.setStepname( newMeta.getName() ); } } } } } } }