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

mgrigorov pushed a commit to branch wicket-8.x
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit 2c46ad329e25056a32fb765e642457fa176f82c5
Author: Martin Tzvetanov Grigorov <[email protected]>
AuthorDate: Mon Apr 19 16:32:00 2021 +0300

    WICKET-6877 Removing component's MetaData during detach phase from within a 
Behavior causes issue
    
    Reset the iteration index and upper bound while detaching Component's 
behaviors if the Behavior modifies the Component's data anyhow
    
    (cherry picked from commit e11bc07c1b147c55766638ecaba899956505857b)
---
 .../src/main/java/org/apache/wicket/Behaviors.java | 16 ++++
 .../src/main/java/org/apache/wicket/Component.java |  2 +-
 .../org/apache/wicket/BehaviorsDetachTest.java     | 37 +++++++++
 .../apache/wicket/BehavioursDetachTestPage.html    | 16 ++++
 .../apache/wicket/BehavioursDetachTestPage.java    | 90 ++++++++++++++++++++++
 5 files changed, 160 insertions(+), 1 deletion(-)

diff --git a/wicket-core/src/main/java/org/apache/wicket/Behaviors.java 
b/wicket-core/src/main/java/org/apache/wicket/Behaviors.java
index fc99c6c..ed0298b 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Behaviors.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Behaviors.java
@@ -156,6 +156,22 @@ final class Behaviors
 
                                behavior.detach(component);
 
+                               final int currentLength = 
component.data_length();
+                               if (len != currentLength)
+                               {
+                                       // if the length has changed then reset 
'i' and 'len'
+                                       for (int j = start; j < currentLength; 
j++)
+                                       {
+                                               // find the new index of the 
current behavior by identity
+                                               if (behavior == 
component.data_get(j))
+                                               {
+                                                       i = j;
+                                                       len = currentLength;
+                                                       break;
+                                               }
+                                       }
+                               }
+
                                if (behavior.isTemporary(component))
                                {
                                        internalRemove(component, behavior);
diff --git a/wicket-core/src/main/java/org/apache/wicket/Component.java 
b/wicket-core/src/main/java/org/apache/wicket/Component.java
index c1ae312..76a0533 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Component.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Component.java
@@ -2884,7 +2884,7 @@ public abstract class Component
                MetaDataEntry<?>[] old = getMetaData();
 
                Object metaData = null;
-               MetaDataEntry<?>[] metaDataArray = key.set(getMetaData(), 
object);
+               MetaDataEntry<?>[] metaDataArray = key.set(old, object);
                if (metaDataArray != null && metaDataArray.length > 0)
                {
                        metaData = (metaDataArray.length > 1) ? metaDataArray : 
metaDataArray[0];
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/BehaviorsDetachTest.java 
b/wicket-core/src/test/java/org/apache/wicket/BehaviorsDetachTest.java
new file mode 100644
index 0000000..90c1640
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/BehaviorsDetachTest.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket;
+
+import org.apache.wicket.util.tester.WicketTestCase;
+import org.junit.Test;
+
+/**
+ * Tests for {@link Behaviors#detach(Component)} method
+ */
+public class BehaviorsDetachTest extends WicketTestCase {
+
+    /**
+     * https://issues.apache.org/jira/browse/WICKET-6877
+     */
+    @Test
+    public void 
detach_whenRemovingTheLastMetaData_thenUpdateComponentDataAndDetachAllFollowingBehaviors()
 {
+        final BehavioursDetachTestPage page = 
tester.startPage(BehavioursDetachTestPage.class);
+        assertFalse("The LoadableDetachableModel should be in detached 
state!", page.theModel.isAttached());
+    }
+
+
+}
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/BehavioursDetachTestPage.html 
b/wicket-core/src/test/java/org/apache/wicket/BehavioursDetachTestPage.html
new file mode 100644
index 0000000..46b6cd4
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/BehavioursDetachTestPage.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html xmlns:wicket="http://wicket.apache.org";>
+       <head>
+               <meta charset="utf-8" />
+               <title>Apache Wicket Quickstart</title>
+       </head>
+       <body>
+               <div id="hd">
+                       <p>
+                               <a wicket:id="link">Link</a>
+                       </p>
+               </div>
+               <div id="ft">
+               </div>
+       </body>
+</html>
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/BehavioursDetachTestPage.java 
b/wicket-core/src/test/java/org/apache/wicket/BehavioursDetachTestPage.java
new file mode 100644
index 0000000..65191a2
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/BehavioursDetachTestPage.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket;
+
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+public class BehavioursDetachTestPage extends WebPage {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * This model should be detached after page rendering
+     */
+    final LoadableDetachableModel<String> theModel;
+
+    public BehavioursDetachTestPage(final PageParameters parameters) {
+        super(parameters);
+
+        // Bug seems to only occur on stateful pages,
+        // hence a Link to force it to be stateful in this quickstart
+        Link<String> link = new Link<String>("link") {
+            @Override
+            public void onClick() {/*NoOp*/}
+        };
+        queue(link);
+
+        // A behavior that causes the problem
+        link.add(new VisibilityBehavior());
+
+        theModel = LoadableDetachableModel.of(() -> "attribute value");
+
+        // AttributeModifier and thus its LoadableDetachableModel don't get 
detached
+        link.add(AttributeModifier.replace("some-random-attribute", theModel));
+    }
+
+    /**
+     * A behavior that modifies the component's data by removing the last 
MetaDataEntry
+     * in its detach() method
+     */
+    public static class VisibilityBehavior extends Behavior {
+
+        private static final MetaDataKey<Boolean> META_DATA_KEY = new 
MetaDataKey<Boolean>() {};
+
+        @Override
+        public void onConfigure(Component component) {
+            super.onConfigure(component);
+
+            // If no other Behavior of this kind deemed the component to be 
hidden yet,
+            // calculate its visibilty now
+            Boolean calculatdVisibilitySoFar = 
component.getMetaData(META_DATA_KEY);
+            if (!Boolean.FALSE.equals(calculatdVisibilitySoFar)) {
+                boolean calculatedVisibility = calculateVisibility();
+                component.setVisibilityAllowed(calculatedVisibility);
+                component.setMetaData(META_DATA_KEY, calculatedVisibility);
+            }
+        }
+
+        // usually abstract and gets overridden in subclasses with more 
meaningful code
+        protected boolean calculateVisibility() {
+            return true;
+        }
+
+        @Override
+        public void detach(Component component) {
+            // Reset visibility information so it's not being used in the next 
request anymore.
+
+            // ==> Setting the MetaData to "null" here causes the issue
+            component.setMetaData(META_DATA_KEY, null);
+            super.detach(component);
+        }
+    }
+
+}

Reply via email to