Hi Oscar,
Thanks for sharing that - looks like a very flexible system you have built. 
Cheers,David.

     On Tuesday, 28 July 2015 9:24 PM, GESCONSULTOR - Óscar Bou 
<[email protected]> wrote:
   

 Hi to all.
I have a domain implemented in Apache Isis with some similarities.
In our case, we have Item entities with a LOT of custom options that can be 
defined over them (ItemOption).Those ItemOption’s are grouped in 
ItemOptionGroup’s, that can be reused by different Item’s.
ItemOptions can be of different kinds. Currently implemented ones:- 
GenericItemOptionWithChoices- GenericItemOptionsForDate- 
GenericItemOptionsForNumber- GenericItemOptionsForText



Also, one Item can have SubItems (which are other Item that must be bought 
together - and that can also contain its own ItemOption’s -).

There’s also an Order entity where users can order specific Product 
configurations. so when placing the Order you must concrete which Product 
options you want.
The Ordered Item Options, etc. have custom "compareTo” and “title” methods to 
properly show selected values.

Current entities are similar to this:
**** ITEM-RELATED ENTITIES ****


@PersistenceCapable
public abstract class ItemOption extends AbstractMultiTenantEntity {

…@PersistenceCapable@XMSEntityNames({ @XMSEntityName(locale = "es", name = 
"Grupo de Opciones de Artículo") })
public abstract class ItemOptionsGroup extends AbstractMultiTenantEntity {

