From 4190ad19f422bfd342a26ae07b675ce1e877a77c Mon Sep 17 00:00:00 2001
From: Ralph Soika <ralph.soika@imixs.com>
Date: Sat, 18 Feb 2023 16:34:09 +0100
Subject: [PATCH] refactoring

Issue #183
---
 .../AbstractBPMNElementExtension.java         |  50 ++-
 .../ConditionalEventDefinitionExtension.java  | 179 ++++++++
 .../DefaultBPMNDataObjectExtension.java       |  41 +-
 .../DefaultBPMNDefinitionsExtension.java      |  73 ++--
 .../extension/DefaultBPMNEdgeExtension.java   |  34 +-
 .../extension/DefaultBPMNEventExtension.java  | 398 ++----------------
 .../DefaultBPMNGatewayExtension.java          |  51 +--
 .../DefaultBPMNMessageExtension.java          |  41 +-
 .../DefaultBPMNParticipantExtension.java      | 104 ++---
 .../DefaultBPMNSequenceFlowExtension.java     |   5 +-
 .../extension/DefaultBPMNTaskExtension.java   |  48 +--
 .../DefaultBPMNTextAnnotationExtension.java   |  49 +--
 .../LinkEventDefinitionExtension.java         | 143 +++++++
 .../SignalEventDefinitionExtension.java       | 187 ++++++++
 .../TimerEventDefinitionExtension.java        |  75 +---
 .../org/openbpmn/glsp/BPMNDiagramModule.java  |   6 +
 .../glsp/model/BPMNGModelFactory.java         |  11 +-
 .../bpmn/elements/core/BPMNElement.java       |  12 +-
 18 files changed, 753 insertions(+), 754 deletions(-)
 create mode 100644 open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/ConditionalEventDefinitionExtension.java
 create mode 100644 open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/LinkEventDefinitionExtension.java
 create mode 100644 open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/SignalEventDefinitionExtension.java

diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/AbstractBPMNElementExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/AbstractBPMNElementExtension.java
index f5ce0d39..a456a911 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/AbstractBPMNElementExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/AbstractBPMNElementExtension.java
@@ -15,8 +15,21 @@
  ********************************************************************************/
 package org.openbpmn.extension;
 
+import java.util.Optional;
+
+import javax.json.JsonObject;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.eclipse.glsp.graph.GModelElement;
+import org.eclipse.glsp.graph.GNode;
 import org.openbpmn.bpmn.BPMNNS;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
+import org.openbpmn.glsp.bpmn.LabelGNode;
+import org.openbpmn.glsp.model.BPMNGModelState;
+import org.openbpmn.glsp.utils.BPMNGraphUtil;
+
+import com.google.inject.Inject;
 
 /**
  * This is Abstract implementation provides some core funtionallity like update
@@ -28,6 +41,15 @@
  */
 abstract class AbstractBPMNElementExtension implements BPMNExtension {
 
+    private static Logger logger = LogManager.getLogger(AbstractBPMNElementExtension.class);
+
+    @Inject
+    protected BPMNGModelState modelState;
+
+    public BPMNGModelState getModelState() {
+        return modelState;
+    }
+
     /**
      * Returns the Extension label to be used in the Tool Palette. The default name
      * is the namespace. Implementations should overwrite this method.
@@ -61,7 +83,33 @@ public String getNamespaceURI() {
 
     @Override
     public int getPriority() {
-        return 999999;
+        return 1;
+    }
+
+    /**
+     * This method updates the name attribute of a BPMNElement and also the
+     * corresponding GNode Element in the diagram plane.
+     * 
+     * @param json
+     * @param bpmnElement
+     * @param gNodeElement
+     */
+    public void updateNameProperty(final JsonObject json, BPMNElement bpmnElement, final GModelElement gNodeElement) {
+        // Update the name feature
+        String name = json.getString("name", "");
+        if (!name.equals(bpmnElement.getName())) {
+            bpmnElement.setName(name);
+            // Update Label...
+            Optional<GModelElement> label = modelState.getIndex().get(gNodeElement.getId() + "_bpmnlabel");
+            if (!label.isEmpty()) {
+                LabelGNode lgn = (LabelGNode) label.get();
+                // update the bpmn-text-node of the GNodeElement
+                GNode gnode = BPMNGraphUtil.findMultiLineTextNode(lgn);
+                if (gnode != null) {
+                    gnode.getArgs().put("text", name);
+                }
+            }
+        }
     }
 
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/ConditionalEventDefinitionExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/ConditionalEventDefinitionExtension.java
new file mode 100644
index 00000000..a2562e73
--- /dev/null
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/ConditionalEventDefinitionExtension.java
@@ -0,0 +1,179 @@
+/********************************************************************************
+ * Copyright (c) 2022 Imixs Software Solutions GmbH and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
+ * with the GNU Classpath Exception which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ ********************************************************************************/
+package org.openbpmn.extension;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.eclipse.glsp.graph.GModelElement;
+import org.openbpmn.bpmn.BPMNTypes;
+import org.openbpmn.bpmn.elements.Event;
+import org.openbpmn.bpmn.elements.core.BPMNElement;
+import org.openbpmn.glsp.jsonforms.DataBuilder;
+import org.openbpmn.glsp.jsonforms.SchemaBuilder;
+import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
+import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
+import org.w3c.dom.Element;
+
+/**
+ * The TimerEventDefinitionExtension is responsible to read and update optional
+ * TimerEventDefinitions from the BPMN model. The Extension builds a custom
+ * property section named 'Timers' shown a list of all TimerEventDefinitions
+ * define in a Event.
+ * 
+ * @author rsoika
+ */
+public class ConditionalEventDefinitionExtension extends DefaultBPMNEventExtension {
+
+    private static Logger logger = LogManager.getLogger(DefaultBPMNSequenceFlowExtension.class);
+
+    @Override
+    public int getPriority() {
+        return 101;
+    }
+
+    /**
+     * Returns if this Extension can be applied to the given elementTypeID
+     */
+    @Override
+    public boolean handlesElementTypeId(final String elementTypeId) {
+        return BPMNTypes.BPMN_EVENTS.contains(elementTypeId);
+    }
+
+    /**
+     * This Helper Method generates a JSON Object with the BPMNElement properties.
+     * <p>
+     * This json object is used on the GLSP Client to generate the EMF JsonForms
+     */
+    @Override
+    public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder dataBuilder,
+            final SchemaBuilder schemaBuilder, final UISchemaBuilder uiSchemaBuilder) {
+
+        Event event = (Event) bpmnElement;
+
+        // Conditional
+
+        Set<Element> conditionalEventDefinition = event.getEventDefinitionsByType("conditionalEventDefinition");
+
+        if (conditionalEventDefinition.size() > 0) {
+
+            JsonObject multilineOption = Json.createObjectBuilder() //
+                    .add("multi", true).build();
+
+            uiSchemaBuilder. //
+                    addCategory("Conditions"). //
+                    addLayout(Layout.VERTICAL);
+
+            // create a detail control Layout....
+            JsonArrayBuilder controlsArrayBuilder = Json.createArrayBuilder();
+            controlsArrayBuilder //
+                    .add(Json.createObjectBuilder() //
+                            .add("type", "Control") //
+                            .add("scope", "#/properties/language"))//
+                    .add(Json.createObjectBuilder() //
+                            .add("type", "Control") //
+                            .add("scope", "#/properties/expression") //
+                            .add("label", "Expression") //
+                            .add("options", multilineOption) //
+                    );
+
+            JsonObjectBuilder detailLayoutBuilder = Json.createObjectBuilder(). //
+                    add("type", "VerticalLayout"). ///
+                    add("elements", controlsArrayBuilder);
+
+            JsonObjectBuilder detailBuilder = Json.createObjectBuilder(). //
+                    add("detail", detailLayoutBuilder.build());
+            uiSchemaBuilder.addDetailLayout("conditions", "Conditions", detailBuilder.build());
+
+            /*
+             * Add the Schema ....
+             */
+            schemaBuilder.addArray("conditions");
+            schemaBuilder.addProperty("language", "string", null, null);
+            schemaBuilder.addProperty("expression", "string", null, null);
+
+            /*
+             * Now we can create the data structure - each conditionalEventDefinition is
+             * represented as a separate object
+             */
+            dataBuilder.addArray("conditions");
+            for (Element definition : conditionalEventDefinition) {
+                dataBuilder.addObject();
+                dataBuilder.addData("language", definition.getAttribute("language"));
+                dataBuilder.addData("expression", definition.getAttribute("expression"));
+            }
+
+        }
+    }
+
+    /**
+     * Update the timers definitions
+     * 
+     * This method updates all timerEventDefinitions. The method expects a
+     * dataList containing all timer definitions with its values.
+     * The method simply overwrites all timerEventDefinitions.
+     * <p>
+     * Example:
+     * 
+     * <pre>
+     * {@code
+     *  <bpmn2:startEvent id="event_n8bj0g" name="Event-1">
+     *    <bpmn2:documentation id="documentation_4XhEKA"/>
+     *     <bpmn2:timerEventDefinition id="timerEventDefinition_hElKhw">
+     *      <bpmn2:timeDuration id="FormalExpression_0" xsi:type=
+    "bpmn2:tFormalExpression">3cc</bpmn2:timeDuration>
+     *       </bpmn2:timerEventDefinition>
+     *   </bpmn2:startEvent>
+     * }
+    * </pre>
+     */
+    @Override
+    public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
+            final GModelElement gNodeElement) {
+        Event bpmnEvent = (Event) bpmnElement;
+        JsonArray dataList = json.getJsonArray("conditions");
+
+        // synchronize the definition list of the event element
+        Set<Element> conditionalEventDefinitions = synchronizeEventDefinitions("conditionalEventDefinition", bpmnEvent,
+                dataList);
+
+        // now we can update the values one by one
+        // NOTE: the id can change within the definitionList if an element was deleted
+        // or moved!
+        // but we do not care about this issue.
+        Iterator<Element> iter = conditionalEventDefinitions.iterator();
+        int i = 0;
+        while (iter.hasNext()) {
+            Element eventDefinitionElement = iter.next();
+            JsonObject jsonData = dataList.getJsonObject(i); // .get(i);
+            if (jsonData != null) {
+                eventDefinitionElement.setAttribute("language", jsonData.getString("language", ""));
+                eventDefinitionElement.setAttribute("expression", jsonData.getString("expression", ""));
+            }
+            i++;
+            // update completed
+        }
+
+    }
+}
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDataObjectExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDataObjectExtension.java
index 7407ae1d..03d63707 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDataObjectExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDataObjectExtension.java
@@ -17,24 +17,18 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
 
 import javax.json.JsonObject;
 
 import org.eclipse.glsp.graph.GModelElement;
