Skip to content

Commit

Permalink
[PDI-14852] setVariable in Javascript Step with scope of parent job d…
Browse files Browse the repository at this point in the history
…oes not work

- Refactoring (changing variable names, representing variable scopes as enums, separating logic of setting variable on different scope-levels in different methods)
- Starting to climb variable-space hierarchy from the step's transformation (not from the step itself, as the first call to step's parent will lead to the transformation itself, which is not the expected behavior)
  • Loading branch information
Ivan Nikolaichuk authored and Ivan Nikolaichuk committed May 18, 2016
1 parent 20f428f commit f66b87c
Show file tree
Hide file tree
Showing 3 changed files with 388 additions and 74 deletions.
Expand Up @@ -79,6 +79,7 @@
import org.pentaho.di.core.util.EnvUtil;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.core.vfs.KettleVFS;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.steps.loadfileinput.LoadFileInput;

Expand Down Expand Up @@ -107,6 +108,15 @@ public class ScriptValuesAddedFunctions extends ScriptableObject {
"protectXMLCDATA", "unEscapeXml", "escapeSQL", "escapeHtml", "unEscapeHtml", "loadFileContent",
"getOcuranceString", "removeCRLF" };


enum VariableScope {
SYSTEM,
ROOT,
PARENT,
GRAND_PARENT
}


