Merge pull request #2974 from hansva/master

Update dependencies that we have controle over. fixes #2957
diff --git a/core/src/main/java/org/apache/hop/core/Const.java b/core/src/main/java/org/apache/hop/core/Const.java
index a2ec520..7dedb21 100644
--- a/core/src/main/java/org/apache/hop/core/Const.java
+++ b/core/src/main/java/org/apache/hop/core/Const.java
@@ -522,7 +522,8 @@
   public static boolean toBoolean(String string) {
     return "y".equalsIgnoreCase(string)
         || "yes".equalsIgnoreCase(string)
-        || "true".equalsIgnoreCase(string);
+        || "true".equalsIgnoreCase(string)
+        || "t".equalsIgnoreCase(string);
   }
 
   /**
diff --git a/core/src/test/java/org/apache/hop/core/ConstTest.java b/core/src/test/java/org/apache/hop/core/ConstTest.java
index 115b38d..db795ce 100644
--- a/core/src/test/java/org/apache/hop/core/ConstTest.java
+++ b/core/src/test/java/org/apache/hop/core/ConstTest.java
@@ -2756,6 +2756,8 @@
     assertTrue(Const.toBoolean("true"));
     assertTrue(Const.toBoolean("True"));
     assertTrue(Const.toBoolean("TRUE"));
+    assertTrue(Const.toBoolean("T"));
+    assertTrue(Const.toBoolean("t"));
     assertFalse(Const.toBoolean("N"));
     assertFalse(Const.toBoolean("n"));
     assertFalse(Const.toBoolean("treu"));
diff --git a/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariables.java b/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariables.java
index 3a0fd28..e885241 100644
--- a/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariables.java
+++ b/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariables.java
@@ -17,18 +17,24 @@
 
 package org.apache.hop.workflow.actions.setvariables;
 
-import org.apache.hop.core.Const;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
 import org.apache.hop.core.ICheckResult;
 import org.apache.hop.core.Result;
 import org.apache.hop.core.annotations.Action;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopWorkflowException;
-import org.apache.hop.core.exception.HopXmlException;
 import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.core.vfs.HopVfs;
-import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.metadata.api.HopMetadataProperty;
+import org.apache.hop.metadata.api.IEnumHasCode;
+import org.apache.hop.metadata.api.IEnumHasCodeAndDescription;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.resource.ResourceEntry;
 import org.apache.hop.resource.ResourceEntry.ResourceType;
@@ -41,14 +47,6 @@
 import org.apache.hop.workflow.action.validator.AndValidator;
 import org.apache.hop.workflow.action.validator.ValidatorContext;
 import org.apache.hop.workflow.engine.IWorkflowEngine;
-import org.w3c.dom.Node;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
 
 /** This defines a 'Set variables' action. */
 @Action(
@@ -62,124 +60,122 @@
 public class ActionSetVariables extends ActionBase implements Cloneable, IAction {
   private static final Class<?> PKG = ActionSetVariables.class; // For Translator
 
-  public boolean replaceVars;
+  @HopMetadataProperty(key = "replacevars")
+  private boolean replaceVars;
 
-  public String[] variableName;
+  @HopMetadataProperty(groupKey = "fields", key = "field")
+  private List<VariableDefinition> variableDefinitions;
 
-  public String[] variableValue;
+  @HopMetadataProperty(key = "filename")
+  private String filename;
 
-  public int[] variableType;
+  @HopMetadataProperty(key = "file_variable_type")
+  private VariableType fileVariableType;
 
-  public String filename;
+  public enum VariableType implements IEnumHasCodeAndDescription {
+    JVM(BaseMessages.getString(PKG, "ActionSetVariables.VariableType.JVM")),
+    CURRENT_WORKFLOW(
+        BaseMessages.getString(PKG, "ActionSetVariables.VariableType.CurrentWorkflow")),
+    PARENT_WORKFLOW(BaseMessages.getString(PKG, "ActionSetVariables.VariableType.ParentWorkflow")),
+    ROOT_WORKFLOW(BaseMessages.getString(PKG, "ActionSetVariables.VariableType.RootWorkflow"));
 
-  public int fileVariableType;
+    private final String description;
 
-  public static final int VARIABLE_TYPE_JVM = 0;
-  public static final int VARIABLE_TYPE_CURRENT_WORKFLOW = 1;
-  public static final int VARIABLE_TYPE_PARENT_WORKFLOW = 2;
-  public static final int VARIABLE_TYPE_ROOT_WORKFLOW = 3;
+    VariableType(String description) {
+      this.description = description;
+    }
 
-  public static final String[] variableTypeCode = {
-    "JVM", "CURRENT_WORKFLOW", "PARENT_WORKFLOW", "ROOT_WORKFLOW"
-  };
-  private static final String[] variableTypeDesc = {
-    BaseMessages.getString(PKG, "ActionSetVariables.VariableType.JVM"),
-    BaseMessages.getString(PKG, "ActionSetVariables.VariableType.CurrentWorkflow"),
-    BaseMessages.getString(PKG, "ActionSetVariables.VariableType.ParentWorkflow"),
-    BaseMessages.getString(PKG, "ActionSetVariables.VariableType.RootWorkflow"),
-  };
+    public static String[] getDescriptions() {
+      return IEnumHasCodeAndDescription.getDescriptions(VariableType.class);
+    }
+
+    public static VariableType lookupDescription(final String description) {
+      return IEnumHasCodeAndDescription.lookupDescription(VariableType.class, description, JVM);
+    }
+
+    public static VariableType lookupCode(final String code) {
+      return IEnumHasCode.lookupCode(VariableType.class, code, JVM);
+    }
+
+    @Override
+    public String getCode() {
+      return name();
+    }
+
+    @Override
+    public String getDescription() {
+      return description;
+    }
+  }
+
+  public static final class VariableDefinition {
+    public VariableDefinition() {
+      super();
+    }
+
+    public VariableDefinition(String name, String value, VariableType type) {
+      super();
+      this.name = name;
+      this.value = value;
+      this.type = type;
+    }
+
+    @HopMetadataProperty(key = "variable_name")
+    private String name;
+
+    @HopMetadataProperty(key = "variable_value")
+    private String value;
+
+    @HopMetadataProperty(key = "variable_type")
+    private VariableType type;
+
+    public String getName() {
+      return name;
+    }
+
+    public void setName(String name) {
+      this.name = name;
+    }
+
+    public String getValue() {
+      return value;
+    }
+
+    public void setValue(String value) {
+      this.value = value;
+    }
+
+    public VariableType getType() {
+      return type;
+    }
+
+    public void setType(VariableType type) {
+      this.type = type;
+    }
+  }
 
   public ActionSetVariables(String n) {
     super(n, "");
     replaceVars = true;
-    variableName = null;
-    variableValue = null;
+    fileVariableType = VariableType.CURRENT_WORKFLOW;
+    variableDefinitions = new ArrayList<>();
   }
 
   public ActionSetVariables() {
     this("");
   }
 
-  public void allocate(int nrFields) {
-    variableName = new String[nrFields];
-    variableValue = new String[nrFields];
-    variableType = new int[nrFields];
+  public ActionSetVariables(ActionSetVariables other) {
+    super(other.getName(), other.getDescription(), other.getPluginId());
+    this.filename = other.getFilename();
+    this.fileVariableType = other.getFileVariableType();
+    this.replaceVars = other.isReplaceVars();
+    this.variableDefinitions = other.getVariableDefinitions();
   }
 
   @Override
   public Object clone() {
-    ActionSetVariables je = (ActionSetVariables) super.clone();
-    if (variableName != null) {
-      int nrFields = variableName.length;
-      je.allocate(nrFields);
-      System.arraycopy(variableName, 0, je.variableName, 0, nrFields);
-      System.arraycopy(variableValue, 0, je.variableValue, 0, nrFields);
-      System.arraycopy(variableType, 0, je.variableType, 0, nrFields);
-    }
-    return je;
-  }
-
-  @Override
-  public String getXml() {
-    StringBuilder retval = new StringBuilder(300);
-    retval.append(super.getXml());
-    retval.append("      ").append(XmlHandler.addTagValue("replacevars", replaceVars));
-
-    retval.append("      ").append(XmlHandler.addTagValue("filename", filename));
-    retval
-        .append("      ")
-        .append(
-            XmlHandler.addTagValue("file_variable_type", getVariableTypeCode(fileVariableType)));
-
-    retval.append("      <fields>").append(Const.CR);
-    if (variableName != null) {
-      for (int i = 0; i < variableName.length; i++) {
-        retval.append("        <field>").append(Const.CR);
-        retval
-            .append("          ")
-            .append(XmlHandler.addTagValue("variable_name", variableName[i]));
-        retval
-            .append("          ")
-            .append(XmlHandler.addTagValue("variable_value", variableValue[i]));
-        retval
-            .append("          ")
-            .append(XmlHandler.addTagValue("variable_type", getVariableTypeCode(variableType[i])));
-        retval.append("        </field>").append(Const.CR);
-      }
-    }
-    retval.append("      </fields>").append(Const.CR);
-
-    return retval.toString();
-  }
-
-  @Override
-  public void loadXml(Node entrynode, IHopMetadataProvider metadataProvider, IVariables variables)
-      throws HopXmlException {
-    try {
-      super.loadXml(entrynode);
-      replaceVars = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, "replacevars"));
-
-      filename = XmlHandler.getTagValue(entrynode, "filename");
-      fileVariableType = getVariableType(XmlHandler.getTagValue(entrynode, "file_variable_type"));
-
-      Node fields = XmlHandler.getSubNode(entrynode, "fields");
-      // How many field variableName?
-      int nrFields = XmlHandler.countNodes(fields, "field");
-      allocate(nrFields);
-
-      // Read them all...
-      for (int i = 0; i < nrFields; i++) {
-        Node fnode = XmlHandler.getSubNodeByNr(fields, "field", i);
-
-        variableName[i] = XmlHandler.getTagValue(fnode, "variable_name");
-        variableValue[i] = XmlHandler.getTagValue(fnode, "variable_value");
-        variableType[i] = getVariableType(XmlHandler.getTagValue(fnode, "variable_type"));
-      }
-    } catch (HopXmlException xe) {
-      throw new HopXmlException(
-          BaseMessages.getString(PKG, "ActionSetVariables.Meta.UnableLoadXML", xe.getMessage()),
-          xe);
-    }
+    return new ActionSetVariables(this);
   }
 
   @Override
@@ -188,9 +184,7 @@
     result.setNrErrors(0);
     try {
 
-      List<String> variables = new ArrayList<>();
-      List<String> variableValues = new ArrayList<>();
-      List<Integer> variableTypes = new ArrayList<>();
+      List<VariableDefinition> definitions = new ArrayList<>();
 
       String realFilename = resolve(filename);
       if (!Utils.isEmpty(realFilename)) {
@@ -201,9 +195,9 @@
           Properties properties = new Properties();
           properties.load(reader);
           for (Object key : properties.keySet()) {
-            variables.add((String) key);
-            variableValues.add((String) properties.get(key));
-            variableTypes.add(fileVariableType);
+            definitions.add(
+                new VariableDefinition(
+                    (String) key, (String) properties.get(key), fileVariableType));
           }
         } catch (Exception e) {
           throw new HopException(
@@ -212,13 +206,7 @@
         }
       }
 
-      if (variableName != null) {
-        for (int i = 0; i < variableName.length; i++) {
-          variables.add(variableName[i]);
-          variableValues.add(variableValue[i]);
-          variableTypes.add(variableType[i]);
-        }
-      }
+      definitions.addAll(variableDefinitions);
 
       // if parentWorkflow exists - clear/reset all entrySetVariables before applying the actual
       // ones
@@ -239,85 +227,84 @@
         }
       }
 