-import org.eclipse.glsp.graph.GNode;
 import org.openbpmn.bpmn.BPMNTypes;
 import org.openbpmn.bpmn.elements.DataObject;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
-import org.openbpmn.bpmn.elements.core.BPMNElementNode;
-import org.openbpmn.glsp.bpmn.LabelGNode;
 import org.openbpmn.glsp.jsonforms.DataBuilder;
 import org.openbpmn.glsp.jsonforms.SchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
 import org.openbpmn.glsp.model.BPMNGModelState;
-import org.openbpmn.glsp.utils.BPMNGraphUtil;
 
 import com.google.inject.Inject;
 
@@ -94,37 +88,14 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
 
     }
 
+    /**
+     * Update the DataObject properties
+     */
     @Override
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
-
-        // default update of name and documentation
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-
-            if ("name".equals(feature)) {
-                String text = json.getString(feature);
-                bpmnElement.setName(text);
-                // Update GModelElement Label...
-                Optional<GModelElement> label = modelState.getIndex().get(gNodeElement.getId() + "_bpmnlabel");
-                if (!label.isEmpty()) {
-                    LabelGNode lgn = (LabelGNode) label.get();
-                    // update the bpmn-text-node of the GNodeElement
-                    GNode gnode = BPMNGraphUtil.findMultiLineTextNode(lgn);
-                    if (gnode != null) {
-                        gnode.getArgs().put("text", text);
-                    }
-                    continue;
-                }
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                ((BPMNElementNode) bpmnElement).setDocumentation(json.getString(feature));
-                continue;
-            }
-
-        }
-
+        updateNameProperty(json, bpmnElement, gNodeElement);
+        // update attributes and tags
+        bpmnElement.setDocumentation(json.getString("documentation"));
     }
-
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDefinitionsExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDefinitionsExtension.java
index c177e837..38003b7e 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDefinitionsExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNDefinitionsExtension.java
@@ -17,7 +17,6 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 
 import javax.json.Json;
 import javax.json.JsonArray;
@@ -122,57 +121,37 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
 
     }
 
+    /**
+     * Updates the BPMN Diagram definition properties
+     */
     @Override
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
         Element definitions = modelState.getBpmnModel().getDefinitions();
-        // check custom features
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-            if ("name".equals(feature)) {
-                bpmnElement.setName(json.getString(feature));
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                bpmnElement.setDocumentation(json.getString(feature));
-                continue;
-            }
-            if ("targetNamespace".equals(feature)) {
-                definitions.setAttribute(feature, json.getString(feature));
-                continue;
-            }
-            if ("exporter".equals(feature)) {
-                definitions.setAttribute(feature, json.getString(feature));
-                continue;
-            }
-            if ("exporterVersion".equals(feature)) {
-                definitions.setAttribute(feature, json.getString(feature));
-                continue;
-            }
 
-            // Signals...
-            if ("signals".equals(feature)) {
-                logger.debug("...update feature = " + feature);
-                JsonArray signalSetValues = json.getJsonArray(feature);
-                for (JsonValue laneValue : signalSetValues) {
-                    // update signal properties
-                    JsonObject signalData = (JsonObject) laneValue;
-
-                    String id = signalData.getString("id", null);
-                    Signal signal = (Signal) modelState.getBpmnModel().findElementById(id);
-                    if (signal != null) {
-                        signal.setName(signalData.getString("name"));
-                    } else {
-                        // signal did not yet exist in definition list - so we create a new one
-                        int i = modelState.getBpmnModel().getSignals().size() + 1;
-                        try {
-                            modelState.getBpmnModel().addSignal("signal_" + i, "Signal " + i);
-                            modelState.reset();
-                        } catch (BPMNModelException e) {
-                            logger.warn("Unable to add new signal: " + e.getMessage());
-                        }
-
-                    }
+        bpmnElement.setName(json.getString("name"));
+        bpmnElement.setDocumentation(json.getString("documentation"));
+        definitions.setAttribute("targetNamespace", json.getString("targetNamespace"));
+        definitions.setAttribute("exporter", json.getString("exporter"));
+        definitions.setAttribute("exporterVersion", json.getString("exporterVersion"));
+
+        // update signal properties...
+        logger.debug("...update signals.. ");
+        JsonArray signalSetValues = json.getJsonArray("signals");
+        for (JsonValue laneValue : signalSetValues) {
+            JsonObject signalData = (JsonObject) laneValue;
+            String id = signalData.getString("id", null);
+            Signal signal = (Signal) modelState.getBpmnModel().findElementById(id);
+            if (signal != null) {
+                signal.setName(signalData.getString("name"));
+            } else {
+                // signal did not yet exist in definition list - so we create a new one
+                int i = modelState.getBpmnModel().getSignals().size() + 1;
+                try {
+                    modelState.getBpmnModel().addSignal("signal_" + i, "Signal " + i);
+                    modelState.reset();
+                } catch (BPMNModelException e) {
+                    logger.warn("Unable to add new signal: " + e.getMessage());
                 }
             }
         }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEdgeExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEdgeExtension.java
index 89a4345f..deb6b81f 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEdgeExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEdgeExtension.java
@@ -17,14 +17,11 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
 
 import javax.json.JsonObject;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.eclipse.glsp.graph.GLabel;
 import org.eclipse.glsp.graph.GModelElement;
 import org.openbpmn.bpmn.BPMNTypes;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
@@ -101,35 +98,14 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
     }
 
     /**
-     * This Helper Method updates the BPMNElement data properties.
-     * <p>
+     * Update the default edge properties.
+     *
      */
     @Override
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
-
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-
-            if ("name".equals(feature)) {
-                bpmnElement.setName(json.getString(feature));
-                // Update Label...
-                Optional<GModelElement> label = modelState.getIndex().get(gNodeElement.getId() + "_bpmnlabel");
-                if (!label.isEmpty()) {
-                    GLabel glabel = (GLabel) label.get();
-                    if (glabel != null) {
-                        glabel.setText(json.getString(feature));
-                    }
-                }
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                bpmnElement.setDocumentation(json.getString(feature));
-                continue;
-            }
-
-        }
-
+        updateNameProperty(json, bpmnElement, gNodeElement);
+        // update attributes and tags
+        bpmnElement.setDocumentation(json.getString("documentation"));
     }
-
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEventExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEventExtension.java
index 9600a8a3..6aff942a 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEventExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNEventExtension.java
@@ -16,38 +16,24 @@
 package org.openbpmn.extension;
 
 import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Collectors;
 
-import javax.json.Json;
 import javax.json.JsonArray;
-import javax.json.JsonArrayBuilder;
 import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.eclipse.glsp.graph.GModelElement;
-import org.eclipse.glsp.graph.GNode;
 import org.openbpmn.bpmn.BPMNTypes;
 import org.openbpmn.bpmn.elements.Event;
-import org.openbpmn.bpmn.elements.Signal;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
-import org.openbpmn.bpmn.exceptions.BPMNInvalidReferenceException;
-import org.openbpmn.bpmn.exceptions.BPMNInvalidTypeException;
-import org.openbpmn.bpmn.exceptions.BPMNMissingElementException;
 import org.openbpmn.bpmn.exceptions.BPMNModelException;
-import org.openbpmn.glsp.bpmn.LabelGNode;
 import org.openbpmn.glsp.jsonforms.DataBuilder;
 import org.openbpmn.glsp.jsonforms.SchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
 import org.openbpmn.glsp.model.BPMNGModelState;