// This is only used for reading, so no concurrency problems.
// todo: move in the real variables of the step.
// private static VariableSpace variables = Variables.getADefaultVariableSpace();
Expand Down Expand Up @@ -395,11 +405,11 @@ public static Object ceil( Context actualContext, Scriptable actualObject, Objec
if ( ArgList.length == 1 ) {
try {
if ( isNull( ArgList[0] ) ) {
return new Double( Double.NaN );
return Double.NaN;
} else if ( isUndefined( ArgList[0] ) ) {
return Context.getUndefinedValue();
} else {
return new Double( Math.ceil( Context.toNumber( ArgList[0] ) ) );
return Math.ceil( Context.toNumber( ArgList[ 0 ] ) );
}
} catch ( Exception e ) {
return null;
Expand Down Expand Up @@ -1692,14 +1702,14 @@ public static String substr( Context actualContext, Scriptable actualObject, Obj
// Resolve an IP address
public static String resolveIP( Context actualContext, Scriptable actualObject, Object[] ArgList,
Function FunctionContext ) {
String sRC = "";
String sRC;
if ( ArgList.length == 2 ) {
try {
InetAddress addr = InetAddress.getByName( Context.toString( ArgList[0] ) );
InetAddress address = InetAddress.getByName( Context.toString( ArgList[0] ) );
if ( Context.toString( ArgList[1] ).equals( "IP" ) ) {
sRC = addr.getHostName();
sRC = address.getHostName();
} else {
sRC = addr.getHostAddress();
sRC = address.getHostAddress();
}
if ( sRC.equals( Context.toString( ArgList[0] ) ) ) {
sRC = "-";
Expand Down Expand Up @@ -1790,77 +1800,92 @@ private static void checkAndLoadJSFile( Context actualContext, Scriptable eval_s
}
}

// Setting Variable
public static void setVariable( Context actualContext, Scriptable actualObject, Object[] ArgList,
Function FunctionContext ) {
String sArg1 = "";
String sArg2 = "";
String sArg3 = "";
if ( ArgList.length == 3 ) {
try {
Object scmo = actualObject.get( "_step_", actualObject );
Object scmO = Context.jsToJava( scmo, StepInterface.class );
if ( scmO instanceof StepInterface ) {
StepInterface scm = (StepInterface) scmO;
public static void setVariable( Context actualContext, Scriptable actualObject, Object[] arguments,
Function functionContext ) {

sArg1 = Context.toString( ArgList[0] );
sArg2 = Context.toString( ArgList[1] );
sArg3 = Context.toString( ArgList[2] );
if ( arguments.length != 3 ) {
throw Context.reportRuntimeError( "The function call setVariable requires 3 arguments." );
}

Object stepObject = Context.jsToJava( actualObject.get( "_step_", actualObject ), StepInterface.class );
if ( stepObject instanceof StepInterface ) {
StepInterface step = (StepInterface) stepObject;
Trans trans = step.getTrans();
final String variableName = Context.toString( arguments[ 0 ] );
final String variableValue = Context.toString( arguments[ 1 ] );
final VariableScope variableScope = getVariableScope( Context.toString( arguments[ 2 ] ) );

switch( variableScope ) {
case PARENT:
setParentScopeVariable( trans, variableName, variableValue );
break;
case GRAND_PARENT:
setGrandParentScopeVariable( trans, variableName, variableValue );
break;
case ROOT:
setRootScopeVariable( trans, variableName, variableValue );
break;
case SYSTEM:
setSystemScopeVariable( trans, variableName, variableValue );
break;
}
}
}

if ( "s".equals( sArg3 ) ) {
// System wide properties
System.setProperty( sArg1, sArg2 );
static void setRootScopeVariable( Trans trans, String variableName, String variableValue ) {
trans.setVariable( variableName, variableValue );

// Set also all the way to the root as else we will take
// stale values
scm.setVariable( sArg1, sArg2 );
VariableSpace parentSpace = trans.getParentVariableSpace();
while ( parentSpace != null ) {
parentSpace.setVariable( variableName, variableValue );
parentSpace = parentSpace.getParentVariableSpace();
}
}

VariableSpace parentSpace = scm.getParentVariableSpace();
while ( parentSpace != null ) {
parentSpace.setVariable( sArg1, sArg2 );
parentSpace = parentSpace.getParentVariableSpace();
}
} else if ( "r".equals( sArg3 ) ) {
// Upto the root... this should be the default.
scm.setVariable( sArg1, sArg2 );

VariableSpace parentSpace = scm.getParentVariableSpace();
while ( parentSpace != null ) {
parentSpace.setVariable( sArg1, sArg2 );
parentSpace = parentSpace.getParentVariableSpace();
}
} else if ( "p".equals( sArg3 ) ) {
// Upto the parent
scm.setVariable( sArg1, sArg2 );
static void setSystemScopeVariable( Trans trans, final String variableName, final String variableValue ) {
System.setProperty( variableName, variableValue );

VariableSpace parentSpace = scm.getParentVariableSpace();
if ( parentSpace != null ) {
parentSpace.setVariable( sArg1, sArg2 );
}
} else if ( "g".equals( sArg3 ) ) {
// Upto the grand parent
scm.setVariable( sArg1, sArg2 );

VariableSpace parentSpace = scm.getParentVariableSpace();
if ( parentSpace != null ) {
parentSpace.setVariable( sArg1, sArg2 );
VariableSpace grandParentSpace = parentSpace.getParentVariableSpace();
if ( grandParentSpace != null ) {
grandParentSpace.setVariable( sArg1, sArg2 );
}
}
} else {
throw Context.reportRuntimeError( "The argument type of function call "
+ "setVariable should either be \"s\", \"r\", \"p\", or \"g\"." );
}
}
// Ignore else block for now... if we're executing via the Test Button
// Set also all the way to the root as else we will take
// stale values
setRootScopeVariable( trans, variableName, variableValue );
}

} catch ( Exception e ) {
throw Context.reportRuntimeError( e.toString() );
static void setParentScopeVariable( Trans trans, String variableName, String variableValue ) {
trans.setVariable( variableName, variableValue );

VariableSpace parentSpace = trans.getParentVariableSpace();
if ( parentSpace != null ) {
parentSpace.setVariable( variableName, variableValue );
}
}

static void setGrandParentScopeVariable( Trans trans, String variableName, String variableValue ) {
trans.setVariable( variableName, variableValue );

VariableSpace parentSpace = trans.getParentVariableSpace();
if ( parentSpace != null ) {
parentSpace.setVariable( variableName, variableValue );
VariableSpace grandParentSpace = parentSpace.getParentVariableSpace();
if ( grandParentSpace != null ) {
grandParentSpace.setVariable( variableName, variableValue );
}
} else {
throw Context.reportRuntimeError( "The function call setVariable requires 3 arguments." );
}
}


static VariableScope getVariableScope( String codeOfScope ) {
switch( codeOfScope ) {
case "s":
return VariableScope.SYSTEM;
case "r":
return VariableScope.ROOT;
case "p":
return VariableScope.PARENT;
case "g":
return VariableScope.GRAND_PARENT;
default:
throw Context.reportRuntimeError( "The argument type of function call "
+ "setVariable should either be \"s\", \"r\", \"p\", or \"g\"." );
}
}

Expand Down Expand Up @@ -2580,7 +2605,7 @@ public static String execProcess( Context actualContext, Scriptable actualObject
while ( ( ligne = br.readLine() ) != null ) {
buffer.append( ligne );
}
// if (processrun.exitValue()!=0) throw Context.reportRuntimeError("Error while running " + ArgList[0]);
// if (processrun.exitValue()!=0) throw Context.reportRuntimeError("Error while running " + arguments[0]);

retval = buffer.toString();

Expand Down Expand Up @@ -2623,7 +2648,7 @@ public static Boolean isEmpty( Context actualContext, Scriptable actualObject, O

public static Boolean isMailValid( Context actualContext, Scriptable actualObject, Object[] ArgList,
Function FunctionContext ) {
Boolean retval = Boolean.FALSE;
Boolean isValid;
if ( ArgList.length == 1 ) {
try {
if ( isUndefined( ArgList[0] ) ) {
Expand All @@ -2641,12 +2666,12 @@ public static Boolean isMailValid( Context actualContext, Scriptable actualObjec
return Boolean.FALSE;
}

retval = Boolean.TRUE;
isValid = Boolean.TRUE;

} catch ( Exception e ) {
throw Context.reportRuntimeError( "Error in isMailValid function: " + e.getMessage() );
}
return retval;
return isValid;
} else {
throw Context.reportRuntimeError( "The function call isMailValid is not valid" );
}
Expand Down
@@ -0,0 +1,57 @@
/*! ******************************************************************************
*
* 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.trans.steps.scriptvalues_mod;

import org.junit.Test;
import org.mozilla.javascript.EvaluatorException;

import static junit.framework.Assert.assertEquals;

public class ScriptValueAddFunctions_GetVariableScopeTest {

@Test
public void getSystemVariableScope() {
assertEquals( ScriptValuesAddedFunctions.getVariableScope( "s" ), ScriptValuesAddedFunctions.VariableScope.SYSTEM );
}

@Test
public void getRootVariableScope() {
assertEquals( ScriptValuesAddedFunctions.getVariableScope( "r" ), ScriptValuesAddedFunctions.VariableScope.ROOT );
}

@Test
public void getParentVariableScope() {
assertEquals( ScriptValuesAddedFunctions.getVariableScope( "p" ), ScriptValuesAddedFunctions.VariableScope.PARENT );
}

@Test
public void getGrandParentVariableScope() {
assertEquals( ScriptValuesAddedFunctions.getVariableScope( "g" ),
ScriptValuesAddedFunctions.VariableScope.GRAND_PARENT );
}

@Test( expected = EvaluatorException.class )
public void getNonExistingVariableScope() {
ScriptValuesAddedFunctions.getVariableScope( "dummy" );
}
}

0 comments on commit f66b87c

Please sign in to comment.