This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new c91b694e69 issue #1866 (Automated XML serialization of WorkflowMeta) 
(#6943)
c91b694e69 is described below

commit c91b694e695ba3c6d0f35575dd007798dc0a8b59
Author: Matt Casters <[email protected]>
AuthorDate: Fri Apr 3 08:31:27 2026 +0200

    issue #1866 (Automated XML serialization of WorkflowMeta) (#6943)
    
    * issue #1866 (Automated XML serialization of WorkflowMeta)
    
    * issue #1866 (Automated XML serialization of WorkflowMeta)
---
 .../main/java/org/apache/hop/base/BaseHopMeta.java |  14 +-
 .../org/apache/hop/pipeline/PipelineHopMeta.java   |  11 +
 .../hop/pipeline/transforms/missing/Missing.java   |  21 +-
 .../org/apache/hop/workflow/WorkflowHopMeta.java   |  14 +
 .../java/org/apache/hop/workflow/WorkflowMeta.java | 739 +++++++--------------
 .../org/apache/hop/workflow/action/ActionBase.java |  16 +-
 .../org/apache/hop/workflow/action/ActionMeta.java |  29 +-
 .../org/apache/hop/workflow/action/IAction.java    |  24 +
 .../org/apache/hop/workflow/WorkflowMetaTest.java  | 117 +++-
 .../apache/hop/workflow/actions/ActionFake.java}   |  49 +-
 .../mdi/files/excelwriter-mdi-test.xlsx            | Bin 3311 -> 3310 bytes
 plugins/misc/git/pom.xml                           |  12 +
 .../test/java/org/apache/hop/git/HopDiffTest.java  |  14 +-
 plugins/misc/git/src/test/resources/r1.hwf         |   4 +-
 plugins/misc/git/src/test/resources/r2.hwf         |   4 +-
 .../hop/ui/workflow/dialog/WorkflowDialog.java     |  41 +-
 16 files changed, 485 insertions(+), 624 deletions(-)

