You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by pa...@apache.org on 2020/05/06 19:33:28 UTC
[wicket] branch wicket-6774 updated (091d0e0 -> 343b0d24)
This is an automated email from the ASF dual-hosted git repository.
papegaaij pushed a change to branch wicket-6774
in repository https://gitbox.apache.org/repos/asf/wicket.git.
from 091d0e0 WICKET-6774: minor performance improvements, fixed header
new 8ba675c WICKET-6774: mutable state
new 2628cb6 WICKET-6774: add documentation
new 343b0d24 WICKET-6774: keep behavior ids stable during request
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../java/org/apache/wicket/ComponentState.java | 639 ++++++++++++++-------
.../wicket/ajax/AbstractDefaultAjaxBehavior.java | 6 -
.../wicket/behavior/ImmutableBehaviorIdsTest.java | 30 +-
3 files changed, 440 insertions(+), 235 deletions(-)
[wicket] 02/03: WICKET-6774: add documentation
Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
papegaaij pushed a commit to branch wicket-6774
in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 2628cb621e625e03f71691fe5436b34a63ab191b
Author: Emond Papegaaij <em...@topicus.nl>
AuthorDate: Wed May 6 17:01:37 2020 +0200
WICKET-6774: add documentation
---
.../java/org/apache/wicket/ComponentState.java | 155 +++++++++++++++++----
1 file changed, 128 insertions(+), 27 deletions(-)
diff --git a/wicket-core/src/main/java/org/apache/wicket/ComponentState.java b/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
index afd9ac9..c95a81c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
@@ -56,6 +56,11 @@ abstract class ComponentState implements Serializable
*/
abstract IModel< ? > getModel();
+ /**
+ * @param model
+ * the new model or null
+ * @return the new state for the component using the rules defined above
+ */
abstract Object setModel(IModel< ? > model);
/**
@@ -63,6 +68,11 @@ abstract class ComponentState implements Serializable
*/
abstract Object getBehaviors();
+ /**
+ * @param behaviors
+ * the new behaviors (null, one behavior or an array of behaviors)
+ * @return the new state for the component using the rules defined above
+ */
abstract Object setBehaviors(Object behaviors);
/**
@@ -71,6 +81,11 @@ abstract class ComponentState implements Serializable
*/
abstract Object getMetaData();
+ /**
+ * @param metaData
+ * the new meta data entries (null, one entry or an array of entries)
+ * @return the new state for the component using the rules defined above
+ */
abstract Object setMetaData(Object metaData);
/**
@@ -350,19 +365,29 @@ abstract class ComponentState implements Serializable
}
}
+ /**
+ * @param state
+ * the component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @return the model from the given state or null
+ */
static IModel< ? > getModel(Object state, boolean modelSet)
{
- if (!modelSet || state == null)
- {
- return null;
- }
- if (state instanceof IModel)
+ if (state instanceof ComponentState)
{
- return (IModel< ? >) state;
+ return ((ComponentState) state).getModel();
}
- return ((ComponentState) state).getModel();
+ return modelSet ? (IModel< ? >) state : null;
}
+ /**
+ * @param state
+ * the component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @return the behaviors from the given state: null, one behavior or an array of behaviors
+ */
static Object getBehaviors(Object state, boolean modelSet)
{
if (state instanceof ComponentState)
@@ -373,6 +398,13 @@ abstract class ComponentState implements Serializable
: state;
}
+ /**
+ * @param state
+ * the component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @return the meta data entries from the given state: null, one entry or an array of entries
+ */
static Object getMetaData(Object state, boolean modelSet)
{
if (state instanceof ComponentState)
@@ -383,6 +415,17 @@ abstract class ComponentState implements Serializable
? null : state;
}
+ /**
+ * Construct a new component state with the given model value
+ *
+ * @param model
+ * the new model to set or null to clear
+ * @param state
+ * the current component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @return the new component state
+ */
static Object setModel(IModel< ? > model, Object state, boolean modelSet)
{
if (state instanceof ComponentState)
@@ -394,6 +437,7 @@ abstract class ComponentState implements Serializable
{
return model;
}
+ // state does not have a model, clear is a no-op
else if (model == null)
{
return state;
@@ -408,19 +452,32 @@ abstract class ComponentState implements Serializable
}
}
+ /**
+ * Construct a new component state with the given behaviors added
+ *
+ * @param component
+ * the component to add the behaviors to
+ * @param state
+ * the current component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @param behaviorsToAdd
+ * the behaviors to add
+ * @return the new component state
+ */
static Object addBehaviors(Component component, Object state, boolean modelSet,
Behavior... behaviorsToAdd)
{
- if (state instanceof ComponentState)
+ if (behaviorsToAdd.length == 0)
+ {
+ return state;
+ }
+ else if (state instanceof ComponentState)
{
ComponentState compState = (ComponentState) state;
return compState
.setBehaviors(addBehaviors(component, compState.getBehaviors(), behaviorsToAdd));
}
- else if (behaviorsToAdd.length == 0)
- {
- return state;
- }
else if (modelSet)
{
return new ModelBehaviorsComponentState((IModel< ? >) state,
@@ -437,19 +494,32 @@ abstract class ComponentState implements Serializable
}
}
+ /**
+ * Construct a new component state with the given behaviors removed
+ *
+ * @param component
+ * the component to remove the behaviors from
+ * @param state
+ * the current component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @param behaviorsToRemove
+ * the behaviors to removed
+ * @return the new component state
+ */
static Object removeBehaviors(Component component, Object state, boolean modelSet,
Behavior... behaviorsToRemove)
{
- if (state instanceof ComponentState)
+ if (behaviorsToRemove.length == 0)
+ {
+ return state;
+ }
+ else if (state instanceof ComponentState)
{
ComponentState compState = (ComponentState) state;
return compState.setBehaviors(
removeBehaviors(component, compState.getBehaviors(), behaviorsToRemove));
}
- else if (behaviorsToRemove.length == 0)
- {
- return state;
- }
else if (modelSet)
{
throw cannotRemove(behaviorsToRemove[0]);
@@ -464,6 +534,17 @@ abstract class ComponentState implements Serializable
}
}
+ /**
+ * Construct a new component state with the behaviors replaced
+ *
+ * @param state
+ * the current component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @param behaviors
+ * the new value for the behaviors: null, one behavior or an array of behaviors
+ * @return the new component state
+ */
static Object setBehaviors(Object state, boolean modelSet, Object behaviors)
{
if (state instanceof ComponentState)
@@ -489,6 +570,19 @@ abstract class ComponentState implements Serializable
}
}
+ /**
+ * Construct a new component state with the given meta data entry set or reset
+ *
+ * @param state
+ * the current component state
+ * @param modelSet
+ * a boolean indicating if the model is set
+ * @param key
+ * the key to replace the value for
+ * @param data
+ * the new value for the meta data entry, null to clear
+ * @return the new component state
+ */
static <T> Object setMetaData(Object state, boolean modelSet, MetaDataKey<T> key, T data)
{
if (state instanceof ComponentState)
@@ -496,7 +590,8 @@ abstract class ComponentState implements Serializable
ComponentState compState = (ComponentState) state;
return compState.setMetaData(setMetaData(compState.getMetaData(), key, data));
}
- else if (state instanceof MetaDataEntry || state instanceof MetaDataEntry[] || state == null)
+ else if (state instanceof MetaDataEntry || state instanceof MetaDataEntry[]
+ || state == null)
{
return setMetaData(state, key, data);
}
@@ -515,6 +610,21 @@ abstract class ComponentState implements Serializable
}
}
+ /**
+ * Bind a behavior to a component, adding a state change if needed.
+ *
+ * @param component
+ * @param behavior
+ */
+ static void bindBehavior(Component component, Behavior behavior)
+ {
+ if (!behavior.isTemporary(component))
+ {
+ component.addStateChange();
+ }
+ behavior.bind(component);
+ }
+
private static Object addBehaviors(Component component, Object behaviors,
Behavior... behaviorsToAdd)
{
@@ -559,15 +669,6 @@ abstract class ComponentState implements Serializable
return ret;
}
- static void bindBehavior(Component component, Behavior behavior)
- {
- if (!behavior.isTemporary(component))
- {
- component.addStateChange();
- }
- behavior.bind(component);
- }
-
private static Object removeBehaviors(Component component, Object behaviors,
Behavior... behaviorsToRemove)
{
[wicket] 03/03: WICKET-6774: keep behavior ids stable during request
Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
papegaaij pushed a commit to branch wicket-6774
in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 343b0d2421bddaca250181846b852604bd4ea071
Author: Emond Papegaaij <em...@topicus.nl>
AuthorDate: Wed May 6 21:33:08 2020 +0200
WICKET-6774: keep behavior ids stable during request
---
.../java/org/apache/wicket/ComponentState.java | 123 ++++++++++-----------
.../wicket/ajax/AbstractDefaultAjaxBehavior.java | 6 -
.../wicket/behavior/ImmutableBehaviorIdsTest.java | 30 ++++-
3 files changed, 84 insertions(+), 75 deletions(-)
diff --git a/wicket-core/src/main/java/org/apache/wicket/ComponentState.java b/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
index c95a81c..52249e4 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
@@ -716,7 +716,7 @@ abstract class ComponentState implements Serializable
throw cannotRemove(behaviorToRemove);
}
}
- return compactBehaviors(component, behaviorArr);
+ return behaviorArr;
}
private static IllegalStateException cannotRemove(Behavior behavior)
@@ -736,64 +736,6 @@ abstract class ComponentState implements Serializable
behavior.detach(component);
}
- private static Object compactBehaviors(Component component, Behavior[] behaviors)
- {
- // first find the number of behaviors and the highest statefull one
- Behavior singleBehavior = null;
- int highestId = -1;
- int filledSlots = 0;
- for (int i = 0; i < behaviors.length; i++)
- {
- Behavior curBehavior = behaviors[i];
- if (curBehavior != null)
- {
- singleBehavior = curBehavior;
- filledSlots++;
- if (!curBehavior.getStatelessHint(component))
- {
- highestId = i;
- }
- }
- }
-
- int newSize = Math.max(highestId + 1, filledSlots);
- if (newSize == 0)
- {
- return null;
- }
- if (newSize == 1)
- {
- return singleBehavior;
- }
-
- // multiple behaviors (or one with an id > 0)
- Behavior[] ret = new Behavior[newSize];
- int checkSlot = 0;
- for (int i = 0; i < behaviors.length; i++)
- {
- Behavior curBehavior = behaviors[i];
- if (curBehavior == null)
- {
- continue;
- }
- // statefull behaviors stay at their index
- if (!curBehavior.getStatelessHint(component))
- {
- ret[i] = curBehavior;
- }
- else
- {
- // for all others, find the first free slot
- while (ret[checkSlot] != null)
- {
- checkSlot++;
- }
- ret[checkSlot] = curBehavior;
- }
- }
- return ret;
- }
-
private static int getBehaviorsLength(Object behaviors)
{
if (behaviors == null)
@@ -1018,8 +960,14 @@ abstract class ComponentState implements Serializable
}
else if (behaviors instanceof Behavior[])
{
- boolean changed = false;
+ // remove temporary behaviors and compact the array
+ Behavior singleBehavior = null;
+ int highestId = -1;
+ int filledSlots = 0;
Behavior[] behaviorsArr = (Behavior[]) behaviors;
+
+ // iterate over all behaviors, detaching them and removing temporary behaviors
+ // remaining behaviors are counted and for stateful behaviors slots assigned
for (int i = 0; i < behaviorsArr.length; i++)
{
Behavior curBehavior = behaviorsArr[i];
@@ -1030,14 +978,63 @@ abstract class ComponentState implements Serializable
{
curBehavior.unbind(component);
behaviorsArr[i] = null;
- changed = true;
+ }
+ else
+ {
+ singleBehavior = curBehavior;
+ filledSlots++;
+ if (!curBehavior.getStatelessHint(component))
+ {
+ highestId = i;
+ }
}
}
}
- if (changed)
+
+ // if at most 1 behavior remains, no array is needed
+ int newSize = Math.max(highestId + 1, filledSlots);
+ if (newSize == 0)
+ {
+ return setBehaviors(state, modelSet, null);
+ }
+ if (newSize == 1)
+ {
+ return setBehaviors(state, modelSet, singleBehavior);
+ }
+
+ // the calculated size is equal to the current size, cannot compact
+ if (newSize == behaviorsArr.length)
+ {
+ return state;
+ }
+
+ // multiple behaviors (or one with an id > 0)
+ // construct a new array and compact the behaviors
+ Behavior[] ret = new Behavior[newSize];
+ int checkSlot = 0;
+ for (int i = 0; i < behaviorsArr.length; i++)
{
- return setBehaviors(state, modelSet, behaviorsArr);
+ Behavior curBehavior = behaviorsArr[i];
+ if (curBehavior == null)
+ {
+ continue;
+ }
+ // statefull behaviors stay at their index
+ if (!curBehavior.getStatelessHint(component))
+ {
+ ret[i] = curBehavior;
+ }
+ else
+ {
+ // for all others, find the first free slot
+ while (ret[checkSlot] != null)
+ {
+ checkSlot++;
+ }
+ ret[checkSlot] = curBehavior;
+ }
}
+ return setBehaviors(state, modelSet, ret);
}
return state;
}
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java
index 291303f..76c4fb4 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java
@@ -83,12 +83,6 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior
final Component component = getComponent();
component.setOutputMarkupId(true);
-
- if (getStatelessHint(component))
- {
- //generate behavior id
- component.getBehaviorId(this);
- }
}
/**
diff --git a/wicket-core/src/test/java/org/apache/wicket/behavior/ImmutableBehaviorIdsTest.java b/wicket-core/src/test/java/org/apache/wicket/behavior/ImmutableBehaviorIdsTest.java
index de15cfe..1f489f5 100644
--- a/wicket-core/src/test/java/org/apache/wicket/behavior/ImmutableBehaviorIdsTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/behavior/ImmutableBehaviorIdsTest.java
@@ -17,6 +17,7 @@
package org.apache.wicket.behavior;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
@@ -128,30 +129,47 @@ class ImmutableBehaviorIdsTest extends WicketTestCase
page.getContainer().remove(border);
behaviors = page.getContainer().getBehaviors();
assertEquals(5, behaviors.size());
-// assertEquals(autoId, page.container.getBehaviorId(auto));
+ assertEquals(autoId, page.container.getBehaviorId(auto));
assertEquals(link2Id, page.container.getBehaviorId(link2));
// auto,link,border2,link2,auto2
page.getContainer().remove(link);
behaviors = page.getContainer().getBehaviors();
assertEquals(4, behaviors.size());
-// assertEquals(autoId, page.container.getBehaviorId(auto));
+ assertEquals(autoId, page.container.getBehaviorId(auto));
assertEquals(link2Id, page.container.getBehaviorId(link2));
// auto,border2,link2,auto2
page.getContainer().remove(auto2);
behaviors = page.getContainer().getBehaviors();
assertEquals(3, behaviors.size());
-// assertEquals(autoId, page.container.getBehaviorId(auto));
+ assertEquals(autoId, page.container.getBehaviorId(auto));
assertEquals(link2Id, page.container.getBehaviorId(link2));
// auto,border2,link2
page.getContainer().remove(link2); // last IBehaviorListener
behaviors = page.getContainer().getBehaviors();
assertEquals(2, behaviors.size());
-// assertEquals(autoId, page.container.getBehaviorId(auto));
-// assertEquals(border2Id, page.container.getBehaviorId(border2));
-
+ assertEquals(autoId, page.container.getBehaviorId(auto));
+ assertEquals(border2Id, page.container.getBehaviorId(border2));
+
+ // add and remove some again
+ page.getContainer().add(border, link, link2, auto2);
+ borderId = page.container.getBehaviorId(border);
+ border2Id = page.container.getBehaviorId(border2);
+ autoId = page.container.getBehaviorId(auto);
+ auto2Id = page.container.getBehaviorId(auto2);
+ linkId = page.container.getBehaviorId(link);
+ link2Id = page.container.getBehaviorId(link2);
+ page.getContainer().remove(border, link2, auto2);
+
+ page.detach();
+ behaviors = page.getContainer().getBehaviors();
+ assertEquals(3, behaviors.size());
+ assertEquals(linkId, page.container.getBehaviorId(link));
+ // This unequality is not a requirement, but after compacting the behaviors during detach,
+ // the id does change. It does show the difference between stateless and stateful behaviors.
+ assertNotEquals(autoId, page.container.getBehaviorId(auto));
}
private static class LinkBehavior extends Behavior implements IRequestListener
[wicket] 01/03: WICKET-6774: mutable state
Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
papegaaij pushed a commit to branch wicket-6774
in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 8ba675c0b59a6eefe70f038ed9a8f253fa34d01e
Author: Emond Papegaaij <em...@topicus.nl>
AuthorDate: Wed May 6 16:02:31 2020 +0200
WICKET-6774: mutable state
---
.../java/org/apache/wicket/ComponentState.java | 381 +++++++++++++--------
1 file changed, 238 insertions(+), 143 deletions(-)
diff --git a/wicket-core/src/main/java/org/apache/wicket/ComponentState.java b/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
index 776d0d2..afd9ac9 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ComponentState.java
@@ -25,17 +25,58 @@ import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.behavior.InvalidBehaviorIdException;
import org.apache.wicket.model.IModel;
+/**
+ * This class keeps track of the flexible state of a component: model, behaviors and meta data.
+ * These types of state vary per component. Not every component contains these elements or their
+ * numbers differ. The state is stored in the {@code data} field in {@link Component}. To keep the
+ * size of this state as small as possible, the following cases are identified:
+ * <ul>
+ * <li>No state at all: {@code data} is {@code null}
+ * <li>Only a model: {@code data} contains the model
+ * <li>Only one or more behaviors: {@code data} contains the behavior, or an array of behaviors
+ * <li>Only one or more meta data entries: {@code data} contains the entry, or an array of entries
+ * <li>A model and one or more behaviors: {@code data} contains an instance of
+ * {@link ModelBehaviorsComponentState}
+ * <li>A model and one or more meta data entries: {@code data} contains an instance of
+ * {@link ModelMetaDataComponentState}
+ * <li>One or more behaviors and one or more meta data entries: {@code data} contains an instance of
+ * {@link BehaviorsMetaDataComponentState}
+ * <li>A model, one or more behaviors and one or more meta data entries: {@code data} contains an
+ * instance of {@link ModelBehaviorsMetaDataComponentState}
+ * </ul>
+ *
+ * @author papegaaij
+ */
abstract class ComponentState implements Serializable
{
private static final long serialVersionUID = 1L;
+ /**
+ * @return The model stored by this state, or null.
+ */
abstract IModel< ? > getModel();
+ abstract Object setModel(IModel< ? > model);
+
+ /**
+ * @return The behaviors stored by this state: null, a single behavior or an array of behaviors.
+ */
abstract Object getBehaviors();
+ abstract Object setBehaviors(Object behaviors);
+
+ /**
+ * @return The meta data entries stored by this state: null, a single entry or an array of
+ * entries.
+ */
abstract Object getMetaData();
- static class ModelBehaviorComponentState extends ComponentState
+ abstract Object setMetaData(Object metaData);
+
+ /**
+ * Combines a model and one or more behaviors.
+ */
+ static class ModelBehaviorsComponentState extends ComponentState
{
private static final long serialVersionUID = 1L;
@@ -43,7 +84,7 @@ abstract class ComponentState implements Serializable
private Object behaviors;
- private ModelBehaviorComponentState(IModel< ? > model, Object behaviors)
+ private ModelBehaviorsComponentState(IModel< ? > model, Object behaviors)
{
this.model = model;
this.behaviors = behaviors;
@@ -56,18 +97,53 @@ abstract class ComponentState implements Serializable
}
@Override
+ Object setModel(IModel< ? > model)
+ {
+ if (model == null)
+ {
+ return behaviors;
+ }
+ this.model = model;
+ return this;
+ }
+
+ @Override
Object getBehaviors()
{
return behaviors;
}
@Override
+ Object setBehaviors(Object behaviors)
+ {
+ if (behaviors == null)
+ {
+ return model;
+ }
+ this.behaviors = behaviors;
+ return this;
+ }
+
+ @Override
Object getMetaData()
{
return null;
}
+
+ @Override
+ Object setMetaData(Object metaData)
+ {
+ if (metaData == null)
+ {
+ return this;
+ }
+ return new ModelBehaviorsMetaDataComponentState(model, behaviors, metaData);
+ }
}
+ /**
+ * Combines a model and one or more meta data entries.
+ */
static class ModelMetaDataComponentState extends ComponentState
{
private static final long serialVersionUID = 1L;
@@ -89,18 +165,53 @@ abstract class ComponentState implements Serializable
}
@Override
+ Object setModel(IModel< ? > model)
+ {
+ if (model == null)
+ {
+ return metaData;
+ }
+ this.model = model;
+ return this;
+ }
+
+ @Override
Object getBehaviors()
{
return null;
}
@Override
+ Object setBehaviors(Object behaviors)
+ {
+ if (behaviors == null)
+ {
+ return this;
+ }
+ return new ModelBehaviorsMetaDataComponentState(model, behaviors, metaData);
+ }
+
+ @Override
Object getMetaData()
{
return metaData;
}
+
+ @Override
+ Object setMetaData(Object metaData)
+ {
+ if (metaData == null)
+ {
+ return model;
+ }
+ this.metaData = metaData;
+ return this;
+ }
}
+ /**
+ * Combines one or more behaviors and one ore more meta data entries.
+ */
static class BehaviorsMetaDataComponentState extends ComponentState
{
private static final long serialVersionUID = 1L;
@@ -122,18 +233,53 @@ abstract class ComponentState implements Serializable
}
@Override
+ Object setModel(IModel< ? > model)
+ {
+ if (model == null)
+ {
+ return this;
+ }
+ return new ModelBehaviorsMetaDataComponentState(model, behaviors, metaData);
+ }
+
+ @Override
Object getBehaviors()
{
return behaviors;
}
@Override
+ Object setBehaviors(Object behaviors)
+ {
+ if (behaviors == null)
+ {
+ return metaData;
+ }
+ this.behaviors = behaviors;
+ return this;
+ }
+
+ @Override
Object getMetaData()
{
return metaData;
}
+
+ @Override
+ Object setMetaData(Object metaData)
+ {
+ if (metaData == null)
+ {
+ return behaviors;
+ }
+ this.metaData = metaData;
+ return this;
+ }
}
+ /**
+ * Combines a model, one or more behaviors and one or more meta data entries.
+ */
static class ModelBehaviorsMetaDataComponentState extends ComponentState
{
private static final long serialVersionUID = 1L;
@@ -159,16 +305,49 @@ abstract class ComponentState implements Serializable
}
@Override
+ Object setModel(IModel< ? > model)
+ {
+ if (model == null)
+ {
+ return new BehaviorsMetaDataComponentState(behaviors, metaData);
+ }
+ this.model = model;
+ return this;
+ }
+
+ @Override
Object getBehaviors()
{
return behaviors;
}
@Override
+ Object setBehaviors(Object behaviors)
+ {
+ if (behaviors == null)
+ {
+ return new ModelMetaDataComponentState(model, metaData);
+ }
+ this.behaviors = behaviors;
+ return this;
+ }
+
+ @Override
Object getMetaData()
{
return metaData;
}
+
+ @Override
+ Object setMetaData(Object metaData)
+ {
+ if (metaData == null)
+ {
+ return new ModelBehaviorsComponentState(model, behaviors);
+ }
+ this.metaData = metaData;
+ return this;
+ }
}
static IModel< ? > getModel(Object state, boolean modelSet)
@@ -206,215 +385,133 @@ abstract class ComponentState implements Serializable
static Object setModel(IModel< ? > model, Object state, boolean modelSet)
{
- Object stateBehavior;
- Object stateMetaData;
if (state instanceof ComponentState)
{
ComponentState compState = (ComponentState) state;
- stateBehavior = compState.getBehaviors();
- stateMetaData = compState.getMetaData();
+ return compState.setModel(model);
}
- else if (modelSet)
+ else if (modelSet || state == null)
{
return model;
}
+ else if (model == null)
+ {
+ return state;
+ }
else if (state instanceof MetaDataEntry || state instanceof MetaDataEntry[])
{
- stateBehavior = null;
- stateMetaData = state;
+ return new ModelMetaDataComponentState(model, state);
}
else
{
- stateBehavior = state;
- stateMetaData = null;
+ return new ModelBehaviorsComponentState(model, state);
}
-
- return createState(state, model, stateBehavior, stateMetaData);
}
static Object addBehaviors(Component component, Object state, boolean modelSet,
Behavior... behaviorsToAdd)
{
- IModel< ? > stateModel;
- Object stateBehavior;
- Object stateMetaData;
if (state instanceof ComponentState)
{
ComponentState compState = (ComponentState) state;
- stateModel = compState.getModel();
- stateBehavior = compState.getBehaviors();
- stateMetaData = compState.getMetaData();
+ return compState
+ .setBehaviors(addBehaviors(component, compState.getBehaviors(), behaviorsToAdd));
+ }
+ else if (behaviorsToAdd.length == 0)
+ {
+ return state;
}
else if (modelSet)
{
- stateModel = (IModel< ? >) state;
- stateBehavior = null;
- stateMetaData = null;
+ return new ModelBehaviorsComponentState((IModel< ? >) state,
+ addBehaviors(component, null, behaviorsToAdd));
}
else if (state instanceof MetaDataEntry || state instanceof MetaDataEntry[])
{
- stateModel = null;
- stateBehavior = null;
- stateMetaData = state;
+ return new BehaviorsMetaDataComponentState(
+ addBehaviors(component, null, behaviorsToAdd), state);
}
else
{
return addBehaviors(component, state, behaviorsToAdd);
}
-
- return createState(state, stateModel,
- addBehaviors(component, stateBehavior, behaviorsToAdd), stateMetaData);
}
static Object removeBehaviors(Component component, Object state, boolean modelSet,
Behavior... behaviorsToRemove)
{
- IModel< ? > stateModel;
- Object stateBehavior;
- Object stateMetaData;
if (state instanceof ComponentState)
{
ComponentState compState = (ComponentState) state;
- stateModel = compState.getModel();
- stateBehavior = compState.getBehaviors();
- stateMetaData = compState.getMetaData();
+ return compState.setBehaviors(
+ removeBehaviors(component, compState.getBehaviors(), behaviorsToRemove));
+ }
+ else if (behaviorsToRemove.length == 0)
+ {
+ return state;
}
else if (modelSet)
{
- stateModel = (IModel< ? >) state;
- stateBehavior = null;
- stateMetaData = null;
+ throw cannotRemove(behaviorsToRemove[0]);
}
else if (state instanceof MetaDataEntry || state instanceof MetaDataEntry[])
{
- stateModel = null;
- stateBehavior = null;
- stateMetaData = state;
+ throw cannotRemove(behaviorsToRemove[0]);
}
else
{
return removeBehaviors(component, state, behaviorsToRemove);
}
-
- return createState(state, stateModel,
- removeBehaviors(component, stateBehavior, behaviorsToRemove), stateMetaData);
}
- static <T> Object setMetaData(Object state, boolean modelSet, MetaDataKey<T> key, T data)
+ static Object setBehaviors(Object state, boolean modelSet, Object behaviors)
{
- IModel< ? > stateModel;
- Object stateBehavior;
- Object stateMetaData;
if (state instanceof ComponentState)
{
ComponentState compState = (ComponentState) state;
- stateModel = compState.getModel();
- stateBehavior = compState.getBehaviors();
- stateMetaData = compState.getMetaData();
+ return compState.setBehaviors(behaviors);
}
- else if (modelSet)
+ else if (state instanceof Behavior || state instanceof Behavior[] || state == null)
{
- stateModel = (IModel< ? >) state;
- stateBehavior = null;
- stateMetaData = null;
+ return behaviors;
}
- else if (state instanceof MetaDataEntry || state instanceof MetaDataEntry[])
+ else if (behaviors == null)
{
- return setMetaData(state, key, data);
+ return state;
+ }
+ else if (modelSet)
+ {
+ return new ModelBehaviorsComponentState((IModel< ? >) state, behaviors);
}
else
{
- stateModel = null;
- stateBehavior = state;
- stateMetaData = null;
+ return new BehaviorsMetaDataComponentState(behaviors, state);
}
-
- return createState(state, stateModel, stateBehavior, setMetaData(stateMetaData, key, data));
}
- private static Object createState(Object oldState, IModel< ? > model, Object behaviors,
- Object metaData)
+ static <T> Object setMetaData(Object state, boolean modelSet, MetaDataKey<T> key, T data)
{
- if (model == null)
+ if (state instanceof ComponentState)
{
- if (behaviors == null)
- {
- if (metaData == null)
- {
- return null;
- }
- else
- {
- return metaData;
- }
- }
- else
- {
- if (metaData == null)
- {
- return behaviors;
- }
- else
- {
- if (oldState instanceof BehaviorsMetaDataComponentState)
- {
- BehaviorsMetaDataComponentState old =
- (BehaviorsMetaDataComponentState) oldState;
- old.behaviors = behaviors;
- old.metaData = metaData;
- return old;
- }
- return new BehaviorsMetaDataComponentState(behaviors, metaData);
- }
- }
+ ComponentState compState = (ComponentState) state;
+ return compState.setMetaData(setMetaData(compState.getMetaData(), key, data));
+ }
+ else if (state instanceof MetaDataEntry || state instanceof MetaDataEntry[] || state == null)
+ {
+ return setMetaData(state, key, data);
+ }
+ else if (data == null)
+ {
+ return state;
+ }
+ else if (modelSet)
+ {
+ return new ModelMetaDataComponentState((IModel< ? >) state,
+ new MetaDataEntry<>(key, data));
}
else
{
- if (behaviors == null)
- {
- if (metaData == null)
- {
- return model;
- }
- else
- {
- if (oldState instanceof ModelMetaDataComponentState)
- {
- ModelMetaDataComponentState old = (ModelMetaDataComponentState) oldState;
- old.model = model;
- old.metaData = metaData;
- return old;
- }
- return new ModelMetaDataComponentState(model, metaData);
- }
- }
- else
- {
- if (metaData == null)
- {
- if (oldState instanceof ModelBehaviorComponentState)
- {
- ModelBehaviorComponentState old = (ModelBehaviorComponentState) oldState;
- old.model = model;
- old.behaviors = behaviors;
- return old;
- }
- return new ModelBehaviorComponentState(model, behaviors);
- }
- else
- {
- if (oldState instanceof ModelBehaviorsMetaDataComponentState)
- {
- ModelBehaviorsMetaDataComponentState old =
- (ModelBehaviorsMetaDataComponentState) oldState;
- old.model = model;
- old.behaviors = behaviors;
- old.metaData = metaData;
- return old;
- }
- return new ModelBehaviorsMetaDataComponentState(model, behaviors, metaData);
- }
- }
+ return new BehaviorsMetaDataComponentState(state, new MetaDataEntry<>(key, data));
}
}
@@ -815,8 +912,7 @@ abstract class ComponentState implements Serializable
if (behavior.isTemporary(component))
{
behavior.unbind(component);
- return createState(state, getModel(state, modelSet), null,
- getMetaData(state, modelSet));
+ return setBehaviors(state, modelSet, null);
}
}
else if (behaviors instanceof Behavior[])
@@ -839,8 +935,7 @@ abstract class ComponentState implements Serializable
}
if (changed)
{
- return createState(state, getModel(state, modelSet),
- compactBehaviors(component, behaviorsArr), getMetaData(state, modelSet));
+ return setBehaviors(state, modelSet, behaviorsArr);
}
}
return state;