-import org.openbpmn.glsp.utils.BPMNGraphUtil;
 import org.w3c.dom.Element;
 
 import com.google.inject.Inject;
@@ -59,8 +45,7 @@
  *
  */
 public class DefaultBPMNEventExtension extends AbstractBPMNElementExtension {
-
-    private static Logger logger = LogManager.getLogger(DefaultBPMNEventExtension.class);
+    private static Logger logger = LogManager.getLogger(DefaultBPMNTaskExtension.class);
 
     @Inject
     protected BPMNGModelState modelState;
@@ -107,8 +92,6 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
                 addProperty("name", "string", null). //
                 addProperty("documentation", "string", null);
 
-        Event bpmnEvent = (Event) bpmnElement;
-
         Map<String, String> multilineOption = new HashMap<>();
         multilineOption.put("multi", "true");
         Map<String, String> radioOption = new HashMap<>();
@@ -120,22 +103,6 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
                 addElements("name"). //
                 addElement("documentation", "Documentation", multilineOption);
 
-        Set<Element> eventDefinitions = bpmnEvent.getEventDefinitions();
-        // Conditional
-        List<Element> conditionalEventDefinitions = eventDefinitions.stream()
-                .filter(c -> "conditionalEventDefinition".equals(c.getLocalName())).collect(Collectors.toList());
-        addConditionalEventDefinitions(conditionalEventDefinitions, dataBuilder, schemaBuilder, uiSchemaBuilder);
-
-        // Signal
-        List<Element> signalEventDefinitions = eventDefinitions.stream()
-                .filter(c -> "signalEventDefinition".equals(c.getLocalName())).collect(Collectors.toList());
-        addSignalEventDefinitions(signalEventDefinitions, dataBuilder, schemaBuilder, uiSchemaBuilder);
-
-        // Link
-        List<Element> linkEventDefinitions = eventDefinitions.stream()
-                .filter(c -> "linkEventDefinition".equals(c.getLocalName())).collect(Collectors.toList());
-        addLinkEventDefinitions(linkEventDefinitions, dataBuilder, schemaBuilder, uiSchemaBuilder);
-
     }
 
     /**
@@ -147,355 +114,56 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
 
-        Event bpmnEvent = (Event) bpmnElement;
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-
-            if ("name".equals(feature)) {
-                String text = json.getString(feature);
-                bpmnElement.setName(text);
-                // Update Label...
-                Optional<GModelElement> label = modelState.getIndex().get(gNodeElement.getId() + "_bpmnlabel");
-                if (!label.isEmpty()) {
-                    LabelGNode lgn = (LabelGNode) label.get();
-                    // update the bpmn-text-node of the GNodeElement
-                    GNode gnode = BPMNGraphUtil.findMultiLineTextNode(lgn);
-                    if (gnode != null) {
-                        gnode.getArgs().put("text", text);
-                    }
-                    continue;
-                }
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                bpmnElement.setDocumentation(json.getString(feature));
-                continue;
-            }
-
-            // Update eventDefinitions for each definition type...
-            Set<Element> eventDefinitions = bpmnEvent.getEventDefinitions();
-            if ("signals".equals(feature)) {
-                JsonArray signalDataList = json.getJsonArray("signals");
-                updateSignalEventDefinitions(bpmnEvent, signalDataList);
-            }
-            if ("conditions".equals(feature)) {
-                JsonArray conditionsDataList = json.getJsonArray("conditions");
-                updateConditionalEventDefinitions(bpmnEvent, conditionsDataList);
-            }
-            if ("links".equals(feature)) {
-                JsonArray signalDataList = json.getJsonArray("links");
-                // find all Signal definitions of this event
-                List<Element> conditionalEventDefinitions = eventDefinitions.stream()
-                        .filter(c -> "linkEventDefinition".equals(c.getLocalName())).collect(Collectors.toList());
-                updateLinkEventDefinitions(conditionalEventDefinitions, signalDataList);
-            }
-        }
-
-    }
-
-    /*
-     * This method updates the signalEventDefinitions. The method expects a
-     * dataList containing all conditions with its values (including the id).
-     * The method simply overwrites all csignalEventDefinitions.
-     * 
-     * @See addSignalEventDefinitions how we map between the signal name and its id.
-     */
-    private void updateSignalEventDefinitions(final Event bpmnEvent, final JsonArray dataList) {
-
-        // find all conditionalEventDefinitions for this event
-        Set<Element> signalEventDefinitions = bpmnEvent.getEventDefinitionsByType("signalEventDefinition");
-        // If the size of the conditionalDataList is not equals the size of the
-        // DefinitionList we add or remove conditions...
-        while (signalEventDefinitions.size() != dataList.size()) {
-            try {
-                if (signalEventDefinitions.size() < dataList.size()) {
-                    // add a new empty condition placeholder...
-                    bpmnEvent.addEventDefinition("signalEventDefinition");
-                }
-                if (signalEventDefinitions.size() > dataList.size()) {
-                    // delete first condition from the list
-                    Element definition = signalEventDefinitions.iterator().next();
-                    String id = definition.getAttribute("id");
-                    bpmnEvent.deleteEventDefinition(id);
-                }
-            } catch (BPMNModelException e) {
-                logger.error("Failed to update BPMN Event Definition list: " + e.getMessage());
-                e.printStackTrace();
-            }
-            // Update event definition list
-            signalEventDefinitions = bpmnEvent.getEventDefinitionsByType("signalEventDefinition");
-        }
-
-        // now we can update the values one by referring to the signalRef id by
-        // comparing the name
-        Iterator<Element> iter = signalEventDefinitions.iterator();
-        int i = 0;
-        while (iter.hasNext()) {
-            Element eventDefinitionElement = iter.next();
-            JsonObject jsonData = dataList.getJsonObject(i); // .get(i);
-            if (jsonData != null) {
-
-                String signalName = "";
-
-                try {
-                    signalName = jsonData.getString("signal");
-                } catch (NullPointerException en) {
-                    // no name defined!
-                }
-                logger.debug("signal=" + signalName);
-                try {
-                    // fetch the signal from teh Model Signal list by name...
-                    Signal signal = modelState.getBpmnModel().findSignalByName(signalName);
-                    if (signal != null) {
-                        eventDefinitionElement.setAttribute("signalRef", signal.getId());
-                    } else {
-                        // no signal defintion found - delete signalRef...
-                        eventDefinitionElement.setAttribute("signalRef", "");
-                    }
-                } catch (BPMNInvalidReferenceException | BPMNMissingElementException | BPMNInvalidTypeException e) {
-                    e.printStackTrace();
-                }
-            }
-            i++;
-            // update completed
-        }
+        updateNameProperty(json, bpmnElement, gNodeElement);
+        // update attributes and tags
+        bpmnElement.setDocumentation(json.getString("documentation"));
 
     }
 
     /**
-     * This method updates the conditionalEventDefinitions. The method expects a
-     * dataList containing all conditions with its values (including the id).
-     * The method simpl overwrites all conditionalEventDefinitions.
+     * This helper method verifies if the count of definitions matches the given
+     * size of a dataList containing definition data and updates the elements
+     * definition list.
+     * The method returns an updated list of definition elements
      * 
+     * @param definitionName
      * @param bpmnEvent
      * @param dataList
+     * @return - updated list of definition elements
      */