diff --git a/engine/src/main/java/org/apache/hop/base/BaseHopMeta.java 
b/engine/src/main/java/org/apache/hop/base/BaseHopMeta.java
index e37cd6998a..fe3011bc5d 100644
--- a/engine/src/main/java/org/apache/hop/base/BaseHopMeta.java
+++ b/engine/src/main/java/org/apache/hop/base/BaseHopMeta.java
@@ -35,11 +35,13 @@ public abstract class BaseHopMeta<T> {
 
   protected boolean split = false;
 
-  @HopMetadataProperty(key = "from", storeWithName = true, lookupInList = 
"transforms")
-  protected T from;
+  protected abstract T getFrom();
 
-  @HopMetadataProperty(key = "to", storeWithName = true, lookupInList = 
"transforms")
-  protected T to;
+  protected abstract void setFrom(T from);
+
+  protected abstract T getTo();
+
+  protected abstract void setTo(T to);
 
   @HopMetadataProperty(key = "enabled")
   protected boolean enabled;
@@ -52,8 +54,8 @@ public abstract class BaseHopMeta<T> {
   protected BaseHopMeta(
       boolean split, T from, T to, boolean enabled, boolean changed, boolean 
errorHop) {
     this.split = split;
-    this.from = from;
-    this.to = to;
+    setFrom(from);
+    setTo(to);
     this.enabled = enabled;
     this.changed = changed;
     this.errorHop = errorHop;
diff --git a/engine/src/main/java/org/apache/hop/pipeline/PipelineHopMeta.java 
b/engine/src/main/java/org/apache/hop/pipeline/PipelineHopMeta.java
index 25712058fd..b6be07ee76 100644
--- a/engine/src/main/java/org/apache/hop/pipeline/PipelineHopMeta.java
+++ b/engine/src/main/java/org/apache/hop/pipeline/PipelineHopMeta.java
@@ -19,21 +19,32 @@ package org.apache.hop.pipeline;
 
 import java.util.List;
 import java.util.Objects;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.hop.base.BaseHopMeta;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopXmlException;
 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.serializer.xml.XmlMetadataUtil;
 import org.apache.hop.pipeline.transform.TransformMeta;
 import org.w3c.dom.Node;
 
 /** Defines a link between 2 transforms in a pipeline */
+@Getter
+@Setter
 public class PipelineHopMeta extends BaseHopMeta<TransformMeta>
     implements Comparable<PipelineHopMeta>, Cloneable {
   private static final Class<?> PKG = Pipeline.class;
   public static final String CONST_SPACES = "      ";
 
+  @HopMetadataProperty(key = "from", storeWithName = true, lookupInList = 
"transforms")
+  protected TransformMeta from;
+
+  @HopMetadataProperty(key = "to", storeWithName = true, lookupInList = 
"transforms")
+  protected TransformMeta to;
+
   public PipelineHopMeta(TransformMeta from, TransformMeta to, boolean en) {
     this.from = from;
     this.to = to;
diff --git 
a/engine/src/main/java/org/apache/hop/pipeline/transforms/missing/Missing.java 
b/engine/src/main/java/org/apache/hop/pipeline/transforms/missing/Missing.java
index b6522a8c2b..3f50fae925 100644
--- 
a/engine/src/main/java/org/apache/hop/pipeline/transforms/missing/Missing.java
+++ 
b/engine/src/main/java/org/apache/hop/pipeline/transforms/missing/Missing.java
@@ -17,10 +17,13 @@
 
 package org.apache.hop.pipeline.transforms.missing;
 
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.hop.pipeline.transform.BaseTransformMeta;
 
+@Getter
+@Setter
 public class Missing extends BaseTransformMeta<MissingTransform, MissingData> {
-
   private String transformName;
   private String missingPluginId;
 
@@ -28,20 +31,4 @@ public class Missing extends 
BaseTransformMeta<MissingTransform, MissingData> {
     this.transformName = transformName;
     this.missingPluginId = missingPluginId;
   }
-
-  public String getTransformName() {
-    return transformName;
-  }
-
-  public void setTransformName(String transformName) {
-    this.transformName = transformName;
-  }
-
-  public String getMissingPluginId() {
-    return missingPluginId;
-  }
-
-  public void setMissingPluginId(String missingPluginId) {
-    this.missingPluginId = missingPluginId;
-  }
 }
diff --git a/engine/src/main/java/org/apache/hop/workflow/WorkflowHopMeta.java 
b/engine/src/main/java/org/apache/hop/workflow/WorkflowHopMeta.java
index 0f491c3368..2b33ca3550 100644
--- a/engine/src/main/java/org/apache/hop/workflow/WorkflowHopMeta.java
+++ b/engine/src/main/java/org/apache/hop/workflow/WorkflowHopMeta.java
@@ -18,15 +18,20 @@
 package org.apache.hop.workflow;
 
 import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.hop.base.BaseHopMeta;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.exception.HopXmlException;
 import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.metadata.api.HopMetadataProperty;
 import org.apache.hop.workflow.action.ActionMeta;
 import org.w3c.dom.Node;
 
 /** This class defines a hop from one action copy to another. */
+@Getter
+@Setter
 public class WorkflowHopMeta extends BaseHopMeta<ActionMeta> implements 
Cloneable {
   private static final Class<?> PKG = WorkflowHopMeta.class;
 
@@ -34,7 +39,16 @@ public class WorkflowHopMeta extends BaseHopMeta<ActionMeta> 
implements Cloneabl
   public static final String XML_UNCONDITIONAL_TAG = "unconditional";
   private static final String CONST_SPACE = "      ";
 
+  @HopMetadataProperty(key = "from", storeWithName = true, lookupInList = 
"workflowActions")
+  protected ActionMeta from;
+
+  @HopMetadataProperty(key = "to", storeWithName = true, lookupInList = 
"workflowActions")
+  protected ActionMeta to;
+
+  @HopMetadataProperty(key = "evaluation")
   private boolean evaluation;
+
+  @HopMetadataProperty(key = "unconditional")
   private boolean unconditional;
 
   public WorkflowHopMeta() {
diff --git a/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java 
b/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java
index 8b08c5a0f9..be0d4c550f 100644
--- a/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java
+++ b/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java
@@ -31,7 +31,6 @@ import org.apache.commons.vfs2.FileName;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.commons.vfs2.FileSystemException;
 import org.apache.hop.base.AbstractMeta;
-import org.apache.hop.base.BaseHopMeta;
 import org.apache.hop.core.CheckResult;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.HopVersionProvider;
@@ -40,7 +39,6 @@ import org.apache.hop.core.IProgressMonitor;
 import org.apache.hop.core.NotePadMeta;
 import org.apache.hop.core.ProgressNullMonitorListener;
 import org.apache.hop.core.SqlStatement;
-import org.apache.hop.core.attributes.AttributesUtil;
 import org.apache.hop.core.database.DatabaseMeta;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopFileException;
@@ -52,9 +50,7 @@ import org.apache.hop.core.file.IHasFilename;
 import org.apache.hop.core.gui.Point;
 import org.apache.hop.core.logging.LogChannel;
 import org.apache.hop.core.logging.LoggingObjectType;
-import org.apache.hop.core.parameters.INamedParameters;
 import org.apache.hop.core.parameters.NamedParameters;
-import org.apache.hop.core.parameters.UnknownParamException;
 import org.apache.hop.core.reflection.StringSearchResult;
 import org.apache.hop.core.reflection.StringSearcher;
 import org.apache.hop.core.util.StringUtil;
@@ -67,6 +63,7 @@ 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.metadata.serializer.xml.XmlMetadataUtil;
 import org.apache.hop.resource.IResourceExport;
 import org.apache.hop.resource.IResourceNaming;
 import org.apache.hop.resource.ResourceDefinition;
@@ -74,15 +71,18 @@ import org.apache.hop.resource.ResourceReference;
 import org.apache.hop.workflow.action.ActionMeta;
 import org.apache.hop.workflow.action.IAction;
 import org.apache.hop.workflow.actions.missing.MissingAction;
+import org.jspecify.annotations.NonNull;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
 /**
  * The definition of a Hop workflow is represented by a WorkflowMeta object. 
It is typically loaded
- * from a .hwf file or it is generated dynamically. The declared parameters of 
the workflow
+ * from a .hwf file, or it is generated dynamically. The declared parameters 
of the workflow
  * definition are then queried using listParameters() and assigned values 
using calls to
- * setParameterValue(..). WorkflowMeta provides methods to load, save, verify, 
etc.
+ * setParameterValue(). WorkflowMeta provides methods to load, save, verify, 
etc.
  */
+@Getter
+@Setter
 public class WorkflowMeta extends AbstractMeta
     implements Cloneable, Comparable<WorkflowMeta>, IXml, IResourceExport, 
IHasFilename {
   public static final String WORKFLOW_EXTENSION = ".hwf";
@@ -106,19 +106,21 @@ public class WorkflowMeta extends AbstractMeta
   private static final String CONST_PARAMETER = "parameter";
   private static final String CONST_SPACE = "        ";
 
-  /**
-   * List of booleans indicating whether or not to remember the size and 
position of the different
-   * windows...
-   */
-  public boolean[] max = new boolean[1];
-
   @HopMetadataProperty(inline = true)
   protected WorkflowMetaInfo info;
 
+  @HopMetadataProperty(key = "workflow_version")
   protected String workflowVersion;
-  protected int workflowStatus;
+
+  @HopMetadataProperty(key = "parameters")
+  protected NamedParameters namedParameters;
+
+  @HopMetadataProperty(key = "action", groupKey = "actions")
   protected List<ActionMeta> workflowActions;
+
+  @HopMetadataProperty(key = "hop", groupKey = "hops")
   protected List<WorkflowHopMeta> workflowHops;
+
   protected String[] arguments;
   protected boolean changedActions;
   protected boolean changedHops;
@@ -130,43 +132,41 @@ public class WorkflowMeta extends AbstractMeta
 
   private List<MissingAction> missingActions;
 
-  @Getter @Setter protected INamedParameters namedParameters;
-
   /** Instantiates a new workflow meta. */
   public WorkflowMeta() {
     clear();
   }
 
   /**
-   * Instantiates a new workflow meta.
+   * Loads metadata from XML into this object.
    *
-   * @param fname the fname
-   * @throws HopXmlException the hop xml exception
+   * @param filename the filename
+   * @throws HopXmlException In case something goes wrong loading XML content.
    */
-  public WorkflowMeta(String fname) throws HopXmlException {
-    this(null, fname, null);
+  public WorkflowMeta(String filename) throws HopXmlException {
+    this(null, filename, null);
   }
 
   /**
    * Load the workflow from the XML file specified
    *
-   * @param variables
-   * @param fname
-   * @param metadataProvider
-   * @throws HopXmlException
+   * @param variables The variables to use
+   * @param filename The file name
+   * @param metadataProvider The metadata provider
+   * @throws HopXmlException In case something goes wrong loading XML content.
    */
-  public WorkflowMeta(IVariables variables, String fname, IHopMetadataProvider 
metadataProvider)
+  public WorkflowMeta(IVariables variables, String filename, 
IHopMetadataProvider metadataProvider)
       throws HopXmlException {
     this.metadataProvider = metadataProvider;
-    loadXml(variables, fname, metadataProvider);
+    loadXml(variables, filename, metadataProvider);
   }
 
   /**
    * Instantiates a new workflow meta.
    *
    * @param inputStream the input stream
-   * @param variables
-   * @throws HopXmlException the hop xml exception
+   * @param variables The variables to reference for the copyright header.
+   * @throws HopXmlException In case something goes wrong loading XML content.
    */
   public WorkflowMeta(
       InputStream inputStream, IHopMetadataProvider metadataProvider, 
IVariables variables)
@@ -179,11 +179,11 @@ public class WorkflowMeta extends AbstractMeta
   }
 
   /**
-   * Create a new WorkflowMeta object by loading it from a a DOM node.
+   * Create a new WorkflowMeta object by loading it from a DOM node.
    *
    * @param workflowNode The node to load from
-   * @param variables
-   * @throws HopXmlException
+   * @param variables The variables to reference for the copyright header.
+   * @throws HopXmlException In case something goes wrong loading XML content.
    */
   public WorkflowMeta(
       Node workflowNode, IHopMetadataProvider metadataProvider, IVariables 
variables)
@@ -193,7 +193,7 @@ public class WorkflowMeta extends AbstractMeta
     loadXml(workflowNode, null, metadataProvider, variables);
   }
 
-  /** Clears or reinitializes many of the WorkflowMeta properties. */
+  /** Clears or re-initializes many of the WorkflowMeta properties. */
   @Override
   public void clear() {
     workflowActions = new ArrayList<>();
@@ -206,7 +206,6 @@ public class WorkflowMeta extends AbstractMeta
     super.clear();
     loopCache = new HashMap<>();
     addDefaults();
-    workflowStatus = -1;
     workflowVersion = null;
   }
 
@@ -252,7 +251,7 @@ public class WorkflowMeta extends AbstractMeta
   }
 
   /**
-   * Compares this workflow's meta-data to the specified workflow's meta-data. 
This method simply
+   * Compares this workflow's metadata to the specified workflow's metadata. 
This method simply
    * calls compare(this, o)
    *
    * @param o the o
@@ -261,13 +260,13 @@ public class WorkflowMeta extends AbstractMeta
    * @see Comparable#compareTo(Object)
    */
   @Override
-  public int compareTo(WorkflowMeta o) {
+  public int compareTo(@NonNull WorkflowMeta o) {
     return compare(this, o);
   }
 
   /**
-   * Checks whether this workflow's meta-data object is equal to the specified 
object. If the
-   * specified object is not an instance of WorkflowMeta, false is returned. 
Otherwise the method
+   * Checks whether this workflow's metadata object is equal to the specified 
object. If the
+   * specified object is not an instance of WorkflowMeta, false is returned, 
otherwise the method
    * returns whether a call to compare() indicates equality (i.e. compare(this,
    * (WorkflowMeta)obj)==0).
    *
@@ -276,6 +275,7 @@ public class WorkflowMeta extends AbstractMeta
    * @see #compare(WorkflowMeta, WorkflowMeta)
    * @see Object#equals(Object)
    */
+  @Override
   public boolean equals(Object obj) {
     if (!(obj instanceof WorkflowMeta)) {
       return false;
@@ -284,10 +284,15 @@ public class WorkflowMeta extends AbstractMeta
     return compare(this, (WorkflowMeta) obj) == 0;
   }
 
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+
   /**
-   * Clones the workflow meta-data object.
+   * Clones the workflow metadata object.
    *
-   * @return a clone of the workflow meta-data object
+   * @return a clone of the workflow metadata object
    * @see Object#clone()
    */
   @Override
@@ -296,7 +301,7 @@ public class WorkflowMeta extends AbstractMeta
   }
 
   /**
-   * Perform a real clone of the workflow meta-data object, including cloning 
all lists and copying
+   * Perform a real clone of the workflow metadata object, including cloning 
all lists and copying
    * all values. If the doClear parameter is true, the clone will be cleared 
of ALL values before
    * the copy. If false, only the copied fields will be cleared.
    *
@@ -369,113 +374,37 @@ public class WorkflowMeta extends AbstractMeta
   /**
    * Gets the XML representation of this workflow.
    *
+   * @param variables The variables to use for checking the license header 
inclusion.
    * @return the XML representation of this workflow
    * @throws HopException if any errors occur during generation of the XML
    * @see IXml#getXml(IVariables)
-   * @param variables
    */
   @Override
   public String getXml(IVariables variables) throws HopException {
-
-    StringBuilder xml = new StringBuilder(500);
-
-    xml.append(XmlHandler.getLicenseHeader(variables));
-
-    xml.append(XmlHandler.openTag(XML_TAG)).append(Const.CR);
-
-    xml.append("  ")
-        .append(
-            XmlHandler.addTagValue("name", getName())); // lossy if name is 
sync'ed with filename
-    xml.append("  ")
-        .append(
-            XmlHandler.addTagValue(
-                "name_sync_with_filename", 
info.isNameSynchronizedWithFilename()));
-
-    xml.append("  ").append(XmlHandler.addTagValue(CONST_DESCRIPTION, 
info.getDescription()));
-    xml.append("  ")
-        .append(XmlHandler.addTagValue("extended_description", 
info.getExtendedDescription()));
-    xml.append("  ").append(XmlHandler.addTagValue("workflow_version", 
workflowVersion));
-    if (workflowStatus >= 0) {
-      xml.append("  ").append(XmlHandler.addTagValue("workflow_status", 
workflowStatus));
-    }
-
-    xml.append("  ").append(XmlHandler.addTagValue("created_user", 
info.getCreatedUser()));
-    xml.append("  ")
-        .append(
-            XmlHandler.addTagValue("created_date", 
XmlHandler.date2string(info.getCreatedDate())));
-    xml.append("  ").append(XmlHandler.addTagValue("modified_user", 
info.getModifiedUser()));
-    xml.append("  ")
-        .append(
-            XmlHandler.addTagValue(
-                "modified_date", 
XmlHandler.date2string(info.getModifiedDate())));
-
-    xml.append("    
").append(XmlHandler.openTag(XML_TAG_PARAMETERS)).append(Const.CR);
-    String[] parameters = listParameters();
-    for (String parameter : parameters) {
-      xml.append("      
").append(XmlHandler.openTag(CONST_PARAMETER)).append(Const.CR);
-      xml.append(CONST_SPACE).append(XmlHandler.addTagValue("name", 
parameter));
-      try {
-        xml.append(CONST_SPACE)
-            .append(XmlHandler.addTagValue("default_value", 
getParameterDefault(parameter)));
-        xml.append(CONST_SPACE)
-            .append(XmlHandler.addTagValue(CONST_DESCRIPTION, 
getParameterDescription(parameter)));
-      } catch (UnknownParamException e) {
-        // skip the default value and/or description. This exception should 
never happen because we
-        // use listParameters()
-        // above.
-      }
-      xml.append("      
").append(XmlHandler.closeTag(CONST_PARAMETER)).append(Const.CR);
-    }
-    xml.append("    
").append(XmlHandler.closeTag(XML_TAG_PARAMETERS)).append(Const.CR);
-
-    xml.append("  
").append(XmlHandler.openTag(XML_TAG_ACTIONS)).append(Const.CR);
-    for (int i = 0; i < nrActions(); i++) {
-      ActionMeta jge = getAction(i);
-      xml.append(jge.getXml());
-    }
-    xml.append("  
").append(XmlHandler.closeTag(XML_TAG_ACTIONS)).append(Const.CR);
-
-    xml.append("  ").append(XmlHandler.openTag(XML_TAG_HOPS)).append(Const.CR);
-    for (WorkflowHopMeta hi : workflowHops) {
-      // Look at all the hops
-      xml.append(hi.getXml());
-    }
-    xml.append("  
").append(XmlHandler.closeTag(XML_TAG_HOPS)).append(Const.CR);
-
-    xml.append("  
").append(XmlHandler.openTag(XML_TAG_NOTEPADS)).append(Const.CR);
-    for (int i = 0; i < nrNotes(); i++) {
-      NotePadMeta ni = getNote(i);
-      xml.append(ni.getXml());
-    }
-    xml.append("  
").append(XmlHandler.closeTag(XML_TAG_NOTEPADS)).append(Const.CR);
-
-    // Also store the attribute groups
-    //
-    xml.append(AttributesUtil.getAttributesXml(attributesMap));
-
-    xml.append(XmlHandler.closeTag(XML_TAG)).append(Const.CR);
-
-    return XmlFormatter.format(xml.toString());
+    return XmlHandler.getLicenseHeader(variables)
+        + XmlFormatter.format(
+            XmlHandler.aroundTag(XML_TAG, 
XmlMetadataUtil.serializeObjectToXml(this)));
   }
 
-  public void loadXml(IVariables variables, String fname, IHopMetadataProvider 
metadataProvider)
+  public void loadXml(IVariables variables, String filename, 
IHopMetadataProvider metadataProvider)
       throws HopXmlException {
     try {
       // OK, try to load using the VFS stuff...
-      Document doc = XmlHandler.loadXmlFile(HopVfs.getFileObject(fname));
+      Document doc = XmlHandler.loadXmlFile(HopVfs.getFileObject(filename));
       if (doc != null) {
         // The workflowNode
         Node workflowNode = XmlHandler.getSubNode(doc, XML_TAG);
 
-        loadXml(workflowNode, fname, metadataProvider, variables);
+        loadXml(workflowNode, filename, metadataProvider, variables);
       } else {
         throw new HopXmlException(
-            BaseMessages.getString(PKG, 
"WorkflowMeta.Exception.ErrorReadingFromXMLFile") + fname);
+            BaseMessages.getString(PKG, 
"WorkflowMeta.Exception.ErrorReadingFromXMLFile")
+                + filename);
       }
     } catch (Exception e) {
       throw new HopXmlException(
           BaseMessages.getString(PKG, 
"WorkflowMeta.Exception.UnableToLoadWorkflowFromXMLFile")
-              + fname
+              + filename
               + "]",
           e);
     }
@@ -486,9 +415,9 @@ public class WorkflowMeta extends AbstractMeta
    *
    * @param workflowNode The node to load from
    * @param filename The filename
-   * @param metadataProvider the MetaStore to use
-   * @param variables
-   * @throws HopXmlException
+   * @param metadataProvider the metadata provider to use for referencing 
external objects.
+   * @param variables The variables to reference for the copyright header.
+   * @throws HopXmlException In case something goes wrong loading XML content.
    */
   public void loadXml(
       Node workflowNode,
@@ -502,116 +431,47 @@ public class WorkflowMeta extends AbstractMeta
 
       setFilename(filename);
 
-      // get workflow info:
+      // De-serialize the XML using @HopMetadataProperty annotations
       //
-      info.setName(XmlHandler.getTagValue(workflowNode, "name"));
+      XmlMetadataUtil.deSerializeFromXml(
+          null, null, workflowNode, WorkflowMeta.class, this, 
metadataProvider);
 
-      info.setNameSynchronizedWithFilename(
-          "Y".equalsIgnoreCase(XmlHandler.getTagValue(workflowNode, 
"name_sync_with_filename")));
-
-      // description
-      info.setDescription(XmlHandler.getTagValue(workflowNode, 
CONST_DESCRIPTION));
-
-      // extended description
-      info.setExtendedDescription(XmlHandler.getTagValue(workflowNode, 
"extended_description"));
-
-      // workflow version
-      workflowVersion = XmlHandler.getTagValue(workflowNode, 
"workflow_version");
-
-      // workflow status
-      workflowStatus = Const.toInt(XmlHandler.getTagValue(workflowNode, 
"workflow_status"), -1);
-
-      // Created user/date
-      info.setCreatedUser(XmlHandler.getTagValue(workflowNode, 
"created_user"));
-      String createDate = XmlHandler.getTagValue(workflowNode, "created_date");
-
-      if (createDate != null) {
-        info.setCreatedDate(XmlHandler.stringToDate(createDate));
-      }
-
-      // Changed user/date
-      info.setModifiedUser(XmlHandler.getTagValue(workflowNode, 
"modified_user"));
-      String modDate = XmlHandler.getTagValue(workflowNode, "modified_date");
-      if (modDate != null) {
-        info.setModifiedDate(XmlHandler.stringToDate(modDate));
-      }
-
-      // Read the named parameters.
-      //
-      Node paramsNode = XmlHandler.getSubNode(workflowNode, 
XML_TAG_PARAMETERS);
-      List<Node> paramNodes = XmlHandler.getNodes(paramsNode, CONST_PARAMETER);
-      for (Node paramNode : paramNodes) {
-        String parameterName = XmlHandler.getTagValue(paramNode, "name");
-        String defaultValue = XmlHandler.getTagValue(paramNode, 
"default_value");
-        String description = XmlHandler.getTagValue(paramNode, 
CONST_DESCRIPTION);
-
-        addParameterDefinition(parameterName, defaultValue, description);
-      }
-
-      // read the action metadata
-      //
-      Node actionsNode = XmlHandler.getSubNode(workflowNode, XML_TAG_ACTIONS);
-      List<Node> actionNodes = XmlHandler.getNodes(actionsNode, 
ActionMeta.XML_TAG);
-      for (Node actionNode : actionNodes) {
-        ActionMeta actionMeta = new ActionMeta(actionNode, metadataProvider, 
variables);
-
-        if (actionMeta.isMissing()) {
-          addMissingAction((MissingAction) actionMeta.getAction());
-        }
-        ActionMeta prev = findAction(actionMeta.getName());
-        if (prev != null) {
-          // See if the action already exists!
-          // Replace previous version with this one: remove it first
-          //
-          int idx = indexOfAction(prev);
-          removeAction(idx);
-        }
-        // Add the ActionCopy...
-        addAction(actionMeta);
-      }
-
-      Node hopsNode = XmlHandler.getSubNode(workflowNode, XML_TAG_HOPS);
-      List<Node> hopNodes = XmlHandler.getNodes(hopsNode, 
BaseHopMeta.XML_HOP_TAG);
-      for (Node hopNode : hopNodes) {
-        WorkflowHopMeta hi = new WorkflowHopMeta(hopNode, this);
-        workflowHops.add(hi);
-      }
-
-      // Read the notes...
-      //
-      Node notepadsNode = XmlHandler.getSubNode(workflowNode, 
XML_TAG_NOTEPADS);
-      List<Node> nodepadNodes = XmlHandler.getNodes(notepadsNode, 
NotePadMeta.XML_TAG);
-      for (Node notepadNode : nodepadNodes) {
-        NotePadMeta ni = new NotePadMeta(notepadNode);
-        notes.add(ni);
-      }
-
-      // Load the attribute groups map
-      //
-      attributesMap =
-          AttributesUtil.loadAttributes(
-              XmlHandler.getSubNode(workflowNode, AttributesUtil.XML_TAG));
+      lookupReferencesAfterLoading();
 
       clearChanged();
 
       ExtensionPointHandler.callExtensionPoint(
           LogChannel.GENERAL, variables, 
HopExtensionPoint.WorkflowMetaLoaded.id, this);
-
     } catch (Exception e) {
       throw new HopXmlException(
           BaseMessages.getString(PKG, 
"WorkflowMeta.Exception.UnableToLoadWorkflowFromXMLNode"), e);
     }
   }
 
+  /**
+   * After loading there can still be some references to other transforms or 
indeed this pipeline
+   * that need to be set. This is happening here.
+   */
+  public void lookupReferencesAfterLoading() {
+    for (ActionMeta actionMeta : workflowActions) {
+      IAction action = actionMeta.getAction();
+
+      // Also set the parent workflow to which this action belongs.
+      // This is rarely used, for example in getTableFields.getTableFields()
+      //
+      action.setParentWorkflowMeta(this);
+    }
+  }
+
   /**
    * Gets the action copy.
    *
    * @param x the x
    * @param y the y
-   * @param iconsize the iconsize
+   * @param iconSize the iconSize
    * @return the action copy
    */
-  public ActionMeta getAction(int x, int y, int iconsize) {
+  public ActionMeta getAction(int x, int y, int iconSize) {
     int i;
     int s;
     s = nrActions();
@@ -620,7 +480,7 @@ public class WorkflowMeta extends AbstractMeta
 
       ActionMeta action = getAction(i);
       Point p = action.getLocation();
-      if (p != null && x >= p.x && x <= p.x + iconsize && y >= p.y && y <= p.y 
+ iconsize) {
+      if (p != null && x >= p.x && x <= p.x + iconSize && y >= p.y && y <= p.y 
+ iconSize) {
         return action;
       }
     }
@@ -722,7 +582,6 @@ public class WorkflowMeta extends AbstractMeta
   public void removeAction(int index) {
     ActionMeta deleted = workflowActions.remove(index);
     if (deleted != null) {
-      // give transform a chance to cleanup
       deleted.setParentWorkflowMeta(null);
       if (deleted.getAction() instanceof MissingAction missingAction) {
         removeMissingAction(missingAction);
@@ -1147,7 +1006,7 @@ public class WorkflowMeta extends AbstractMeta
         hops.add(hop);
       }
     }
-    return hops.toArray(new WorkflowHopMeta[hops.size()]);
+    return hops.toArray(new WorkflowHopMeta[0]);
   }
 
   public boolean isPathExist(IAction from, IAction to) {
@@ -1219,47 +1078,6 @@ public class WorkflowMeta extends AbstractMeta
     return new Point(maxx + 100, maxy + 100);
   }
 
-  /**
-   * Get the minimum point on the canvas of a workflow
-   *
-   * @return Minimum coordinate of a transform in the workflow
-   */
-  public Point getMinimum() {
-    int minx = Integer.MAX_VALUE;
-    int miny = Integer.MAX_VALUE;
-    for (ActionMeta action : workflowActions) {
-      Point loc = action.getLocation();
-      if (loc.x < minx) {
-        minx = loc.x;
-      }
-      if (loc.y < miny) {
-        miny = loc.y;
-      }
-    }
-    for (NotePadMeta note : getNotes()) {
-      Point loc = note.getLocation();
-      if (loc.x < minx) {
-        minx = loc.x;
-      }
-      if (loc.y < miny) {
-        miny = loc.y;
-      }
-    }
-
-    if (minx > BORDER_INDENT && minx != Integer.MAX_VALUE) {
-      minx -= BORDER_INDENT;
-    } else {
-      minx = 0;
-    }
-    if (miny > BORDER_INDENT && miny != Integer.MAX_VALUE) {
-      miny -= BORDER_INDENT;
-    } else {
-      miny = 0;
-    }
-
-    return new Point(minx, miny);
-  }
-
   /**
    * Gets the selected actions locations.
    *
@@ -1289,7 +1107,7 @@ public class WorkflowMeta extends AbstractMeta
       points.add(new Point(p.x, p.y)); // explicit copy of location
     }
 
-    return points.toArray(new Point[points.size()]);
+    return points.toArray(new Point[0]);
   }
 
   /**
@@ -1409,120 +1227,131 @@ public class WorkflowMeta extends AbstractMeta
    * @return A list of StringSearchResult with strings used in the workflow
    */
   public List<StringSearchResult> getStringList(
-      boolean searchTransforms, boolean searchDatabases, boolean searchNotes) {
+      boolean searchActions, boolean searchDatabases, boolean searchNotes) {
     List<StringSearchResult> stringList = new ArrayList<>();
 
-    if (searchTransforms) {
-      // Loop over all transforms in the pipeline and see what the used
-      // vars are...
-      for (int i = 0; i < nrActions(); i++) {
-        ActionMeta actionMeta = getAction(i);
-        stringList.add(
-            new StringSearchResult(
-                actionMeta.getName(),
-                actionMeta,
-                this,
-                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.ActionName")));
-        if (actionMeta.getDescription() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  actionMeta.getDescription(),
-                  actionMeta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.ActionDescription")));
-        }
-        IAction action = actionMeta.getAction();
-        StringSearcher.findMetaData(action, 1, stringList, actionMeta, this);
-      }
+    if (searchActions) {
+      // Loop over all actions in the workflow and see what the used variables 
are etc.
+      //
+      getStringListFromActions(stringList);
     }
 
     // Loop over all transforms in the pipeline and see what the used vars
     // are...
     if (searchDatabases) {
-      for (DatabaseMeta meta : getDatabases()) {
+      getStringListFromDatabases(stringList);
+    }
+
+    // Loop over all transforms in the pipeline and see what the used vars
+    // are...
+    if (searchNotes) {
+      getStringListFromNotes(stringList);
+    }
+
+    return stringList;
+  }
+
+  private void getStringListFromNotes(List<StringSearchResult> stringList) {
+    for (int i = 0; i < nrNotes(); i++) {
+      NotePadMeta meta = getNote(i);
+      if (meta.getNote() != null) {
         stringList.add(
             new StringSearchResult(
-                meta.getName(),
+                meta.getNote(),
                 meta,
                 this,
-                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseConnectionName")));
-        if (meta.getHostname() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getHostname(),
-                  meta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseHostName")));
-        }
-        if (meta.getDatabaseName() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getDatabaseName(),
-                  meta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseName")));
-        }
-        if (meta.getUsername() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getUsername(),
-                  meta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseUsername")));
-        }
-        if (meta.getPluginId() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getPluginId(),
-                  meta,
-                  this,
-                  BaseMessages.getString(
-                      PKG, 
"WorkflowMeta.SearchMetadata.DatabaseTypeDescription")));
-        }
-        if (meta.getPort() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getPort(),
-                  meta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabasePort")));
-        }
-        if (meta.getServername() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getServername(),
-                  meta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseServer")));
-        }
-        if (meta.getPassword() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getPassword(),
-                  meta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabasePassword")));
-        }
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.NotepadText")));
       }
     }
+  }
 
-    // Loop over all transforms in the pipeline and see what the used vars
-    // are...
-    if (searchNotes) {
-      for (int i = 0; i < nrNotes(); i++) {
-        NotePadMeta meta = getNote(i);
-        if (meta.getNote() != null) {
-          stringList.add(
-              new StringSearchResult(
-                  meta.getNote(),
-                  meta,
-                  this,
-                  BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.NotepadText")));
-        }
+  private void getStringListFromDatabases(List<StringSearchResult> stringList) 
{
+    for (DatabaseMeta meta : getDatabases()) {
+      stringList.add(
+          new StringSearchResult(
+              meta.getName(),
+              meta,
+              this,
+              BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseConnectionName")));
+      if (meta.getHostname() != null) {
+        stringList.add(
+            new StringSearchResult(
+                meta.getHostname(),
+                meta,
+                this,
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseHostName")));
+      }
+      if (meta.getDatabaseName() != null) {
+        stringList.add(
+            new StringSearchResult(
+                meta.getDatabaseName(),
+                meta,
+                this,
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseName")));
+      }
+      if (meta.getUsername() != null) {
+        stringList.add(
+            new StringSearchResult(
+                meta.getUsername(),
+                meta,
+                this,
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseUsername")));
+      }
+      if (meta.getPluginId() != null) {
+        stringList.add(
+            new StringSearchResult(
+                meta.getPluginId(),
+                meta,
+                this,
+                BaseMessages.getString(
+                    PKG, 
"WorkflowMeta.SearchMetadata.DatabaseTypeDescription")));
+      }
+      if (meta.getPort() != null) {
+        stringList.add(
+            new StringSearchResult(
+                meta.getPort(),
+                meta,
+                this,
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabasePort")));
+      }
+      if (meta.getServername() != null) {
+        stringList.add(
+            new StringSearchResult(
+                meta.getServername(),
+                meta,
+                this,
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabaseServer")));
+      }
+      if (meta.getPassword() != null) {
+        stringList.add(
+            new StringSearchResult(
+                meta.getPassword(),
+                meta,
+                this,
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.DatabasePassword")));
       }
     }
+  }
 
-    return stringList;
+  private void getStringListFromActions(List<StringSearchResult> stringList) {
+    for (ActionMeta actionMeta : workflowActions) {
+      stringList.add(
+          new StringSearchResult(
+              actionMeta.getName(),
+              actionMeta,
+              this,
+              BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.ActionName")));
+      if (actionMeta.getDescription() != null) {
+        stringList.add(
+            new StringSearchResult(
+                actionMeta.getDescription(),
+                actionMeta,
+                this,
+                BaseMessages.getString(PKG, 
"WorkflowMeta.SearchMetadata.ActionDescription")));
+      }
+      IAction action = actionMeta.getAction();
+      StringSearcher.findMetaData(action, 1, stringList, actionMeta, this);
+    }
   }
 
   /**
@@ -1581,42 +1410,6 @@ public class WorkflowMeta extends AbstractMeta
     return false;
   }
 
-  /**
-   * Gets the version of the workflow.
-   *
-   * @return The version of the workflow
-   */
-  public String getWorkflowVersion() {
-    return workflowVersion;
-  }
-
-  /**
-   * Set the version of the workflow.
-   *
-   * @param jobVersion The new version description of the workflow
-   */
-  public void setWorkflowVersion(String jobVersion) {
-    this.workflowVersion = jobVersion;
-  }
-
-  /**
-   * Gets the status of the workflow.
-   *
-   * @return the status of the workflow
-   */
-  public int getWorkflowStatus() {
-    return workflowStatus;
-  }
-
-  /**
-   * Set the status of the workflow.
-   *
-   * @param status The new status description of the workflow
-   */
-  public void setWorkflowStatus(int status) {
-    this.workflowStatus = status;
-  }
-
   /** This method sets various internal hop variables that can be used by the 
pipeline. */
   @Override
   public void setInternalHopVariables(IVariables variables) {
@@ -1722,15 +1515,7 @@ public class WorkflowMeta extends AbstractMeta
           BaseMessages.getString(PKG, 
"WorkflowMeta.Monitor.VerifyingThisActionTask.Title"),
           actions.size());
 
-      // Check for the presence of a start action
-      if (findStart() == null) {
-        remarks.add(
-            new CheckResult(
-                ICheckResult.TYPE_RESULT_ERROR,
-                BaseMessages.getString(
-                    PKG, 
"WorkflowMeta.CheckResult.StartActionIsMissing.Description"),
-                null));
-      }
+      checkStartPresent(remarks);
 
       int worked = 1;
       for (ActionMeta actionMeta : actions) {
@@ -1740,42 +1525,7 @@ public class WorkflowMeta extends AbstractMeta
 
         IAction action = actionMeta.getAction();
         if (action != null) {
-          monitor.subTask(
-              BaseMessages.getString(
-                  PKG, "WorkflowMeta.Monitor.VerifyingAction.Title", 
action.getName()));
-
-          // Check missing action plugin
-          if (action instanceof MissingAction missingAction) {
-            remarks.add(
-                new CheckResult(
-                    ICheckResult.TYPE_RESULT_ERROR,
-                    BaseMessages.getString(
-                        PKG,
-                        
"WorkflowMeta.CheckResult.ActionPluginNotFound.Description",
-                        missingAction.getMissingPluginId()),
-                    action));
-          }
-
-          // Check deprecated action plugin
-          if (actionMeta.isDeprecated()) {
-            remarks.add(
-                new CheckResult(
-                    ICheckResult.TYPE_RESULT_WARNING,
-                    BaseMessages.getString(
-                        PKG, 
"WorkflowMeta.CheckResult.DeprecatedActionPlugin.Description"),
-                    action));
-          }
-
-          if (isActionUsedInHops(actionMeta) || getActions().size() == 1) {
-            action.check(remarks, this, variables, metadataProvider);
-          } else {
-            remarks.add(
-                new CheckResult(
-                    ICheckResult.TYPE_RESULT_WARNING,
-                    BaseMessages.getString(
-                        PKG, 
"WorkflowMeta.CheckResult.ActionIsNotUsed.Description"),
-                    action));
-          }
+          checkAction(remarks, monitor, variables, metadataProvider, 
actionMeta, action);
         }
         // Progress bar...
         monitor.worked(worked++);
@@ -1787,6 +1537,62 @@ public class WorkflowMeta extends AbstractMeta
     }
   }
 
+  private void checkAction(
+      List<ICheckResult> remarks,
+      IProgressMonitor monitor,
+      IVariables variables,
+      IHopMetadataProvider metadataProvider,
+      ActionMeta actionMeta,
+      IAction action) {
+    monitor.subTask(
+        BaseMessages.getString(
+            PKG, "WorkflowMeta.Monitor.VerifyingAction.Title", 
action.getName()));
+
+    // Check missing action plugin
+    if (action instanceof MissingAction missingAction) {
+      remarks.add(
+          new CheckResult(
+              ICheckResult.TYPE_RESULT_ERROR,
+              BaseMessages.getString(
+                  PKG,
+                  "WorkflowMeta.CheckResult.ActionPluginNotFound.Description",
+                  missingAction.getMissingPluginId()),
+              action));
+    }
+
+    // Check deprecated action plugin
+    if (actionMeta.isDeprecated()) {
+      remarks.add(
+          new CheckResult(
+              ICheckResult.TYPE_RESULT_WARNING,
+              BaseMessages.getString(
+                  PKG, 
"WorkflowMeta.CheckResult.DeprecatedActionPlugin.Description"),
+              action));
+    }
+
+    if (isActionUsedInHops(actionMeta) || getActions().size() == 1) {
+      action.check(remarks, this, variables, metadataProvider);
+    } else {
+      remarks.add(
+          new CheckResult(
+              ICheckResult.TYPE_RESULT_WARNING,
+              BaseMessages.getString(PKG, 
"WorkflowMeta.CheckResult.ActionIsNotUsed.Description"),
+              action));
+    }
+  }
+
+  private void checkStartPresent(List<ICheckResult> remarks) {
+    // Check for the presence of a start action
+    if (findStart() == null) {
+      remarks.add(
+          new CheckResult(
+              ICheckResult.TYPE_RESULT_ERROR,
+              BaseMessages.getString(
+                  PKG, 
"WorkflowMeta.CheckResult.StartActionIsMissing.Description"),
+              null));
+    }
+  }
+
   /**
    * Gets the resource dependencies.
    *
@@ -1919,19 +1725,10 @@ public class WorkflowMeta extends AbstractMeta
     return workflowActions;
   }
 
-  /**
-   * Gets the workflow hops.
-   *
-   * @return the workflow hops
-   */
-  public List<WorkflowHopMeta> getWorkflowHops() {
-    return workflowHops;
-  }
-
   /**
    * Create a unique list of action interfaces
    *
-   * @return
+   * @return The list of unique actions
    */
   public List<IAction> composeActionList() {
     List<IAction> list = new ArrayList<>();
@@ -1967,10 +1764,6 @@ public class WorkflowMeta extends AbstractMeta
     return workflowActions.contains(actionMeta);
   }
 
-  public List<MissingAction> getMissingActions() {
-    return missingActions;
-  }
-
   public void addMissingAction(MissingAction missingAction) {
     if (missingActions == null) {
       missingActions = new ArrayList<>();
@@ -1989,44 +1782,10 @@ public class WorkflowMeta extends AbstractMeta
     return !Utils.isEmpty(missingActions);
   }
 
-  public String getStartActionName() {
-    return startActionName;
-  }
-
-  public void setStartActionName(String name) {
-    this.startActionName = name;
-  }
-
-  public boolean isExpandingRemoteWorkflow() {
-    return expandingRemoteWorkflow;
-  }
-
-  public void setExpandingRemoteWorkflow(boolean expandingRemoteWorkflow) {
-    this.expandingRemoteWorkflow = expandingRemoteWorkflow;
-  }
-
   public boolean isEmpty() {
     return nrActions() == 0 && nrNotes() == 0;
   }
 
-  /**
-   * Gets info
-   *
-   * @return value of info
-   */
-  public WorkflowMetaInfo getInfo() {
-    return info;
-  }
-
-  /**
-   * Sets info
-   *
-   * @param info value of info
-   */
-  public void setInfo(WorkflowMetaInfo info) {
-    this.info = info;
-  }
-
   /**
    * Get the name of the workflow. If the name is synchronized with the 
filename, we return the base
    * filename.
diff --git 
a/engine/src/main/java/org/apache/hop/workflow/action/ActionBase.java 
b/engine/src/main/java/org/apache/hop/workflow/action/ActionBase.java
index 7357ce93f4..a71e7f1822 100644
--- a/engine/src/main/java/org/apache/hop/workflow/action/ActionBase.java
+++ b/engine/src/main/java/org/apache/hop/workflow/action/ActionBase.java
@@ -23,6 +23,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.IAttributes;
@@ -52,6 +54,7 @@ import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.core.variables.Variables;
 import org.apache.hop.core.xml.XmlHandler;
+import org.apache.hop.metadata.api.HopMetadataProperty;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.metadata.serializer.xml.XmlMetadataUtil;
 import org.apache.hop.resource.IResourceHolder;
@@ -68,6 +71,8 @@ import org.w3c.dom.Node;
  * does not implement IAction (although it implements most of the same 
methods), so individual
  * action classes must implement IAction and specifically the 
<code>execute()</code> method.
  */
+@Getter
+@Setter
 public abstract class ActionBase
     implements IAction,
         Cloneable,
@@ -78,12 +83,13 @@ public abstract class ActionBase
         IResourceHolder {
 
   /** The name of the action */
-  private String name;
+  @HopMetadataProperty private String name;
 
   /** The description of the action */
-  private String description;
+  @HopMetadataProperty private String description;
 
   /** ID as defined in the xml or annotation. */
+  @HopMetadataProperty(key = "type")
   private String pluginId;
 
   /** Whether the action has changed. */
@@ -109,6 +115,12 @@ public abstract class ActionBase
 
   private IHopMetadataProvider metadataProvider;
 
+  @HopMetadataProperty(
+      key = "group",
+      groupKey = "attributes",
+      mapKeyWrapper = "name",
+      mapValueWrapper = "attribute",
+      mapValueClass = HashMap.class)
   protected Map<String, Map<String, String>> attributesMap;
 
   protected Map<String, Object> extensionDataMap;
diff --git 
a/engine/src/main/java/org/apache/hop/workflow/action/ActionMeta.java 
b/engine/src/main/java/org/apache/hop/workflow/action/ActionMeta.java
index a1eb6a9e67..1cf0e16f70 100644
--- a/engine/src/main/java/org/apache/hop/workflow/action/ActionMeta.java
+++ b/engine/src/main/java/org/apache/hop/workflow/action/ActionMeta.java
@@ -32,6 +32,8 @@ import org.apache.hop.core.plugins.IPlugin;
 import org.apache.hop.core.plugins.PluginRegistry;
 import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.core.xml.XmlHandler;
+import org.apache.hop.metadata.api.HopMetadataProperty;
+import org.apache.hop.metadata.api.IHasName;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.pipeline.transform.copy.CopyContext;
 import org.apache.hop.workflow.WorkflowMeta;
@@ -43,29 +45,40 @@ import org.w3c.dom.Node;
  * This class describes the fact that a single Action can be used multiple 
times in the same
  * Workflow. Therefore, it contains a link to an Action, a position, a number, 
etc.
  */
-public class ActionMeta implements Cloneable, IGuiPosition, IChanged, 
IAttributes, IBaseMeta {
+public class ActionMeta
+    implements Cloneable, IGuiPosition, IChanged, IAttributes, IBaseMeta, 
IHasName {
   public static final String XML_TAG = "action";
 
   private static final String XML_ATTRIBUTE_WORKFLOW_ACTION_COPY = 
AttributesUtil.XML_TAG + "_hac";
   private static final String CONST_SPACE = "      ";
 
+  @HopMetadataProperty(inline = true)
   private IAction action;
 
+  @HopMetadataProperty(inline = true)
+  private Point location;
+
+  /** Flag to indicate that the actions following this one are launched in 
parallel */
+  @HopMetadataProperty(key = "parallel")
+  private boolean launchingInParallel;
+
+  /** protected for easy access by subclasses */
+  @HopMetadataProperty(
+      key = "group",
+      groupKey = XML_ATTRIBUTE_WORKFLOW_ACTION_COPY,
+      mapKeyWrapper = "name",
+      mapValueWrapper = "attribute",
+      mapValueClass = HashMap.class)
+  private Map<String, Map<String, String>> attributesMap;
+
   private String suggestion = "";
 
   private boolean selected;
 
   private boolean isDeprecated;
 
-  private Point location;
-
-  /** Flag to indicate that the actions following this one are launched in 
parallel */
-  private boolean launchingInParallel;
-
   private WorkflowMeta parentWorkflowMeta;
 
-  private Map<String, Map<String, String>> attributesMap;
-
   public ActionMeta() {
     clear();
   }
diff --git a/engine/src/main/java/org/apache/hop/workflow/action/IAction.java 
b/engine/src/main/java/org/apache/hop/workflow/action/IAction.java
index 805992ca6f..91f18e1ead 100644
--- a/engine/src/main/java/org/apache/hop/workflow/action/IAction.java
+++ b/engine/src/main/java/org/apache/hop/workflow/action/IAction.java
@@ -19,6 +19,7 @@ package org.apache.hop.workflow.action;
 
 import java.util.List;
 import java.util.Map;
+import java.util.MissingResourceException;
 import org.apache.hop.core.ICheckResult;
 import org.apache.hop.core.ICheckResultSource;
 import org.apache.hop.core.IExtensionData;
@@ -29,7 +30,11 @@ import org.apache.hop.core.exception.HopXmlException;
 import org.apache.hop.core.file.IHasFilename;
 import org.apache.hop.core.logging.IHasLogChannel;
 import org.apache.hop.core.logging.ILogChannel;
+import org.apache.hop.core.plugins.ActionPluginType;
+import org.apache.hop.core.plugins.PluginRegistry;
 import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.metadata.api.HopMetadataObject;
+import org.apache.hop.metadata.api.IHopMetadataObjectFactory;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.resource.IResourceNaming;
 import org.apache.hop.resource.ResourceDefinition;
@@ -127,6 +132,7 @@ import org.w3c.dom.Node;
  *       Finally, the passed in prevResult object must be returned.
  * </ul>
  */
+@HopMetadataObject(xmlKey = "type", objectFactory = 
IAction.ActionFactory.class)
 public interface IAction extends IVariables, IHasLogChannel, 
ICheckResultSource, IExtensionData {
 
   /**
@@ -445,4 +451,22 @@ public interface IAction extends IVariables, 
IHasLogChannel, ICheckResultSource,
   default boolean supportsDrillDown() {
     return false;
   }
+
+  final class ActionFactory implements IHopMetadataObjectFactory {
+    @Override
+    public Object createObject(String id, Object parentObject) throws 
HopException {
+      IAction action =
+          PluginRegistry.getInstance().loadClass(ActionPluginType.class, id, 
IAction.class);
+      if (action == null) {
+        throw new MissingResourceException(
+            "Action plugin with ID '" + id + "' was not found", 
IAction.class.getName(), id);
+      }
+      return action;
+    }
+
+    @Override
+    public String getObjectId(Object object) throws HopException {
+      return PluginRegistry.getInstance().getPluginId(ActionPluginType.class, 
object);
+    }
+  }
 }
diff --git a/engine/src/test/java/org/apache/hop/workflow/WorkflowMetaTest.java 
b/engine/src/test/java/org/apache/hop/workflow/WorkflowMetaTest.java
index 9c2a1efac1..3e723c803d 100644
--- a/engine/src/test/java/org/apache/hop/workflow/WorkflowMetaTest.java
+++ b/engine/src/test/java/org/apache/hop/workflow/WorkflowMetaTest.java
@@ -30,15 +30,20 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import org.apache.hop.core.Const;
-import org.apache.hop.core.NotePadMeta;
+import org.apache.hop.core.annotations.Action;
 import org.apache.hop.core.exception.HopException;
-import org.apache.hop.core.gui.Point;
+import org.apache.hop.core.exception.HopPluginException;
 import org.apache.hop.core.listeners.IContentChangedListener;
+import org.apache.hop.core.plugins.ActionPluginType;
+import org.apache.hop.core.plugins.PluginRegistry;
 import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.core.variables.Variables;
+import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.metadata.serializer.memory.MemoryMetadataProvider;
 import org.apache.hop.workflow.action.ActionMeta;
 import org.apache.hop.workflow.action.IAction;
+import org.apache.hop.workflow.actions.ActionFake;
 import org.apache.hop.workflow.actions.dummy.ActionDummy;
 import org.apache.hop.workflow.engine.IWorkflowEngine;
 import org.apache.hop.workflow.engines.local.LocalWorkflowEngine;
@@ -56,7 +61,7 @@ class WorkflowMetaTest {
   private IContentChangedListener listener;
 
   @BeforeEach
-  void setUp() {
+  void setUp() throws HopPluginException {
     workflowMeta = new WorkflowMeta();
     workflowMeta.setNameSynchronizedWithFilename(false);
     // prepare
@@ -65,6 +70,9 @@ class WorkflowMetaTest {
     workflowMeta.setName(WORKFLOW_META_NAME);
 
     variables = new Variables();
+
+    PluginRegistry registry = PluginRegistry.getInstance();
+    registry.registerPluginClass(ActionFake.class.getName(), 
ActionPluginType.class, Action.class);
   }
 
   @Test
@@ -125,35 +133,6 @@ class WorkflowMetaTest {
     verifyNoMoreInteractions(listener);
   }
 
-  @Test
-  void 
shouldUseCoordinatesOfItsTransformsAndNotesWhenCalculatingMinimumPoint() {
-    Point actionPoint = new Point(500, 500);
-    Point notePadMetaPoint = new Point(400, 400);
-    ActionMeta actionMeta = mock(ActionMeta.class);
-    when(actionMeta.getLocation()).thenReturn(actionPoint);
-    NotePadMeta notePadMeta = mock(NotePadMeta.class);
-    when(notePadMeta.getLocation()).thenReturn(notePadMetaPoint);
-
-    // empty Workflow return 0 coordinate point
-    Point point = workflowMeta.getMinimum();
-    assertEquals(0, point.x);
-    assertEquals(0, point.y);
-
-    // when Workflow contains a single transform or note, then workflowMeta 
should return
-    // coordinates of it, subtracting borders
-    workflowMeta.addAction(0, actionMeta);
-    Point actualTransformPoint = workflowMeta.getMinimum();
-    assertEquals(actionPoint.x - WorkflowMeta.BORDER_INDENT, 
actualTransformPoint.x);
-    assertEquals(actionPoint.y - WorkflowMeta.BORDER_INDENT, 
actualTransformPoint.y);
-
-    // when Workflow contains transform or notes, then workflowMeta should 
return minimal
-    // coordinates of them, subtracting borders
-    workflowMeta.addNote(notePadMeta);
-    Point transformPoint = workflowMeta.getMinimum();
-    assertEquals(notePadMetaPoint.x - WorkflowMeta.BORDER_INDENT, 
transformPoint.x);
-    assertEquals(notePadMetaPoint.y - WorkflowMeta.BORDER_INDENT, 
transformPoint.y);
-  }
-
   @Test
   void testEquals_oneNameNull() {
     assertFalse(testEquals(null, null));
@@ -345,4 +324,78 @@ class WorkflowMetaTest {
         "Original value defined at run execution",
         variables.getVariable(Const.INTERNAL_VARIABLE_ENTRY_CURRENT_FOLDER));
   }
+
+  @Test
+  void testXmlSerialization() throws Exception {
+    ActionFake fake1 = new ActionFake();
+    fake1.setSomeProperty("prop1");
+    ActionMeta a1 = new ActionMeta(fake1);
+    a1.setName("a1");
+    workflowMeta.addAction(a1);
+
+    ActionFake fake2 = new ActionFake();
+    fake2.setSomeProperty("prop2");
+    ActionMeta a2 = new ActionMeta(fake2);
+    a2.setName("a2");
+    workflowMeta.addAction(a2);
+
+    ActionFake fake3 = new ActionFake();
+    fake3.setSomeProperty("prop3");
+    ActionMeta a3 = new ActionMeta(fake3);
+    a3.setName("a3");
+    workflowMeta.addAction(a3);
+
+    WorkflowHopMeta a12 = new WorkflowHopMeta(a1, a2);
+    a12.setEvaluation(true);
+    a12.setUnconditional(false);
+    workflowMeta.addWorkflowHop(a12);
+    WorkflowHopMeta a23 = new WorkflowHopMeta(a2, a3);
+    a23.setEvaluation(false);
+    a23.setUnconditional(true);
+    workflowMeta.addWorkflowHop(a23);
+
+    // Serialize to XML
+    String xml = workflowMeta.getXml(new Variables());
+
+    // Re-inflate it
+    //
+    Node node = XmlHandler.loadXmlString(xml, WorkflowMeta.XML_TAG);
+    WorkflowMeta copy = new WorkflowMeta(node, new MemoryMetadataProvider(), 
new Variables());
+
+    assertEquals(3, copy.nrActions());
+
+    ActionMeta copy1 = copy.getAction(0);
+    assertEquals("a1", copy1.getName());
+    assertNotNull(copy1.getAction());
+    if (copy1.getAction() instanceof ActionFake action) {
+      assertEquals("prop1", action.getSomeProperty());
+    }
+
+    ActionMeta copy2 = copy.getAction(1);
+    assertEquals("a2", copy2.getName());
+    assertNotNull(copy2.getAction());
+    if (copy2.getAction() instanceof ActionFake action) {
+      assertEquals("prop2", action.getSomeProperty());
+    }
+
+    ActionMeta copy3 = copy.getAction(2);
+    assertEquals("a3", copy3.getName());
+    assertNotNull(copy3.getAction());
+    if (copy3.getAction() instanceof ActionFake action) {
+      assertEquals("prop3", action.getSomeProperty());
+    }
+
+    assertEquals(2, copy.nrWorkflowHops());
+    WorkflowHopMeta copy12 = copy.getWorkflowHop(0);
+    assertTrue(copy12.isEvaluation());
+    assertFalse(copy12.isUnconditional());
+    assertEquals(copy1, copy12.getFrom());
+    assertEquals(copy2, copy12.getTo());
+
+    WorkflowHopMeta copy23 = copy.getWorkflowHop(1);
+    assertFalse(copy23.isEvaluation());
+    assertTrue(copy23.isUnconditional());
+    assertEquals(copy2, copy23.getFrom());
+    assertEquals(copy3, copy23.getTo());
+  }
 }
diff --git 
a/engine/src/main/java/org/apache/hop/pipeline/transforms/missing/Missing.java 
b/engine/src/test/java/org/apache/hop/workflow/actions/ActionFake.java
similarity index 52%
copy from 
engine/src/main/java/org/apache/hop/pipeline/transforms/missing/Missing.java
copy to engine/src/test/java/org/apache/hop/workflow/actions/ActionFake.java
index b6522a8c2b..993a55e9f5 100644
--- 
a/engine/src/main/java/org/apache/hop/pipeline/transforms/missing/Missing.java
+++ b/engine/src/test/java/org/apache/hop/workflow/actions/ActionFake.java
@@ -13,35 +13,32 @@
  * 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.pipeline.transforms.missing;
-
-import org.apache.hop.pipeline.transform.BaseTransformMeta;
-
-public class Missing extends BaseTransformMeta<MissingTransform, MissingData> {
-
-  private String transformName;
-  private String missingPluginId;
-
-  public Missing(String transformName, String missingPluginId) {
-    this.transformName = transformName;
-    this.missingPluginId = missingPluginId;
-  }
-
-  public String getTransformName() {
-    return transformName;
-  }
-
-  public void setTransformName(String transformName) {
-    this.transformName = transformName;
-  }
-
-  public String getMissingPluginId() {
-    return missingPluginId;
+package org.apache.hop.workflow.actions;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.hop.core.Result;
+import org.apache.hop.core.annotations.Action;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.metadata.api.HopMetadataProperty;
+import org.apache.hop.workflow.action.ActionBase;
+import org.apache.hop.workflow.action.IAction;
+
+@Action(id = "ActionFake", name = "Fake action")
+@Getter
+@Setter
+public class ActionFake extends ActionBase implements IAction {
+  @HopMetadataProperty private String someProperty;
+
+  public ActionFake() {
+    super("", "", "ActionFake");
   }
 
-  public void setMissingPluginId(String missingPluginId) {
-    this.missingPluginId = missingPluginId;
+  @Override
+  public Result execute(Result prevResult, int nr) throws HopException {
+    return prevResult;
   }
 }
diff --git a/integration-tests/mdi/files/excelwriter-mdi-test.xlsx 
b/integration-tests/mdi/files/excelwriter-mdi-test.xlsx
index ef8f12feb6..89dc9f1333 100644
Binary files a/integration-tests/mdi/files/excelwriter-mdi-test.xlsx and 
b/integration-tests/mdi/files/excelwriter-mdi-test.xlsx differ
diff --git a/plugins/misc/git/pom.xml b/plugins/misc/git/pom.xml
index 7b7a7056b2..00f80f381e 100644
--- a/plugins/misc/git/pom.xml
+++ b/plugins/misc/git/pom.xml
@@ -67,6 +67,18 @@
             <version>4.13.2</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.hop</groupId>
+            <artifactId>hop-action-pipeline</artifactId>
+            <version>2.18.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.hop</groupId>
+            <artifactId>hop-action-workflow</artifactId>
+            <version>2.18.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.apache.hop</groupId>
             <artifactId>hop-transform-calculator</artifactId>
diff --git a/plugins/misc/git/src/test/java/org/apache/hop/git/HopDiffTest.java 
b/plugins/misc/git/src/test/java/org/apache/hop/git/HopDiffTest.java
index 19f757ec16..42d6c0226b 100644
--- a/plugins/misc/git/src/test/java/org/apache/hop/git/HopDiffTest.java
+++ b/plugins/misc/git/src/test/java/org/apache/hop/git/HopDiffTest.java
@@ -32,8 +32,10 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
 import org.apache.hop.core.HopClientEnvironment;
+import org.apache.hop.core.annotations.Action;
 import org.apache.hop.core.annotations.Transform;
 import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.plugins.ActionPluginType;
 import org.apache.hop.core.plugins.PluginRegistry;
 import org.apache.hop.core.plugins.TransformPluginType;
 import org.apache.hop.core.variables.Variables;
@@ -45,6 +47,9 @@ import 
org.apache.hop.pipeline.transforms.checksum.CheckSumMeta;
 import org.apache.hop.pipeline.transforms.csvinput.CsvInputMeta;
 import org.apache.hop.pipeline.transforms.selectvalues.SelectValuesMeta;
 import org.apache.hop.workflow.WorkflowMeta;
+import org.apache.hop.workflow.actions.pipeline.ActionPipeline;
+import org.apache.hop.workflow.actions.start.ActionStart;
+import org.apache.hop.workflow.actions.workflow.ActionWorkflow;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -66,7 +71,14 @@ class HopDiffTest {
     PluginRegistry.getInstance()
         .registerPluginClass(
             CheckSumMeta.class.getName(), TransformPluginType.class, 
Transform.class);
-    // HopEnvironment.init();
+
+    PluginRegistry.getInstance()
+        .registerPluginClass(ActionStart.class.getName(), 
ActionPluginType.class, Action.class);
+    PluginRegistry.getInstance()
+        .registerPluginClass(ActionWorkflow.class.getName(), 
ActionPluginType.class, Action.class);
+    PluginRegistry.getInstance()
+        .registerPluginClass(ActionPipeline.class.getName(), 
ActionPluginType.class, Action.class);
+
     metadataProvider = new MemoryMetadataProvider();
   }
 
diff --git a/plugins/misc/git/src/test/resources/r1.hwf 
b/plugins/misc/git/src/test/resources/r1.hwf
index 86a2af45d0..e90a43da69 100644
--- a/plugins/misc/git/src/test/resources/r1.hwf
+++ b/plugins/misc/git/src/test/resources/r1.hwf
@@ -52,7 +52,7 @@ limitations under the License.
     <action>
       <name>Workflow</name>
       <description />
-      <type>JOB</type>
+      <type>WORKFLOW</type>
       <specification_method>filename</specification_method>
       <job_object_id />
       <filename />
@@ -84,7 +84,7 @@ limitations under the License.
     <action>
       <name>Pipeline</name>
       <description />
-      <type>TRANS</type>
+      <type>PIPELINE</type>
       <specification_method>filename</specification_method>
       <trans_object_id />
       <filename />
diff --git a/plugins/misc/git/src/test/resources/r2.hwf 
b/plugins/misc/git/src/test/resources/r2.hwf
index 4d10bc8a11..16c17c1f80 100644
--- a/plugins/misc/git/src/test/resources/r2.hwf
+++ b/plugins/misc/git/src/test/resources/r2.hwf
@@ -55,7 +55,7 @@ limitations under the License.
     <action>
       <name>Workflow</name>
       <description />
-      <type>JOB</type>
+      <type>WORKFLOW</type>
       <specification_method>filename</specification_method>
       <job_object_id />
       <filename />
@@ -84,7 +84,7 @@ limitations under the License.
     <action>
       <name>Workflow 2</name>
       <description />
-      <type>JOB</type>
+      <type>WORKFLOW</type>
       <specification_method>filename</specification_method>
       <job_object_id />
       <filename />
diff --git 
a/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialog.java 
b/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialog.java
index 184edc288e..b187f8c312 100644
--- a/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialog.java
@@ -54,7 +54,6 @@ import org.eclipse.swt.layout.FormAttachment;
 import org.eclipse.swt.layout.FormData;
 import org.eclipse.swt.layout.FormLayout;
 import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Dialog;
@@ -96,8 +95,6 @@ public class WorkflowDialog extends Dialog {
 
   private Text wExtendedDescription;
 
-  private Combo wWorkflowStatus;
-
   // Workflow version
   private Text wVersion;
 
@@ -313,30 +310,6 @@ public class WorkflowDialog extends Dialog {
     fdExtendedDescription.bottom = new FormAttachment(50, -margin);
     wExtendedDescription.setLayoutData(fdExtendedDescription);
 
-    // Workflow Status
-    Label wlWorkflowStatus = new Label(wWorkflowComp, SWT.RIGHT);
-    wlWorkflowStatus.setText(BaseMessages.getString(PKG, 
"WorkflowDialog.WorkflowStatus.Label"));
-    PropsUi.setLook(wlWorkflowStatus);
-    FormData fdlWorkflowStatus = new FormData();
-    fdlWorkflowStatus.left = new FormAttachment(0, 0);
-    fdlWorkflowStatus.right = new FormAttachment(middle, -margin);
-    fdlWorkflowStatus.top = new FormAttachment(wExtendedDescription, margin);
-    wlWorkflowStatus.setLayoutData(fdlWorkflowStatus);
-    wWorkflowStatus = new Combo(wWorkflowComp, SWT.SINGLE | SWT.READ_ONLY | 
SWT.BORDER);
-    wWorkflowStatus.add(BaseMessages.getString(PKG, 
"WorkflowDialog.Draft_WorkflowStatus.Label"));
-    wWorkflowStatus.add(
-        BaseMessages.getString(PKG, 
"WorkflowDialog.Production_WorkflowStatus.Label"));
-    wWorkflowStatus.add("");
-    // +1: starts at -1
-    wWorkflowStatus.select(-1);
-
-    PropsUi.setLook(wWorkflowStatus);
-    FormData fdWorkflowStatus = new FormData();
-    fdWorkflowStatus.left = new FormAttachment(middle, 0);
-    fdWorkflowStatus.top = new FormAttachment(wExtendedDescription, margin);
-    fdWorkflowStatus.right = new FormAttachment(100, 0);
-    wWorkflowStatus.setLayoutData(fdWorkflowStatus);
-
     // Workflow version:
     Label wlVersion = new Label(wWorkflowComp, SWT.RIGHT);
     wlVersion.setText(BaseMessages.getString(PKG, 
"WorkflowDialog.Version.Label"));
@@ -344,14 +317,14 @@ public class WorkflowDialog extends Dialog {
     FormData fdlVersion = new FormData();
     fdlVersion.left = new FormAttachment(0, 0);
     fdlVersion.right = new FormAttachment(middle, -margin);
-    fdlVersion.top = new FormAttachment(wWorkflowStatus, margin);
+    fdlVersion.top = new FormAttachment(wExtendedDescription, margin);
     wlVersion.setLayoutData(fdlVersion);
     wVersion = new Text(wWorkflowComp, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
     PropsUi.setLook(wVersion);
     wVersion.addModifyListener(lsMod);
     FormData fdVersion = new FormData();
     fdVersion.left = new FormAttachment(middle, 0);
-    fdVersion.top = new FormAttachment(wWorkflowStatus, margin);
+    fdVersion.top = new FormAttachment(wExtendedDescription, margin);
     fdVersion.right = new FormAttachment(100, 0);
     wVersion.setLayoutData(fdVersion);
 
@@ -539,7 +512,7 @@ public class WorkflowDialog extends Dialog {
     shell.dispose();
   }
 
-  /** Copy information from the meta-data input to the dialog fields. */
+  /** Copy information from the metadata input to the dialog fields. */
   public void getData() {
     wWorkflowName.setText(Const.NVL(workflowMeta.getName(), ""));
     
wNameFilenameSync.setSelection(workflowMeta.isNameSynchronizedWithFilename());
@@ -548,7 +521,6 @@ public class WorkflowDialog extends Dialog {
     wDescription.setText(Const.NVL(workflowMeta.getDescription(), ""));
     
wExtendedDescription.setText(Const.NVL(workflowMeta.getExtendedDescription(), 
""));
     wVersion.setText(Const.NVL(workflowMeta.getWorkflowVersion(), ""));
-    wWorkflowStatus.select(workflowMeta.getWorkflowStatus() - 1);
 
     if (workflowMeta.getCreatedUser() != null) {
       wCreateUser.setText(workflowMeta.getCreatedUser());
@@ -609,13 +581,6 @@ public class WorkflowDialog extends Dialog {
     workflowMeta.setDescription(wDescription.getText());
     workflowMeta.setExtendedDescription(wExtendedDescription.getText());
     workflowMeta.setWorkflowVersion(wVersion.getText());
-    if (wWorkflowStatus.getSelectionIndex() != 2) {
-      // Saving the index as meta data is in fact pretty bad, but since
-      // it was already in ...
-      workflowMeta.setWorkflowStatus(wWorkflowStatus.getSelectionIndex() + 1);
-    } else {
-      workflowMeta.setWorkflowStatus(-1);
-    }
 
     // Clear and add parameters
     workflowMeta.removeAllParameters();

Reply via email to