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

gitgabrio pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-runtimes.git


The following commit(s) were added to refs/heads/main by this push:
     new d67f9297cb [incubator-kie-issues#1497] Using the 
getSerializableNodeInstances inside ProtobufProcessInstanceWriter  (#3707)
d67f9297cb is described below

commit d67f9297cbabcefd5cfe626fdd055a9bab24b4f9
Author: Gabriele Cardosi <[email protected]>
AuthorDate: Fri Oct 18 12:39:54 2024 +0200

    [incubator-kie-issues#1497] Using the getSerializableNodeInstances inside 
ProtobufProcessInstanceWriter  (#3707)
    
    * [incubator-kie-issues#1497] Using the getSerializableNodeInstances inside 
ProtobufProcessInstanceWriter
    
    * [incubator-kie-issues#1497] Overriding  getSerializableNodeInstances 
inside CompositeNodeInstance
    
    * [incubator-kie-issues#1497] Implementing  getNotSerializableClasses 
inside CompositeNodeInstance - overriding in ForEachNodeInstance
    
    * [incubator-kie-issues#1497] Unit-testing ForEachNodeInstance
    
    * [incubator-kie-issues#1497] Improving Serializable Nodes management - 
avoid stream/filter on each getSerializableNodeInstances invocation
    
    * [incubator-kie-issues#1497] Fix formatting
    
    * [incubator-kie-issues#1497] Fix imports
    
    * [incubator-kie-issues#1497] Implemented 
ProtobufProcessInstanceWriterTest.buildWorkflowContext unit test
    
    * [incubator-kie-issues#1497] Removing serializableNodes list
    
    * [incubator-kie-issues#1497] Reverting to modification only in 
ForEachNodeInstance
    
    * [incubator-kie-issues#1497] Fix format/imports
    
    ---------
    
    Co-authored-by: Gabriele-Cardosi <[email protected]>
---
 .../instance/node/CompositeNodeInstance.java       |   6 +-
 .../instance/node/ForEachNodeInstance.java         |  21 ++-
 .../instance/node/ForEachNodeInstanceTest.java     |  75 +++++++++++
 .../impl/ProtobufProcessInstanceWriter.java        |   6 +-
 .../impl/ProtobufProcessInstanceWriterTest.java    | 149 +++++++++++++++++++++
 5 files changed, 250 insertions(+), 7 deletions(-)

diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
index 2612be7998..ea9a677462 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
@@ -54,7 +54,7 @@ import static 
org.kie.kogito.internal.process.runtime.KogitoProcessInstance.STAT
 
 /**
  * Runtime counterpart of a composite node.
- * 
+ *
  */
 public class CompositeNodeInstance extends StateBasedNodeInstance implements 
NodeInstanceContainer, EventNodeInstanceInterface, 
EventBasedNodeInstanceInterface {
 
@@ -190,7 +190,7 @@ public class CompositeNodeInstance extends 
StateBasedNodeInstance implements Nod
     @Override
     public void addNodeInstance(final NodeInstance nodeInstance) {
         if (nodeInstance.getStringId() == null) {
-            // assign new id only if it does not exist as it might already be 
set by marshalling 
+            // assign new id only if it does not exist as it might already be 
set by marshalling
             // it's important to keep same ids of node instances as they might 
be references e.g. exclusive group
             ((NodeInstanceImpl) 
nodeInstance).setId(UUID.randomUUID().toString());
         }
@@ -204,7 +204,7 @@ public class CompositeNodeInstance extends 
StateBasedNodeInstance implements Nod
 
     @Override
     public Collection<org.kie.api.runtime.process.NodeInstance> 
getNodeInstances() {
-        return new ArrayList<>(getNodeInstances(false));
+        return Collections.unmodifiableCollection(nodeInstances);
     }
 
     @Override
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
index 339f48d3f2..9b17022e46 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
@@ -26,6 +26,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.jbpm.process.core.ContextContainer;
 import org.jbpm.process.core.context.variable.VariableScope;
@@ -58,6 +60,8 @@ import org.mvel2.integration.impl.SimpleValueResolver;
 public class ForEachNodeInstance extends CompositeContextNodeInstance {
 
     private static final long serialVersionUID = 510L;
+    private static final Set<Class<? extends 
org.kie.api.runtime.process.NodeInstance>> NOT_SERIALIZABLE_CLASSES = 
Set.of(ForEachJoinNodeInstance.class); // using Arrays.asList to allow multiple 
exclusions
+
     public static final String TEMP_OUTPUT_VAR = "foreach_output";
 
     private int totalInstances;
@@ -346,10 +350,25 @@ public class ForEachNodeInstance extends 
CompositeContextNodeInstance {
 
     @Override
     public int getLevelForNode(String uniqueID) {
-        // always 1 for for each
+        // always 1 for each
         return 1;
     }
 
+    @Override
+    public Collection<org.kie.api.runtime.process.NodeInstance> 
getSerializableNodeInstances() {
+        return 
getNodeInstances().stream().filter(ForEachNodeInstance::isSerializable).collect(Collectors.toUnmodifiableList());
+    }
+
+    /**
+     * Check if the given 
<code>org.kie.api.runtime.process.NodeInstance</code> is serializable.
+     *
+     * @param toCheck
+     * @return
+     */
+    static boolean isSerializable(org.kie.api.runtime.process.NodeInstance 
toCheck) {
+        return !NOT_SERIALIZABLE_CLASSES.contains(toCheck.getClass());
+    }
+
     private class ForEachNodeInstanceResolverFactory extends 
NodeInstanceResolverFactory {
 
         private static final long serialVersionUID = -8856846610671009685L;
diff --git 
a/jbpm/jbpm-flow/src/test/java/org/jbpm/workflow/instance/node/ForEachNodeInstanceTest.java
 
b/jbpm/jbpm-flow/src/test/java/org/jbpm/workflow/instance/node/ForEachNodeInstanceTest.java
new file mode 100644
index 0000000000..23194d3027
--- /dev/null
+++ 
b/jbpm/jbpm-flow/src/test/java/org/jbpm/workflow/instance/node/ForEachNodeInstanceTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jbpm.workflow.instance.node;
+
+import java.util.Collection;
+
+import org.junit.jupiter.api.Test;
+import org.kie.api.runtime.process.NodeInstance;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class ForEachNodeInstanceTest {
+
+    @Test
+    void getNodeInstances() {
+        ForEachNodeInstance toTest = new ForEachNodeInstance();
+        CompositeNodeInstance compositeNodeInstance = new 
CompositeNodeInstance();
+        toTest.addNodeInstance(compositeNodeInstance);
+        Collection<NodeInstance> nodeInstances = toTest.getNodeInstances();
+        assertThat(nodeInstances)
+                .isNotNull()
+                .hasSize(1)
+                .contains(compositeNodeInstance);
+        ForEachNodeInstance.ForEachJoinNodeInstance forEachJoinNodeInstance = 
toTest.new ForEachJoinNodeInstance();
+        toTest.addNodeInstance(forEachJoinNodeInstance);
+        nodeInstances = toTest.getNodeInstances();
+        assertThat(nodeInstances)
+                .isNotNull()
+                .hasSize(2)
+                .contains(compositeNodeInstance, forEachJoinNodeInstance);
+    }
+
+    @Test
+    void getSerializableNodeInstances() {
+        ForEachNodeInstance toTest = new ForEachNodeInstance();
+        CompositeNodeInstance compositeNodeInstance = new 
CompositeNodeInstance();
+        toTest.addNodeInstance(compositeNodeInstance);
+        Collection<NodeInstance> serializableNodeInstances = 
toTest.getSerializableNodeInstances();
+        assertThat(serializableNodeInstances)
+                .isNotNull()
+                .hasSize(1)
+                .contains(compositeNodeInstance);
+        ForEachNodeInstance.ForEachJoinNodeInstance forEachJoinNodeInstance = 
toTest.new ForEachJoinNodeInstance();
+        toTest.addNodeInstance(forEachJoinNodeInstance);
+        serializableNodeInstances = toTest.getSerializableNodeInstances();
+        assertThat(serializableNodeInstances)
+                .isNotNull()
+                .hasSize(1)
+                .contains(compositeNodeInstance);
+    }
+
+    @Test
+    void isSerializable() {
+        assertThat(ForEachNodeInstance.isSerializable(new 
CompositeNodeInstance())).isTrue();
+        assertThat(ForEachNodeInstance.isSerializable(new 
ForEachNodeInstance())).isTrue();
+        assertThat(ForEachNodeInstance.isSerializable(new 
ForEachNodeInstance().new ForEachJoinNodeInstance())).isFalse();
+    }
+
+}
diff --git 
a/jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/impl/ProtobufProcessInstanceWriter.java
 
b/jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/impl/ProtobufProcessInstanceWriter.java
index b0f67430db..700d7abd42 100644
--- 
a/jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/impl/ProtobufProcessInstanceWriter.java
+++ 
b/jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/impl/ProtobufProcessInstanceWriter.java
@@ -175,7 +175,7 @@ public class ProtobufProcessInstanceWriter {
         return contexts;
     }
 
-    private KogitoTypesProtobuf.WorkflowContext 
buildWorkflowContext(List<NodeInstance> nodeInstances,
+    protected KogitoTypesProtobuf.WorkflowContext 
buildWorkflowContext(List<NodeInstance> nodeInstances,
             List<ContextInstance> exclusiveGroupInstances,
             List<Entry<String, Object>> variables,
             List<Entry<String, Integer>> iterationlevels) {
@@ -248,8 +248,8 @@ public class ProtobufProcessInstanceWriter {
         return null;
     }
 
-    private <T extends NodeInstanceContainer & ContextInstanceContainer & 
ContextableInstance> WorkflowContext buildWorkflowContext(T nodeInstance) {
-        List<NodeInstance> nodeInstances = new 
ArrayList<>(nodeInstance.getNodeInstances());
+    protected <T extends NodeInstanceContainer & ContextInstanceContainer & 
ContextableInstance> WorkflowContext buildWorkflowContext(T nodeInstance) {
+        List<NodeInstance> nodeInstances = new 
ArrayList<>(nodeInstance.getSerializableNodeInstances());
         List<ContextInstance> exclusiveGroupInstances = 
nodeInstance.getContextInstances(ExclusiveGroup.EXCLUSIVE_GROUP);
         VariableScopeInstance variableScopeInstance = (VariableScopeInstance) 
nodeInstance.getContextInstance(VariableScope.VARIABLE_SCOPE);
         List<Map.Entry<String, Object>> variables = (variableScopeInstance != 
null) ? new ArrayList<>(variableScopeInstance.getVariables().entrySet()) : 
Collections.emptyList();
diff --git 
a/jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/impl/ProtobufProcessInstanceWriterTest.java
 
b/jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/impl/ProtobufProcessInstanceWriterTest.java
new file mode 100644
index 0000000000..4d37ade30f
--- /dev/null
+++ 
b/jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/impl/ProtobufProcessInstanceWriterTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jbpm.flow.serialization.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+import org.jbpm.flow.serialization.MarshallerContextName;
+import org.jbpm.flow.serialization.NodeInstanceWriter;
+import org.jbpm.flow.serialization.ObjectMarshallerStrategyHelper;
+import org.jbpm.process.core.context.variable.VariableScope;
+import org.jbpm.process.instance.ContextInstance;
+import org.jbpm.process.instance.context.variable.VariableScopeInstance;
+import org.jbpm.ruleflow.core.WorkflowElementIdentifierFactory;
+import org.jbpm.util.JbpmClassLoaderUtil;
+import org.jbpm.workflow.core.impl.WorkflowProcessImpl;
+import org.jbpm.workflow.instance.node.ForEachNodeInstance;
+import org.jbpm.workflow.instance.node.HumanTaskNodeInstance;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.kie.api.definition.process.WorkflowElementIdentifier;
+import org.kie.api.runtime.process.NodeInstance;
+import org.kie.kogito.internal.process.runtime.KogitoProcessRuntime;
+import org.kie.kogito.process.impl.AbstractProcess;
+import org.mockito.ArgumentCaptor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class ProtobufProcessInstanceWriterTest {
+
+    private static AbstractProcess<?> mockProcess;
+    private static NodeInstanceWriter[] nodeInstanceWriters;
+    private ProtobufProcessMarshallerWriteContext writeContext;
+
+    @BeforeAll
+    static void setup() {
+        ServiceLoader<NodeInstanceWriter> writerLoader = 
ServiceLoader.load(NodeInstanceWriter.class, 
JbpmClassLoaderUtil.findClassLoader());
+        int items = (int) writerLoader.stream().count();
+        nodeInstanceWriters = 
writerLoader.stream().map(ServiceLoader.Provider::get).map(NodeInstanceWriter.class::cast).toArray(value
 -> new NodeInstanceWriter[items]);
+        mockProcess = getMockedProcess();
+    }
+
+    @BeforeEach
+    void init() {
+        writeContext = new ProtobufProcessMarshallerWriteContext(new 
ByteArrayOutputStream());
+        writeContext.set(MarshallerContextName.OBJECT_MARSHALLING_STRATEGIES, 
ObjectMarshallerStrategyHelper.defaultStrategies());
+        writeContext.set(MarshallerContextName.MARSHALLER_PROCESS, 
mockProcess);
+        
writeContext.set(MarshallerContextName.MARSHALLER_NODE_INSTANCE_WRITER, 
nodeInstanceWriters);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    void buildWorkflowContext() {
+        ProtobufProcessInstanceWriter spiedProtobufProcessInstanceWriter = 
spy(new ProtobufProcessInstanceWriter(writeContext));
+        ForEachNodeInstance nodeInstance = getNodeInstanceContainer();
+        try {
+            
spiedProtobufProcessInstanceWriter.buildWorkflowContext(nodeInstance);
+        } catch (Exception e) {
+            // expected due to partial instantiation
+            assertThat(e).isInstanceOf(NullPointerException.class);
+            ArgumentCaptor<List<NodeInstance>> nodeInstancesCapture = 
ArgumentCaptor.forClass(ArrayList.class);
+            ArgumentCaptor<List<ContextInstance>> 
exclusiveGroupInstancesCapture = ArgumentCaptor.forClass(ArrayList.class);
+            ArgumentCaptor<List<Map.Entry<String, Object>>> variablesCapture = 
ArgumentCaptor.forClass(ArrayList.class);
+            ArgumentCaptor<List<Map.Entry<String, Integer>>> 
iterationlevelsCapture = ArgumentCaptor.forClass(ArrayList.class);
+            
verify(spiedProtobufProcessInstanceWriter).buildWorkflowContext(nodeInstancesCapture.capture(),
 exclusiveGroupInstancesCapture.capture(), variablesCapture.capture(),
+                    iterationlevelsCapture.capture());
+            Collection<NodeInstance> expected = 
nodeInstance.getSerializableNodeInstances();
+            List<NodeInstance> retrieved = nodeInstancesCapture.getValue();
+            
assertThat(retrieved).isNotNull().hasSize(expected.size()).allMatch(expected::contains);
+        }
+    }
+
+    private ForEachNodeInstance getNodeInstanceContainer() {
+        String id = "NodeInstanceContainer";
+        ForEachNodeInstance toReturn = new ForEachNodeInstance();
+        toReturn.setId(id);
+        toReturn.setLevel(1);
+        toReturn.addNodeInstance(getNodeInstanceSerializable(id));
+        toReturn.addNodeInstance(getNodeInstanceNotSerializable(id));
+        toReturn.setNodeId(getWorkflowElementIdentifier(id));
+        toReturn.setContextInstance(VariableScope.VARIABLE_SCOPE, new 
VariableScopeInstance());
+        Collection<NodeInstance> nodeInstances = toReturn.getNodeInstances();
+        assertThat(nodeInstances)
+                .isNotNull()
+                .hasSize(2)
+                .anyMatch(HumanTaskNodeInstance.class::isInstance)
+                
.anyMatch(ForEachNodeInstance.ForEachJoinNodeInstance.class::isInstance);
+        Collection<NodeInstance> serializableNodeInstances = 
toReturn.getSerializableNodeInstances();
+        assertThat(serializableNodeInstances)
+                .isNotNull()
+                .hasSize(1)
+                .allMatch(HumanTaskNodeInstance.class::isInstance);
+        return toReturn;
+    }
+
+    private ForEachNodeInstance.ForEachJoinNodeInstance 
getNodeInstanceNotSerializable(String parent) {
+        String id = String.format("%s-%s", parent, 
"nestedNodeInstanceNotSerializable");
+        ForEachNodeInstance.ForEachJoinNodeInstance toReturn = new 
ForEachNodeInstance().new ForEachJoinNodeInstance();
+        toReturn.setId(id);
+        toReturn.setLevel(2);
+        return toReturn;
+    }
+
+    private HumanTaskNodeInstance getNodeInstanceSerializable(String parent) {
+        String id = String.format("%s-%s", parent, 
"nestedNodeInstanceSerializable");
+        HumanTaskNodeInstance toReturn = new HumanTaskNodeInstance();
+        toReturn.setId(id);
+        toReturn.setNodeId(getWorkflowElementIdentifier(id));
+        return toReturn;
+    }
+
+    private WorkflowElementIdentifier getWorkflowElementIdentifier(String 
parent) {
+        String id = String.format("%s-%s", parent, 
"workflowElementIdentifier");
+        return WorkflowElementIdentifierFactory.fromExternalFormat(id);
+    }
+
+    private static AbstractProcess<?> getMockedProcess() {
+        AbstractProcess<?> toReturn = mock(AbstractProcess.class);
+        
when(toReturn.getProcessRuntime()).thenReturn(mock(KogitoProcessRuntime.class));
+        when(toReturn.get()).thenReturn(new WorkflowProcessImpl());
+        return toReturn;
+    }
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to