-    private void updateConditionalEventDefinitions(final Event bpmnEvent, final JsonArray dataList) {
-        // find all conditionalEventDefinitions for this event
-        Set<Element> conditionalEventDefinitions = bpmnEvent.getEventDefinitionsByType("conditionalEventDefinition");
-        // If the size of the conditionalDataList is not equals the size of the
-        // DefinitionList we add or remove conditions...
-        while (conditionalEventDefinitions.size() != dataList.size()) {
+    Set<Element> synchronizeEventDefinitions(final String definitionName, final Event bpmnEvent,
+            final JsonArray dataList) {
+
+        // find all named eventDefinitions for this event
+        Set<Element> eventDefinitions = bpmnEvent.getEventDefinitionsByType(definitionName);
+
+        if (dataList == null && eventDefinitions.size() == 0) {
+            // no update needed at all
+            return eventDefinitions;
+        }
+        // If the size of the eventDefinition List is not equals the size of the
+        // dataList we add or remove eventDefinitions...
+        while ((dataList == null && eventDefinitions.size() > 0)
+                || (eventDefinitions.size() != dataList.size())) {
             try {
-                if (conditionalEventDefinitions.size() < dataList.size()) {
-                    // add a new empty condition placeholder...
-                    bpmnEvent.addEventDefinition("conditionalEventDefinition");
-                }
-                if (conditionalEventDefinitions.size() > dataList.size()) {
+                if ((dataList == null && eventDefinitions.size() > 0)
+                        || eventDefinitions.size() > dataList.size()) {
                     // delete first condition from the list
-                    Element definition = conditionalEventDefinitions.iterator().next();
+                    Element definition = eventDefinitions.iterator().next();
                     String id = definition.getAttribute("id");
                     bpmnEvent.deleteEventDefinition(id);
+                } else if (eventDefinitions.size() < dataList.size()) {
+                    // add a new empty condition placeholder...
+                    bpmnEvent.addEventDefinition(definitionName);
                 }
+
             } catch (BPMNModelException e) {
                 logger.error("Failed to update BPMN Event Definition list: " + e.getMessage());
                 e.printStackTrace();
             }
             // Update event definition list
-            conditionalEventDefinitions = bpmnEvent.getEventDefinitionsByType("conditionalEventDefinition");
-        }
-        // now we can update the values one by one
-        // NOTE: the id can change within the definitionList if an element was deleted
-        // or moved!
-        // but we do not care about this issue.
-        Iterator<Element> iter = conditionalEventDefinitions.iterator();
-        int i = 0;
-        while (iter.hasNext()) {
-            Element eventDefinitionElement = iter.next();
-            JsonObject jsonData = dataList.getJsonObject(i); // .get(i);
-            if (jsonData != null) {
-                eventDefinitionElement.setAttribute("language", jsonData.getString("language", ""));
-                eventDefinitionElement.setAttribute("expression", jsonData.getString("expression", ""));
-            }
-            i++;
-            // update completed
+            eventDefinitions = bpmnEvent.getEventDefinitionsByType(definitionName);
         }
+        return eventDefinitions;
     }
-
-    private void updateLinkEventDefinitions(final List<Element> eventDefinitions, final JsonArray dataList) {
-        // If the size of the conditionalDataList is not equals the size of the known
-        // eventConditionalDefinitions we print a warning
-        if (eventDefinitions.size() != dataList.size()) {
-            logger.warn("dataList does not match the EventDefinition list!");
-        }
-        // just update the values one by one by referring to the signalRef id by
-        // comparing the name
-        for (int i = 0; i < eventDefinitions.size(); i++) {
-            Element eventDefinitionElement = eventDefinitions.get(i);
-            JsonObject jsonData = dataList.getJsonObject(i); // .get(i);
-            if (jsonData != null) {
-                eventDefinitionElement.setAttribute("name", jsonData.getString("name", ""));
-                eventDefinitionElement.setAttribute("target", jsonData.getString("target", ""));
-            }
-            // update completed
-        }
-    }
-
-    /**
-     * Adds the ConditionalEvent definitions. Here we use a detail-control layout to
-     * have more flexibility designing the widgets.
-     *
-     * @param eventDefinitions
-     * @param dataBuilder
-     * @param schemaBuilder
-     * @param uiSchemaBuilder
-     */
-    private void addConditionalEventDefinitions(final List<Element> eventDefinitions, final DataBuilder dataBuilder,
-            final SchemaBuilder schemaBuilder, final UISchemaBuilder uiSchemaBuilder) {
-        if (eventDefinitions.size() > 0) {
-
-            JsonObject multilineOption = Json.createObjectBuilder() //
-                    .add("multi", true).build();
-
-            uiSchemaBuilder. //
-                    addCategory("Conditions"). //
-                    addLayout(Layout.VERTICAL);
-
-            // create a detail control Layout....
-            JsonArrayBuilder controlsArrayBuilder = Json.createArrayBuilder();
-            controlsArrayBuilder //
-                    .add(Json.createObjectBuilder() //
-                            .add("type", "Control") //
-                            .add("scope", "#/properties/language"))//
-                    .add(Json.createObjectBuilder() //
-                            .add("type", "Control") //
-                            .add("scope", "#/properties/expression") //
-                            .add("label", "Expression") //
-                            .add("options", multilineOption) //
-                    );
-
-            JsonObjectBuilder detailLayoutBuilder = Json.createObjectBuilder(). //
-                    add("type", "VerticalLayout"). ///
-                    add("elements", controlsArrayBuilder);
-
-            JsonObjectBuilder detailBuilder = Json.createObjectBuilder(). //
-                    add("detail", detailLayoutBuilder.build());
-            uiSchemaBuilder.addDetailLayout("conditions", "Conditions", detailBuilder.build());
-
-            /*
-             * Add the Schema ....
-             */
-            schemaBuilder.addArray("conditions");
-            schemaBuilder.addProperty("language", "string", null, null);
-            schemaBuilder.addProperty("expression", "string", null, null);
-
-            /*
-             * Now we can create the data structure - each conditionalEventDefinition is
-             * represented as a separate object
-             */
-            dataBuilder.addArray("conditions");
-            for (Element definition : eventDefinitions) {
-                dataBuilder.addObject();
-                dataBuilder.addData("language", definition.getAttribute("language"));
-                dataBuilder.addData("expression", definition.getAttribute("expression"));
-            }
-        }
-    }
-
-    /**
-     * Adds the SignalEvent definitions
-     * <p>
-     * Note: Internally we need a mapping between the Signal name (Label) and the
-     * Signal id (value). As
-     * discussed here
-     * (https://jsonforms.discourse.group/t/how-to-separate-value-and-label-in-a-combobox/1200)
-     * we do not have this feature yet. Currently the efforts seems to be to high to
-     * implement a new
-     * renderer for JsonForms.
-     *
-     * @param eventDefinitions
-     * @param dataBuilder
-     * @param schemaBuilder
-     * @param uiSchemaBuilder
-     */
-    private void addSignalEventDefinitions(final List<Element> eventDefinitions, final DataBuilder dataBuilder,
-            final SchemaBuilder schemaBuilder, final UISchemaBuilder uiSchemaBuilder) {
-        if (eventDefinitions.size() > 0) {
-            Map<String, String> arrayDetailOption = new HashMap<>();
-            // GENERATED HorizontalLayout
-            arrayDetailOption.put("detail", "GENERATED");
-
-            uiSchemaBuilder. //
-                    addCategory("Signals"). //
-                    addLayout(Layout.VERTICAL);
-            uiSchemaBuilder.addElement("signals", "Signals", arrayDetailOption);
-            // uiSchemaBuilder.addElement("formalExpression", "Script", multilineOption);
-
-            schemaBuilder.addArray("signals");
-
-            // find all signals in the current model and build an array...
-            Set<Signal> bpmnSignals = modelState.getBpmnModel().getSignals();
-            String[] signalOptions = new String[bpmnSignals.size()];
-            int i = 0;
-            for (Signal bpmnSignal : bpmnSignals) {
-                signalOptions[i] = bpmnSignal.getName();
-                i++;
-                // signalOptions[i] = bpmnSignal.getId() + "|" + bpmnSignal.getName();
-            }
-            schemaBuilder.addProperty("signal", "string", null, signalOptions);
-            // schemaBuilder.addPropertyOneOf("signal", "string", null, signalOptions);
-
-            /*
-             * Now we can create the data structure - each signalEventDefinition is
-             * represented as a separate object. We resolve the signalRef
-             */
-            dataBuilder.addArray("signals");
-            for (Element definition : eventDefinitions) {
-                dataBuilder.addObject();
-                String signalRefID = definition.getAttribute("signalRef");
-                // fetch the corresponding Signal
-                Signal bpmnSignal = (Signal) modelState.getBpmnModel().findElementById(signalRefID);
-                if (bpmnSignal != null) {
-                    dataBuilder.addData("signal", bpmnSignal.getName());
-                } else {
-                    logger.warn("invalid signalRefID found: " + signalRefID);
-                }
-
-            }
-        }
-
-    }
-
-    /**
-     * Adds the LinkEvent definitions.
-     * <p>
-     * This is a simple detail section without custom layout. So we use
-     * detail=GERNERATED here.
-     *
-     * @param eventDefinitions
-     * @param dataBuilder
-     * @param schemaBuilder
-     * @param uiSchemaBuilder
-     */
-    private void addLinkEventDefinitions(final List<Element> eventDefinitions, final DataBuilder dataBuilder,
-            final SchemaBuilder schemaBuilder, final UISchemaBuilder uiSchemaBuilder) {
-        if (eventDefinitions.size() > 0) {
-            Map<String, String> arrayDetailOption = new HashMap<>();
-            // GENERATED HorizontalLayout
-            arrayDetailOption.put("detail", "GENERATED");
-
-            uiSchemaBuilder. //
-                    addCategory("Link"). //
-                    addLayout(Layout.VERTICAL);
-            uiSchemaBuilder.addElement("links", "Links", arrayDetailOption);
-
-            schemaBuilder.addArray("links");
-            schemaBuilder.addProperty("name", "string", null, null);
-            schemaBuilder.addProperty("target", "string", null, null);
-
-            /*
-             * Now we can create the data structure - each conditionalEventDefinition is
-             * represented as a separate object
-             */
-            dataBuilder.addArray("links");
-            logger.warn(" addLinkEventDefinitions not yet implemented");
-            for (Element definition : eventDefinitions) {
-                dataBuilder.addObject();
-                dataBuilder.addData("name", definition.getAttribute("name"));
-                dataBuilder.addData("target", definition.getAttribute("target"));
-            }
-        }
-
-    }
-
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNGatewayExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNGatewayExtension.java
index 24d28b8d..b7c1110b 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNGatewayExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNGatewayExtension.java
@@ -17,26 +17,18 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
 import java.util.logging.Logger;
 
 import javax.json.JsonObject;
 
 import org.eclipse.glsp.graph.GModelElement;
-import org.eclipse.glsp.graph.GNode;
 import org.openbpmn.bpmn.BPMNTypes;
 import org.openbpmn.bpmn.elements.Gateway;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
-import org.openbpmn.glsp.bpmn.LabelGNode;
 import org.openbpmn.glsp.jsonforms.DataBuilder;
 import org.openbpmn.glsp.jsonforms.SchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
-import org.openbpmn.glsp.model.BPMNGModelState;
-import org.openbpmn.glsp.utils.BPMNGraphUtil;
-
-import com.google.inject.Inject;
 
 /**
  * This is the Default BPMNEvent extension providing the JSONForms shemata.
@@ -49,9 +41,6 @@ public class DefaultBPMNGatewayExtension extends AbstractBPMNElementExtension {
     @SuppressWarnings("unused")
     private static Logger logger = Logger.getLogger(DefaultBPMNGatewayExtension.class.getName());
 
-    @Inject
-    protected BPMNGModelState modelState;
-
     public DefaultBPMNGatewayExtension() {
         super();
     }
@@ -106,42 +95,16 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
 
     }
 
+    /**
+     * Update the Gateway Properties
+     */
     @Override
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
 
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-
-            if ("name".equals(feature)) {
-                String text = json.getString(feature);
-                bpmnElement.setName(text);
-                // Update Label...
-                Optional<GModelElement> label = modelState.getIndex().get(gNodeElement.getId() + "_bpmnlabel");
-                if (!label.isEmpty()) {
-                    LabelGNode lgn = (LabelGNode) label.get();
-                    // update the bpmn-text-node of the GNodeElement
-                    GNode gnode = BPMNGraphUtil.findMultiLineTextNode(lgn);
-                    if (gnode != null) {
-                        gnode.getArgs().put("text", text);
-                    }
-                    continue;
-                }
-
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                bpmnElement.setDocumentation(json.getString(feature));
-                continue;
-            }
-
-            if ("gatewaydirection".equals(feature)) {
-                bpmnElement.setAttribute("gatewayDirection", json.getString(feature));
-                continue;
-            }
-            // TODO implement Event features
-        }
-
+        updateNameProperty(json, bpmnElement, gNodeElement);
+        // update attributes and tags
+        bpmnElement.setDocumentation(json.getString("documentation"));
+        bpmnElement.setAttribute("gatewayDirection", json.getString("gatewaydirection"));
     }
-
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNMessageExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNMessageExtension.java
index 2f3665fa..fdfd85f2 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNMessageExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNMessageExtension.java
@@ -17,24 +17,18 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
 
 import javax.json.JsonObject;
 
 import org.eclipse.glsp.graph.GModelElement;
-import org.eclipse.glsp.graph.GNode;
 import org.openbpmn.bpmn.BPMNTypes;
 import org.openbpmn.bpmn.elements.Message;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
-import org.openbpmn.bpmn.elements.core.BPMNElementNode;
-import org.openbpmn.glsp.bpmn.LabelGNode;
 import org.openbpmn.glsp.jsonforms.DataBuilder;
 import org.openbpmn.glsp.jsonforms.SchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
 import org.openbpmn.glsp.model.BPMNGModelState;
-import org.openbpmn.glsp.utils.BPMNGraphUtil;
 
 import com.google.inject.Inject;
 
@@ -94,37 +88,14 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
 
     }
 