-      for (int i = 0; i < variables.size(); i++) {
-        String varname = variables.get(i);
-        String value = variableValues.get(i);
-        int type = variableTypes.get(i);
+      for (VariableDefinition definition : definitions) {
+        String name = definition.getName();
+        String value = definition.getValue();
 
         if (replaceVars) {
-          varname = resolve(varname);
+          name = resolve(name);
           value = resolve(value);
         }
 
         // OK, where do we set this value...
-        switch (type) {
-          case VARIABLE_TYPE_JVM:
+        switch (definition.getType()) {
+          case JVM:
             if (value != null) {
-              System.setProperty(varname, value);
+              System.setProperty(name, value);
             } else {
-              System.clearProperty(varname);
+              System.clearProperty(name);
             }
-            setVariable(varname, value);
+            setVariable(name, value);
             IWorkflowEngine<WorkflowMeta> parentWorkflowTraverse = parentWorkflow;
             while (parentWorkflowTraverse != null) {
-              parentWorkflowTraverse.setVariable(varname, value);
+              parentWorkflowTraverse.setVariable(name, value);
               parentWorkflowTraverse = parentWorkflowTraverse.getParentWorkflow();
             }
             break;
 
-          case VARIABLE_TYPE_ROOT_WORKFLOW:
+          case ROOT_WORKFLOW:
             // set variable in this action
-            setVariable(varname, value);
+            setVariable(name, value);
             IWorkflowEngine<WorkflowMeta> rootWorkflow = parentWorkflow;
             while (rootWorkflow != null) {
-              rootWorkflow.setVariable(varname, value);
+              rootWorkflow.setVariable(name, value);
               rootWorkflow = rootWorkflow.getParentWorkflow();
             }
             break;
 
-          case VARIABLE_TYPE_CURRENT_WORKFLOW:
-            setVariable(varname, value);
+          case CURRENT_WORKFLOW:
+            setVariable(name, value);
 
             if (parentWorkflow != null) {
-              String parameterValue = parentWorkflow.getParameterValue(varname);
+              String parameterValue = parentWorkflow.getParameterValue(name);
               // if not a parameter, set the value
               if (parameterValue == null) {
-                setEntryTransformSetVariable(varname, value);
+                setEntryTransformSetVariable(name, value);
               } else {
                 // if parameter, save the initial parameter value for use in reset/clear variables
                 // in future calls
                 if (parameterValue != null
-                    && parameterValue != value
-                    && !entryTransformSetVariablesMap.containsKey(varname)) {
-                  setEntryTransformSetVariable(varname, parameterValue);
+                    && !parameterValue.equals(value)
+                    && !entryTransformSetVariablesMap.containsKey(name)) {
+                  setEntryTransformSetVariable(name, parameterValue);
                 }
               }
-              parentWorkflow.setVariable(varname, value);
+              parentWorkflow.setVariable(name, value);
 
             } else {
               throw new HopWorkflowException(
                   BaseMessages.getString(
-                      PKG, "ActionSetVariables.Error.UnableSetVariableCurrentWorkflow", varname));
+                      PKG, "ActionSetVariables.Error.UnableSetVariableCurrentWorkflow", name));
             }
             break;
 
-          case VARIABLE_TYPE_PARENT_WORKFLOW:
-            setVariable(varname, value);
+          case PARENT_WORKFLOW:
+            setVariable(name, value);
 
             if (parentWorkflow != null) {
-              parentWorkflow.setVariable(varname, value);
+              parentWorkflow.setVariable(name, value);
               IWorkflowEngine<WorkflowMeta> gpWorkflow = parentWorkflow.getParentWorkflow();
               if (gpWorkflow != null) {
-                gpWorkflow.setVariable(varname, value);
+                gpWorkflow.setVariable(name, value);
               } else {
                 throw new HopWorkflowException(
                     BaseMessages.getString(
-                        PKG, "ActionSetVariables.Error.UnableSetVariableParentWorkflow", varname));
+                        PKG, "ActionSetVariables.Error.UnableSetVariableParentWorkflow", name));
               }
             } else {
               throw new HopWorkflowException(
                   BaseMessages.getString(
-                      PKG, "ActionSetVariables.Error.UnableSetVariableCurrentWorkflow", varname));
+                      PKG, "ActionSetVariables.Error.UnableSetVariableCurrentWorkflow", name));
             }
             break;
 
@@ -329,7 +316,7 @@
         if (log.isDetailed()) {
           logDetailed(
               BaseMessages.getString(
-                  PKG, "ActionSetVariables.Log.SetVariableToValue", varname, value));
+                  PKG, "ActionSetVariables.Log.SetVariableToValue", name, value));
         }
       }
     } catch (Exception e) {
@@ -355,64 +342,12 @@
     return replaceVars;
   }
 
