tkobayas commented on code in PR #7127:
URL: https://github.com/apache/incubator-kie/pull/7127#discussion_r4102169212


##########
drools-serialization-protobuf/src/test/java/org/drools/serialization/protobuf/DynamicFactMarshallingTest.java:
##########
@@ -0,0 +1,230 @@
+/*
+ * 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.drools.serialization.protobuf;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Serializable;
+import java.io.StringReader;
+
+import org.drools.core.impl.RuleBaseFactory;
+import org.drools.kiesession.rulebase.InternalKnowledgeBase;
+import org.drools.kiesession.rulebase.KnowledgeBaseFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.kie.api.KieBase;
+import org.kie.api.io.ResourceType;
+import org.kie.api.runtime.KieSession;
+import org.kie.internal.builder.KnowledgeBuilder;
+import org.kie.internal.builder.KnowledgeBuilderFactory;
+import org.kie.internal.io.ResourceFactory;
+import org.kie.internal.marshalling.MarshallerFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * A dynamic fact is one whose setters notify the session, so that changing it 
re-evaluates the
+ * rules matching it without an explicit {@code update}. The notification is a 
JavaBeans
+ * {@link PropertyChangeListener} registration, and the listener is the entry 
point itself, which
+ * is not serializable: {@link PropertyChangeSupport} drops it on write and 
the unmarshalled fact
+ * comes back with an empty listener list. These tests pin that a round trip 
keeps the fact
+ * dynamic for types declared with {@code @propertyChangeSupport}.
+ */
+public class DynamicFactMarshallingTest {
+
+    private final DeserializationFilterTestSupport filterSupport = new 
DeserializationFilterTestSupport();
+
+    @BeforeEach
+    public void setUpDeserializationFilter() {
+        // the fact carries its PropertyChangeSupport into the blob
+        
filterSupport.setUp("org.drools.serialization.protobuf.DynamicFactMarshallingTest$DynamicFact",
+                            "java.beans.*",
+                            "java.util.*");
+    }
+
+    @AfterEach
+    public void clearDeserializationFilter() {
+        filterSupport.tearDown();
+    }
+
+    private static final String RULE =
+            "import " + DynamicFact.class.getCanonicalName() + ";\n" +
+            "rule \"name changed\"\n" +
+            "when\n" +
+            "    DynamicFact( name == \"changed\" )\n" +
+            "then\n" +
+            "end\n";
+
+    private static final String DECLARED_DYNAMIC_RULE =
+            "import " + DynamicFact.class.getCanonicalName() + ";\n" +
+            "declare DynamicFact\n" +
+            "    @propertyChangeSupport\n" +
+            "end\n" +
+            RULE;
+
+    /**
+     * Sanity check on a session that was never marshalled: this is the 
behaviour the round trip
+     * has to preserve.
+     */
+    @Test
+    public void 
factOfTypeDeclaredWithPropertyChangeSupport_inALiveSession_reevaluatesRulesOnSetter()
 {
+        final KieBase kieBase = knowledgeBase(DECLARED_DYNAMIC_RULE);
+        final KieSession session = kieBase.newKieSession();
+        try {
+            final DynamicFact fact = new DynamicFact("initial");
+            session.insert(fact);
+
+            assertThat(session.fireAllRules()).isZero();
+
+            fact.setName("changed");
+
+            assertThat(session.fireAllRules()).isEqualTo(1);
+        } finally {
+            session.dispose();
+        }
+    }
+
+    @Test
+    public void 
factOfTypeDeclaredWithPropertyChangeSupport_afterRoundTrip_reevaluatesRulesOnSetter()
 throws Exception {
+        final KieBase kieBase = knowledgeBase(DECLARED_DYNAMIC_RULE);
+        final KieSession session = kieBase.newKieSession();
+        session.insert(new DynamicFact("initial"));
+        session.fireAllRules();
+
+        final KieSession restored = roundTrip(kieBase, session);
+        try {
+            final DynamicFact restoredFact = theFactIn(restored);
+            restoredFact.setName("changed");
+
+            assertThat(restored.fireAllRules())
+                    .as("the restored fact lost its PropertyChangeListener, so 
the setter did not notify the session")
+                    .isEqualTo(1);
+        } finally {
+            restored.dispose();
+        }
+    }
+
+    @Test
+    public void 
factOfTypeDeclaredWithPropertyChangeSupport_afterRoundTripAndDelete_removesListener()
 throws Exception {
+        final KieBase kieBase = knowledgeBase(DECLARED_DYNAMIC_RULE);
+        final KieSession session = kieBase.newKieSession();
+        session.insert(new DynamicFact("initial"));
+        session.fireAllRules();
+
+        final KieSession restored = roundTrip(kieBase, session);
+        try {
+            final DynamicFact restoredFact = theFactIn(restored);
+            
assertThat(restoredFact.support.getPropertyChangeListeners()).hasSize(1);
+
+            restored.delete(restored.getFactHandle(restoredFact));
+
+            
assertThat(restoredFact.support.getPropertyChangeListeners()).isEmpty();
+            restoredFact.setName("changed");
+            assertThat(restored.fireAllRules()).isZero();
+        } finally {
+            restored.dispose();
+        }
+    }
+
+    /**
+     * A fact whose type is not declared dynamic must stay non-dynamic across 
a round trip: the fix
+     * re-registers the listeners that were there, it does not hand one to 
every fact that happens
+     * to expose {@code addPropertyChangeListener}.
+     */
+    @Test
+    public void plainlyInsertedFact_afterRoundTrip_staysNonDynamic() throws 
Exception {

Review Comment:
   This is intentional. We limit the scope of the fix to 
`@propertyChangeSupport` only.
   `insert(fact, true)` is deprecated. -> 
https://github.com/apache/incubator-kie/issues/7132



##########
drools-serialization-protobuf/src/main/java/org/drools/serialization/protobuf/ProtobufInputMarshaller.java:
##########
@@ -425,12 +425,33 @@ public static void readFactHandles( 
ProtobufMarshallerReaderContext context,
                 assertHandleIntoOTN( context, wm, handle, pctxs );
             }
 
+            reattachPropertyChangeListener( entryPoint, handle );
+
             if (handle.isExpired()) {
                 wm.addPropagation(new 
WorkingMemoryReteExpireAction((DefaultEventHandle) handle));
             }
         }
     }
 
+    /**
+     * Restores the listener for types declared with {@code 
@propertyChangeSupport}.
+     * JavaBeans PropertyChangeSupport drops the non-serializable entry point 
listener
+     * during marshalling, so it must be registered again on read.
+     */
+    private static void reattachPropertyChangeListener( EntryPoint entryPoint,
+                                                        InternalFactHandle 
handle ) {
+        Object object = handle.getObject();
+        if ( object == null || !(entryPoint instanceof NamedEntryPoint) ) {
+            return;
+        }
+        NamedEntryPoint namedEntryPoint = (NamedEntryPoint) entryPoint;
+        ObjectTypeConf typeConf = 
namedEntryPoint.getObjectTypeConfigurationRegistry()
+                .getOrCreateObjectTypeConf( namedEntryPoint.getEntryPoint(), 
object );
+        if ( typeConf.isDynamic() ) {
+            namedEntryPoint.addPropertyChangeListener( handle, false );

Review Comment:
   This is intentional. We limit the scope of the fix to 
`@propertyChangeSupport` only.
   `insert(fact, true)` is deprecated. -> 
https://github.com/apache/incubator-kie/issues/7132



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to