+    /**
+     * Update the Message default properties
+     */
     @Override
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
-
-        // default update of name and documentation
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-
-            if ("name".equals(feature)) {
-                String text = json.getString(feature);
-                bpmnElement.setName(text);
-                // Update GModelElement Label...
-                Optional<GModelElement> label = modelState.getIndex().get(gNodeElement.getId() + "_bpmnlabel");
-                if (!label.isEmpty()) {
-                    LabelGNode lgn = (LabelGNode) label.get();
-                    // update the bpmn-text-node of the GNodeElement
-                    GNode gnode = BPMNGraphUtil.findMultiLineTextNode(lgn);
-                    if (gnode != null) {
-                        gnode.getArgs().put("text", text);
-                    }
-                    continue;
-                }
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                ((BPMNElementNode) bpmnElement).setDocumentation(json.getString(feature));
-                continue;
-            }
-
-        }
-
+        updateNameProperty(json, bpmnElement, gNodeElement);
+        // update attributes and tags
+        bpmnElement.setDocumentation(json.getString("documentation"));
     }
-
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNParticipantExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNParticipantExtension.java
index 332f94a7..b42c3698 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNParticipantExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNParticipantExtension.java
@@ -20,7 +20,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 
 import javax.json.Json;
 import javax.json.JsonArray;
