You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@isis.apache.org by Dan Haywood <da...@haywood-associates.co.uk> on 2013/10/04 12:49:46 UTC

New view model support (ISIS-553)

Folks,
A new feature that I think you might quite like :-)

Isis - and more generally naked objects pattern - is predicated on the idea
that many use cases can be supported by allowing the user to interact
directly with the domain objects.  This is especially true for domains
where the users are expert in the domain - biased towards "problem solvers
rather than process followers" [1,2].

However, even with expert users (and definitely with non expert "process
followers"), there will always be use cases that should be optimised.  For
example, in the Estatio estate management app [3] that Jeroen and I are
building, the system generates invoices to be sent to the accounting
package.  This process involves the invoices going through several states;
the users need to be able to get a handle on the state of these invoices
quickly, split out by fixed asset.  This is the most important use case of
the app, and is worthy of some optimisation.

The new feature, then, is the ability to create view models that can sit in
front of the domain objects, and pull together arbitrary information and
provide actions to interact with them.  However, these view models are not
stored in the database, but are constructed on the fly.  In order that they
are addressable as objects, they must implement a new ViewModel interface.
 This requires that the view model can provide a memento of itself (from a
string) and "rehydrate" itself in subsequent interactions using the same
string.

For example, in the ToDo app, the new ToDoItemsByCategoryViewModel uses the
category as its memento:

public class ToDoItemsByCategoryViewModel
        extends AbstractViewModel ... {

    @Override
    public String viewModelMemento() {
        return getCategory().name();
    }

    @Override
    public void viewModelInit(String memento) {
        setCategory(Category.valueOf(memento));
    }

    ...
}

These view models can be initially created in one of two ways.  The first
is using a domain service that calls a new "newViewModelInstance(...)"
method on the DomainObjectContainer.  This is how the ToDoApp does this, in
a new ToDoItemAnalysis service:

    public List<ToDoItemsByCategoryViewModel> toDoItemsByCategory() {
        final List<Category> categories = Arrays.asList(Category.values());
        return Lists.newArrayList(Iterables.transform(categories,
byCategory()));
    }

    private Function<Category, ToDoItemsByCategoryViewModel> byCategory() {
        return new Function<Category, ToDoItemsByCategoryViewModel>(){
             @Override
             public ToDoItemsByCategoryViewModel apply(final Category
category) {
                 final ToDoItemsByCategoryViewModel byCategory =

 getContainer().newViewModelInstance(ToDoItemsByCategoryViewModel.class,
category.name());
                 byCategory.setCategory(category);
                 return byCategory;
             }
         };
    }


Alternatively, it is also possible to have DataNucleus create the view
models, by mapping the view model itself as an IdentityType.NONDURABLE
entity [x].  This is how the Estatio application will most likely work (for
efficiency reasons).  For example [4]:

@javax.jdo.annotations.PersistenceCapable(
        identityType = IdentityType.NONDURABLE,
        table = "PROPERTYINVOICESUMMARY",
        extensions = {
                @Extension(vendorName = "datanucleus", key =
"view-definition",
                        value = "CREATE VIEW \"PROPERTYINVOICESUMMARY\" "
                                + "( "
                                + "{this.reference}, "
                                + "{this.name} "
                                + ") AS "
                                + "SELECT \"REFERENCE\", \"NAME\" "
                                + "FROM \"FIXEDASSET\" "
                                + "WHERE \"DISCRIMINATOR\" =
'org.estatio.dom.asset.Property'")
        })
@javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public class PropertyInvoiceSummary
        extends EstatioDomainObject<PropertyInvoiceSummary>
        implements ViewModel {
        ...
}


Last thing to mention is that this feature works on Restful Objects viewer
as well as the Wicket viewer; it was something I sketched out in chapter 32
of the RO spec [5].  These view models therefore provide an abstraction in
front of the domain object model; a necessity when the RESTful client
evolves independently from the server.

~~~
Do try out this new feature (ISIS-553 [6]); any questions, ask here.

Cheers
Dan


[1] http://c2.com/cgi/wiki?TheNakedObjectsFramework
[2]
http://www.interaction-design.org/mads/articles/object_orientation_redefined.html
[3] https://github.com/estatio/estatio
[4]
https://github.com/estatio/estatio/blob/367c472f4b6a6419d3a6ed48d589c9f2d03f7e29/dom/src/main/java/org/estatio/app/PropertyInvoiceSummary.java
[5] http://restfulobjects.org/
[6] https://issues.apache.org/jira/browse/ISIS-553