    // {{ Options (Collection)
    @Persistent(mappedBy = "itemOptionGroup", dependentElement = "true")
    private SortedSet<ItemOptionGroupOption> options = new 
TreeSet<ItemOptionGroupOption>();

...
    // }}

}
@PersistenceCapablepublic class ItemOptionGroupOption extends 
AbstractMultiTenantUnnamedEntity {
    // {{ ItemOptionsGroup (property)    private ItemOptionsGroup 
itemOptionsGroup;
...    // }}
    // {{ ItemOption (property)    private ItemOption itemOption;
   ...    // }}
    // {{ OrderingCode (property)    private String orderingCode;
…
    // }}



@PersistenceCapable
@XMSEntityNames({ @XMSEntityName(locale = "es", name = "Artículo") })
public abstract class Item extends AbstractMultiTenantEntity {

    // {{ OptionGroup (property)
    private ItemOptionsGroup optionsGroup;

...


    // }}

    // {{ SubItems (Collection)
    @Persistent(mappedBy = "parentItem", dependentElement = "true")
    private SortedSet<SubItem> subItems = new TreeSet<SubItem>();

   …
    // }}




**** ORDER-RELATED ENTITIES ****
@PersistenceCapable
public abstract class Order extends AbstractMultiTenantUnnamedEntity {

    // {{ ItemsOrdered (Collection)
    @Persistent(mappedBy = "order", dependentElement = "true")
    private SortedSet<OrderedItem> itemsOrdered = new TreeSet<OrderedItem>();

   ...

    // {{ addItem (action)
    @ActionSemantics(Of.SAFE)
    @MemberOrder(name = "itemsOrdered", sequence = "010")
    public abstract OrderedItem addItem(@XMSActionField(locales = { 
@XMSLocale(locale = "es", caption = "Artículo") }) @Named("Item") final Item 
item, @XMSActionField(locales = { @XMSLocale(locale = "es", caption = 
"Unidades") }) @Named("Units") final BigDecimal units,
            @XMSActionField(locales = { @XMSLocale(locale = "es", caption = 
"Descripción") }) @Named("Description") @Optional final String description);

    protected <T extends OrderedItem> T createPersistentOrderedItem(final 
Class<T> clazz, final Item item, final BigDecimal amount, final String 
description) {

        T orderedItem = 
this.getDomainFactoryService().newTransientMultiTenantUnnamedEntity(clazz, 
null, description);

        this.wrapSkipRules(orderedItem).setOrder(this);
        this.wrap(orderedItem).setQuantity(amount);
        this.wrap(orderedItem).setDescription(description);

        orderedItem = this.onInitializeTransientOrderedItem(orderedItem);

        // This setter invokation will persist the Entity, as it will also
        // insert on dependant entities if there are Options or Sub-Items.
        this.wrapSkipRules(orderedItem).setItem(item);

        // if no Options or SubItems present ...
        this.persistIfNotAlready(orderedItem);

        return orderedItem;

    }


————
@PersistenceCapable
public abstract class OrderedItem extends AbstractMultiTenantUnnamedEntity {

    // {{ Options (Collection)
    @Persistent(mappedBy = "orderedItem", dependentElement = "true")
    private SortedSet<OrderedItemOption> options = new 
TreeSet<OrderedItemOption>();

 ….

    private void configureOptions(final Item newItem) {

        // Clear previously existing options.
        this.clearOptions();

        // Create new ones.
        if ((newItem != null) && (newItem.getOptionsGroup() != null)) {
            for (final ItemOptionGroupOption current : 
this.getItem().getOptionsGroup().getOptions()) {
                final Class<? extends OrderedItemOption> clazz1 = 
this.orderedItemOptionsEquivalences.orderedItemOptionClassFor(current.getItemOption().getClass());
                final OrderedItemOption orderedItemOption = 
(this.getDomainFactoryService()).newTransientMultiTenantUnnamedEntity(clazz1, 
null, null);

                this.wrapSkipRules(orderedItemOption).setOrderedItem(this);
                this.wrapSkipRules(orderedItemOption).setGroupOption(current);

                this.persist(orderedItemOption);

            }
        }
    }

    private void clearOptions() {
        final Set<OrderedItemOption> copySet = 
Sets.newHashSet(this.getOptions());
        for (final OrderedItemOption current : copySet) {
            this.getOptions().remove(current);
            this.getContainer().flush();
        }
    }
————
@PersistenceCapable
@XMSEntityNames({ @XMSEntityName(locale = "es", name = "Artículo Principal del 
Pedido") })
public class OrderedMainItem extends OrderedItem {

…}
————

@PersistenceCapable
public class OrderedSubItem extends OrderedItem {

    // {{ SubItem (property)
    private SubItem subItem;

…
}
————

@PersistenceCapable@XMSEntityNames({ @XMSEntityName(locale = "es", name = 
"Opción de Artículo del Pedido") })public abstract class OrderedItemOption 
extends AbstractMultiTenantUnnamedEntity {
    // {{ OrderedItem (property)    private OrderedItem orderedItem;
…
    // }}
    // {{ ItemOptionGroupOption (property)    private ItemOptionGroupOption 
groupOption;


——

And after that some specialized classes for the different types of ItemOption 
the app manages:
@PersistenceCapable@XMSEntityNames({ @XMSEntityName(locale = "es", name = 
"Opción con Elección del Artículo del Pedido Genérico") })public class 
GenericOrderedItemOptionWithChoices extends OrderedItemOption {
    // {{ ChoiceSelected (property)    private 
GenericItemOptionWithChoicesChoice choiceSelected;

…}
@PersistenceCapable@XMSEntityNames({ @XMSEntityName(locale = "es", name = 
"Opción con Fecha del Artículo del Pedido Genérico") })public class 
GenericOrderedItemOptionWithDate extends OrderedItemOption {
    // {{ DateSelected (property)    private Date dateSelected;
...    // }} @PersistenceCapable@XMSEntityNames({ @XMSEntityName(locale = "es", 
name = "Opción con Número del Artículo del Pedido Genérico") })public class 
GenericOrderedItemOptionWithNumber extends OrderedItemOption {
    // {{ NumberEntered (property)    private BigDecimal numberEntered;
…}


 
HTH,
Oscar


El 28/7/2015, a las 10:15, Stephen Cameron <[email protected]> 
escribió:

Hi David,

My two bits worth, I think Apache Isis is the last thing i would use for
this kind of a task. If the information collected is that complex, then
trying to fit in into a relational database via an object model makes no
sense. Just use an XML database and XForms.

There are server-side implementations of XForms that work well, namely
Orbeon and BetterForms, if you want to hide the declarative form logic from
users.

For me, its Isis for behaviour and XForms/XQuery for complex data, both are
efficient in their domains of specialisation.

Where the boundary lies is an interesting puzzle to me. There is paper that
myself and another wrote, somewhat on this contrast, here [1].

XForms is efficient as all the complexity that you describe can be done
declaratively via XPath predicates [2]. That said, there is no validating
compiler, so refactoring is a pain for example. Joeron's suggestion of two
domain models might be alluding to that perhaps? But subforms do provide a
means to manage this.

Finally, XForms can be fun too, see [3]

Cheers
Steve Cameron

[1]
http://www.balisage.net/Proceedings/vol10/html/Velasquez01/BalisageVol10-Velasquez01.html
[2] http://lib.tkk.fi/Diss/2007/isbn9789512285662/article3.pdf
[3]
http://exist-db.org/exist/apps/XSLTForms-Demo/modules/form.xq?form=tic-tac-toe.xml



On Sun, Jul 26, 2015 at 11:38 AM, David Tildesley <[email protected]>
wrote:


Hi,
I am looking for some ideas around how ISIS could be helpful in the
following Use Case. N.B. For non-disclosure reasons, I have to mask the
real problem domain however at the same time try and give you a sense of
what it all about and the degree of complexity.
UC1. "Apply for 'XYZ'"
N.B. 'XYZ' in truth has many variations ('XYZa, XYZb, XYZc, ...) which
differ substantially in the information that must be collected from the
Applicant(s). There is only a very small subset of information that is
common.
1. The Applicant(s) (individual(s)) core details (name, contact details,
dob, identity document number, ...). Depending on the type of 'XYZ' a very
large set of additional information about these parties must be collected
(e.g. educational qualifications, military history, job history, ...)2.
Depending on the type of 'XYZ' and the answers to previous questions,
information about other Parties ("Organisation" or "Individual") must be
collected.3. The system needs to be reactive to the user input. The user
should only be presented with the relevant forms question/input that comply
with the rules for the 'XYZ' type and context (their answers to previous
questions that may trigger another set of questions).4. The system should
group questions into multiple input forms rather than have one large
form.5. The system should allow the user to "navigate" between the
collection of forms until the "OK to submit" rule is satisfied, only
displaying the relevant form questions for the 'XYZ' type and context.
There over 1500 information elements in the superset and it is likely that
even for the simplest 'XYZ' type (single party), at least 50 information
elements will be required. There will be collections in some cases (e.g.
"job history").
The rules while many, are not complex (no calculations) and focused around
"If the user answered "yes" to this question then ask them to complete
another section of information." Some rules will apply to multiple 'XYZ'
types. I
ISIS allows us to hide/unhide, enable/disable properties, objects, etc.
dynamically. It's just a question of the rules. Coding the rules would be
difficult to maintain because of the size of the data set and the number of
'XYZ' types (About 10 main types, with each type having several variations).
>From a domain model perspective, there is :
A "Party" component which has Party details, Party relationships, contact
details. fairly standard stuff
A "XyzApplication Lodgement" component that is centered around a
Moment-Interval archetype called "XyzApplication" which as you might guess,
has a large number of MI-Detail class/object (e.g. JobHistory). And it has
a large number of Role archetype class/object that are roles played by
"Party" wrt "XyzApplication".
Any thoughts on how and what for the rules management and present "smart
form" would be appreciated.
N.B> If you think you might like to answer this, there is no urgency for
answers - if I don't see anything for a few weeks, I will try again :)
Regards,David.






Óscar Bou Bou
Responsable de Producto
Auditor Jefe de Certificación ISO 27001 en BSI
CISA, CRISC, APMG ISO 20000, ITIL-F

   902 900 231 / 620 267 520
   http://www.twitter.com/oscarbou
   http://es.linkedin.com/in/oscarbou
   http://www.GesConsultor.com 



Este mensaje y los ficheros anexos son confidenciales. Los mismos contienen 
información reservada que no puede ser difundida. Si usted ha recibido este 
correo por error, tenga la amabilidad de eliminarlo de su sistema y avisar al 
remitente mediante reenvío a su dirección electrónica; no deberá copiar el 
mensaje ni divulgar su contenido a ninguna persona.Su dirección de correo 
electrónico junto a sus datos personales constan en un fichero titularidad de 
Gesdatos Software, S.L. cuya finalidad es la de mantener el contacto con Ud. Si 
quiere saber de qué información disponemos de Ud., modificarla, y en su caso, 
cancelarla, puede hacerlo enviando un escrito al efecto, acompañado de una 
fotocopia de su D.N.I. a la siguiente dirección: Gesdatos Software, S.L. , 
Paseo de la Castellana, 153 bajo - 28046 (Madrid), y Avda. Cortes Valencianas 
num. 50, 1ºC - 46015 (Valencia). Asimismo, es su responsabilidad comprobar que 
este mensaje o sus archivos adjuntos no contengan virus informáticos, y en caso 
que los tuvieran eliminarlos.






  

Reply via email to