within...
On 2 October 2013 03:45, Ezequiel Celiz <[email protected]> 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 <[email protected]> > > > 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 <[email protected]> > > > > > 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 <[email protected]> > > > 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 <[email protected]> > > > > > > > > > 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 > > > > > > > > > > > > > > >