-  public String[] getVariableValue() {
-    return variableValue;
+  public List<VariableDefinition> getVariableDefinitions() {
+    return variableDefinitions;
   }
 
-  /** @param fieldValue The fieldValue to set. */
-  public void setVariableName(String[] fieldValue) {
-    this.variableName = fieldValue;
-  }
-
-  /**
-   * @return Returns the local variable flag: true if this variable is only valid in the parents
-   *     workflow.
-   */
-  public int[] getVariableType() {
-    return variableType;
-  }
-
-  /**
-   * @param variableType The variable type, see also VARIABLE_TYPE_...
-   * @return the variable type code for this variable type
-   */
-  public static final String getVariableTypeCode(int variableType) {
-    return variableTypeCode[variableType];
-  }
-
-  /**
-   * @param variableType The variable type, see also VARIABLE_TYPE_...
-   * @return the variable type description for this variable type
-   */
-  public static final String getVariableTypeDescription(int variableType) {
-    return variableTypeDesc[variableType];
-  }
-
-  /**
-   * @param variableType The code or description of the variable type
-   * @return The variable type
-   */
-  public static final int getVariableType(String variableType) {
-    for (int i = 0; i < variableTypeCode.length; i++) {
-      if (variableTypeCode[i].equalsIgnoreCase(variableType)) {
-        return i;
-      }
-    }
-    for (int i = 0; i < variableTypeDesc.length; i++) {
-      if (variableTypeDesc[i].equalsIgnoreCase(variableType)) {
-        return i;
-      }
-    }
-    return VARIABLE_TYPE_JVM;
-  }
-
-  /** @param localVariable The localVariable to set. */
-  public void setVariableType(int[] localVariable) {
-    this.variableType = localVariable;
-  }
-
-  public static final String[] getVariableTypeDescriptions() {
-    return variableTypeDesc;
+  public void setVariableDefinitions(List<VariableDefinition> variableDefinitions) {
+    this.variableDefinitions = variableDefinitions;
   }
 
   @Override
@@ -429,7 +364,7 @@
                 remarks,
                 AndValidator.putValidators(ActionValidatorUtils.notNullValidator()));
 
-    if (res == false) {
+    if (!res) {
       return;
     }
 
@@ -437,48 +372,49 @@
     AbstractFileValidator.putVariableSpace(ctx, getVariables());
     AndValidator.putValidators(
         ctx, ActionValidatorUtils.notNullValidator(), ActionValidatorUtils.fileExistsValidator());
-
-    for (int i = 0; i < variableName.length; i++) {
-      ActionValidatorUtils.andValidator().validate(this, "variableName[" + i + "]", remarks, ctx);
-    }
   }
 
   @Override
   public List<ResourceReference> getResourceDependencies(
       IVariables variables, WorkflowMeta workflowMeta) {
     List<ResourceReference> references = super.getResourceDependencies(variables, workflowMeta);
-    if (variableName != null) {
-      ResourceReference reference = null;
-      for (int i = 0; i < variableName.length; i++) {
-        String filename = resolve(variableName[i]);
-        if (reference == null) {
-          reference = new ResourceReference(this);
-          references.add(reference);
-        }
-        reference.getEntries().add(new ResourceEntry(filename, ResourceType.FILE));
-      }
+
+    String realFilename = resolve(this.filename);
+    if (!Utils.isEmpty(realFilename)) {
+      ResourceReference reference = new ResourceReference(this);
+      references.add(reference);
+      reference.getEntries().add(new ResourceEntry(realFilename, ResourceType.FILE));
     }
+
     return references;
   }
 
-  /** @return the filename */
+  /**
+   * @return the filename
+   */
   @Override
   public String getFilename() {
     return filename;
   }
 
-  /** @param filename the filename to set */
+  /**
+   * @param filename the filename to set
+   */
   public void setFilename(String filename) {
     this.filename = filename;
   }
 
-  /** @return the fileVariableType */
-  public int getFileVariableType() {
+  /**
+   * @return the fileVariableType
+   */
+  public VariableType getFileVariableType() {
     return fileVariableType;
   }
 
-  /** @param fileVariableType the fileVariableType to set */
-  public void setFileVariableType(int fileVariableType) {
-    this.fileVariableType = fileVariableType;
+  /**
+   * @param scope the fileVariableType to set
+   */
+  public void setFileVariableType(VariableType scope) {
+    this.fileVariableType = scope;
   }
 }
diff --git a/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariablesDialog.java b/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariablesDialog.java
index 1af2dea..1ee36b9 100644
--- a/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariablesDialog.java
+++ b/plugins/actions/setvariables/src/main/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariablesDialog.java
@@ -17,6 +17,8 @@
 
 package org.apache.hop.workflow.actions.setvariables;
 
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
@@ -33,11 +35,11 @@
 import org.apache.hop.workflow.WorkflowMeta;
 import org.apache.hop.workflow.action.IAction;
 import org.apache.hop.workflow.action.IActionDialog;
+import org.apache.hop.workflow.actions.setvariables.ActionSetVariables.VariableDefinition;
+import org.apache.hop.workflow.actions.setvariables.ActionSetVariables.VariableType;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.CCombo;
 import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.layout.FormAttachment;
 import org.eclipse.swt.layout.FormData;
 import org.eclipse.swt.layout.FormLayout;
@@ -170,7 +172,7 @@
     fdFileVariableType.top = new FormAttachment(wFilename, margin);
     fdFileVariableType.right = new FormAttachment(100, 0);
     wFileVariableType.setLayoutData(fdFileVariableType);
-    wFileVariableType.setItems(ActionSetVariables.getVariableTypeDescriptions());
+    wFileVariableType.setItems(VariableType.getDescriptions());
 
     FormData fdgFilename = new FormData();
     fdgFilename.left = new FormAttachment(0, margin);
@@ -206,13 +208,7 @@
     fdVarSubs.top = new FormAttachment(wlVarSubs, 0, SWT.CENTER);
     fdVarSubs.right = new FormAttachment(100, 0);
     wVarSubs.setLayoutData(fdVarSubs);
-    wVarSubs.addSelectionListener(
-        new SelectionAdapter() {
-          @Override
-          public void widgetSelected(SelectionEvent e) {
-            action.setChanged();
-          }
-        });
+    wVarSubs.addListener(SWT.Selection, e -> action.setChanged());
 
     FormData fdgSettings = new FormData();
     fdgSettings.left = new FormAttachment(0, margin);
@@ -232,10 +228,7 @@
     fdlFields.top = new FormAttachment(gSettings, margin);
     wlFields.setLayoutData(fdlFields);
 
-    int rows =
-        action.variableName == null
-            ? 1
-            : (action.variableName.length == 0 ? 0 : action.variableName.length);
+    int rows = action.getVariableDefinitions().size();
     final int FieldsRows = rows;
 
     ColumnInfo[] colinf = {
@@ -250,7 +243,7 @@
       new ColumnInfo(
           BaseMessages.getString(PKG, "ActionSetVariables.Fields.Column.VariableType"),
           ColumnInfo.COLUMN_TYPE_CCOMBO,
-          ActionSetVariables.getVariableTypeDescriptions(),
+          VariableType.getDescriptions(),
           false),
     };
     colinf[0].setUsingVariables(true);
@@ -285,22 +278,17 @@
     wName.setText(Const.nullToEmpty(action.getName()));
 
     wFilename.setText(Const.NVL(action.getFilename(), ""));
-    wFileVariableType.setText(
-        ActionSetVariables.getVariableTypeDescription(action.getFileVariableType()));
+    wFileVariableType.setText(action.getFileVariableType().getDescription());
 
     wVarSubs.setSelection(action.isReplaceVars());
 
-    if (action.variableName != null) {
-      for (int i = 0; i < action.variableName.length; i++) {
-        TableItem ti = wFields.table.getItem(i);
-        if (action.variableName[i] != null) {
-          ti.setText(1, action.variableName[i]);
-        }
-        if (action.getVariableValue()[i] != null) {
-          ti.setText(2, action.getVariableValue()[i]);
-        }
-
-        ti.setText(3, ActionSetVariables.getVariableTypeDescription(action.getVariableType()[i]));
+    if (action.getVariableDefinitions() != null) {
+      int i = 0;
+      for (VariableDefinition definition : action.getVariableDefinitions()) {
+        TableItem item = wFields.table.getItem(i++);
+        item.setText(1, Const.nullToEmpty(definition.getName()));
+        item.setText(2, Const.nullToEmpty(definition.getValue()));
+        item.setText(3, definition.getType().getDescription());
       }
       wFields.setRowNums();
       wFields.optWidth(true);
@@ -324,37 +312,23 @@
       mb.open();
       return;
     }
-    action.setName(wName.getText());
 
+    action.setName(wName.getText());
     action.setFilename(wFilename.getText());
-    action.setFileVariableType(ActionSetVariables.getVariableType(wFileVariableType.getText()));
+    action.setFileVariableType(VariableType.lookupDescription(wFileVariableType.getText()));
     action.setReplaceVars(wVarSubs.getSelection());
 
     int nrItems = wFields.nrNonEmpty();
-    int nr = 0;
+    List<VariableDefinition> list = new ArrayList<>();
     for (int i = 0; i < nrItems; i++) {
-      String arg = wFields.getNonEmpty(i).getText(1);
-      if (arg != null && arg.length() != 0) {
-        nr++;
+      String name = wFields.getNonEmpty(i).getText(1);
+      if (name != null && name.length() != 0) {
+        String value = wFields.getNonEmpty(i).getText(2);
+        VariableType scope = VariableType.lookupDescription(wFields.getNonEmpty(i).getText(3));
+        list.add(new VariableDefinition(name, value, scope));
       }
     }
-    action.variableName = new String[nr];
-    action.variableValue = new String[nr];
-    action.variableType = new int[nr];
-
-    nr = 0;
-    for (int i = 0; i < nrItems; i++) {
-      String varname = wFields.getNonEmpty(i).getText(1);
-      String varvalue = wFields.getNonEmpty(i).getText(2);
-      String vartype = wFields.getNonEmpty(i).getText(3);
-
-      if (varname != null && varname.length() != 0) {
-        action.variableName[nr] = varname;
-        action.variableValue[nr] = varvalue;
-        action.variableType[nr] = ActionSetVariables.getVariableType(vartype);
-        nr++;
-      }
-    }
+    action.setVariableDefinitions(list);
 
     dispose();
   }
diff --git a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_en_US.properties b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_en_US.properties
index d447ebf..671df4b 100644
--- a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_en_US.properties
+++ b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_en_US.properties
@@ -34,7 +34,6 @@
 ActionSetVariables.Title=Set variables
 ActionSetVariables.Fields.Column.VariableType=Variable scope type
 ActionSetVariables.VariableType.CurrentWorkflow=Valid in the current workflow
-ActionSetVariables.Meta.UnableLoadXML=Unable to load action of type ''Set variables'' from XML node.Exception \: {0}
 ActionSetVariables.Fields.Column.Value=Value
 ActionSetVariables.VariableType.ParentWorkflow=Valid in the parent workflow
 ActionSetVariables.Settings.Label=Settings
diff --git a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_es_AR.properties b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_es_AR.properties
index 8a9dfce..75c6ba2 100644
--- a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_es_AR.properties
+++ b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_es_AR.properties
@@ -32,7 +32,6 @@
 ActionSetVariables.Title=Establecer Variables
 ActionSetVariables.Fields.Column.VariableType=Alcance de la variable
 ActionSetVariables.VariableType.CurrentWorkflow=V\u00E1lido en el presente trabajo
-ActionSetVariables.Meta.UnableLoadXML=Imposible cargar la entrada de trabajo del tipo "Establecer Variables" desde el nodo XML. Excepci\u00F3n\: {0}
 ActionSetVariables.Fields.Column.Value=Valor
 ActionSetVariables.VariableType.ParentWorkflow=V\u00E1lido en el trabajo padre
 ActionSetVariables.Settings.Label=Ajustes
diff --git a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_fr_FR.properties b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_fr_FR.properties
index ffd15bf..94a49b4 100644
--- a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_fr_FR.properties
+++ b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_fr_FR.properties
@@ -34,7 +34,6 @@
 ActionSetVariables.Title=Affectation variables
 ActionSetVariables.Fields.Column.VariableType=Port\u00E9e variable
 ActionSetVariables.VariableType.CurrentWorkflow=Valide dans le workflow courant
-ActionSetVariables.Meta.UnableLoadXML=Impossible de charger depuis le fichier XML, l''action de type ''Affectation variables''. Exception\:{0}
 ActionSetVariables.Fields.Column.Value=Valeur
 ActionSetVariables.VariableType.ParentWorkflow=Valide dans le workflow parent
 ActionSetVariables.Settings.Label=Param\u00E8tres
diff --git a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_it_IT.properties b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_it_IT.properties
index f2c257a..77d94d5 100644
--- a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_it_IT.properties
+++ b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_it_IT.properties
@@ -36,7 +36,6 @@
 ActionSetVariables.Title=Imposta variabili
 ActionSetVariables.Fields.Column.VariableType=Tipo di scope per la variabile
 ActionSetVariables.VariableType.CurrentWorkflow=Valido nel workflow corrente
-ActionSetVariables.Meta.UnableLoadXML=Impossibile caricare la action di tipo ''Imposta variabili'' dal nodo XML. Eccezione\: {0}
 ActionSetVariables.Error.UnableReadPropertiesFile=Errore durante la lettura del file di propriet\u00E0 ''{0}''\: 
 ActionSetVariables.Fields.Column.Value=Valore
 ActionSetVariables.VariableType.ParentWorkflow=Valido nel workflow padre
diff --git a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ja_JP.properties b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ja_JP.properties
index a3ab42e..d9543f6 100644
--- a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ja_JP.properties
+++ b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ja_JP.properties
@@ -34,7 +34,6 @@
 ActionSetVariables.Title=\u5909\u6570\u3092\u8a2d\u5b9a
 ActionSetVariables.Fields.Column.VariableType=\u5909\u6570\u306e\u30b9\u30b3\u30fc\u30d7
 ActionSetVariables.VariableType.CurrentWorkflow=\u6709\u52b9\u306a\u73fe\u5728\u306e\u30b8\u30e7\u30d6
-ActionSetVariables.Meta.UnableLoadXML=Unable to load action of type ''Set variables'' from XML node.Exception \: {0}
 ActionSetVariables.Fields.Column.Value=\u5024
 ActionSetVariables.VariableType.ParentWorkflow=\u6709\u52b9\u306a\u89aa\u30b8\u30e7\u30d6
 ActionSetVariables.Settings.Label=\u8a2d\u5b9a
diff --git a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ko_KR.properties b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ko_KR.properties
index 206064f..cab8310 100644
--- a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ko_KR.properties
+++ b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_ko_KR.properties
@@ -32,7 +32,6 @@
 ActionSetVariables.Title=Set variables
 ActionSetVariables.Fields.Column.VariableType=\uBCC0\uC218 \uBC94\uC704 \uC885\uB958
 ActionSetVariables.VariableType.CurrentWorkflow=Valid in the current workflow
-ActionSetVariables.Meta.UnableLoadXML=XML \uB178\uB4DC\uC5D0\uC11C Workflow \uC5D4\uD2B8\uB9AC \uD615\uC2DD 'Set variables''\uC744 \uB85C\uB4DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC608\uC678\:{1} 
 ActionSetVariables.Fields.Column.Value=\uAC12
 ActionSetVariables.VariableType.ParentWorkflow=Valid in the parent workflow
 ActionSetVariables.Settings.Label=\uC124\uC815
diff --git a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_zh_CN.properties b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_zh_CN.properties
index 46aba7a..a3dac40 100644
--- a/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_zh_CN.properties
+++ b/plugins/actions/setvariables/src/main/resources/org/apache/hop/workflow/actions/setvariables/messages/messages_zh_CN.properties
@@ -27,7 +27,6 @@
 ActionSetVariables.Filename.Label=\u5C5E\u6027\u6587\u4EF6\u540D
 ActionSetVariables.FilenameGroup.Label=\u5C5E\u6027\u6587\u4EF6
 ActionSetVariables.Log.SetVariableToValue=Set variable {0} to value [{1}]
-ActionSetVariables.Meta.UnableLoadXML=Unable to load action of type ''Set variables'' from XML node.Exception \: {0}
 ActionSetVariables.Name=\u8BBE\u7F6E\u53D8\u91CF
 ActionSetVariables.Name.Default=\u8BBE\u7F6E\u53D8\u91CF
 ActionSetVariables.Name.Label=Action \u540D\u79F0\:
diff --git a/plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/WorkflowEntrySetVariablesTest.java b/plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariablesTest.java
similarity index 82%
rename from plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/WorkflowEntrySetVariablesTest.java
rename to plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariablesTest.java
index 8cd66ed..2f5dd37 100644
--- a/plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/WorkflowEntrySetVariablesTest.java
+++ b/plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/ActionSetVariablesTest.java
@@ -17,6 +17,11 @@
 
 package org.apache.hop.workflow.actions.setvariables;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -26,14 +31,19 @@
 import java.nio.charset.StandardCharsets;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.ParserConfigurationException;
+import org.apache.hop.core.HopClientEnvironment;
 import org.apache.hop.core.Result;
 import org.apache.hop.core.logging.HopLogStore;
 import org.apache.hop.core.variables.Variables;
 import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.core.xml.XmlParserFactoryProducer;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.metadata.serializer.memory.MemoryMetadataProvider;
 import org.apache.hop.workflow.WorkflowMeta;
 import org.apache.hop.workflow.action.ActionMeta;
+import org.apache.hop.workflow.action.ActionSerializationTestUtil;
+import org.apache.hop.workflow.actions.setvariables.ActionSetVariables.VariableDefinition;
+import org.apache.hop.workflow.actions.setvariables.ActionSetVariables.VariableType;
 import org.apache.hop.workflow.engine.IWorkflowEngine;
 import org.apache.hop.workflow.engines.local.LocalWorkflowEngine;
 import org.junit.After;
@@ -46,12 +56,7 @@
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-public class WorkflowEntrySetVariablesTest {
+public class ActionSetVariablesTest {
   private IWorkflowEngine<WorkflowMeta> workflow;
   private ActionSetVariables action;
 
@@ -76,6 +81,41 @@
   public void tearDown() throws Exception {}
 
   @Test
+  public void testSerialization() throws Exception {
+    HopClientEnvironment.init();
+    MemoryMetadataProvider provider = new MemoryMetadataProvider();
+
+    ActionSetVariables action =
+        ActionSerializationTestUtil.testSerialization(
+            "/set-variables-action.xml", ActionSetVariables.class, provider);
+
+    // Properties file variables
+    assertEquals(VariableType.CURRENT_WORKFLOW, action.getFileVariableType());
+    assertEquals("filename.txt", action.getFilename());
+
+    // Settings
+    assertTrue(action.isReplaceVars());
+
+    // Static variables
+    VariableDefinition definition = action.getVariableDefinitions().get(0);
+    assertEquals("VAR_CURRENT", definition.getName());
+    assertEquals("current", definition.getValue());
+    assertEquals(VariableType.CURRENT_WORKFLOW, definition.getType());
+    definition = action.getVariableDefinitions().get(1);
+    assertEquals("VAR_PARENT", definition.getName());
+    assertEquals("parent", definition.getValue());
+    assertEquals(VariableType.PARENT_WORKFLOW, definition.getType());
+    definition = action.getVariableDefinitions().get(2);
+    assertEquals("VAR_ROOT", definition.getName());
+    assertEquals("root", definition.getValue());
+    assertEquals(VariableType.ROOT_WORKFLOW, definition.getType());
+    definition = action.getVariableDefinitions().get(3);
+    assertEquals("VAR_JVM", definition.getName());
+    assertEquals("jvm", definition.getValue());
+    assertEquals(VariableType.JVM, definition.getType());
+  }
+
+  @Test
   public void testASCIIText() throws Exception {
     // properties file with native2ascii
     action.setFilename(
@@ -129,7 +169,7 @@
   public void testParentJobVariablesExecutingFilePropertiesThatChangesVariablesAndParameters()
       throws Exception {
     action.setReplaceVars(true);
-    action.setFileVariableType(1);
+    action.setFileVariableType(VariableType.CURRENT_WORKFLOW);
 
     IWorkflowEngine<WorkflowMeta> parentWorkflow = action.getParentWorkflow();
 
@@ -186,7 +226,7 @@
   }
 
   @Test
-  public void testJobEntrySetVariablesExecute_VARIABLE_TYPE_CURRENT_WORKFLOW_NullVariable()
+  public void testSetVariablesExecute_VARIABLE_TYPE_CURRENT_WORKFLOW_NullVariable()
       throws Exception {
     IHopMetadataProvider metadataProvider = mock(IHopMetadataProvider.class);
     action.loadXml(
@@ -197,7 +237,7 @@
   }
 
   @Test
-  public void testJobEntrySetVariablesExecute_VARIABLE_TYPE_JVM_VariableNotNull() throws Exception {
+  public void testSetVariablesExecute_VARIABLE_TYPE_JVM_VariableNotNull() throws Exception {
     IHopMetadataProvider metadataProvider = mock(IHopMetadataProvider.class);
     action.loadXml(
         getEntryNode("variableNotNull", "someValue", "JVM"), metadataProvider, new Variables());
@@ -208,7 +248,7 @@
   }
 
   @Test
-  public void testJobEntrySetVariablesExecute_VARIABLE_TYPE_CURRENT_WORKFLOW_VariableNotNull()
+  public void testSetVariablesExecute_VARIABLE_TYPE_CURRENT_WORKFLOW_VariableNotNull()
       throws Exception {
     IHopMetadataProvider metadataProvider = mock(IHopMetadataProvider.class);
     action.loadXml(
diff --git a/plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/WorkflowActionSetVariablesLoadSaveTest.java b/plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/WorkflowActionSetVariablesLoadSaveTest.java
deleted file mode 100644
index 57bb1e0..0000000
--- a/plugins/actions/setvariables/src/test/java/org/apache/hop/workflow/actions/setvariables/WorkflowActionSetVariablesLoadSaveTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.hop.workflow.actions.setvariables;
-
-import org.apache.hop.junit.rules.RestoreHopEngineEnvironment;
-import org.apache.hop.pipeline.transforms.loadsave.validator.ArrayLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.IntLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.PrimitiveIntArrayLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.StringLoadSaveValidator;
-import org.apache.hop.workflow.action.loadsave.WorkflowActionLoadSaveTestSupport;
-import org.junit.ClassRule;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
-public class WorkflowActionSetVariablesLoadSaveTest
-    extends WorkflowActionLoadSaveTestSupport<ActionSetVariables> {
-  @ClassRule public static RestoreHopEngineEnvironment env = new RestoreHopEngineEnvironment();
-
-  @Override
-  protected Class<ActionSetVariables> getActionClass() {
-    return ActionSetVariables.class;
-  }
-
-  @Override
-  protected List<String> listAttributes() {
-    return Arrays.asList(
-            "replaceVars",
-            "filename",
-            "fileVariableType",
-            "variableName",
-            "variableValue",
-            "variableType");
-  }
-
-  @Override
-  protected Map<String, IFieldLoadSaveValidator<?>> createAttributeValidatorsMap() {
-    Map<String, IFieldLoadSaveValidator<?>> validators = new HashMap<>();
-    validators.put(
-        "fileVariableType", new IntLoadSaveValidator(ActionSetVariables.variableTypeCode.length));
-
-    int count = new Random().nextInt(50) + 1;
-
-    validators.put(
-        "variableName", new ArrayLoadSaveValidator<>(new StringLoadSaveValidator(), count));
-    validators.put(
-        "variableValue", new ArrayLoadSaveValidator<>(new StringLoadSaveValidator(), count));
-    validators.put(
-        "variableType", new PrimitiveIntArrayLoadSaveValidator(new IntLoadSaveValidator(3), count));
-
-    return validators;
-  }
-}
diff --git a/plugins/actions/setvariables/src/test/resources/set-variables-action.xml b/plugins/actions/setvariables/src/test/resources/set-variables-action.xml
new file mode 100644
index 0000000..2fa27ee
--- /dev/null
+++ b/plugins/actions/setvariables/src/test/resources/set-variables-action.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Licensed to the Apache Software Foundation (ASF) under one or more 
+	~
+contributor license agreements. See the NOTICE file distributed with ~ 
+	this
+work for additional information regarding copyright ownership. ~ The 
+	ASF
+licenses this file to You 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. ~ -->
+<action>
+	<name>Set variables</name>
+	<description />
+	<type>SET_VARIABLES</type>
+	<attributes />
+	<replacevars>Y</replacevars>
+	<filename>filename.txt</filename>
+	<file_variable_type>CURRENT_WORKFLOW</file_variable_type>
+	<fields>
+		<field>
+			<variable_name>VAR_CURRENT</variable_name>
+			<variable_value>current</variable_value>
+			<variable_type>CURRENT_WORKFLOW</variable_type>
+		</field>
+		<field>
+			<variable_name>VAR_PARENT</variable_name>
+			<variable_value>parent</variable_value>
+			<variable_type>PARENT_WORKFLOW</variable_type>
+		</field>
+		<field>
+			<variable_name>VAR_ROOT</variable_name>
+			<variable_value>root</variable_value>
+			<variable_type>ROOT_WORKFLOW</variable_type>
+		</field>
+		<field>
+			<variable_name>VAR_JVM</variable_name>
+			<variable_type>JVM</variable_type>
+			<variable_value>jvm</variable_value>
+		</field>
+	</fields>
+	<parallel>N</parallel>
+	<xloc>352</xloc>
+	<yloc>48</yloc>
+	<attributes_hac />
+</action>
\ No newline at end of file
diff --git a/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSql.java b/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSql.java
index 3499d5e..e769f38 100644
--- a/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSql.java
+++ b/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSql.java
@@ -25,13 +25,11 @@
 import org.apache.hop.core.database.Database;
 import org.apache.hop.core.database.DatabaseMeta;
 import org.apache.hop.core.exception.HopDatabaseException;
-import org.apache.hop.core.exception.HopException;
-import org.apache.hop.core.exception.HopXmlException;
 import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.core.vfs.HopVfs;
-import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.metadata.api.HopMetadataProperty;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.resource.ResourceEntry;
 import org.apache.hop.resource.ResourceEntry.ResourceType;
@@ -41,8 +39,6 @@
 import org.apache.hop.workflow.action.IAction;
 import org.apache.hop.workflow.action.validator.ActionValidatorUtils;
 import org.apache.hop.workflow.action.validator.AndValidator;
-import org.w3c.dom.Node;
-
 import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.InputStream;
@@ -61,11 +57,17 @@
 public class ActionSql extends ActionBase implements Cloneable, IAction {
   private static final Class<?> PKG = ActionSql.class; // For Translator
 
+  @HopMetadataProperty(key = "sql")
   private String sql;
-  private DatabaseMeta connection;
+  @HopMetadataProperty(key = "connection")
+  private String connection;
+  @HopMetadataProperty(key = "useVariableSubstitution")
   private boolean useVariableSubstitution = false;
-  private boolean sqlfromfile = false;
-  private String sqlfilename;
+  @HopMetadataProperty(key = "sqlfromfile")
+  private boolean sqlFromFile = false;
+  @HopMetadataProperty(key = "sqlfilename")
+  private String sqlFilename;
+  @HopMetadataProperty(key = "sendOneStatement")
   private boolean sendOneStatement = false;
 
   public ActionSql(String n) {
@@ -84,62 +86,6 @@
     return je;
   }
 
-  @Override
-  public String getXml() {
-    StringBuilder retval = new StringBuilder(200);
-
-    retval.append(super.getXml());
-
-    retval.append("      ").append(XmlHandler.addTagValue("sql", sql));
-    retval
-        .append("      ")
-        .append(
-            XmlHandler.addTagValue("useVariableSubstitution", useVariableSubstitution ? "T" : "F"));
-    retval.append("      ").append(XmlHandler.addTagValue("sqlfromfile", sqlfromfile ? "T" : "F"));
-    retval.append("      ").append(XmlHandler.addTagValue("sqlfilename", sqlfilename));
-    retval
-        .append("      ")
-        .append(XmlHandler.addTagValue("sendOneStatement", sendOneStatement ? "T" : "F"));
-
-    retval
-        .append("      ")
-        .append(
-            XmlHandler.addTagValue("connection", connection == null ? null : connection.getName()));
-
-    return retval.toString();
-  }
-
-  @Override
-  public void loadXml(Node entrynode, IHopMetadataProvider metadataProvider, IVariables variables)
-      throws HopXmlException {
-    try {
-      super.loadXml(entrynode);
-      sql = XmlHandler.getTagValue(entrynode, "sql");
-      String dbname = XmlHandler.getTagValue(entrynode, "connection");
-      String sSubs = XmlHandler.getTagValue(entrynode, "useVariableSubstitution");
-
-      if (sSubs != null && sSubs.equalsIgnoreCase("T")) {
-        useVariableSubstitution = true;
-      }
-      connection = DatabaseMeta.loadDatabase(metadataProvider, dbname);
-
-      String ssql = XmlHandler.getTagValue(entrynode, "sqlfromfile");
-      if (ssql != null && ssql.equalsIgnoreCase("T")) {
-        sqlfromfile = true;
-      }
-
-      sqlfilename = XmlHandler.getTagValue(entrynode, "sqlfilename");
-
-      String sOneStatement = XmlHandler.getTagValue(entrynode, "sendOneStatement");
-      if (sOneStatement != null && sOneStatement.equalsIgnoreCase("T")) {
-        sendOneStatement = true;
-      }
-
-    } catch (HopException e) {
-      throw new HopXmlException("Unable to load action of type 'sql' from XML node", e);
-    }
-  }
-
   public void setSql(String sql) {
     this.sql = sql;
   }
@@ -149,14 +95,14 @@
   }
 
   public String getSqlFilename() {
-    return sqlfilename;
+    return sqlFilename;
   }
 
   public void setSqlFilename(String sqlfilename) {
-    this.sqlfilename = sqlfilename;
+    this.sqlFilename = sqlfilename;
   }
 
-  public boolean getUseVariableSubstitution() {
+  public boolean isUseVariableSubstitution() {
     return useVariableSubstitution;
   }
 
@@ -165,11 +111,11 @@
   }
 
   public void setSqlFromFile(boolean sqlfromfilein) {
-    sqlfromfile = sqlfromfilein;
+    sqlFromFile = sqlfromfilein;
   }
 
-  public boolean getSqlFromFile() {
-    return sqlfromfile;
+  public boolean isSqlFromFile() {
+    return sqlFromFile;
   }
 
   public boolean isSendOneStatement() {
@@ -180,11 +126,11 @@
     sendOneStatement = sendOneStatementin;
   }
 
-  public void setDatabase(DatabaseMeta database) {
-    this.connection = database;
+  public void setConnection(String connection) {
+    this.connection = connection;
   }
 
-  public DatabaseMeta getDatabase() {
+  public String getConnection() {
     return connection;
   }
 
@@ -192,20 +138,21 @@
   public Result execute(Result previousResult, int nr) {
     Result result = previousResult;
 
-    if (connection != null) {
+    DatabaseMeta databaseMeta = parentWorkflowMeta.findDatabase(connection, getVariables());
+    if (databaseMeta != null) {
       FileObject sqlFile = null;
-      try (Database db = new Database(this, this, connection)) {
+      try (Database db = new Database(this, this, databaseMeta)) {
         String theSql = null;
         db.connect();
 
-        if (sqlfromfile) {
-          if (sqlfilename == null) {
+        if (sqlFromFile) {
+          if (sqlFilename == null) {
             throw new HopDatabaseException(
                 BaseMessages.getString(PKG, "ActionSQL.NoSQLFileSpecified"));
           }
 
           try {
-            String realfilename = resolve(sqlfilename);
+            String realfilename = resolve(sqlFilename);
             sqlFile = HopVfs.getFileObject(realfilename);
             if (!sqlFile.exists()) {
               logError(BaseMessages.getString(PKG, "ActionSQL.SQLFileNotExist", realfilename));
@@ -297,21 +244,20 @@
 
   @Override
   public DatabaseMeta[] getUsedDatabaseConnections() {
-    return new DatabaseMeta[] {
-      connection,
-    };
+    return new DatabaseMeta[0];
   }
 
   @Override
   public List<ResourceReference> getResourceDependencies(
       IVariables variables, WorkflowMeta workflowMeta) {
     List<ResourceReference> references = super.getResourceDependencies(variables, workflowMeta);
-    if (connection != null) {
+    DatabaseMeta databaseMeta = parentWorkflowMeta.findDatabase(connection, getVariables());
+    if (databaseMeta != null) {
       ResourceReference reference = new ResourceReference(this);
-      reference.getEntries().add(new ResourceEntry(connection.getHostname(), ResourceType.SERVER));
+      reference.getEntries().add(new ResourceEntry(databaseMeta.getHostname(), ResourceType.SERVER));
       reference
           .getEntries()
-          .add(new ResourceEntry(connection.getDatabaseName(), ResourceType.DATABASENAME));
+          .add(new ResourceEntry(databaseMeta.getDatabaseName(), ResourceType.DATABASENAME));
       references.add(reference);
     }
     return references;
diff --git a/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSqlDialog.java b/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSqlDialog.java
index ebee0d0..9e1552f 100644
--- a/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSqlDialog.java
+++ b/plugins/actions/sql/src/main/java/org/apache/hop/workflow/actions/sql/ActionSqlDialog.java
@@ -36,14 +36,6 @@
 import org.apache.hop.workflow.action.IAction;
 import org.apache.hop.workflow.action.IActionDialog;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.layout.FormAttachment;
 import org.eclipse.swt.layout.FormData;
 import org.eclipse.swt.layout.FormLayout;
@@ -144,7 +136,8 @@
     wName.setLayoutData(fdName);
 
     // Connection line
-    wConnection = addConnectionLine(shell, wName, action.getDatabase(), null);
+    DatabaseMeta databaseMeta = workflowMeta.findDatabase(action.getConnection(), variables);
+    wConnection = addConnectionLine(shell, wName, databaseMeta, null);
 
     // SQL from file?
     Label wlSqlFromFile = new Label(shell, SWT.RIGHT);
@@ -163,14 +156,10 @@
     fdSqlFromFile.top = new FormAttachment(wlSqlFromFile, 0, SWT.CENTER);
     fdSqlFromFile.right = new FormAttachment(100, 0);
     wSqlFromFile.setLayoutData(fdSqlFromFile);
-    wSqlFromFile.addSelectionListener(
-        new SelectionAdapter() {
-          @Override
-          public void widgetSelected(SelectionEvent e) {
-            activeSqlFromFile();
-            action.setChanged();
-          }
-        });
+    wSqlFromFile.addListener(SWT.Selection, e -> {
+      activeSqlFromFile();
+      action.setChanged();
+    });
 
     // Filename line
     wlFilename = new Label(shell, SWT.RIGHT);
@@ -232,13 +221,7 @@
     fdUseOneStatement.top = new FormAttachment(wlUseOneStatement, 0, SWT.CENTER);
     fdUseOneStatement.right = new FormAttachment(100, 0);
     wSendOneStatement.setLayoutData(fdUseOneStatement);
-    wSendOneStatement.addSelectionListener(
-        new SelectionAdapter() {
-          @Override
-          public void widgetSelected(SelectionEvent e) {
-            action.setChanged();
-          }
-        });
+    wSendOneStatement.addListener(SWT.Selection, e -> action.setChanged());
 
     // Use variable substitution?
     Label wlUseSubs = new Label(shell, SWT.RIGHT);
@@ -257,14 +240,10 @@
     fdUseSubs.top = new FormAttachment(wlUseSubs, 0, SWT.CENTER);
     fdUseSubs.right = new FormAttachment(100, 0);
     wUseSubs.setLayoutData(fdUseSubs);
-    wUseSubs.addSelectionListener(
-        new SelectionAdapter() {
-          @Override
-          public void widgetSelected(SelectionEvent e) {
-            action.setUseVariableSubstitution(!action.getUseVariableSubstitution());
-            action.setChanged();
-          }
-        });
+    wUseSubs.addListener(SWT.Selection, e -> {
+      action.setUseVariableSubstitution(!action.isUseVariableSubstitution());
+      action.setChanged();
+    });
 
     wlPosition = new Label(shell, SWT.NONE);
     wlPosition.setText(BaseMessages.getString(PKG, "ActionSQL.LineNr.Label", "0"));
@@ -294,49 +273,14 @@
     fdSql.right = new FormAttachment(100, -20);
     fdSql.bottom = new FormAttachment(wlPosition, -margin);
     wSql.setLayoutData(fdSql);
-    wSql.addModifyListener(arg0 -> setPosition());
-
-    wSql.addKeyListener(
-        new KeyAdapter() {
-          @Override
-          public void keyPressed(KeyEvent e) {
-            setPosition();
-          }
-
-          @Override
-          public void keyReleased(KeyEvent e) {
-            setPosition();
-          }
-        });
-    wSql.addFocusListener(
-        new FocusAdapter() {
-          @Override
-          public void focusGained(FocusEvent e) {
-            setPosition();
-          }
-
-          @Override
-          public void focusLost(FocusEvent e) {
-            setPosition();
-          }
-        });
-    wSql.addMouseListener(
-        new MouseAdapter() {
-          @Override
-          public void mouseDoubleClick(MouseEvent e) {
-            setPosition();
-          }
-
-          @Override
-          public void mouseDown(MouseEvent e) {
-            setPosition();
-          }
-
-          @Override
-          public void mouseUp(MouseEvent e) {
-            setPosition();
-          }
-        });
+    wSql.addListener(SWT.Modify, e -> setPosition());
+    wSql.addListener(SWT.KeyDown, e -> setPosition());
+    wSql.addListener(SWT.KeyUp, e -> setPosition());
+    wSql.addListener(SWT.FocusIn, e -> setPosition());
+    wSql.addListener(SWT.FocusOut, e -> setPosition());
+    wSql.addListener(SWT.MouseDoubleClick, e -> setPosition());
+    wSql.addListener(SWT.MouseDown, e -> setPosition());
+    wSql.addListener(SWT.MouseUp, e -> setPosition());
 
     getData();
     activeSqlFromFile();
@@ -358,17 +302,10 @@
   public void getData() {
     wName.setText(Const.nullToEmpty(action.getName()));
     wSql.setText(Const.nullToEmpty(action.getSql()));
-    DatabaseMeta dbinfo = action.getDatabase();
-    if (dbinfo != null && dbinfo.getName() != null) {
-      wConnection.setText(dbinfo.getName());
-    } else {
-      wConnection.setText("");
-    }
-
-    wUseSubs.setSelection(action.getUseVariableSubstitution());
-    wSqlFromFile.setSelection(action.getSqlFromFile());
+    wConnection.setText(Const.nullToEmpty(action.getConnection()));
+    wUseSubs.setSelection(action.isUseVariableSubstitution());
+    wSqlFromFile.setSelection(action.isSqlFromFile());
     wSendOneStatement.setSelection(action.isSendOneStatement());
-
     wFilename.setText(Const.nullToEmpty(action.getSqlFilename()));
 
     wName.selectAll();
@@ -398,12 +335,12 @@
       return;
     }
     action.setName(wName.getText());
+    action.setConnection(wConnection.getText());
     action.setSql(wSql.getText());
     action.setUseVariableSubstitution(wUseSubs.getSelection());
     action.setSqlFromFile(wSqlFromFile.getSelection());
     action.setSqlFilename(wFilename.getText());
-    action.setSendOneStatement(wSendOneStatement.getSelection());
-    action.setDatabase(getWorkflowMeta().findDatabase(wConnection.getText(), variables));
+    action.setSendOneStatement(wSendOneStatement.getSelection());    
     action.setChanged();
 
     dispose();
diff --git a/plugins/actions/sql/src/test/java/org/apache/hop/workflow/actions/sql/WorkflowActionSqlTest.java b/plugins/actions/sql/src/test/java/org/apache/hop/workflow/actions/sql/WorkflowActionSqlTest.java
index df0afee..64978a0 100644
--- a/plugins/actions/sql/src/test/java/org/apache/hop/workflow/actions/sql/WorkflowActionSqlTest.java
+++ b/plugins/actions/sql/src/test/java/org/apache/hop/workflow/actions/sql/WorkflowActionSqlTest.java
@@ -38,21 +38,21 @@
     return Arrays.asList(
         "sql",
         "useVariableSubstitution",
-        "sqlfromfile",
-        "sqlfilename",
+        "sqlFromFile",
+        "sqlFilename",
         "sendOneStatement",
-        "database");
+        "connection");
   }
 
   @Override
   protected Map<String, String> createGettersMap() {
     return toMap(
         "sql", "getSql",
-        "useVariableSubstitution", "getUseVariableSubstitution",
-        "sqlfromfile", "getSqlFromFile",
-        "sqlfilename", "getSqlFilename",
+        "useVariableSubstitution", "isUseVariableSubstitution",
+        "sqlFromFile", "isSqlFromFile",
+        "sqlFilename", "getSqlFilename",
         "sendOneStatement", "isSendOneStatement",
-        "database", "getDatabase");
+        "connection", "getConnection");
   }
 
   @Override
@@ -60,9 +60,9 @@
     return toMap(
         "sql", "setSql",
         "useVariableSubstitution", "setUseVariableSubstitution",
-        "sqlfromfile", "setSqlFromFile",
-        "sqlfilename", "setSqlFilename",
+        "sqlFromFile", "setSqlFromFile",
+        "sqlFilename", "setSqlFilename",
         "sendOneStatement", "setSendOneStatement",
-        "database", "setDatabase");
+        "connection", "setConnection");
   }
 }
diff --git a/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExists.java b/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExists.java
index dd5ba7c..540ef7d 100644
--- a/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExists.java
+++ b/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExists.java
@@ -17,17 +17,17 @@
 
 package org.apache.hop.workflow.actions.tableexists;
 
+import java.util.List;
 import org.apache.hop.core.ICheckResult;
 import org.apache.hop.core.Result;
 import org.apache.hop.core.annotations.Action;
 import org.apache.hop.core.database.Database;
 import org.apache.hop.core.database.DatabaseMeta;
 import org.apache.hop.core.exception.HopDatabaseException;
-import org.apache.hop.core.exception.HopException;
-import org.apache.hop.core.exception.HopXmlException;
+import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
-import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.metadata.api.HopMetadataProperty;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.resource.ResourceEntry;
 import org.apache.hop.resource.ResourceEntry.ResourceType;
@@ -37,9 +37,6 @@
 import org.apache.hop.workflow.action.IAction;
 import org.apache.hop.workflow.action.validator.ActionValidatorUtils;
 import org.apache.hop.workflow.action.validator.AndValidator;
-import org.w3c.dom.Node;
-
-import java.util.List;
 
 /** This defines a table exists action. */
 @Action(
@@ -53,13 +50,18 @@
 public class ActionTableExists extends ActionBase implements Cloneable, IAction {
   private static final Class<?> PKG = ActionTableExists.class; // For Translator
 
+  @HopMetadataProperty(key = "tablename")
   private String tableName;
-  private String schemaname;
-  private DatabaseMeta connection;
+
+  @HopMetadataProperty(key = "schemaname")
+  private String schemaName;
+
+  @HopMetadataProperty(key = "connection")
+  private String connection;
 
   public ActionTableExists(String n) {
     super(n, "");
-    schemaname = null;
+    schemaName = null;
     tableName = null;
     connection = null;
   }
@@ -74,61 +76,30 @@
     return je;
   }
 
-  @Override
-  public String getXml() {
-    StringBuilder retval = new StringBuilder(200);
-
-    retval.append(super.getXml());
-
-    retval.append("      ").append(XmlHandler.addTagValue("tablename", tableName));
-    retval.append("      ").append(XmlHandler.addTagValue("schemaname", schemaname));
-    retval
-        .append("      ")
-        .append(
-            XmlHandler.addTagValue("connection", connection == null ? null : connection.getName()));
-
-    return retval.toString();
-  }
-
-  @Override
-  public void loadXml(Node entrynode, IHopMetadataProvider metadataProvider, IVariables variables)
-      throws HopXmlException {
-    try {
-      super.loadXml(entrynode);
-
-      tableName = XmlHandler.getTagValue(entrynode, "tablename");
-      schemaname = XmlHandler.getTagValue(entrynode, "schemaname");
-      String dbname = XmlHandler.getTagValue(entrynode, "connection");
-      connection = DatabaseMeta.loadDatabase(metadataProvider, dbname);
-    } catch (HopException e) {
-      throw new HopXmlException(BaseMessages.getString(PKG, "TableExists.Meta.UnableLoadXml"), e);
-    }
-  }
-
-  public void setTablename(String tableName) {
+  public void setTableName(String tableName) {
     this.tableName = tableName;
   }
 
-  public String getTablename() {
+  public String getTableName() {
     return tableName;
   }
 
-  public String getSchemaname() {
-    return schemaname;
+  public String getSchemaName() {
+    return schemaName;
   }
 
-  public void setSchemaname(String schemaname) {
-    this.schemaname = schemaname;
+  public void setSchemaName(String schemaName) {
+    this.schemaName = schemaName;
   }
 
-  public void setDatabase(DatabaseMeta database) {
-    this.connection = database;
-  }
-
-  public DatabaseMeta getDatabase() {
+  public String getConnection() {
     return connection;
   }
 
+  public void setConnection(String connection) {
+    this.connection = connection;
+  }
+
   @Override
   public boolean isEvaluation() {
     return true;
@@ -144,33 +115,38 @@
     Result result = previousResult;
     result.setResult(false);
 
-    if (connection != null) {
-      Database db = new Database(this, this, connection);
-      try {
-        db.connect();
-        String realTablename = resolve(tableName);
-        String realSchemaname = resolve(schemaname);
+    if (!Utils.isEmpty(connection)) {
+      DatabaseMeta dbMeta = parentWorkflowMeta.findDatabase(connection, getVariables());
+      if (dbMeta != null) {
+        Database db = new Database(this, this, dbMeta);
+        try {
+          db.connect();
+          String realTableName = resolve(tableName);
+          String realSchemaName = resolve(schemaName);
 
-        if (db.checkTableExists(realSchemaname, realTablename)) {
-          if (log.isDetailed()) {
-            logDetailed(BaseMessages.getString(PKG, "TableExists.Log.TableExists", realTablename));
+          if (db.checkTableExists(realSchemaName, realTableName)) {
+            if (log.isDetailed()) {
+              logDetailed(
+                  BaseMessages.getString(PKG, "TableExists.Log.TableExists", realTableName));
+            }
+            result.setResult(true);
+          } else {
+            if (log.isDetailed()) {
+              logDetailed(
+                  BaseMessages.getString(PKG, "TableExists.Log.TableNotExists", realTableName));
+            }
           }
-          result.setResult(true);
-        } else {
-          if (log.isDetailed()) {
-            logDetailed(
-                BaseMessages.getString(PKG, "TableExists.Log.TableNotExists", realTablename));
-          }
-        }
-      } catch (HopDatabaseException dbe) {
-        result.setNrErrors(1);
-        logError(BaseMessages.getString(PKG, "TableExists.Error.RunningAction", dbe.getMessage()));
-      } finally {
-        if (db != null) {
-          try {
-            db.disconnect();
-          } catch (Exception e) {
-            /* Ignore */
+        } catch (HopDatabaseException dbe) {
+          result.setNrErrors(1);
+          logError(
+              BaseMessages.getString(PKG, "TableExists.Error.RunningAction", dbe.getMessage()));
+        } finally {
+          if (db != null) {
+            try {
+              db.disconnect();
+            } catch (Exception e) {
+              /* Ignore */
+            }
           }
         }
       }
@@ -183,22 +159,16 @@
   }
 
   @Override
-  public DatabaseMeta[] getUsedDatabaseConnections() {
-    return new DatabaseMeta[] {
-      connection,
-    };
-  }
-
-  @Override
   public List<ResourceReference> getResourceDependencies(
       IVariables variables, WorkflowMeta workflowMeta) {
     List<ResourceReference> references = super.getResourceDependencies(variables, workflowMeta);
-    if (connection != null) {
+    DatabaseMeta dbMeta = parentWorkflowMeta.findDatabase(connection, getVariables());
+    if (dbMeta != null) {
       ResourceReference reference = new ResourceReference(this);
-      reference.getEntries().add(new ResourceEntry(connection.getHostname(), ResourceType.SERVER));
+      reference.getEntries().add(new ResourceEntry(dbMeta.getHostname(), ResourceType.SERVER));
       reference
           .getEntries()
-          .add(new ResourceEntry(connection.getDatabaseName(), ResourceType.DATABASENAME));
+          .add(new ResourceEntry(dbMeta.getDatabaseName(), ResourceType.DATABASENAME));
       references.add(reference);
     }
     return references;
diff --git a/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExistsDialog.java b/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExistsDialog.java
index fc27a0c..9eec18c 100644
--- a/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExistsDialog.java
+++ b/plugins/actions/tableexists/src/main/java/org/apache/hop/workflow/actions/tableexists/ActionTableExistsDialog.java
@@ -118,17 +118,17 @@
     wName.setLayoutData(fdName);
 
     // Connection line
-    wConnection = addConnectionLine(shell, wName, action.getDatabase(), lsMod);
+    wConnection = addConnectionLine(shell, wName, action.getConnection(), lsMod);
 
     // Schema name line
-    Label wlSchemaname = new Label(shell, SWT.RIGHT);
-    wlSchemaname.setText(BaseMessages.getString(PKG, "ActionTableExists.Schemaname.Label"));
-    PropsUi.setLook(wlSchemaname);
-    FormData fdlSchemaname = new FormData();
-    fdlSchemaname.left = new FormAttachment(0, 0);
-    fdlSchemaname.right = new FormAttachment(middle, -margin);
-    fdlSchemaname.top = new FormAttachment(wConnection, 2 * margin);
-    wlSchemaname.setLayoutData(fdlSchemaname);
+    Label wlSchemaName = new Label(shell, SWT.RIGHT);
+    wlSchemaName.setText(BaseMessages.getString(PKG, "ActionTableExists.Schemaname.Label"));
+    PropsUi.setLook(wlSchemaName);
+    FormData fdlSchemaName = new FormData();
+    fdlSchemaName.left = new FormAttachment(0, 0);
+    fdlSchemaName.right = new FormAttachment(middle, -margin);
+    fdlSchemaName.top = new FormAttachment(wConnection, 2 * margin);
+    wlSchemaName.setLayoutData(fdlSchemaName);
 
     Button wbSchema = new Button(shell, SWT.PUSH | SWT.CENTER);
     PropsUi.setLook(wbSchema);
@@ -209,10 +209,10 @@
   /** Copy information from the meta-data input to the dialog fields. */
   public void getData() {
     wName.setText(Const.nullToEmpty(action.getName()));
-    wTablename.setText(Const.nullToEmpty(action.getTablename()));
-    wSchemaname.setText(Const.nullToEmpty(action.getSchemaname()));
-    if (action.getDatabase() != null) {
-      wConnection.setText(action.getDatabase().getName());
+    wTablename.setText(Const.nullToEmpty(action.getTableName()));
+    wSchemaname.setText(Const.nullToEmpty(action.getSchemaName()));
+    if (action.getConnection() != null) {
+      wConnection.setText(action.getConnection());
     }
 
     wName.selectAll();
@@ -234,9 +234,9 @@
       return;
     }
     action.setName(wName.getText());
-    action.setDatabase(getWorkflowMeta().findDatabase(wConnection.getText(), variables));
-    action.setTablename(wTablename.getText());
-    action.setSchemaname(wSchemaname.getText());
+    action.setConnection(wConnection.getText());
+    action.setTableName(wTablename.getText());
+    action.setSchemaName(wSchemaname.getText());
 
     dispose();
   }
diff --git a/plugins/actions/tableexists/src/main/resources/org/apache/hop/workflow/actions/tableexists/messages/messages_it_IT.properties b/plugins/actions/tableexists/src/main/resources/org/apache/hop/workflow/actions/tableexists/messages/messages_it_IT.properties
index f2703ad..d8de4d9 100644
--- a/plugins/actions/tableexists/src/main/resources/org/apache/hop/workflow/actions/tableexists/messages/messages_it_IT.properties
+++ b/plugins/actions/tableexists/src/main/resources/org/apache/hop/workflow/actions/tableexists/messages/messages_it_IT.properties
@@ -14,14 +14,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-ActionTableExists.Name=La tabella esiste
-TableExists.Meta.UnableLoadXml=Impossibile caricare la action di tipo 'tabella esiste' dal nodo XML
-ActionTableExists.Tablename.Label=Nome tabella\: 
-TableExists.Error.RunningAction=Si \u00E8 verificato un errore durante l''esecuzione di questo transform\: {0}
-TableExists.Error.NoConnectionDefined=Nessuna connessione di database \u00E8 stata definita.
-TableExists.Log.TableNotExists=La tabella [{0}] nion esiste\!
+
+ActionTableExists.Tablename.Label=Tabella\: 
+TableExists.Error.RunningAction=Si \u00E8 verificato un errore durante l''esecuzione di questa action\: {0}
+TableExists.Error.NoConnectionDefined=Non \u00E8 stata definita alcuna connessione al database .
+TableExists.Log.TableNotExists=La tabella [{0}] non esiste\!
 TableExists.Log.TableExists=La tabella [{0}] esiste.
-ActionTableExists.Title=La tabella esiste
+ActionTableExists.Title=Table exists
 ActionTableExists.Name.Label=Nome action\: 
-ActionTableExists.Schemaname.Label=Nome dello schema\: 
-ActionTableExists.Name.Default=La tabella esiste
\ No newline at end of file
+ActionTableExists.Schemaname.Label=Schema\: 
+ActionTableExists.Name.Default=Table exists
\ No newline at end of file
diff --git a/plugins/actions/tableexists/src/test/java/org/apache/hop/workflow/actions/tableexists/WorkflowActionTableExistsLoadSaveTest.java b/plugins/actions/tableexists/src/test/java/org/apache/hop/workflow/actions/tableexists/WorkflowActionTableExistsLoadSaveTest.java
index 83e9a3f..15d3839 100644
--- a/plugins/actions/tableexists/src/test/java/org/apache/hop/workflow/actions/tableexists/WorkflowActionTableExistsLoadSaveTest.java
+++ b/plugins/actions/tableexists/src/test/java/org/apache/hop/workflow/actions/tableexists/WorkflowActionTableExistsLoadSaveTest.java
@@ -35,6 +35,6 @@
 
   @Override
   protected List<String> listAttributes() {
-    return Arrays.asList("tablename", "schemaname", "database");
+    return Arrays.asList("tableName", "schemaName", "connection");
   }
 }
diff --git a/plugins/tech/parquet/pom.xml b/plugins/tech/parquet/pom.xml
index ac9b955..cff748c 100755
--- a/plugins/tech/parquet/pom.xml
+++ b/plugins/tech/parquet/pom.xml
@@ -42,7 +42,7 @@
     </licenses>
 
     <properties>
-        <parquet.version>1.12.3</parquet.version>
+        <parquet.version>1.13.1</parquet.version>
     </properties>
 
     <dependencies>
diff --git a/plugins/tech/parquet/src/main/java/org/apache/hop/parquet/transforms/output/ParquetOutputMeta.java b/plugins/tech/parquet/src/main/java/org/apache/hop/parquet/transforms/output/ParquetOutputMeta.java
index 3869a0e..dc8a878 100644
--- a/plugins/tech/parquet/src/main/java/org/apache/hop/parquet/transforms/output/ParquetOutputMeta.java
+++ b/plugins/tech/parquet/src/main/java/org/apache/hop/parquet/transforms/output/ParquetOutputMeta.java
@@ -88,9 +88,9 @@
     filenameExtension = "parquet";
     filenameDateTimeFormat = "yyyyMMdd-HHmmss";
     compressionCodec = CompressionCodecName.UNCOMPRESSED;
-    version = ParquetVersion.Version1; // The default is v1
-    rowGroupSize = Integer.toString(ParquetProperties.DEFAULT_PAGE_ROW_COUNT_LIMIT);
-    dataPageSize = Integer.toString(ParquetProperties.DEFAULT_PAGE_SIZE);
+    version = ParquetVersion.Version2; // The default is v2
+    rowGroupSize = Integer.toString(268435456);
+    dataPageSize = Integer.toString(8192);
     dictionaryPageSize = Integer.toString(ParquetProperties.DEFAULT_DICTIONARY_PAGE_SIZE);
     fields = new ArrayList<>();
     filenameIncludingCopyNr = true;
diff --git a/ui/src/main/java/org/apache/hop/ui/pipeline/transform/BaseTransformDialog.java b/ui/src/main/java/org/apache/hop/ui/pipeline/transform/BaseTransformDialog.java
index 9a239b8..316d619 100644
--- a/ui/src/main/java/org/apache/hop/ui/pipeline/transform/BaseTransformDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/pipeline/transform/BaseTransformDialog.java
@@ -1266,7 +1266,7 @@
         mb.open();
       }
     }
-    return addConnectionLine(shell, wTransformName, databaseMeta, lsMod);
+    return addConnectionLine(parent, previous, databaseMeta, lsMod);
   }
 
   public interface IFieldsChoiceDialogProvider {
diff --git a/ui/src/main/java/org/apache/hop/ui/workflow/action/ActionDialog.java b/ui/src/main/java/org/apache/hop/ui/workflow/action/ActionDialog.java
index 0706288..705aa14 100644
--- a/ui/src/main/java/org/apache/hop/ui/workflow/action/ActionDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/workflow/action/ActionDialog.java
@@ -26,6 +26,7 @@
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.pipeline.transform.ITransform;
 import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.core.dialog.MessageBox;
 import org.apache.hop.ui.core.gui.WindowProperty;
 import org.apache.hop.ui.core.widget.MetaSelectionLine;
 import org.apache.hop.workflow.WorkflowMeta;
@@ -127,6 +128,36 @@
     return wConnection;
   }
 
+  /**
+   * Adds the connection line for the given parent and previous control, and returns a meta
+   * selection manager control
+   *
+   * @param parent the parent composite object
+   * @param previous the previous control
+   * @param connection
+   * @param lsMod
+   * @return the combo box UI component
+   */
+  public MetaSelectionLine<DatabaseMeta> addConnectionLine(
+      Composite parent, Control previous, String connection, ModifyListener lsMod) {
+
+    DatabaseMeta databaseMeta = getWorkflowMeta().findDatabase(connection, variables);
+    // If we are unable to find the database metadata, display only a warning message so that the
+    // user
+    // can proceed to correct the issue in the affected pipeline
+    if (databaseMeta == null) {
+      MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_WARNING);
+      mb.setMessage(
+          BaseMessages.getString(
+              PKG,
+              "BaseTransformDialog.InvalidConnection.DialogMessage",
+              variables.resolve(connection)));
+      mb.setText(BaseMessages.getString(PKG, "BaseTransformDialog.InvalidConnection.DialogTitle"));
+      mb.open();
+    }
+    return addConnectionLine(parent, previous, databaseMeta, lsMod);
+  }
+
   public IHopMetadataProvider getMetadataProvider() {
     return metadataProvider;
   }