@@ -120,68 +119,57 @@ public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnEl
         Participant participant = (Participant) bpmnElement;
         try {
             BPMNProcess process = modelState.getBpmnModel().openProcess(participant.getProcessRef());
-            // check custom features
-            Set<String> features = json.keySet();
-            for (String feature : features) {
-                if ("name".equals(feature)) {
-                    bpmnElement.setName(json.getString(feature));
-                    process.setName(json.getString(feature));
-                    // Update Label...
-                    ((BPMNGNode) gNodeElement).setName(json.getString(feature));
-                    continue;
-                }
-                if ("documentation".equals(feature)) {
-                    bpmnElement.setDocumentation(json.getString(feature));
-                    continue;
-                }
 
-                // LaneSet...
-                if ("lanes".equals(feature)) {
-                    List<String> laneDataIDs = new ArrayList<>(); // collect remaining lanes
-                    logger.debug("...update feature = " + feature);
-                    JsonArray laneSetValues = json.getJsonArray(feature);
-                    for (JsonValue laneValue : laneSetValues) {
-                        // update lane properties
-                        JsonObject laneData = (JsonObject) laneValue;
-                        if (laneData.get("id") != null) {
-                            String id = laneData.getJsonString("id").getString();
-                            // String id = jsonID.toString();
-                            laneDataIDs.add(id);
-                            Lane bpmnLane = process.findLaneById(id);
-                            if (bpmnLane != null) {
-                                bpmnLane.setName(laneData.getString("name"));
-                                bpmnLane.setDocumentation(laneData.getString("documentation"));
-                                // update gnode...
-                                Optional<GModelElement> _gLane = modelState.getIndex().get(bpmnLane.getId());
-                                if (_gLane.isPresent()) {
-                                    LaneGNode gLane = (LaneGNode) _gLane.get();
-                                    gLane.setName(laneData.getString("name"));
-                                }
-                            }
-                        } else {
-                            // this is a new lane - construct the lane in the BPMN model first..
-                            Lane bpmnLane = process.addLane("Lane " + (process.getLanes().size() + 1));
-                            laneDataIDs.add(bpmnLane.getId());
-                            modelState.reset();
-                        }
-                    }
-                    // now we need to delete all lanes no longer part of the laneSetValues
-                    // We need two loops here to avoid concurrency exceptions!
-                    List<String> laneIDsToBeRemoved = new ArrayList<>();
-                    for (Lane bpmnLane : process.getLanes()) {
-                        if (bpmnLane != null && !laneDataIDs.contains(bpmnLane.getId())) {
-                            laneIDsToBeRemoved.add(bpmnLane.getId());
-                        }
-                    }
-                    if (laneIDsToBeRemoved.size() > 0) {
-                        modelState.reset();
-                        for (String lid : laneIDsToBeRemoved) {
-                            // lane was removed, so remove the lane form the process too
-                            process.deleteLane(lid);
+            bpmnElement.setName(json.getString("name", ""));
+            process.setName(json.getString("name", ""));
+            ((BPMNGNode) gNodeElement).setName(json.getString("name", ""));
+            bpmnElement.setDocumentation(json.getString("documentation"));
+
+            // LaneSet...
+            List<String> laneDataIDs = new ArrayList<>(); // collect remaining lanes
+            logger.debug("...update feature = " + "lanes");
+            JsonArray laneSetValues = json.getJsonArray("lanes");
+            for (JsonValue laneValue : laneSetValues) {
+                // update lane properties
+                JsonObject laneData = (JsonObject) laneValue;
+                if (laneData.get("id") != null) {
+                    String id = laneData.getJsonString("id").getString();
+                    // String id = jsonID.toString();
+                    laneDataIDs.add(id);
+                    Lane bpmnLane = process.findLaneById(id);
+                    if (bpmnLane != null) {
+                        bpmnLane.setName(laneData.getString("name"));
+                        bpmnLane.setDocumentation(laneData.getString("documentation"));
+                        // update gnode...
+                        Optional<GModelElement> _gLane = modelState.getIndex().get(bpmnLane.getId());
+                        if (_gLane.isPresent()) {
+                            LaneGNode gLane = (LaneGNode) _gLane.get();
+                            gLane.setName(laneData.getString("name"));
                         }
                     }
+                } else {
+                    // this is a new lane - construct the lane in the BPMN model first..
+                    Lane bpmnLane = process.addLane("Lane " + (process.getLanes().size() + 1));
+                    laneDataIDs.add(bpmnLane.getId());
+                    modelState.reset();
                 }
             }
+            // now we need to delete all lanes no longer part of the laneSetValues
+            // We need two loops here to avoid concurrency exceptions!
+            List<String> laneIDsToBeRemoved = new ArrayList<>();
+            for (Lane bpmnLane : process.getLanes()) {
+                if (bpmnLane != null && !laneDataIDs.contains(bpmnLane.getId())) {
+                    laneIDsToBeRemoved.add(bpmnLane.getId());
+                }
+            }
+            if (laneIDsToBeRemoved.size() > 0) {
+                modelState.reset();
+                for (String lid : laneIDsToBeRemoved) {
+                    // lane was removed, so remove the lane form the process too
+                    process.deleteLane(lid);
+                }
+            }
+
         } catch (BPMNModelException e) {
             logger.error("Failed to update laneSet properties: " + e.getMessage());
         }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNSequenceFlowExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNSequenceFlowExtension.java
index 7962b8ae..2e28e9d9 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNSequenceFlowExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNSequenceFlowExtension.java
@@ -102,11 +102,10 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
         }
         dataBuilder //
                 .addData("conditionExpression", conditionalExpression) //
-                .addData("Default", "test");
+        ;
 
         schemaBuilder. //
-                addProperty("conditionExpression", "string", description). //
-                addProperty("default", "boolean", null);
+                addProperty("conditionExpression", "string", description); //
 
         Map<String, String> multilineOption = new HashMap<>();
         multilineOption.put("multi", "true");
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTaskExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTaskExtension.java
index 0a90949d..25e6e2db 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTaskExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTaskExtension.java
@@ -17,23 +17,20 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 
 import javax.json.JsonObject;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.eclipse.glsp.graph.GModelElement;
-import org.eclipse.glsp.graph.GNode;
+import org.openbpmn.bpmn.BPMNNS;
 import org.openbpmn.bpmn.BPMNTypes;
 import org.openbpmn.bpmn.elements.Activity;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
-import org.openbpmn.glsp.bpmn.BPMNGNode;
 import org.openbpmn.glsp.jsonforms.DataBuilder;
 import org.openbpmn.glsp.jsonforms.SchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
-import org.openbpmn.glsp.utils.BPMNGraphUtil;
 
 /**
  * This is the Default BPMNEvent extension providing the JSONForms shemata.
@@ -95,7 +92,8 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
         if (BPMNTypes.SCRIPT_TASK.equals(taskElement.getType())) {
             dataBuilder //
                     .addData("scriptformat", taskElement.getAttribute("scriptFormat")) //
-                    .addData("script", taskElement.getChildNodeContent("script"));
+                    .addData("script", taskElement
+                            .getChildNodeContent(BPMNNS.BPMN2, "script"));
 
             schemaBuilder. //
                     addProperty("scriptformat", "string", "Format of the script"). //
@@ -112,42 +110,18 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
 
     }
 
+    /**
+     * Update the default activity properties.
+     */
     @Override
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
 
-        // default update of name and documentation
-
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-            if ("name".equals(feature)) {
-                String text = json.getString(feature);
-                bpmnElement.setName(text);
-                // update the bpmn-text-node of the GNodeElement
-                GNode gnode = BPMNGraphUtil.findMultiLineTextNode((BPMNGNode) gNodeElement);
-                if (gnode != null) {
-                    gnode.getArgs().put("text", text);
-                }
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                bpmnElement.setDocumentation(json.getString(feature));
-                continue;
-            }
-
-            logger.debug("...update feature = " + feature);
-
-            if ("scriptformat".equals(feature)) {
-                bpmnElement.setAttribute("scriptFormat", json.getString(feature));
-                continue;
-            }
-
-            if ("script".equals(feature)) {
-                bpmnElement.setChildNodeContent("script", json.getString(feature));
-                continue;
-            }
-        }
-
+        updateNameProperty(json, bpmnElement, gNodeElement);
+        // update attributes and tags
+        bpmnElement.setDocumentation(json.getString("documentation"));
+        bpmnElement.setAttribute("scriptFormat", json.getString("scriptformat"));
+        bpmnElement.setChildNodeContent(BPMNNS.BPMN2, "script", json.getString("script"), true);
     }
 
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTextAnnotationExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTextAnnotationExtension.java
index fa72a732..e4736651 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTextAnnotationExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/DefaultBPMNTextAnnotationExtension.java
@@ -18,7 +18,6 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 
 import javax.json.JsonObject;
 
@@ -76,11 +75,6 @@ public boolean handlesBPMNElement(final BPMNElement bpmnElement) {
     public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder dataBuilder,
             final SchemaBuilder schemaBuilder, final UISchemaBuilder uiSchemaBuilder) {
 
-        if (!(bpmnElement instanceof TextAnnotation)) {
-            logger.warn("invalid BPMN element - TextAnnotation expected!");
-            return;
-        }
-
         String text = ((TextAnnotation) bpmnElement).getText();
 
         dataBuilder //
@@ -104,40 +98,25 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
 
     }
 
+    /**
+     * Updates the textAnnotation properties
+     */
     @Override
     public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
             final GModelElement gNodeElement) {
 
-        if (!(bpmnElement instanceof TextAnnotation)) {
-            logger.warn("invalid BPMN element - TextAnnotation expected!");
-            return;
+        // update attributes and tags
+        bpmnElement.setDocumentation(json.getString("documentation"));
+        bpmnElement.setAttribute("textFormat", json.getString("textFormat"));
+
+        // Update the text property
+        String text = json.getString("text", "");
+        ((TextAnnotation) bpmnElement).setText(text);
+        // Update GModelElement Text Node...
+        Optional<GModelElement> textNode = modelState.getIndex().get(gNodeElement.getId() + "_bpmntext");
+        if (!textNode.isEmpty()) {
+            textNode.get().getArgs().put("text", text);
         }
-
-        // default update of name and documentation
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-
-            if ("textFormat".equals(feature)) {
-                bpmnElement.setAttribute("textFormat", json.getString(feature));
-                continue;
-            }
-            if ("text".equals(feature)) {
-                String text = json.getString(feature);
-                ((TextAnnotation) bpmnElement).setText(text);
-                // Update GModelElement Text Node...
-                Optional<GModelElement> textNode = modelState.getIndex().get(gNodeElement.getId() + "_bpmntext");
-                if (!textNode.isEmpty()) {
-                    textNode.get().getArgs().put("text", text);
-                }
-                continue;
-            }
-            if ("documentation".equals(feature)) {
-                bpmnElement.setDocumentation(json.getString(feature));
-                continue;
-            }
-
-        }
-
     }
 
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/LinkEventDefinitionExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/LinkEventDefinitionExtension.java
new file mode 100644
index 00000000..c2da834e
--- /dev/null
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/LinkEventDefinitionExtension.java
@@ -0,0 +1,143 @@
+/********************************************************************************
+ * Copyright (c) 2022 Imixs Software Solutions GmbH and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
+ * with the GNU Classpath Exception which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ ********************************************************************************/
+package org.openbpmn.extension;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.eclipse.glsp.graph.GModelElement;
+import org.openbpmn.bpmn.BPMNTypes;
+import org.openbpmn.bpmn.elements.Event;
+import org.openbpmn.bpmn.elements.core.BPMNElement;
+import org.openbpmn.glsp.jsonforms.DataBuilder;
+import org.openbpmn.glsp.jsonforms.SchemaBuilder;
+import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
+import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
+import org.w3c.dom.Element;
+
+/**
+ * The LinkEventDefinitionExtension is responsible to read and update optional
+ * LinkEventDefinitions from the BPMN model. The Extension builds a custom
+ * property section named 'Link Definitions' shown a list of all
+ * LinkEventDefinitions
+ * define in a Event.
+ * 
+ * @author rsoika
+ */
+public class LinkEventDefinitionExtension extends DefaultBPMNEventExtension {
+
+    private static Logger logger = LogManager.getLogger(DefaultBPMNSequenceFlowExtension.class);
+
+    @Override
+    public int getPriority() {
+        return 102;
+    }
+
+    /**
+     * Returns if this Extension can be applied to the given elementTypeID
+     */
+    @Override
+    public boolean handlesElementTypeId(final String elementTypeId) {
+        return BPMNTypes.BPMN_EVENTS.contains(elementTypeId);
+    }
+
+    /**
+     * This Helper Method generates a JSON Object with the BPMNElement properties.
+     * <p>
+     * This json object is used on the GLSP Client to generate the EMF JsonForms
+     */
+    @Override
+    public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder dataBuilder,
+            final SchemaBuilder schemaBuilder, final UISchemaBuilder uiSchemaBuilder) {
+
+        Event event = (Event) bpmnElement;
+
+        // Conditional
+
+        Set<Element> linkEventDefinitions = event.getEventDefinitionsByType("linkEventDefinition");
+
+        if (linkEventDefinitions.size() > 0) {
+
+            Map<String, String> arrayDetailOption = new HashMap<>();
+            // GENERATED HorizontalLayout
+            arrayDetailOption.put("detail", "GENERATED");
+
+            uiSchemaBuilder. //
+                    addCategory("Link"). //
+                    addLayout(Layout.VERTICAL);
+            uiSchemaBuilder.addElement("links", "Links", arrayDetailOption);
+
+            schemaBuilder.addArray("links");
+            schemaBuilder.addProperty("name", "string", null, null);
+            schemaBuilder.addProperty("target", "string", null, null);
+
+            /*
+             * Now we can create the data structure - each conditionalEventDefinition is
+             * represented as a separate object
+             */
+            dataBuilder.addArray("links");
+            logger.warn(" addLinkEventDefinitions not yet implemented");
+            for (Element definition : linkEventDefinitions) {
+                dataBuilder.addObject();
+                dataBuilder.addData("name", definition.getAttribute("name"));
+                dataBuilder.addData("target", definition.getAttribute("target"));
+            }
+
+        }
+    }
+
+    /**
+     * Update the link definitions
+     * 
+     * This method updates all linkEventDefinitions. The method expects a
+     * dataList containing all link definitions with its values.
+     * The method simply overwrites all linkEventDefinitions.
+     * <p>
+     * 
+     */
+    @Override
+    public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
+            final GModelElement gNodeElement) {
+        Event bpmnEvent = (Event) bpmnElement;
+        JsonArray dataList = json.getJsonArray("links");
+
+        // synchronize the definition list of the event element
+        Set<Element> linkEventDefinitions = synchronizeEventDefinitions("linkEventDefinition", bpmnEvent,
+                dataList);
+
+        // just update the values one by one by referring to the signalRef id by
+        // comparing the name
+        Iterator<Element> iter = linkEventDefinitions.iterator();
+        int i = 0;
+        while (iter.hasNext()) {
+            Element eventDefinitionElement = iter.next();
+            JsonObject jsonData = dataList.getJsonObject(i); // .get(i);
+            if (jsonData != null) {
+                eventDefinitionElement.setAttribute("name", jsonData.getString("name", ""));
+                eventDefinitionElement.setAttribute("target", jsonData.getString("target", ""));
+            }
+            // update completed
+        }
+
+    }
+}
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/SignalEventDefinitionExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/SignalEventDefinitionExtension.java
new file mode 100644
index 00000000..a47296a8
--- /dev/null
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/SignalEventDefinitionExtension.java
@@ -0,0 +1,187 @@
+/********************************************************************************
+ * Copyright (c) 2022 Imixs Software Solutions GmbH and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
+ * with the GNU Classpath Exception which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ ********************************************************************************/
+package org.openbpmn.extension;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.eclipse.glsp.graph.GModelElement;
+import org.openbpmn.bpmn.BPMNTypes;
+import org.openbpmn.bpmn.elements.Event;
+import org.openbpmn.bpmn.elements.Signal;
+import org.openbpmn.bpmn.elements.core.BPMNElement;
+import org.openbpmn.bpmn.exceptions.BPMNInvalidReferenceException;
+import org.openbpmn.bpmn.exceptions.BPMNInvalidTypeException;
+import org.openbpmn.bpmn.exceptions.BPMNMissingElementException;
+import org.openbpmn.glsp.jsonforms.DataBuilder;
+import org.openbpmn.glsp.jsonforms.SchemaBuilder;
+import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
+import org.openbpmn.glsp.jsonforms.UISchemaBuilder.Layout;
+import org.w3c.dom.Element;
+
+/**
+ * The LinkEventDefinitionExtension is responsible to read and update optional
+ * LinkEventDefinitions from the BPMN model. The Extension builds a custom
+ * property section named 'Link Definitions' shown a list of all
+ * LinkEventDefinitions
+ * define in a Event.
+ * 
+ * @author rsoika
+ */
+public class SignalEventDefinitionExtension extends DefaultBPMNEventExtension {
+
+    private static Logger logger = LogManager.getLogger(DefaultBPMNSequenceFlowExtension.class);
+
+    @Override
+    public int getPriority() {
+        return 103;
+    }
+
+    /**
+     * Returns if this Extension can be applied to the given elementTypeID
+     */
+    @Override
+    public boolean handlesElementTypeId(final String elementTypeId) {
+        return BPMNTypes.BPMN_EVENTS.contains(elementTypeId);
+    }
+
+    /**
+     * Adds the SignalEvent definitions
+     * <p>
+     * Note: Internally we need a mapping between the Signal name (Label) and the
+     * Signal id (value). As
+     * discussed here
+     * (https://jsonforms.discourse.group/t/how-to-separate-value-and-label-in-a-combobox/1200)
+     * we do not have this feature yet. Currently the efforts seems to be to high to
+     * implement a new
+     * renderer for JsonForms.
+     */
+    @Override
+    public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder dataBuilder,
+            final SchemaBuilder schemaBuilder, final UISchemaBuilder uiSchemaBuilder) {
+
+        Event event = (Event) bpmnElement;
+
+        // Conditional
+
+        Set<Element> signalEventDefinitions = event.getEventDefinitionsByType("signalEventDefinition");
+
+        if (signalEventDefinitions.size() > 0) {
+            Map<String, String> arrayDetailOption = new HashMap<>();
+            // GENERATED HorizontalLayout
+            arrayDetailOption.put("detail", "GENERATED");
+
+            uiSchemaBuilder. //
+                    addCategory("Signals"). //
+                    addLayout(Layout.VERTICAL);
+            uiSchemaBuilder.addElement("signals", "Signals", arrayDetailOption);
+            // uiSchemaBuilder.addElement("formalExpression", "Script", multilineOption);
+
+            schemaBuilder.addArray("signals");
+
+            // find all signals in the current model and build an array...
+            Set<Signal> bpmnSignals = modelState.getBpmnModel().getSignals();
+            String[] signalOptions = new String[bpmnSignals.size()];
+            int i = 0;
+            for (Signal bpmnSignal : bpmnSignals) {
+                signalOptions[i] = bpmnSignal.getName();
+                i++;
+                // signalOptions[i] = bpmnSignal.getId() + "|" + bpmnSignal.getName();
+            }
+            schemaBuilder.addProperty("signal", "string", null, signalOptions);
+            // schemaBuilder.addPropertyOneOf("signal", "string", null, signalOptions);
+
+            /*
+             * Now we can create the data structure - each signalEventDefinition is
+             * represented as a separate object. We resolve the signalRef
+             */
+            dataBuilder.addArray("signals");
+            for (Element definition : signalEventDefinitions) {
+                dataBuilder.addObject();
+                String signalRefID = definition.getAttribute("signalRef");
+                // fetch the corresponding Signal
+                Signal bpmnSignal = (Signal) modelState.getBpmnModel().findElementById(signalRefID);
+                if (bpmnSignal != null) {
+                    dataBuilder.addData("signal", bpmnSignal.getName());
+                } else {
+                    logger.warn("invalid signalRefID found: " + signalRefID);
+                }
+
+            }
+        }
+
+    }
+
+    /**
+     * This method updates the signalEventDefinitions. The method expects a
+     * dataList containing all conditions with its values (including the id).
+     * The method simply overwrites all csignalEventDefinitions.
+     * 
+     * @See addSignalEventDefinitions how we map between the signal name and its id.
+     * 
+     */
+    @Override
+    public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
+            final GModelElement gNodeElement) {
+        Event bpmnEvent = (Event) bpmnElement;
+        JsonArray dataList = json.getJsonArray("links");
+
+        // synchronize the definition list of the event element
+        Set<Element> signalEventDefinitions = synchronizeEventDefinitions("signalEventDefinition", bpmnEvent, dataList);
+
+        // now we can update the values one by referring to the signalRef id by
+        // comparing the name
+        Iterator<Element> iter = signalEventDefinitions.iterator();
+        int i = 0;
+        while (iter.hasNext()) {
+            Element eventDefinitionElement = iter.next();
+            JsonObject jsonData = dataList.getJsonObject(i); // .get(i);
+            if (jsonData != null) {
+
+                String signalName = "";
+
+                try {
+                    signalName = jsonData.getString("signal");
+                } catch (NullPointerException en) {
+                    // no name defined!
+                }
+                logger.debug("signal=" + signalName);
+                try {
+                    // fetch the signal from teh Model Signal list by name...
+                    Signal signal = modelState.getBpmnModel().findSignalByName(signalName);
+                    if (signal != null) {
+                        eventDefinitionElement.setAttribute("signalRef", signal.getId());
+                    } else {
+                        // no signal defintion found - delete signalRef...
+                        eventDefinitionElement.setAttribute("signalRef", "");
+                    }
+                } catch (BPMNInvalidReferenceException | BPMNMissingElementException | BPMNInvalidTypeException e) {
+                    e.printStackTrace();
+                }
+            }
+            i++;
+            // update completed
+        }
+
+    }
+}
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/TimerEventDefinitionExtension.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/TimerEventDefinitionExtension.java
index 39d80c98..5fe850f8 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/TimerEventDefinitionExtension.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/extension/TimerEventDefinitionExtension.java
@@ -27,12 +27,10 @@
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.eclipse.glsp.graph.GModelElement;
-import org.openbpmn.bpmn.BPMNModel;
 import org.openbpmn.bpmn.BPMNNS;
 import org.openbpmn.bpmn.BPMNTypes;
 import org.openbpmn.bpmn.elements.Event;
 import org.openbpmn.bpmn.elements.core.BPMNElement;
