You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@isis.apache.org by Ezequiel Celiz <el...@gmail.com> on 2013/10/02 04:45:50 UTC

Re: Custom Value Types (VALUE OBJECTS) and the annotation @Value

Hi Dan,

We are still working on the same, I would like you to take a look to the
things that we tried to do to show the object ContactVO with wicket viewer.

We based on the structure of the component BookmarkedPages
(org.apache.isis.viewer.wicket.ui.components.bookmarkedpages)
where you we have the following files:

* BookmarkedPagesPanelFactory.java
* BookmarkedPagesPanel.java
* BookmarkedPagesPanel.html


We've tried to register the component by the way you suggest and the steps
that we follow are this:

we create this files in this location webapp/src/main/java/app

* ContactVOPagePanelFactoryRegistrar.java
* ContactVOPagePanelFactory.java
* ContactVOPagePanel.java
* ContactVOPagePanel.html

Below I'll write you each class in detail:

////////////////////////////////////////////////////
//////ContactoVOPagePanelFactoryRegistrar///////////
////////////////////////////////////////////////////
@Singleton
public class ContactoVOPagePanelFactoryRegistrar extends
ComponentFactoryRegistrarDefault {
@Override
public void addComponentFactories(ComponentFactoryList componentFactories) {
    componentFactories.add(new ContactVOPagePanelFactory());
    super.addComponentFactories(componentFactories);
    }
}

In the class QuickstartApplication.java we make use of this method:

bind(ComponentFactoryRegistrar.class).to(ContactVOPagePanelFactoryRegistrar.class);

////////////////////////////////////////////////////
///////////ContactVOPagePanelFactory///////////////
////////////////////////////////////////////////////

public class ContactVOPagePanelFactory extends ComponentFactoryAbstract {

    private static final long serialVersionUID = 1L;

    public ContactVOPagePanelFactory() {
        super(ComponentType.VALUE);
    }

    @Override
    public ApplicationAdvice appliesTo(final IModel<?> model) {
        return appliesIf(model instanceof ValueModel);
    }

    @Override
    public Component createComponent(final String id, final IModel<?>
model) {
        final ValueModel valueModel = (ValueModel) model;
        return new ContactVOPagePanel(id, valueModel);
    }

}

We believe that the ComponentType that may help us to resolve our problem
is ComponentType.VALUE


////////////////////////////////////////////////////
//////////////////ContactVOPagePanel///////////////
////////////////////////////////////////////////////

public class ContactVOPagePanel extends PanelAbstract<ValueModel> {

private static final String ID_ADDRESS = "address";
private static final String ID_TELEPHONE = "telephone";
private static final String ID_EMAIL = "email";
 private static final long serialVersionUID = 1L;
 public ContactVOPagePanel(String id, ValueModel model) {
super(id, model);
buildGui();
}

private void buildGui() {
 //final ValueModel contactVOPagePanel = getModel();
 final Label address = new Label(ID_ADDRESS,"address of entity");

final Label telephone = new Label(ID_TELEPHONE,"telephone of entity);

final Label email = new Label(ID_EMAIL,getModel().getObject().toString());
 add(address);
add(telephone);
add(email);
 }
}

////////////////////////////////////////////////////
/////////////ContactoVOPagePanel.html///////////////
////////////////////////////////////////////////////

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:wicket="
http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"
      xml:lang="en"
      lang="en">
<body>
<div>
<table border="0">
<tr>
<td>
ADDRESS:
</td>
<td>
<span wicket:id="address"></span>
</td>
</tr>
<tr>
<td>
TELEPHONE:
</td>
<td>
<span wicket:id="telephone"></span>
</td>
</tr>
<tr>
<td>
EMAIL:
</td>
<td>
<span wicket:id="email"></span>
</td>
</tr>
</table>
</div>
</body>
</html>

Well, now some questions:

1) Are we taking the rigth way to succed in our goal?

2)If an entity needs to use a valueObject Contact, we should add the
property: private ContactVO contactVO;
What do we have to do to make the framework realizes that object type must
use the component previously registered?

3)While drawing the Panel, how do we get the information of the object
contactVO in order to be able of upload them in the corresponding Label? Is
this posible by using ObjectAdapter with getModel().getObject()?

Sorry for the extended mail,
regards!


2013/9/18 Luis Parada <lu...@gmail.com>

