Putting a Custom UI on Naked Objects: Part 4, Business Rules
In the previous post in this series we saw how the Naked Objects metamodel uses Facets to allow arbitrary metadata to be associated to the classes, properties, collections or actions. We’ve already explored the well-defined facets that are used to capture presentation semantics and to enable interactions, but we still need to see how facets enable business rules to be captured.
As I’ve previously blogged about, Naked Objects allows three different types of business rules to be implemented. In the metamodel API there is a corresponding interface for each of these rule types, implemented by Facets:
| Business rule | Description | API | Facet implementation examples |
|---|---|---|---|
| Visibility | can this user see the class member? | HidingInteractionAdvisor | @Hidden annotation, hideXxx() supporting methods |
| Usability | if so, can this user use (edit, modify or invoke) the class member? | DisablingInteractionAdvisor | @Disabled annotation, disableXxx() supporting methods |
| Validity | if so, can this user use (edit, modify or invoke) the class member? | ValidatingInteractionAdvisor | @RegEx annotation, validateXxx() supporting methods |
For example, the following will install a disabling facet for the disableXxx() method, and validation facets for the (lack of an) @Optional annotation and for the @RegEx annotation:
private String name;
@MemberOrder(sequence="1")
@RegEx(validation = "[A-Z][a-z].* [A-Z][a-z].*")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String disableName() {
return isLocked()? "Locked": null; // isLocked() not shown
}
When we query the metamodel for visibility or usability etc, each of the facets are checked to see if they implement the appropriate advisor interface. If they do, then they get the opportunity to veto the interaction.
It’s also possible to implement additional FacetFactorys that install Facets that implement the InteractionAdvisor interface. In an earlier post I showed an example of writing a FacetFactory. It’s worth noting is that there’s nothing in the Naked Objects Framework that assumes that these facet implementations wrap blocks of code; they could veto the interaction based on any criteria you can think of.
Ok, supposing we want to write a custom viewer and want to honour these business rules; how do we actually query the metamodel? Here’s how:
| Business rule | Member type(s) | Description | API |
|---|---|---|---|
| Visibility | property, collection, action | can this user see the class member? | NakedObjectMember#isVisible(AuthenticationSession, NakedObject) |
| Usability | property, collection, action | can this user use the class member (or is it disabled/greyed out)? | NakedObjectMember#isUsable(AuthenticationSession, NakedObject) |
| Validity | property | is the proposed value valid? | OneToOneAssociation#isAssociationValid(NakedObject, NakedObject) |
| collection | is the proposed object valid to add? | OneToManyAssociation#isValidToAdd(NakedObject, NakedObject) | |
| is the proposed object valid to remove? | OneToManyAssociation#isValidToRemove(NakedObject, NakedObject) | ||
| action params | is the proposed argument valid? | NakedObjectActionParameter#isValid(NakedObject, Object) | |
| action | are all the proposed arguments valid? | NakedObjectAction#isProposedArgumentSetValid(NakedObject, NakedObject[]) |
So, given a NakedObject adapter, the viewer:
- looks up the corresponding NakedObjectSpecification
- for each of the specification’s NakedObjectMembers:
- check if it is visible; if not then don’t render it, otherwise (for a property or collection) obtain the current value
- check if it is usable; if not then render the value as disabled/greyed out, otherwise render in an editable field
When an property/collection is edited or action invoked, the viewer then:
- obtain the proposed value/argument
- for properties/collections, check the value is valid
- for actions, check if all arguments are valid individually, then check if the arguments are valid as a set
- if so, perform the interaction (as described in the previous post)
That’s it for now. In the next blog post we’ll look in a little more detail on how to render the class member values.
Posted on December 8, 2009, in apache isis. Bookmark the permalink. 4 Comments.
Hello Dan, sorry for the off-topic.
I have bought you previous book “Better software faster”. Is it possible to get an application developed for this book – CarServe. The last time I checked, the book web site – bettersoftwarefaster.com was dead.
Thank you,
Danylo
Hi Danylo,
Nice to hear you bought my last book. But yes, bettersoftwarefaster.com is indeed dead, as, of course, is TogetherJ (the topic of that book), in spirit if not in name.
In fact, I use CarServ as the case study again in this book. This was born out of piece of work I did many years back with Richard Pawson (the inventor of the Naked Objects pattern) when I redid the CarServ application in a very early version of Naked Objects. He used the results of that work for his thesis, which you can view here. So it seemed like an obvious candidate to use when I wrote my own Naked Objects book.
The scope of CarServ in the DDD/NO book isn’t quite the same as the BSF book; I only take the case study as far as is needed to explain the points I want to put across. But I hope there’s enough for everyone reading the book to see how Naked Objects can be put to work building their own applications.
Feel free to mail me offline if you want to take the discussion further – my email is floating around the web, but dan @ this domain name will also get to me.
Cheers
Dan
Pingback: Tweets that mention Putting a Custom UI on Naked Objects: Part 4, Business Rules | Domain Driven Design using Naked Objects -- Topsy.com
Pingback: Putting a Custom UI on Naked Objects: Part 3, The MetaModel API | Domain Driven Design, Quickly