-import org.openbpmn.bpmn.exceptions.BPMNModelException;
 import org.openbpmn.glsp.jsonforms.DataBuilder;
 import org.openbpmn.glsp.jsonforms.SchemaBuilder;
 import org.openbpmn.glsp.jsonforms.UISchemaBuilder;
@@ -50,9 +48,8 @@
  * 
  * @author rsoika
  */
-public class TimerEventDefinitionExtension extends AbstractBPMNElementExtension {
+public class TimerEventDefinitionExtension extends DefaultBPMNEventExtension {
 
-    @SuppressWarnings("unused")
     private static Logger logger = LogManager.getLogger(DefaultBPMNSequenceFlowExtension.class);
 
     @Inject
@@ -64,7 +61,7 @@ public TimerEventDefinitionExtension() {
 
     @Override
     public int getPriority() {
-        return 100; // below default settings from Edge element
+        return 104; // below default settings from Edge element
     }
 
     /**
@@ -144,14 +141,10 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
             for (Element timerDefinition : linkEventDefinitions) {
                 dataBuilder.addObject();
                 // test the type of the timer object....
-                Element timeDuration = BPMNModel.findChildNodeByName(timerDefinition,
-                        event.getBpmnProcess().getModel().getPrefix(BPMNNS.BPMN2) + ":timeDuration");
-
-                Element timeCycle = BPMNModel.findChildNodeByName(timerDefinition,
-                        event.getBpmnProcess().getModel().getPrefix(BPMNNS.BPMN2) + ":timeCycle");
-
-                Element timeDate = BPMNModel.findChildNodeByName(timerDefinition,
-                        event.getBpmnProcess().getModel().getPrefix(BPMNNS.BPMN2) + ":timeDate");
+                Element timeDuration = event.getModel().findChildNodeByName(timerDefinition, BPMNNS.BPMN2,
+                        "timeDuration");
+                Element timeCycle = event.getModel().findChildNodeByName(timerDefinition, BPMNNS.BPMN2, "timeCycle");
+                Element timeDate = event.getModel().findChildNodeByName(timerDefinition, BPMNNS.BPMN2, "timeDate");
 
                 String timerValue = "";
                 String timerType = "Time/Date"; // default
@@ -175,26 +168,7 @@ public void buildPropertiesForm(final BPMNElement bpmnElement, final DataBuilder
 
     /**
      * Update the timers definitions
-     */
-    @Override
-    public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
-            final GModelElement gNodeElement) {
-
-        Event bpmnEvent = (Event) bpmnElement;
-        Set<String> features = json.keySet();
-        for (String feature : features) {
-
-            // Update eventDefinitions for each definition type...
-            Set<Element> eventDefinitions = bpmnEvent.getEventDefinitions();
-            if ("timers".equals(feature)) {
-                JsonArray dataList = json.getJsonArray("timers");
-                updateTimerEventDefinitions(bpmnEvent, dataList);
-            }
-
-        }
-    }
-
-    /**
+     * 
      * This method updates all timerEventDefinitions. The method expects a
      * dataList containing all timer definitions with its values.
      * The method simply overwrites all timerEventDefinitions.
@@ -212,34 +186,15 @@ public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnEl
      *   </bpmn2:startEvent>
      * }
     * </pre>
-     * 
-     * @param bpmnEvent
-     * @param dataList
      */
-    private void updateTimerEventDefinitions(final Event bpmnEvent, final JsonArray dataList) {
-        // find all conditionalEventDefinitions for this event
-        Set<Element> timerEventDefinitions = bpmnEvent.getEventDefinitionsByType("timerEventDefinition");
-        // If the size of the DataList is not equals the size of the
-        // DefinitionList we add or remove definitions...
-        while (timerEventDefinitions.size() != dataList.size()) {
-            try {
-                if (timerEventDefinitions.size() < dataList.size()) {
-                    // add a new empty condition placeholder...
-                    bpmnEvent.addEventDefinition("timerEventDefinition");
-                }
-                if (timerEventDefinitions.size() > dataList.size()) {
-                    // delete first condition from the list
-                    Element definition = timerEventDefinitions.iterator().next();
-                    String id = definition.getAttribute("id");
-                    bpmnEvent.deleteEventDefinition(id);
-                }
-            } catch (BPMNModelException e) {
-                logger.error("Failed to update BPMN Event Definition list: " + e.getMessage());
-                e.printStackTrace();
-            }
-            // Update event definition list
-            timerEventDefinitions = bpmnEvent.getEventDefinitionsByType("timerEventDefinition");
-        }
+    @Override
+    public void updatePropertiesData(final JsonObject json, final BPMNElement bpmnElement,
+            final GModelElement gNodeElement) {
+        Event bpmnEvent = (Event) bpmnElement;
+        JsonArray dataList = json.getJsonArray("timers");
+
+        // synchronize the definition list of the event element
+        Set<Element> timerEventDefinitions = synchronizeEventDefinitions("timerEventDefinition", bpmnEvent, dataList);
 
         // now we can update the values one by one
         // NOTE: the id can change within the definitionList if an element was deleted
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/BPMNDiagramModule.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/BPMNDiagramModule.java
index c6414a55..b814acf1 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/BPMNDiagramModule.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/BPMNDiagramModule.java
@@ -32,6 +32,7 @@
 import org.eclipse.glsp.server.operations.OperationHandler;
 import org.openbpmn.extension.BPMNCreateExtensionHandler;
 import org.openbpmn.extension.BPMNExtension;
+import org.openbpmn.extension.ConditionalEventDefinitionExtension;
 import org.openbpmn.extension.DefaultBPMNDataObjectExtension;
 import org.openbpmn.extension.DefaultBPMNDefinitionsExtension;
 import org.openbpmn.extension.DefaultBPMNEdgeExtension;
@@ -42,6 +43,8 @@
 import org.openbpmn.extension.DefaultBPMNSequenceFlowExtension;
 import org.openbpmn.extension.DefaultBPMNTaskExtension;
 import org.openbpmn.extension.DefaultBPMNTextAnnotationExtension;
+import org.openbpmn.extension.LinkEventDefinitionExtension;
+import org.openbpmn.extension.SignalEventDefinitionExtension;
 import org.openbpmn.extension.TimerEventDefinitionExtension;
 import org.openbpmn.glsp.elements.data.BPMNApplyEditLabelOperationHandler;
 import org.openbpmn.glsp.elements.data.BPMNCreateDataObjectHandler;
@@ -232,6 +235,9 @@ public void configureBPMNExtensions(final Multibinder<BPMNExtension> binding) {
         binding.addBinding().to(DefaultBPMNEdgeExtension.class);
         binding.addBinding().to(DefaultBPMNSequenceFlowExtension.class);
         binding.addBinding().to(TimerEventDefinitionExtension.class);
+        binding.addBinding().to(SignalEventDefinitionExtension.class);
+        binding.addBinding().to(ConditionalEventDefinitionExtension.class);
+        binding.addBinding().to(LinkEventDefinitionExtension.class);
 
     }
 }
diff --git a/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/model/BPMNGModelFactory.java b/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/model/BPMNGModelFactory.java
index 12cbb498..5b76ec0a 100644
--- a/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/model/BPMNGModelFactory.java
+++ b/open-bpmn.glsp-server/src/main/java/org/openbpmn/glsp/model/BPMNGModelFactory.java
@@ -20,6 +20,8 @@
 import java.io.StringWriter;
 import java.io.Writer;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -264,7 +266,14 @@ void applyBPMNExtensions(final GModelElement elementNode, final BPMNElement bpmn
          * extensions we also add a CSS class
          */
         if (extensions != null) {
-            for (BPMNExtension extension : extensions) {
+
+            // sort extensions by priority
+            List<BPMNExtension> sortedExtensions = new ArrayList<>();
+            sortedExtensions.addAll(extensions);
+            Comparator<BPMNExtension> byPriority = Comparator.comparing(BPMNExtension::getPriority);
+            Collections.sort(sortedExtensions, byPriority);
+
+            for (BPMNExtension extension : sortedExtensions) {
                 // validate if the extension can handle this BPMN element
                 if (extension.handlesBPMNElement(bpmnElement)) {
                     // add JSONForms Schemata
diff --git a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/elements/core/BPMNElement.java b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/elements/core/BPMNElement.java
index b6b71e68..8209c59d 100644
--- a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/elements/core/BPMNElement.java
+++ b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/elements/core/BPMNElement.java
@@ -277,7 +277,8 @@ public String getAttribute(String name) {
     }
 
     /**
-     * Set the value of a given attribute by name.
+     * Set the value of a given attribute by name. If the value is null, the
+     * attribute will be removed.
      * <p>
      * The method operates directly on the attriubteMap loaded in the constructor.
      * 
@@ -288,9 +289,12 @@ public void setAttribute(String name, String value) {
         if (name == null || name.isEmpty() || attributeMap == null) {
             return;
         }
-        // if we did not found the attribute, we add a new one...
-        this.getElementNode().setAttribute(name, value);
-
+        // if the value is null we remove the attibute
+        if (value == null) {
+            this.getElementNode().removeAttribute(name);
+        } else {
+            this.getElementNode().setAttribute(name, value);
+        }
     }
 
     /**