> Thank you Dan, we are going to work with the wicket viewer, so I will let
> you know later if we get something. Best Regards.-
>
>
> 2013/9/18 Dan Haywood <da...@haywood-associates.co.uk>
>
> > Hi Luis,
> > welcome to the Isis mailing list.
> >
> > But my apols to you and Ezequiel, I somehow dropped the ball and missed
> > this question.
> >
> > To answer some of your question: to get the ContactVO to persist - as you
> > have done - it is sufficient only to make it serializable.  However, if
> you
> > want it to be stored as something other than a blob, you'll need to use
> the
> > JDO APIs (eg as is done for Joda types).
> >
> > Your issue, though, is on the UI side.  And, unfortunately, right now
> Isis
> > doesn't provide an out-of-the-box capability to render composite value
> > objects such as you have defined here.  It most certainly ought to do so,
> > and indeed we have a ticket for something very similar... [1] it just
> isn't
> > implemented, I'm afraid.
> >
> > The EncoderDecoder stuff won't help... that is used by some of the other
> > object stores (eg XML, NoSQL).  But it's irrelevant for Wicket/JDO.
> >
> > The main issue is that the Wicket viewer doesn't "look inside" the
> > structure of your ContactVO in order to build up a suitable UI.  For
> > example, the ContactVO is basically 3 string properties, and you would
> > presumably want 3 fields.  It's just not smart enough to do that.
> >
> > I can offer a possible workaround for you, if you want, which *might*
> work.
> >  The Wicket viewer *is* extensible, and so you could define and register
> > your own ContactVOComponentFactory and have it build up a custom
> > ContactVOComponent (a panel) for rendering the parts of the contact as
> > individual fields.
> >
> > Have a look at ComponentFactoryRegistryDefault and how some of the other
> > ComponentFactorys work - it's basically the chain of responsibility
> > pattern.
> >
> > Or... alternatively you might want to generalize this, in other words
> > implement [1].  Note that [1] uses the AggregatedFacet as the indicator
> on
> > the referenced object that it should be displayed "inline".  If this
> > reference is mapped using JDO's @Embedded, it would also save you the
> > hassle of doing extra JDO datatype mappings.
> >
> > HTH, come back to me if none of the above makes sense...
> >
> > Best
> > Dan
> >
> >
> > [1] https://issues.apache.org/jira/browse/ISIS-348
> >
> >
> >
> >
> >
> >
> >
> > On 18 September 2013 13:26, Luis Parada <lu...@gmail.com>
> > wrote:
> >
> > > Hi, I´m working on this with Ezequiel and we could persist the Contact
> > VO.
> > > The problem is that we can not show the object in the viewer because
> the
> > > object is serialized. We found
> > > the public interface EncoderDecoder<T> {} wich implements this method:
> T
> > > fromEncodedString(String encodedString); so we appreciate any help
> > > explaining us how to use it.
> > >
> > > At this moment we have overrided the methods: protected String
> > > doEncode(final Object object) and protected Contact doRestore(final
> > String
> > > data) of ContactoValueSemanticsProvider but is not working yet.
> > >
> > > protected String doEncode(final Object object) {
> > > final Contacto contacto = (Contacto) object;
> > > final String valor = String.valueOf(contacto.getDomicilio() + "-" +
> > > contacto.getEmail() + "-" + contacto.getTelefono());
> > > return valor;
> > > }
> > >
> > > protected Contacto doRestore(final String data) {
> > > final String[] partes = data.split("-");
> > > final String domicilio = partes[0];
> > > final String correo = partes[1];
> > > final String telefono = partes[2];
> > > return new Contacto(domicilio, correo, telefono);
> > > }
> > > Thank´s.
> > >
> > >
> > > 2013/9/12 Ezequiel Celiz <el...@gmail.com>
> > >
> > > > Hi community
> > > >
> > > > I'm trying to implement the annotation @Value in my application to
> use
> > > the
> > > > "Value Objects" as defined in the concept of DDD .
> > > >
> > > > I had no success : How I can set my class as a genuine Custom Value
> > Type?
> > > > so that it can be used in the entities that require it.
> > > >
> > > > I want to create the classic VO : "Contact" which consists of the
> > > following
> > > > properties ( in my case) :
> > > >
> > > > Address, Telephone and Email.
> > > >
> > > >     @Value ( semanticsProviderName = "
> > > >  ContactValueSemanticsProvider.class " )
> > > >     public class Contact  {
> > > >
> > > >     / *
> > > >     / Need to the builder?
> > > >     /
> > > >     / Public Contact ( String a, String t , String e) {
> > > >     / This.address = a;
> > > >     / This.telephone = t;
> > > >     / This.email = e ;
> > > >     / }
> > > >     /
> > > >     / *
> > > >
> > > >     private String address ;
> > > >
> > > >     public String getAddress ( ) {
> > > >         return address ;
> > > >     }
> > > >
> > > >     public void setAddress (String address) {
> > > >         this.address = address ;
> > > >     }
> > > >
> > > >     private String telephone ;
> > > >
> > > >     getTelephone public String ( ) {
> > > >         return telephone ;
> > > >     }
> > > >
> > > >     public void setTelephone (String telephone) {
> > > >         this.telephone = telephone ;
> > > >     }
> > > >
> > > >     private String email ;
> > > >
> > > >     getEmail public String ( ) {
> > > >         return email ;
> > > >     }
> > > >
> > > >     public void setEmail (String email ) {
> > > >         this.email = email ;
> > > >     }
> > > >
> > > >  }
> > > >
> > > > where ContactValueSemanticsProvider.class :
> > > > public final class ContactValueSemanticsProvider
> > > > extends AbstractValueSemanticsProvider <Conctact> {}
> > > >
> > > > Then I wonder if the entity would have to have an attribute :
> > > >
> > > >     private Contact contact ;
> > > >
> > > >     public GetContact ( ) {
> > > >         return contact ;
> > > >     }
> > > >
> > > > Finally in the service when I creating the entity object :
> > > >
> > > >    SomeEntity public newEntity (
> > > >             @ Optional
> > > >             @ Named ( " Address" ) String address,
> > > >             @ Optional
> > > >             @ Named ( " Telephone" ) String telephone ,
> > > >             @ Optional
> > > >             @ Named ( " email " ) String email
> > > >             ) {
> > > >
> > > >    final Contact contact
> > > >
> > > >             / / The correct way to instantiate is THROUGH
> > > > newTransientInstance ( Contact.class ) ?
> > > >
> > > >             pourContacter (contact) ;
> > > >
> > > >  @ Hidden
> > > >  SomeEntity public pourContacter ( ) (
> > > >             Final Contact Contact
> > > >         ) {
> > > >         SomeEntity end someEntity = newTransientInstance (
> > > SomeEntity.class
> > > > ) ;
> > > >         someEntitity.setContact (contact) ;
> > > >         persistIfNotAlready ( someEntity ) ;
> > > >
> > > >         someEntity return ;
> > > >     }
> > > >
> > > > It is the right way? or the way to work with the Value Object in ISIS
> > is
> > > > another?
> > > >
> > > > I welcome your suggestions
> > > > Thank you very much as always for your attention
> > > > Cheers !
> > > > Ezequiel
> > > >
> > >
> >
>

Re: Custom Value Types (VALUE OBJECTS) and the annotation @Value

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
Hi Ezequiel,
ok, I'll pull this down and try to look at it tonight or tomorrow night.
Cheers
Dan


On 7 October 2013 05:15, Ezequiel Celiz <el...@gmail.com> wrote:

> Hi Dan
>
> I tried everything you suggested but I still can show the component with
> the wicket.
>
> The framework throws an Exception when returning the object from the
> object-store:
>
> org.apache.wicket.WicketRuntimeException: Error attaching this container
> for rendering: [WebMarkupContainer [Component id = 1]]
>
> Caused by: org.apache.isis.core.commons.exceptions.IsisException: Failed to
> create instance of type dom.contact.ContactVO
>
> ...
>
> anyway, I uplouded the example to a github repository.
>
> the repository is: git@github.com: eceliz / apache-isis-VO.git
> and the url: https://github.com/eceliz/apache-isis-VO
>
> It would be important to me that we could work together for printing
> objects of this type
>
> Keep in touch
> regards
> Ezequiel
>
>
> 2013/10/3 Dan Haywood <da...@haywood-associates.co.uk>
>
> > On 3 October 2013 13:43, Ezequiel Celiz <el...@gmail.com> wrote:
> >
> > >
> > >
> > > the method getUnderlyingClass() is not part of
>  getTypeOfSpecification()
> > >
> > >
> > sorry, that should be getCorrespondingClass().
> >
>

Re: Custom Value Types (VALUE OBJECTS) and the annotation @Value

Posted by Ezequiel Celiz <el...@gmail.com>.
Hi Dan

I tried everything you suggested but I still can show the component with
the wicket.

The framework throws an Exception when returning the object from the
object-store:

org.apache.wicket.WicketRuntimeException: Error attaching this container
for rendering: [WebMarkupContainer [Component id = 1]]

Caused by: org.apache.isis.core.commons.exceptions.IsisException: Failed to
create instance of type dom.contact.ContactVO

...

anyway, I uplouded the example to a github repository.

the repository is: git@github.com: eceliz / apache-isis-VO.git
and the url: https://github.com/eceliz/apache-isis-VO

It would be important to me that we could work together for printing
objects of this type

Keep in touch
regards
Ezequiel


2013/10/3 Dan Haywood <da...@haywood-associates.co.uk>

> On 3 October 2013 13:43, Ezequiel Celiz <el...@gmail.com> wrote:
>
> >
> >
> > the method getUnderlyingClass() is not part of  getTypeOfSpecification()
> >
> >
> sorry, that should be getCorrespondingClass().
>

Re: Custom Value Types (VALUE OBJECTS) and the annotation @Value

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
On 3 October 2013 13:43, Ezequiel Celiz <el...@gmail.com> wrote:

>
>
> the method getUnderlyingClass() is not part of  getTypeOfSpecification()
>
>
sorry, that should be getCorrespondingClass().

Re: Custom Value Types (VALUE OBJECTS) and the annotation @Value

Posted by Ezequiel Celiz <el...@gmail.com>.
Hi Dan,

> You haven't said, exactly, what your problem is... ?;

The problem that we have is that we need to show an objecto ValueObject as
a property of an entity and the wicket is no being able to explore it.
In this case, ContactVO have 3 attributes with a String type: Telephone,
Adress, email.


While we were  trying  to work we the solution you gave us I got stuck with
this error:

@Override
    public ApplicationAdvice appliesTo(final IModel<?> model) {
     if (!(model instanceof ScalarModel)) {
            return ApplicationAdvice.DOES_NOT_APPLY;
        }

     final ScalarModel scalarModel = (ScalarModel) model;
        scalarModel.getTypeOfSpecification().
     return
appliesIf(ContactoVO.class.isAssignableFrom(scalarModel.getTypeOfSpecification().getUnderlyingClass());
    }

the method getUnderlyingClass() is not part of  getTypeOfSpecification()


I was searching in the web and it seems to be a method of this class:
com.google.api.client.util.ClassInfo;

But I still can't work on it by the way you suggest...
Hope you can help us to close this implementation.

Regards



2013/10/2 Dan Haywood <da...@haywood-associates.co.uk>

> within...
>
>
> On 2 October 2013 03:45, Ezequiel Celiz <el...@gmail.com> wrote:
>
> >
> > [snip] I would like you to take a look to the
> > things that we tried to do to show the object ContactVO with wicket
> viewer.
> >
> > We based on the structure of the component BookmarkedPages [snip]
> >
> > we create this files in this location webapp/src/main/java/app
> >
> > * ContactVOPagePanelFactoryRegistrar.java
> > * ContactVOPagePanelFactory.java
> > * ContactVOPagePanel.java
> > * ContactVOPagePanel.html
> >
> >
> That looks good so far.
>
>
>
>
>
> > Below I'll write you each class in detail:
> >
> > ////////////////////////////////////////////////////
> > //////ContactoVOPagePanelFactoryRegistrar///////////
> > ////////////////////////////////////////////////////
> > @Singleton
> > public class ContactoVOPagePanelFactoryRegistrar extends
> > ComponentFactoryRegistrarDefault {
> > @Override
> > public void addComponentFactories(ComponentFactoryList
> componentFactories)
> > {
> >     componentFactories.add(new ContactVOPagePanelFactory());
> >     super.addComponentFactories(componentFactories);
> >     }
> > }
> >
> >
> That looks ok.  You possibly want to rename the class to
> "MyAppComponentFactoryRegistrarDefault" because if there were any other
> customisations, they would also be registered here.
>
>
>
> [1]
>
> http://isis.apache.org/components/viewers/wicket/customizing-the-viewer.html
>
>
>
> > In the class QuickstartApplication.java we make use of this method:
> >
> >
> >
> bind(ComponentFactoryRegistrar.class).to(ContactVOPagePanelFactoryRegistrar.class);
> >
> >
> Yup; that's correct.
>
> As an alternative to creating your own custom ComponentFactoryRegistrar,
> you can also register component factories by adding some some metadata in
> META-INF/services; Isis can then (using the ServiceLoader API)
> automatically discover the component just by it being on the classpath.
>  There's some detail about this on [1] (search for the "Additional Views of
> Collections" section).
>
>
>
>
> > ////////////////////////////////////////////////////
> > ///////////ContactVOPagePanelFactory///////////////
> > ////////////////////////////////////////////////////
> >
> > public class ContactVOPagePanelFactory extends ComponentFactoryAbstract {
> >
> >     private static final long serialVersionUID = 1L;
> >
> >     public ContactVOPagePanelFactory() {
> >         super(ComponentType.VALUE);
> >     }
> >
> >     @Override
> >     public ApplicationAdvice appliesTo(final IModel<?> model) {
> >         return appliesIf(model instanceof ValueModel);
> >     }
> >
> >     @Override
> >     public Component createComponent(final String id, final IModel<?>
> > model) {
> >         final ValueModel valueModel = (ValueModel) model;
> >         return new ContactVOPagePanel(id, valueModel);
> >     }
> >
> > }
> >
> >
> Um, I'm not sure what sort of model the ContactVO would get created within.
>  I have a feeling it might be in a ScalarModel rather than a ValueModel.
>
> If that's the case, then your appliesTo method would need to look similar
> to that of ValuePanelFactory.  However, you should also filter to make sure
> that the "payload" of the ScalarModel is of the right type, ie an
> instanceof ContactVO.
>
>     @Override
>     public ApplicationAdvice appliesTo(final IModel<?> model) {
>         if (!(model instanceof ScalarModel)) {
>             return ApplicationAdvice.DOES_NOT_APPLY;
>         }
>         final ScalarModel scalarModel = (ScalarModel) model;
>         return
>
> appliesIf(ContactVO.class.isAssignableFrom(scalarModel.getTypeOfSpecification().getUnderlyingClass());
>     }
>
>
> But I might be wrong about this; it is possible that your ContactVO is
> wrapped up in a ValueModel?  In which case the code would still need to
> check the type of the object held within the (value) model.
>
>
>
>
> > We believe that the ComponentType that may help us to resolve our problem
> > is ComponentType.VALUE
> >
> >
> You haven't said, exactly, what your problem is... ?
>
>
>
> > ////////////////////////////////////////////////////
> > //////////////////ContactVOPagePanel///////////////
> > ////////////////////////////////////////////////////
> >
> > public class ContactVOPagePanel extends PanelAbstract<ValueModel> {
> >
> > private static final String ID_ADDRESS = "address";
> > private static final String ID_TELEPHONE = "telephone";
> > private static final String ID_EMAIL = "email";
> >  private static final long serialVersionUID = 1L;
> >  public ContactVOPagePanel(String id, ValueModel model) {
> > super(id, model);
> > buildGui();
> > }
> >
> > private void buildGui() {
> >  //final ValueModel contactVOPagePanel = getModel();
> >  final Label address = new Label(ID_ADDRESS,"address of entity");
> >
> > final Label telephone = new Label(ID_TELEPHONE,"telephone of entity);
> >
> > final Label email = new
> Label(ID_EMAIL,getModel().getObject().toString());
> >  add(address);
> > add(telephone);
> > add(email);
> >  }
> > }
> >
> >
>
> That creates labels, but I suspect you will want to render label/forms.
>  The EntityPropertiesForm#addPropertyInColumn(...) method shows how I use
> the:
>
> getComponentFactoryRegistry().addOrReplaceComponent(container, ID_PROPERTY,
> ComponentType.SCALAR_NAME_AND_VALUE, scalarModel);
>
> to create a component to add for each name/value of an entity.  I think you
> might want to do something similar.
>
>
>
>
> > ////////////////////////////////////////////////////
> > /////////////ContactoVOPagePanel.html///////////////
> > ////////////////////////////////////////////////////
> >
> > <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "
> > http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
> > <html xmlns="http://www.w3.org/1999/xhtml"
> >       xmlns:wicket="
> > http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"
> >       xml:lang="en"
> >       lang="en">
> > <body>
> > <div>
> > <table border="0">
> > <tr>
> > <td>
> > ADDRESS:
> > </td>
> > <td>
> > <span wicket:id="address"></span>
> > </td>
> > </tr>
> > <tr>
> > <td>
> > TELEPHONE:
> > </td>
> > <td>
> > <span wicket:id="telephone"></span>
> > </td>
> > </tr>
> > <tr>
> > <td>
> > EMAIL:
> > </td>
> > <td>
> > <span wicket:id="email"></span>
> > </td>
> > </tr>
> > </table>
> > </div>
> > </body>
> > </html>
> >
> >
>
> In which case, the code here would be similar to the markup in
> EntityPropertiesForm.html:
>
>                  <div class="inputFormTable properties">
>                      <fieldset wicket:id="memberGroup" class="memberGroup
> myBlockContainer">
>                      <legend wicket:id="memberGroupName">[group
> name]</legend>
>                  <div wicket:id="properties">
>                           <div wicket:id="property"
> class="property">[property]</div>
>                  </div>
>                  </fieldset>
>                  </div>
>
>
>
>
> > Well, now some questions:
> >
> > 1) Are we taking the rigth way to succed in our goal?
> >
> >
> Definitely "on the way".
>
>
>
> > 2)If an entity needs to use a valueObject Contact, we should add the
> > property: private ContactVO contactVO;
> > What do we have to do to make the framework realizes that object type
> must
> > use the component previously registered?
> >
> >
> This is the appliesTo method.  I suggest you put a conditional break point
> in one of the existing component factories (eg ValuePanelFactory,
> StandaloneValuePanelFactory) to see what model the framework gives you.
>
>
>
>
> > 3)While drawing the Panel, how do we get the information of the object
> > contactVO in order to be able of upload them in the corresponding Label?
> Is
> > this posible by using ObjectAdapter with getModel().getObject()?
> >
> >
> Yep, the contactVO pojo will be wrapped in an ObjectAdapter, from whence
> you can get to the rest of the Isis metamodel (ObjectSpecification).
>  ObjectAdapter corresponds to java.lang.Object, ObjectSpecification
> corresponds to java.lang.Class.
>
>
>
>
> > Sorry for the extended mail,
> >
>
> No worries.  As I was writing this reply, I was wondering myself how
> feasible this is.  It is possible that you might hit a showstopper
> somewhere, or I might need to dig into things a little myself.  If you want
> to create a sample application up on github, then we could work on it
> together.
>
> Cheers
> Dan
>
>
>
>
> > regards!
> >
> >
> > 2013/9/18 Luis Parada <lu...@gmail.com>
> >
> > > Thank you Dan, we are going to work with the wicket viewer, so I will
> let
> > > you know later if we get something. Best Regards.-
> > >
> > >
> > > 2013/9/18 Dan Haywood <da...@haywood-associates.co.uk>
> > >
> > > > Hi Luis,
> > > > welcome to the Isis mailing list.
> > > >
> > > > But my apols to you and Ezequiel, I somehow dropped the ball and
> missed
> > > > this question.
> > > >
> > > > To answer some of your question: to get the ContactVO to persist - as
> > you
> > > > have done - it is sufficient only to make it serializable.  However,
> if
> > > you
> > > > want it to be stored as something other than a blob, you'll need to
> use
> > > the
> > > > JDO APIs (eg as is done for Joda types).
> > > >
> > > > Your issue, though, is on the UI side.  And, unfortunately, right now
> > > Isis
> > > > doesn't provide an out-of-the-box capability to render composite
> value
> > > > objects such as you have defined here.  It most certainly ought to do
> > so,
> > > > and indeed we have a ticket for something very similar... [1] it just
> > > isn't
> > > > implemented, I'm afraid.
> > > >
> > > > The EncoderDecoder stuff won't help... that is used by some of the
> > other
> > > > object stores (eg XML, NoSQL).  But it's irrelevant for Wicket/JDO.
> > > >
> > > > The main issue is that the Wicket viewer doesn't "look inside" the
> > > > structure of your ContactVO in order to build up a suitable UI.  For
> > > > example, the ContactVO is basically 3 string properties, and you
> would
> > > > presumably want 3 fields.  It's just not smart enough to do that.
> > > >
> > > > I can offer a possible workaround for you, if you want, which *might*
> > > work.
> > > >  The Wicket viewer *is* extensible, and so you could define and
> > register
> > > > your own ContactVOComponentFactory and have it build up a custom
> > > > ContactVOComponent (a panel) for rendering the parts of the contact
> as
> > > > individual fields.
> > > >
> > > > Have a look at ComponentFactoryRegistryDefault and how some of the
> > other
> > > > ComponentFactorys work - it's basically the chain of responsibility
> > > > pattern.
> > > >
> > > > Or... alternatively you might want to generalize this, in other words
> > > > implement [1].  Note that [1] uses the AggregatedFacet as the
> indicator
> > > on
> > > > the referenced object that it should be displayed "inline".  If this
> > > > reference is mapped using JDO's @Embedded, it would also save you the
> > > > hassle of doing extra JDO datatype mappings.
> > > >
> > > > HTH, come back to me if none of the above makes sense...
> > > >
> > > > Best
> > > > Dan
> > > >
> > > >
> > > > [1] https://issues.apache.org/jira/browse/ISIS-348
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > > On 18 September 2013 13:26, Luis Parada <lu...@gmail.com>
> > > > wrote:
> > > >
> > > > > Hi, I´m working on this with Ezequiel and we could persist the
> > Contact
> > > > VO.
> > > > > The problem is that we can not show the object in the viewer
> because
> > > the
> > > > > object is serialized. We found
> > > > > the public interface EncoderDecoder<T> {} wich implements this
> > method:
> > > T
> > > > > fromEncodedString(String encodedString); so we appreciate any help
> > > > > explaining us how to use it.
> > > > >
> > > > > At this moment we have overrided the methods: protected String
> > > > > doEncode(final Object object) and protected Contact doRestore(final
> > > > String
> > > > > data) of ContactoValueSemanticsProvider but is not working yet.
> > > > >
> > > > > protected String doEncode(final Object object) {
> > > > > final Contacto contacto = (Contacto) object;
> > > > > final String valor = String.valueOf(contacto.getDomicilio() + "-" +
> > > > > contacto.getEmail() + "-" + contacto.getTelefono());
> > > > > return valor;
> > > > > }
> > > > >
> > > > > protected Contacto doRestore(final String data) {
> > > > > final String[] partes = data.split("-");
> > > > > final String domicilio = partes[0];
> > > > > final String correo = partes[1];
> > > > > final String telefono = partes[2];
> > > > > return new Contacto(domicilio, correo, telefono);
> > > > > }
> > > > > Thank´s.
> > > > >
> > > > >
> > > > > 2013/9/12 Ezequiel Celiz <el...@gmail.com>
> > > > >
> > > > > > Hi community
> > > > > >
> > > > > > I'm trying to implement the annotation @Value in my application
> to
> > > use
> > > > > the
> > > > > > "Value Objects" as defined in the concept of DDD .
> > > > > >
> > > > > > I had no success : How I can set my class as a genuine Custom
> Value
> > > > Type?
> > > > > > so that it can be used in the entities that require it.
> > > > > >
> > > > > > I want to create the classic VO : "Contact" which consists of the
> > > > > following
> > > > > > properties ( in my case) :
> > > > > >
> > > > > > Address, Telephone and Email.
> > > > > >
> > > > > >     @Value ( semanticsProviderName = "
> > > > > >  ContactValueSemanticsProvider.class " )
> > > > > >     public class Contact  {
> > > > > >
> > > > > >     / *
> > > > > >     / Need to the builder?
> > > > > >     /
> > > > > >     / Public Contact ( String a, String t , String e) {
> > > > > >     / This.address = a;
> > > > > >     / This.telephone = t;
> > > > > >     / This.email = e ;
> > > > > >     / }
> > > > > >     /
> > > > > >     / *
> > > > > >
> > > > > >     private String address ;
> > > > > >
> > > > > >     public String getAddress ( ) {
> > > > > >         return address ;
> > > > > >     }
> > > > > >
> > > > > >     public void setAddress (String address) {
> > > > > >         this.address = address ;
> > > > > >     }
> > > > > >
> > > > > >     private String telephone ;
> > > > > >
> > > > > >     getTelephone public String ( ) {
> > > > > >         return telephone ;
> > > > > >     }
> > > > > >
> > > > > >     public void setTelephone (String telephone) {
> > > > > >         this.telephone = telephone ;
> > > > > >     }
> > > > > >
> > > > > >     private String email ;
> > > > > >
> > > > > >     getEmail public String ( ) {
> > > > > >         return email ;
> > > > > >     }
> > > > > >
> > > > > >     public void setEmail (String email ) {
> > > > > >         this.email = email ;
> > > > > >     }
> > > > > >
> > > > > >  }
> > > > > >
> > > > > > where ContactValueSemanticsProvider.class :
> > > > > > public final class ContactValueSemanticsProvider
> > > > > > extends AbstractValueSemanticsProvider <Conctact> {}
> > > > > >
> > > > > > Then I wonder if the entity would have to have an attribute :
> > > > > >
> > > > > >     private Contact contact ;
> > > > > >
> > > > > >     public GetContact ( ) {
> > > > > >         return contact ;
> > > > > >     }
> > > > > >
> > > > > > Finally in the service when I creating the entity object :
> > > > > >
> > > > > >    SomeEntity public newEntity (
> > > > > >             @ Optional
> > > > > >             @ Named ( " Address" ) String address,
> > > > > >             @ Optional
> > > > > >             @ Named ( " Telephone" ) String telephone ,
> > > > > >             @ Optional
> > > > > >             @ Named ( " email " ) String email
> > > > > >             ) {
> > > > > >
> > > > > >    final Contact contact
> > > > > >
> > > > > >             / / The correct way to instantiate is THROUGH
> > > > > > newTransientInstance ( Contact.class ) ?
> > > > > >
> > > > > >             pourContacter (contact) ;
> > > > > >
> > > > > >  @ Hidden
> > > > > >  SomeEntity public pourContacter ( ) (
> > > > > >             Final Contact Contact
> > > > > >         ) {
> > > > > >         SomeEntity end someEntity = newTransientInstance (
> > > > > SomeEntity.class
> > > > > > ) ;
> > > > > >         someEntitity.setContact (contact) ;
> > > > > >         persistIfNotAlready ( someEntity ) ;
> > > > > >
> > > > > >         someEntity return ;
> > > > > >     }
> > > > > >
> > > > > > It is the right way? or the way to work with the Value Object in
> > ISIS
> > > > is
> > > > > > another?
> > > > > >
> > > > > > I welcome your suggestions
> > > > > > Thank you very much as always for your attention
> > > > > > Cheers !
> > > > > > Ezequiel
> > > > > >
> > > > >
> > > >
> > >
> >
>

Re: Custom Value Types (VALUE OBJECTS) and the annotation @Value

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
within...


On 2 October 2013 03:45, Ezequiel Celiz <el...@gmail.com> wrote:

>
> [snip] I would like you to take a look to the
> things that we tried to do to show the object ContactVO with wicket viewer.
>
> We based on the structure of the component BookmarkedPages [snip]
>
> we create this files in this location webapp/src/main/java/app
>
> * ContactVOPagePanelFactoryRegistrar.java
> * ContactVOPagePanelFactory.java
> * ContactVOPagePanel.java
> * ContactVOPagePanel.html
>
>
That looks good so far.





> Below I'll write you each class in detail:
>
> ////////////////////////////////////////////////////
> //////ContactoVOPagePanelFactoryRegistrar///////////
> ////////////////////////////////////////////////////
> @Singleton
> public class ContactoVOPagePanelFactoryRegistrar extends
> ComponentFactoryRegistrarDefault {
> @Override
> public void addComponentFactories(ComponentFactoryList componentFactories)
> {
>     componentFactories.add(new ContactVOPagePanelFactory());
>     super.addComponentFactories(componentFactories);
>     }
> }
>
>
That looks ok.  You possibly want to rename the class to
"MyAppComponentFactoryRegistrarDefault" because if there were any other
customisations, they would also be registered here.



[1]
http://isis.apache.org/components/viewers/wicket/customizing-the-viewer.html



> In the class QuickstartApplication.java we make use of this method:
>
>
> bind(ComponentFactoryRegistrar.class).to(ContactVOPagePanelFactoryRegistrar.class);
>
>
Yup; that's correct.

As an alternative to creating your own custom ComponentFactoryRegistrar,
you can also register component factories by adding some some metadata in
META-INF/services; Isis can then (using the ServiceLoader API)
automatically discover the component just by it being on the classpath.
 There's some detail about this on [1] (search for the "Additional Views of
Collections" section).




> ////////////////////////////////////////////////////
> ///////////ContactVOPagePanelFactory///////////////
> ////////////////////////////////////////////////////
>
> public class ContactVOPagePanelFactory extends ComponentFactoryAbstract {
>
>     private static final long serialVersionUID = 1L;
>
>     public ContactVOPagePanelFactory() {
>         super(ComponentType.VALUE);
>     }
>
>     @Override
>     public ApplicationAdvice appliesTo(final IModel<?> model) {
>         return appliesIf(model instanceof ValueModel);
>     }
>
>     @Override
>     public Component createComponent(final String id, final IModel<?>
> model) {
>         final ValueModel valueModel = (ValueModel) model;
>         return new ContactVOPagePanel(id, valueModel);
>     }
>
> }
>
>
Um, I'm not sure what sort of model the ContactVO would get created within.
 I have a feeling it might be in a ScalarModel rather than a ValueModel.

If that's the case, then your appliesTo method would need to look similar
to that of ValuePanelFactory.  However, you should also filter to make sure
that the "payload" of the ScalarModel is of the right type, ie an
instanceof ContactVO.

    @Override
    public ApplicationAdvice appliesTo(final IModel<?> model) {
        if (!(model instanceof ScalarModel)) {
            return ApplicationAdvice.DOES_NOT_APPLY;
        }
        final ScalarModel scalarModel = (ScalarModel) model;
        return
appliesIf(ContactVO.class.isAssignableFrom(scalarModel.getTypeOfSpecification().getUnderlyingClass());
    }


But I might be wrong about this; it is possible that your ContactVO is
wrapped up in a ValueModel?  In which case the code would still need to
check the type of the object held within the (value) model.




> We believe that the ComponentType that may help us to resolve our problem
> is ComponentType.VALUE
>
>
You haven't said, exactly, what your problem is... ?



> ////////////////////////////////////////////////////
> //////////////////ContactVOPagePanel///////////////
> ////////////////////////////////////////////////////
>
> public class ContactVOPagePanel extends PanelAbstract<ValueModel> {
>
> private static final String ID_ADDRESS = "address";
> private static final String ID_TELEPHONE = "telephone";
> private static final String ID_EMAIL = "email";
>  private static final long serialVersionUID = 1L;
>  public ContactVOPagePanel(String id, ValueModel model) {
> super(id, model);
> buildGui();
> }
>
> private void buildGui() {
>  //final ValueModel contactVOPagePanel = getModel();
>  final Label address = new Label(ID_ADDRESS,"address of entity");
>
> final Label telephone = new Label(ID_TELEPHONE,"telephone of entity);
>
> final Label email = new Label(ID_EMAIL,getModel().getObject().toString());
>  add(address);
> add(telephone);
> add(email);
>  }
> }
>
>

That creates labels, but I suspect you will want to render label/forms.
 The EntityPropertiesForm#addPropertyInColumn(...) method shows how I use
the:

getComponentFactoryRegistry().addOrReplaceComponent(container, ID_PROPERTY,
ComponentType.SCALAR_NAME_AND_VALUE, scalarModel);

to create a component to add for each name/value of an entity.  I think you
might want to do something similar.




> ////////////////////////////////////////////////////
> /////////////ContactoVOPagePanel.html///////////////
> ////////////////////////////////////////////////////
>
> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "
> http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
> <html xmlns="http://www.w3.org/1999/xhtml"
>       xmlns:wicket="
> http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"
>       xml:lang="en"
>       lang="en">
> <body>
> <div>
> <table border="0">
> <tr>
> <td>
> ADDRESS:
> </td>
> <td>
> <span wicket:id="address"></span>
> </td>
> </tr>
> <tr>
> <td>
> TELEPHONE:
> </td>
> <td>
> <span wicket:id="telephone"></span>
> </td>
> </tr>
> <tr>
> <td>
> EMAIL:
> </td>
> <td>
> <span wicket:id="email"></span>
> </td>
> </tr>
> </table>
> </div>
> </body>
> </html>
>
>

In which case, the code here would be similar to the markup in
EntityPropertiesForm.html:

                 <div class="inputFormTable properties">
                     <fieldset wicket:id="memberGroup" class="memberGroup
myBlockContainer">
                     <legend wicket:id="memberGroupName">[group
name]</legend>
                 <div wicket:id="properties">
                          <div wicket:id="property"
class="property">[property]</div>
                 </div>
                 </fieldset>
                 </div>




> Well, now some questions:
>
> 1) Are we taking the rigth way to succed in our goal?
>
>
Definitely "on the way".



> 2)If an entity needs to use a valueObject Contact, we should add the
> property: private ContactVO contactVO;
> What do we have to do to make the framework realizes that object type must
> use the component previously registered?
>
>
This is the appliesTo method.  I suggest you put a conditional break point
in one of the existing component factories (eg ValuePanelFactory,
StandaloneValuePanelFactory) to see what model the framework gives you.




> 3)While drawing the Panel, how do we get the information of the object
> contactVO in order to be able of upload them in the corresponding Label? Is
> this posible by using ObjectAdapter with getModel().getObject()?
>
>
Yep, the contactVO pojo will be wrapped in an ObjectAdapter, from whence
you can get to the rest of the Isis metamodel (ObjectSpecification).
 ObjectAdapter corresponds to java.lang.Object, ObjectSpecification
corresponds to java.lang.Class.




> Sorry for the extended mail,
>

No worries.  As I was writing this reply, I was wondering myself how
feasible this is.  It is possible that you might hit a showstopper
somewhere, or I might need to dig into things a little myself.  If you want
to create a sample application up on github, then we could work on it
together.

Cheers
Dan




> regards!
>
>
> 2013/9/18 Luis Parada <lu...@gmail.com>
>
> > Thank you Dan, we are going to work with the wicket viewer, so I will let
> > you know later if we get something. Best Regards.-
> >
> >
> > 2013/9/18 Dan Haywood <da...@haywood-associates.co.uk>
> >
> > > Hi Luis,
> > > welcome to the Isis mailing list.
> > >
> > > But my apols to you and Ezequiel, I somehow dropped the ball and missed
> > > this question.
> > >
> > > To answer some of your question: to get the ContactVO to persist - as
> you
> > > have done - it is sufficient only to make it serializable.  However, if
> > you
> > > want it to be stored as something other than a blob, you'll need to use
> > the
> > > JDO APIs (eg as is done for Joda types).
> > >
> > > Your issue, though, is on the UI side.  And, unfortunately, right now
> > Isis
> > > doesn't provide an out-of-the-box capability to render composite value
> > > objects such as you have defined here.  It most certainly ought to do
> so,
> > > and indeed we have a ticket for something very similar... [1] it just
> > isn't
> > > implemented, I'm afraid.
> > >
> > > The EncoderDecoder stuff won't help... that is used by some of the
> other
> > > object stores (eg XML, NoSQL).  But it's irrelevant for Wicket/JDO.
> > >
> > > The main issue is that the Wicket viewer doesn't "look inside" the
> > > structure of your ContactVO in order to build up a suitable UI.  For
> > > example, the ContactVO is basically 3 string properties, and you would
> > > presumably want 3 fields.  It's just not smart enough to do that.
> > >
> > > I can offer a possible workaround for you, if you want, which *might*
> > work.
> > >  The Wicket viewer *is* extensible, and so you could define and
> register
> > > your own ContactVOComponentFactory and have it build up a custom
> > > ContactVOComponent (a panel) for rendering the parts of the contact as
> > > individual fields.
> > >
> > > Have a look at ComponentFactoryRegistryDefault and how some of the
> other
> > > ComponentFactorys work - it's basically the chain of responsibility
> > > pattern.
> > >
> > > Or... alternatively you might want to generalize this, in other words
> > > implement [1].  Note that [1] uses the AggregatedFacet as the indicator
> > on
> > > the referenced object that it should be displayed "inline".  If this
> > > reference is mapped using JDO's @Embedded, it would also save you the
> > > hassle of doing extra JDO datatype mappings.
> > >
> > > HTH, come back to me if none of the above makes sense...
> > >
> > > Best
> > > Dan
> > >
> > >
> > > [1] https://issues.apache.org/jira/browse/ISIS-348
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > > On 18 September 2013 13:26, Luis Parada <lu...@gmail.com>
> > > wrote:
> > >
> > > > Hi, I´m working on this with Ezequiel and we could persist the
> Contact
> > > VO.
> > > > The problem is that we can not show the object in the viewer because
> > the
> > > > object is serialized. We found
> > > > the public interface EncoderDecoder<T> {} wich implements this
> method:
> > T
> > > > fromEncodedString(String encodedString); so we appreciate any help
> > > > explaining us how to use it.
> > > >
> > > > At this moment we have overrided the methods: protected String
> > > > doEncode(final Object object) and protected Contact doRestore(final
> > > String
> > > > data) of ContactoValueSemanticsProvider but is not working yet.
> > > >
> > > > protected String doEncode(final Object object) {
> > > > final Contacto contacto = (Contacto) object;
> > > > final String valor = String.valueOf(contacto.getDomicilio() + "-" +
> > > > contacto.getEmail() + "-" + contacto.getTelefono());
> > > > return valor;
> > > > }
> > > >
> > > > protected Contacto doRestore(final String data) {
> > > > final String[] partes = data.split("-");
> > > > final String domicilio = partes[0];
> > > > final String correo = partes[1];
> > > > final String telefono = partes[2];
> > > > return new Contacto(domicilio, correo, telefono);
> > > > }
> > > > Thank´s.
> > > >
> > > >
> > > > 2013/9/12 Ezequiel Celiz <el...@gmail.com>
> > > >
> > > > > Hi community
> > > > >
> > > > > I'm trying to implement the annotation @Value in my application to
> > use
> > > > the
> > > > > "Value Objects" as defined in the concept of DDD .
> > > > >
> > > > > I had no success : How I can set my class as a genuine Custom Value
> > > Type?
> > > > > so that it can be used in the entities that require it.
> > > > >
> > > > > I want to create the classic VO : "Contact" which consists of the
> > > > following
> > > > > properties ( in my case) :
> > > > >
> > > > > Address, Telephone and Email.
> > > > >
> > > > >     @Value ( semanticsProviderName = "
> > > > >  ContactValueSemanticsProvider.class " )
> > > > >     public class Contact  {
> > > > >
> > > > >     / *
> > > > >     / Need to the builder?
> > > > >     /
> > > > >     / Public Contact ( String a, String t , String e) {
> > > > >     / This.address = a;
> > > > >     / This.telephone = t;
> > > > >     / This.email = e ;
> > > > >     / }
> > > > >     /
> > > > >     / *
> > > > >
> > > > >     private String address ;
> > > > >
> > > > >     public String getAddress ( ) {
> > > > >         return address ;
> > > > >     }
> > > > >
> > > > >     public void setAddress (String address) {
> > > > >         this.address = address ;
> > > > >     }
> > > > >
> > > > >     private String telephone ;
> > > > >
> > > > >     getTelephone public String ( ) {
> > > > >         return telephone ;
> > > > >     }
> > > > >
> > > > >     public void setTelephone (String telephone) {
> > > > >         this.telephone = telephone ;
> > > > >     }
> > > > >
> > > > >     private String email ;
> > > > >
> > > > >     getEmail public String ( ) {
> > > > >         return email ;
> > > > >     }
> > > > >
> > > > >     public void setEmail (String email ) {
> > > > >         this.email = email ;
> > > > >     }
> > > > >
> > > > >  }
> > > > >
> > > > > where ContactValueSemanticsProvider.class :
> > > > > public final class ContactValueSemanticsProvider
> > > > > extends AbstractValueSemanticsProvider <Conctact> {}
> > > > >
> > > > > Then I wonder if the entity would have to have an attribute :
> > > > >
> > > > >     private Contact contact ;
> > > > >
> > > > >     public GetContact ( ) {
> > > > >         return contact ;
> > > > >     }
> > > > >
> > > > > Finally in the service when I creating the entity object :
> > > > >
> > > > >    SomeEntity public newEntity (
> > > > >             @ Optional
> > > > >             @ Named ( " Address" ) String address,
> > > > >             @ Optional
> > > > >             @ Named ( " Telephone" ) String telephone ,
> > > > >             @ Optional
> > > > >             @ Named ( " email " ) String email
> > > > >             ) {
> > > > >
> > > > >    final Contact contact
> > > > >
> > > > >             / / The correct way to instantiate is THROUGH
> > > > > newTransientInstance ( Contact.class ) ?
> > > > >
> > > > >             pourContacter (contact) ;
> > > > >
> > > > >  @ Hidden
> > > > >  SomeEntity public pourContacter ( ) (
> > > > >             Final Contact Contact
> > > > >         ) {
> > > > >         SomeEntity end someEntity = newTransientInstance (
> > > > SomeEntity.class
> > > > > ) ;
> > > > >         someEntitity.setContact (contact) ;
> > > > >         persistIfNotAlready ( someEntity ) ;
> > > > >
> > > > >         someEntity return ;
> > > > >     }
> > > > >
> > > > > It is the right way? or the way to work with the Value Object in
> ISIS
> > > is
> > > > > another?
> > > > >
> > > > > I welcome your suggestions
> > > > > Thank you very much as always for your attention
> > > > > Cheers !
> > > > > Ezequiel
> > > > >
> > > >
> > >
> >
>