Puhh, very long article.

Did you've tried

MyDomainModel myDomainModel;
CompoundPropertyModel model = new CompoundPropertyModel(myDomainModel);
AContainer.add(new MarkupContainer(new PropertyModel(model, "theGetPropertyInMyDomainModelToSubModel"));

If MyDomainModel provides an accessor for theGetPropertyInMyDomainModelToSubModel you can build the chain.

HTH
Per

g...@gmx.net schrieb:
heyho everyone,

since i'm not satisfied with the provided models, i started to write my own.

the current behaviour with compoundproperty model is, that compoundproperty 
model serves as host for an object and components can use properties of that 
host by having the correct id that has to equal the name of the property.

since wicket is a component-oriented framework, there is a use case that 
happens very often. it is that you have some domain-object that you write an 
edit-form for that allows you to edit the properties of this domain-object. now 
if you want to use this edit-form, you have to give it a model, which would be 
a compoundpropertymodel. every component inside can now use it by having the 
correct id.

suppose our domain-object A is in this case a property of another domain-object 
B: B.A . if i want to use the edit-form like it was supposed to, i would have 
to give it a compoundpropertymodel. this means, i have to get A out of B and 
put it inside a new compoundpropertymodel. but i dont want to do this. i want 
to have exactly one object-hosting model off which every other component can 
look up its needed properties.

i believe i'm doing this for reasons of performance, because i believe that if 
a would have another compoundpropertymodel, there would be more 
serialization-work. besides that i would use detachable-models, which would 
worsen the situation, because A would be loaded twice!

the solution for a single object-hosting compoundpropertymodel would be to 
adapt the component ids in A's editform, which is completely unacceptable 
because it would now depend on the fact, that A is now inside another object. 
what if B was a property of C? or if C in turn was a property of D? or if A was 
standalone. only one use case is covered with this solution. its not acceptable 
for a component oriented framework.

thats why i started to write my own models. there should be an object-hosting 
model and some kind of property-model that can use the hosting model. the 
root-markupcontainer would therefor have such a hosting model which provided B. 
this markup-container would hold A's edit-form as a child and give it such a 
property-model that can access the host-model's object. now the magic thing, 
this property-model in turn would serve as host for A's edit-form. all the 
components in this edit-form in turn would have such property-models again, 
that access the edit-forms modelobject and resolve the desired properties.

therefor i called this property-model InheritedPropertyModel. another, in my 
eyes, advantage is, that if a component doesnt have its own model, it will 
receive the next model up in the component-hierarchy. and because i think this 
is good, i also made the host-model an inheritedmodel and since it is also 
chainable, i called it InheritedChainableModel.

now i tried to implement those two and there is a problem i'm facing. i can't 
traverse through the component-hierarchy to find the right model-object. i need 
this object so i can run the propertyresolver on it. i can only call 
getDefaultModelObject() to find out. and now there is the problem:

imagine the following component hierarchy:
panel->markupcontainer->form->label
InheritedChainingModel->InheritedPropertyModel->nothing->InheritedPropertyModel
B->A->nothing->somePropertyOfA

the label calls getObject(): this.owner.getParent().getDefaultModelObject()
the InheritedPropertyModel knows its owner (IComponentAssignedModel) which is 
the label, calls its parent, which is the form and asks for the default 
model-object. since the form doesnt have a model, it's getDefaultModelObject() 
calls: initModel()
initModel() traverses the component-hierarchy up until it finds the first 
IComponentInheritedModel. it finds it in the markupcontainer and its an 
InheritedPropertyModel. this one now is asked getObject():
this.owner.getParent().getDefaultModelObject()
this one will give the object of the hosting InheritedChainingModel of the 
panel with B in it. now B is given back to the markupcontainer which continues 
its getObject():
(W)PropertyResolver.getValue(this.property, target);
property is "A" and target is B -> A as object is returned to the form which in 
turn continues its getObject():
(W)PropertyResolver.getValue(this.property, target);
since this model is an inherited from markupcontainer, it has the same property which is 
"A", but the target this time is A itself, coming from the markupcontainer.

and this is the problem... when i look at a components model, i dont want it to 
be initialized, i just want to know if there is some IComponentInheritedModel. 
getModelImpl() is the way to go, but it is not visible. getInnermostModel() 
calls getDefaultModel(). i dont have a chance. or can somebody see a solution 
to this? i think there isnt any.

since i'm willing to contribute those two models, i propose to change something 
in the wickets component-code. give me a hasModel(). or give me a public 
getModel(). i would do these changes.

tell me your opinion.

regards
garz

ps: here are the sources of the two models:

public class InheritedPropertyModel<T>
        implements IComponentInheritedModel<T>, IComponentAssignedModel<T> {
        
        private String property;

        public InheritedPropertyModel(String property) {
                if (Strings.isEmpty(property))
                        throw new IllegalArgumentException("Parameter property 
cannot be null or empty");
                this.property = property;
        }
        
        @SuppressWarnings("unchecked")
        @Override
        public <W> IWrapModel<W> wrapOnInheritance(Component component) {
                return (IWrapModel<W>) new AttachedInheritedPropertyModel();
        }

        @Override
        public final T getObject() {
                throw new RuntimeException("get object call not expected on a 
IComponentAssignedModel");
        }

        @Override
        public final void setObject(T object) {
                throw new RuntimeException("set object call not expected on a 
IComponentAssignedModel");
        }

        @Override
        public void detach() {
        }

        @Override
        public IWrapModel<T> wrapOnAssignment(Component component) {
                return new AssignedInheritedPropertyModel<T>(property, 
component);
        }
        
        private class AssignedInheritedPropertyModel<W>
                implements IWrapModel<W> {
                
                private String property;
                private Component owner;
                
                public AssignedInheritedPropertyModel(String property, 
Component owner) {
                        this.property = property;
                        this.owner = owner;
                }

                @Override
                public IModel<?> getWrappedModel() {
                        return InheritedPropertyModel.this;
                }

                @SuppressWarnings("unchecked")
                public W getTarget() {
                        return 
(W)this.owner.getParent().getInnermostModel().getObject();
                }
                
                @SuppressWarnings("unchecked")
                @Override
                public W getObject() {
                        final W target = getTarget();
                        if (target != null)
                        {
                                return 
(W)PropertyResolver.getValue(this.property, target);
                        }
                        return null;
                }

                @Override
                public void setObject(W object) {
                        PropertyResolverConverter prc = null;
                        prc = new 
PropertyResolverConverter(Application.get().getConverterLocator(),
                                Session.get().getLocale());
                        PropertyResolver.setValue(this.property, getTarget(), 
object, prc);
                }

                @Override
                public void detach() {
                        
                }

        }
        
        private class AttachedInheritedPropertyModel
                implements IWrapModel<T> {

                @Override
                public IModel<T> getWrappedModel() {
                        return InheritedPropertyModel.this;
                }

                @Override
                public T getObject() {
                        return InheritedPropertyModel.this.getObject();
                }

                @Override
                public void setObject(T object) {
                        InheritedPropertyModel.this.setObject(object);
                }

                @Override
                public void detach() {
                        InheritedPropertyModel.this.detach();
                }

        }
}

public class InheritedChainingModel<T>
        implements IChainingModel<T>, IComponentInheritedModel<T> {
        
        private Object target;
        
        public InheritedChainingModel(final Object object) {
                this.target = object;
        }

        @Override
        public IModel<?> getChainedModel() {
                if (target instanceof IModel<?>)
                {
                        return (IModel<?>)target;
                }
                return null;
        }

        @Override
        public void setChainedModel(IModel<?> model) {
                target = model;
        }

        @SuppressWarnings("unchecked")
        @Override
        public T getObject() {
                if (target instanceof IModel<?>)
                {
                        return ((IModel<T>)target).getObject();
                }
                return (T)target;
        }

        @SuppressWarnings("unchecked")
        @Override
        public void setObject(T object) {
                if (target instanceof IModel<?>)
                {
                        ((IModel<T>)target).setObject(object);
                }
                else
                {
                        target = object;
                }
        }

        @Override
        public void detach() {
                if (target instanceof IDetachable)
                {
                        ((IDetachable)target).detach();
                }
        }

        @SuppressWarnings("unchecked")
        @Override
        public <W> IWrapModel<W> wrapOnInheritance(Component component) {
                return (IWrapModel<W>) new AttachedInheritedChainingModel();
        }
        
        private class AttachedInheritedChainingModel
                extends AbstractWrapModel<T> {
                
                @Override
                public T getObject() {
                        return InheritedChainingModel.this.getObject();
                }
                
                @Override
                public void setObject(T object) {
                        InheritedChainingModel.this.setObject(object);
                }

                @Override
                public IModel<T> getWrappedModel() {
                        return InheritedChainingModel.this;
                }
                
        }

}

pps: as you can see i dont know how to use the wrapOnInheritance() method if 
IComponentInheritedModel exactly and doing an ugly cast: return (IWrapModel<W>) 
new AttachedInheritedChainingModel();
maybe you have an idea for this too.

thanks


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
For additional commands, e-mail: users-h...@wicket.apache.org

Reply via email to