@Override
  public T getMetaForStep( Repository rep, IMetaStore metaStore, VariableSpace space )
    throws KettleException {
    // Note - was a synchronized static method, but as no static variables are manipulated, this is entirely unnecessary

    // baseStepMeta.getParentStepMeta() or getParantTransMeta() is only null when running unit tests
    metaFileCache =
      baseStepMeta.getParentStepMeta() == null || baseStepMeta.getParentStepMeta().getParentTransMeta() == null
        ? null : baseStepMeta.getParentStepMeta().getParentTransMeta().getMetaFileCache();
    T theMeta = null;
    CurrentDirectoryResolver r = new CurrentDirectoryResolver();

    VariableSpace tmpSpace;
    if ( isTransMeta() ) {
      // send restricted parentVariables with several important options
      // Otherwise we destroy child variables and the option "Inherit all variables from the transformation" is enabled
      // always.
      tmpSpace = r.resolveCurrentDirectory( specificationMethod, getVarSpaceOnlyWithRequiredParentVars( space ),
        rep, baseStepMeta.getParentStepMeta(), filename );
    } else {
      tmpSpace =
        r.resolveCurrentDirectory( specificationMethod, space, rep, baseStepMeta.getParentStepMeta(), filename );
    }
    final String[] idContainer = new String[ 1 ]; //unigue portion of cache key passed though argument

    switch ( specificationMethod ) {
      case FILENAME:
        String realFilename = tmpSpace.environmentSubstitute( filename );
        if ( isTransMeta() && space != null ) {
          // This is a parent transformation and parent variable should work here. A child file name can be resolved
          // via parent space.
          realFilename = space.environmentSubstitute( realFilename );
        }
        theMeta = attemptCacheRead( realFilename ); //try to get from the cache first
        if ( theMeta == null ) {
          try {
            // OK, load the meta-data from file...
            // Don't set internal variables: they belong to the parent thread!
            if ( rep != null ) {
              theMeta = getMetaFromRepository2( realFilename, rep, r, idContainer );
            }
            if ( theMeta == null ) {
              theMeta = attemptLoadMeta( realFilename, rep, metaStore, null, tmpSpace, idContainer );
              LogChannel.GENERAL.logDetailed( "Loading " + friendlyMetaType + " from repository",
                friendlyMetaType + " was loaded from XML file [" + realFilename + "]" );
            }
          } catch ( Exception e ) {
            if ( isTransMeta() ) {
              throw new KettleException(
                BaseMessages.getString( persistentClass, "StepWithMappingMeta.Exception.UnableToLoadTrans" ), e );
            } else {
              throw new KettleException(
                BaseMessages.getString( persistentClass, "JobExecutorMeta.Exception.UnableToLoadJob" ), e );
            }
          }
        }
        break;

      case REPOSITORY_BY_NAME:
        String realMetaName = tmpSpace.environmentSubstitute( Const.NVL( metaName, "" ) );
        String realDirectory = tmpSpace.environmentSubstitute( Const.NVL( directory, "" ) );

        if ( isTransMeta() && space != null ) {
          // This is a parent transformation and parent variable should work here. A child file name can be
          // resolved via
          // parent space.
          realMetaName = space.environmentSubstitute( realMetaName );
          realDirectory = space.environmentSubstitute( realDirectory );
        }

        if ( Utils.isEmpty( realDirectory ) && !Utils.isEmpty( realMetaName ) ) {
          int index = realMetaName.lastIndexOf( '/' );
          String transPath = realMetaName;
          realMetaName = realMetaName.substring( index + 1 );
          realDirectory = transPath.substring( 0, index );
        }

        //We will use this key in cache no matter what the final successful path is so that we don't need to hit the
        //  repo the next time it comes in. (ie: rep.findDirectory )
        String cacheKey = realDirectory + "/" + realMetaName;
        theMeta = attemptCacheRead( cacheKey ); //try to get from the cache first
        if ( theMeta == null ) {
          if ( rep != null ) {
            if ( !Utils.isEmpty( realMetaName ) && !Utils.isEmpty( realDirectory ) ) {

              realDirectory = r.normalizeSlashes( realDirectory );
              RepositoryDirectoryInterface repdir = rep.findDirectory( realDirectory );
              if ( repdir != null ) {
                try {
                  // reads the last revision in the repository...
                  theMeta = isTransMeta() ? (T) rep.loadTransformation( realMetaName, repdir, null, true, null )
                    : (T) rep.loadJob( realMetaName, repdir, null, null );
                  if ( theMeta != null ) {
                    idContainer[ 0 ] = cacheKey;
                  }
                  LogChannel.GENERAL.logDetailed( "Loading " + friendlyMetaType + " from repository",
                    "Executor " + friendlyMetaType + " [" + realMetaName + "] was loaded from the repository" );
                } catch ( Exception e ) {
                  throw new KettleException( "Unable to load " + friendlyMetaType + " [" + realMetaName + "]", e );
                }
              }
            }
          } else {
            // rep is null, let's try loading by filename
            try {
              theMeta = attemptLoadMeta( cacheKey, rep, metaStore, null, tmpSpace, idContainer );
            } catch ( KettleException ke ) {
              try {
                // add .ktr extension and try again
                String extension = isTransMeta() ? Const.STRING_TRANS_DEFAULT_EXT : Const.STRING_JOB_DEFAULT_EXT;
                theMeta =
                  attemptLoadMeta( cacheKey + "." + extension, rep, metaStore, null,
                    tmpSpace, idContainer );
                if ( idContainer[ 0 ] != null ) {
                  //It successfully read in the meta but we don't want to cache it with the extension so we override
                  // it here
                  idContainer[ 0 ] = cacheKey;
                }
              } catch ( KettleException ke2 ) {
                if ( isTransMeta() ) {
                  throw new KettleException(
                    BaseMessages.getString( persistentClass, "StepWithMappingMeta.Exception.UnableToLoadTrans",
                      realMetaName ) + realDirectory );
                } else {
                  throw new KettleException(
                    BaseMessages.getString( persistentClass, "JobExecutorMeta.Exception.UnableToLoadJob",
                      realMetaName ) + realDirectory );
                }
              }
            }
          }
        }
        break;

      case REPOSITORY_BY_REFERENCE:
        // Read the last revision by reference...
        theMeta = attemptCacheRead( metaObjectId.toString() );
        if ( theMeta == null ) {
          theMeta = isTransMeta() ? (T) rep.loadTransformation( metaObjectId, null )
            : (T) rep.loadJob( metaObjectId, null );
          if ( theMeta != null ) {
            idContainer[ 0 ] = metaObjectId.toString(); //Only set when not found in cache
          }
        }
        break;
      default:
        break;
    }

    //If theMeta is present and idContainer[0] != null, ( meaning it read it from repo/file ), then cache it
    cacheMeta( idContainer[ 0 ], theMeta );
    return theMeta;
  }
@Test
  //A Transformation getting the TransMeta from the file system
  public void getMetaForStepAsTransFromFileSystemTest() throws Exception {
    setupTransExecutorMeta();
    specificationMethod = ObjectLocationSpecificationMethod.FILENAME;
    MetaFileLoaderImpl metaFileLoader = new MetaFileLoaderImpl<TransMeta>( baseStepMeta, specificationMethod );
    TransMeta transMeta = (TransMeta) metaFileLoader.getMetaForStep( repository, store, space );
    validateFirstTransMetaAccess( transMeta );
    transMeta = (TransMeta) metaFileLoader.getMetaForStep( repository, store, space );
    validateSecondTransMetaAccess( transMeta );
  }