You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@isis.apache.org by "Y.R Tan" <ma...@yuritan.nl> on 2015/12/19 12:43:38 UTC

How should we handle void and null results

Hi everyone, 

When using a void action, let’s say a remove action, the user is redirected to a page "no results". When clicking the back button in the browser the user sees "Object not found" (since you’ve just deleted this object). 

Example:

public class Person {
    ....
    public void remove() {
        ...
    }
}

You can return a list for example to prevent the user from being redirect to a "No results" page, but I think it’s not the responsibility of the controllers in the domain model. A solution could be that wicket viewer goes back one page when encountering a deleted object. And refresh the current page when receiving a null response or invoking a void action. 

What do you guys think that is the best solution? Or do you have another view on this situation?

Looking forward hearing from you.

Regards, 

Yu Ri Tan

RE: How should we handle void and null results

Posted by Cesar Lugo <ce...@sisorg.com.mx>.
Hello. I am just another Isis user like you, but I thought this might help:

Wicket viewer shows what you "return" in your action method, so, because you are returning void, Wicket is showing "no results" message. Usually, you return the thing you create or update, but you can return the parent if that's what you want, or anything else you need, just get it in your code and return it. For example, I have a method that adds a Deliverer that belongs to a BusinessLocation, and after created shows the parent BusinessLocation entity object instead of showing the Deliverer object just created (in my case, when showing the BusinessLocation parent, the Deliverer just  created shows in the collection section, which is what I wanted, because Business have that collection). If you adapt this code to your deletePerson method I think it can work.

My sample code is:

    @Action(
            domainEvent = CreateDomainEvent.class
    )
    @MemberOrder(name = "deliverers",sequence = "24")
    public BusinessLocation addDeliverer(
            final @ParameterLayout(named="Business Location") BusinessLocation businessLocation,
            final @ParameterLayout(named="Deliverer Id") String delivererId,
            final @ParameterLayout(named="First Name") String firstName,
            final @ParameterLayout(named="Middle Name") @Parameter(optionality = Optionality.OPTIONAL)String middleName,
            final @ParameterLayout(named="Last Name") String lastName,
            final @ParameterLayout(named="Last Name 2") @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
            final @ParameterLayout(named="Contact Phone") @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
            final @ParameterLayout(named="Delivery Phone") @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
            final @ParameterLayout(named="Deliverer Picture") @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
    )
    {
        final Deliverer obj = container.newTransientInstance(Deliverer.class);
        obj.setBusinessLocation(businessLocation);
        obj.setDelivererId(delivererId);
        obj.setFirstName(firstName);
        obj.setMiddleName(middleName);
        obj.setLastName(lastName);
        obj.setLastName2(lastName2);
        obj.setContactPhone(contactPhone);
        obj.setDeliveryPhone(deliveryPhone);
        obj.setDelivererPicture(delivererPicture);
        obj.setCreationTime(clockService.nowAsDateTime());
        container.persistIfNotAlready(obj);
        return obj.getBusinessLocation();
    }

If you choose to return the parent of the Person object being deleted, make sure you get the parent before you Delete the person. Have fun!

Cesar.

-----Original Message-----
From: Y.R Tan [mailto:mail@yuritan.nl] 
Sent: Saturday, December 19, 2015 5:44 AM
To: users
Subject: How should we handle void and null results

Hi everyone, 

When using a void action, let’s say a remove action, the user is redirected to a page "no results". When clicking the back button in the browser the user sees "Object not found" (since you’ve just deleted this object). 

Example:

public class Person {
    ....
    public void remove() {
        ...
    }
}

You can return a list for example to prevent the user from being redirect to a "No results" page, but I think it’s not the responsibility of the controllers in the domain model. A solution could be that wicket viewer goes back one page when encountering a deleted object. And refresh the current page when receiving a null response or invoking a void action. 

What do you guys think that is the best solution? Or do you have another view on this situation?

Looking forward hearing from you.

Regards, 

Yu Ri Tan


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


Re: How should we handle void and null results

Posted by Stephen Cameron <st...@gmail.com>.
"controllers in the domain model"? MVC is the most elastic 'pattern', which
defeats the purpose of named patterns. Are there controllers in Naked
Objects? Not really, but the wicket viewer does require a choice to be made
of which object's view to show after an action.

It is an interesting question, I think you are kind of forced to decide
'what is a user most likely to want to see next'?. If there is no answer to
that then taking them back to the home page is maybe best. I don't know how
to do that.

I have been putting this 'remove' issue off myself, to make my client
decide if they really want to have the option to remove records. I wanted
them to focus on how to prevent adding duplicate or dodgy data from the
start, in the interests of data quality.

This approach has sort of worked as remove/delete is now going to be an
admin user only function, in which case the "no record found" after remove
default is not a problem IMO. Also, I'll now add an admin object, in
preference to a big admin menu list, that can be a kind of admin home
page/object.

Removing elements from child collections is not a problem, you can have Add
and Remove action buttons in the heading of each collection. So its really
only a question for removal of parent records I think. So then a question
is why do you need to remove such a record (entity)? Is the data no longer
useful, but I say all data is useful even if its historic data. Is the data
a duplicate, in which case how was it allowed to be created in the first
place (and are there other 'unknown' duplicates now)?

An interesting subject.

Cheers

On Sat, Dec 19, 2015 at 11:32 PM, Martin Grigorov <mg...@apache.org>
wrote:

> Hi,
>
> I'll let the DDD experts suggest proper solution but to me Person#delete()
> (i.e. a person domain object deletes itself) looks strange.
> Usually the repository deals with these matters.
> I'd expect to go back to the listing with the other domain objects from
> this type after the deletion.
>
> Martin Grigorov
> Wicket Training and Consulting
> https://twitter.com/mtgrigorov
>
> On Sat, Dec 19, 2015 at 12:43 PM, Y.R Tan <ma...@yuritan.nl> wrote:
>
> > Hi everyone,
> >
> > When using a void action, let’s say a remove action, the user is
> > redirected to a page "no results". When clicking the back button in the
> > browser the user sees "Object not found" (since you’ve just deleted this
> > object).
> >
> > Example:
> >
> > public class Person {
> >     ....
> >     public void remove() {
> >         ...
> >     }
> > }
> >
> > You can return a list for example to prevent the user from being redirect
> > to a "No results" page, but I think it’s not the responsibility of the
> > controllers in the domain model. A solution could be that wicket viewer
> > goes back one page when encountering a deleted object. And refresh the
> > current page when receiving a null response or invoking a void action.
> >
> > What do you guys think that is the best solution? Or do you have another
> > view on this situation?
> >
> > Looking forward hearing from you.
> >
> > Regards,
> >
> > Yu Ri Tan
>

Re: How should we handle void and null results

Posted by Martin Grigorov <mg...@apache.org>.
Hi,

I'll let the DDD experts suggest proper solution but to me Person#delete()
(i.e. a person domain object deletes itself) looks strange.
Usually the repository deals with these matters.
I'd expect to go back to the listing with the other domain objects from
this type after the deletion.

Martin Grigorov
Wicket Training and Consulting
https://twitter.com/mtgrigorov

On Sat, Dec 19, 2015 at 12:43 PM, Y.R Tan <ma...@yuritan.nl> wrote:

> Hi everyone,
>
> When using a void action, let’s say a remove action, the user is
> redirected to a page "no results". When clicking the back button in the
> browser the user sees "Object not found" (since you’ve just deleted this
> object).
>
> Example:
>
> public class Person {
>     ....
>     public void remove() {
>         ...
>     }
> }
>
> You can return a list for example to prevent the user from being redirect
> to a "No results" page, but I think it’s not the responsibility of the
> controllers in the domain model. A solution could be that wicket viewer
> goes back one page when encountering a deleted object. And refresh the
> current page when receiving a null response or invoking a void action.
>
> What do you guys think that is the best solution? Or do you have another
> view on this situation?
>
> Looking forward hearing from you.
>
> Regards,
>
> Yu Ri Tan

Re: How should we handle void and null results

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
OK, done.

See [1] SPI service, also [2], a supporting service.

The net effect is that any actions returning void or null will now render
the home page if one is defined.  If this behaviour isn't required, then
implement RoutingService with some other algorithm.

Dan


http://isis.apache.org/guides/rgsvc.html#_rgsvc_spi_RoutingService
http://isis.apache.org/guides/rgsvc.html#_rgsvc_api_HomePageProviderService


On 22 December 2015 at 12:02, Dan Haywood <da...@haywood-associates.co.uk>
wrote:

> There was a related discussion a while back [1], revolving around whether
> the Wicket viewer should always render the returned object, or some other
> object (eg the owning object/aggregate root).  I raised a ticket ISIS-666
> [2] for this, and have also now referenced this thread [3].
>
> To pick up on a couple of points made:
>
> * should the object returned by the action determine the next object
> rendered (ie do domain object actions act as "controllers")?  Yu Ri says
> no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think we
> were always saying its ok, but to provide the ability for this to be
> modified (eg to the aggregate root rather than leaf).  We didn't discuss
> the case of returning void, though.
>
> * Martin was wondering about whether Person#delete() even makes sense.  I
> think it does though; at least an end-user would want to press a button
> called "delete" on a domain object.  Behind the covers that might be a
> contributed action or mixin or double-dispatch back to a repository
> service.  But that's an implementation detail: the core responsibility is
> for a domain object to know how to get itself deleted
>
> * Steve suggests that where there is no obvious answer to "which object
> should be shown next", then the home page might be a reasonable default.  I
> agree, and think we should provide such a capability.
>
> * Cesar illustrates how to return a parent object, eg for both delete and
> also for add.
>
> To me it seems that it's unlikely to be a single policy that will support
> all use cases.  So I propose a new optional SPI service that, if present,
> the viewer will consult to determine which object to show next.  I see this
> a quite low-level service and we might use it as a building block to some
> higher-level strategy (eg based on new annotations) at a later date.
>
> The SPI I suggest is:
>
> public interface RoutingService {
>
>      public Object route(Object original);
>
> }
>
> A default implementation could be something like:
>
> public class RoutingServiceDefault {
>
>     public Object route(Object original) {
>         return original != null? original: homePage();
>     }
>
>     private Object homePage() { ... code to find the @HomePage object if
> any ... }
> }
>
> This behaviour could be overridden eg to support the aggregate object idea
> as discussed in [1].
>
> So, that's my proposal.
>
> Cheers
> Dan
>
>
>
> [1] http://markmail.org/message/xhmeq62ywr2vqvje .
> [2] https://issues.apache.org/jira/browse/ISIS-666
>
>
> On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx> wrote:
>
>> Hello. I am just another Isis user like you, but I thought this might
>> help:
>>
>> Wicket viewer shows what you "return" in your action method, so, because
>> you are returning void, Wicket is showing "no results" message. Usually,
>> you return the thing you create or update, but you can return the parent if
>> that's what you want, or anything else you need, just get it in your code
>> and return it. For example, I have a method that adds a Deliverer that
>> belongs to a BusinessLocation, and after created shows the parent
>> BusinessLocation entity object instead of showing the Deliverer object just
>> created (in my case, when showing the BusinessLocation parent, the
>> Deliverer just  created shows in the collection section, which is what I
>> wanted, because Business have that collection). If you adapt this code to
>> your deletePerson method I think it can work.
>>
>> My sample code is:
>>
>>     @Action(
>>             domainEvent = CreateDomainEvent.class
>>     )
>>     @MemberOrder(name = "deliverers",sequence = "24")
>>     public BusinessLocation addDeliverer(
>>             final @ParameterLayout(named="Business Location")
>> BusinessLocation businessLocation,
>>             final @ParameterLayout(named="Deliverer Id") String
>> delivererId,
>>             final @ParameterLayout(named="First Name") String firstName,
>>             final @ParameterLayout(named="Middle Name")
>> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
>>             final @ParameterLayout(named="Last Name") String lastName,
>>             final @ParameterLayout(named="Last Name 2")
>> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
>>             final @ParameterLayout(named="Contact Phone")
>> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
>>             final @ParameterLayout(named="Delivery Phone")
>> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
>>             final @ParameterLayout(named="Deliverer Picture")
>> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
>>     )
>>     {
>>         final Deliverer obj =
>> container.newTransientInstance(Deliverer.class);
>>         obj.setBusinessLocation(businessLocation);
>>         obj.setDelivererId(delivererId);
>>         obj.setFirstName(firstName);
>>         obj.setMiddleName(middleName);
>>         obj.setLastName(lastName);
>>         obj.setLastName2(lastName2);
>>         obj.setContactPhone(contactPhone);
>>         obj.setDeliveryPhone(deliveryPhone);
>>         obj.setDelivererPicture(delivererPicture);
>>         obj.setCreationTime(clockService.nowAsDateTime());
>>         container.persistIfNotAlready(obj);
>>         return obj.getBusinessLocation();
>>     }
>>
>> If you choose to return the parent of the Person object being deleted,
>> make sure you get the parent before you Delete the person. Have fun!
>>
>> Cesar.
>>
>> -----Original Message-----
>> From: Y.R Tan [mailto:mail@yuritan.nl]
>> Sent: Saturday, December 19, 2015 5:44 AM
>> To: users
>> Subject: How should we handle void and null results
>>
>> Hi everyone,
>>
>> When using a void action, let’s say a remove action, the user is
>> redirected to a page "no results". When clicking the back button in the
>> browser the user sees "Object not found" (since you’ve just deleted this
>> object).
>>
>> Example:
>>
>> public class Person {
>>     ....
>>     public void remove() {
>>         ...
>>     }
>> }
>>
>> You can return a list for example to prevent the user from being redirect
>> to a "No results" page, but I think it’s not the responsibility of the
>> controllers in the domain model. A solution could be that wicket viewer
>> goes back one page when encountering a deleted object. And refresh the
>> current page when receiving a null response or invoking a void action.
>>
>> What do you guys think that is the best solution? Or do you have another
>> view on this situation?
>>
>> Looking forward hearing from you.
>>
>> Regards,
>>
>> Yu Ri Tan
>>
>>
>> ---
>> This email has been checked for viruses by Avast antivirus software.
>> https://www.avast.com/antivirus
>>
>>
>

Re: How should we handle void and null results

Posted by "Y.R Tan" <ma...@yuritan.nl>.
You’ve made me very happy. Thx Dan! 

> On 04 Jan 2016, at 17:38, Dan Haywood <da...@haywood-associates.co.uk> wrote:
> 
> The RoutingService (ISIS-666) was implemented in 1.11.0, and I've now also
> added an FAQ [1] which shows how a custom implementation can use the
> breadcrumbs to display the previous object in the result of an object being
> deleted and returning void/null.
> 
> This should give the effect that the OP (Yuri) was original after...
> 
> Thx
> Dan
> 
> [1]
> http://isis.apache.org/guides/ugfun.html#_ugfun_faqs_how-to-handle-void-and-null-results
> 
> On 23 December 2015 at 14:55, Dan Haywood <da...@haywood-associates.co.uk>
> wrote:
> 
>> I've raised ISIS-1282 [1] for this idea.
>> 
>> Thx
>> Dan
>> 
>> [1] https://issues.apache.org/jira/browse/ISIS-1282
>> 
>> On 23 December 2015 at 09:01, Óscar Bou - GOVERTIS <o....@govertis.com>
>> wrote:
>> 
>>> Hi, Dan.
>>> 
>>> I like your proposal to extend the @Action annotation.
>>> 
>>> So, for example, for routing to “this” when returning void or null, would
>>> it be annotated with something like ”routeUsing=ThisRouter.class”.
>>> 
>>> Perhaps something clearer would be to have a complementary one like
>>> “routeTo=THIS” or similar.
>>> 
>>> Cheers,
>>> 
>>> Oscar
>>> 
>>> 
>>> 
>>> 
>>>> El 22 dic 2015, a las 19:13, Dan Haywood <da...@haywood-associates.co.uk>
>>> escribió:
>>>> 
>>>> On 22 December 2015 at 15:19, Óscar Bou - GOVERTIS <o....@govertis.com>
>>>> wrote:
>>>> 
>>>>> 
>>>>> Hi all.
>>>>> 
>>>>> I find the SPI Service really useful for advanced use cases.
>>>>> 
>>>>> But in order to have the desired behavior clearly specified on the same
>>>>> class definition, shouldn't be helpful to also have an annotation
>>>>> indicating the desired behavior (like returning this instance)?
>>>>> 
>>>>> 
>>>> Seems better to provide a lower level SPI service that can work in all
>>> use
>>>> cases, and then use that as a building block for higher level
>>> abstractions
>>>> that might include annotations (or more likely, a new attribute of the
>>>> @Action annotation).
>>>> 
>>>> But to start that conversation, we could have a new "strategy"
>>> attribute,
>>>> eg:
>>>> 
>>>> @Action(
>>>>   routeUsing=MyRouter.class  // implements some sort of "Router"
>>>> interface, similar to our Specification interface
>>>> )
>>>> public void whatever(...) { ... }
>>>> 
>>>> Cheers
>>>> Dan
>>>> 
>>>> 
>>>> 
>>>> 
>>>>> Christmas here also :))
>>>>> 
>>>>> HTH,
>>>>> 
>>>>> Oscar
>>>>> 
>>>>>> El 22 dic 2015, a las 15:54, Cesar Lugo <ce...@sisorg.com.mx>
>>>>> escribió:
>>>>>> 
>>>>>> Dan,
>>>>>> 
>>>>>> I think your proposal is quite good to have a configurable "default"
>>>>> behavior, and having the option to return whatever the developer wants
>>> is
>>>>> quite useful as well. Probably this could evolve to some kind of
>>> wizard (I
>>>>> saw a work in progress in Isis add-ons), or even some integration with
>>> some
>>>>> BPM tool. Just thinking loud here, it's christmas  :) .
>>>>>> 
>>>>>> Cesar.
>>>>>> 
>>>>>> -----Original Message-----
>>>>>> From: Dan Haywood [mailto:dan@haywood-associates.co.uk]
>>>>>> Sent: Tuesday, December 22, 2015 6:02 AM
>>>>>> To: users
>>>>>> Subject: Re: How should we handle void and null results
>>>>>> 
>>>>>> There was a related discussion a while back [1], revolving around
>>>>> whether the Wicket viewer should always render the returned object, or
>>> some
>>>>> other object (eg the owning object/aggregate root).  I raised a ticket
>>>>> ISIS-666 [2] for this, and have also now referenced this thread [3].
>>>>>> 
>>>>>> To pick up on a couple of points made:
>>>>>> 
>>>>>> * should the object returned by the action determine the next object
>>>>> rendered (ie do domain object actions act as "controllers")?  Yu Ri
>>> says
>>>>> no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think
>>> we
>>>>> were always saying its ok, but to provide the ability for this to be
>>>>> modified (eg to the aggregate root rather than leaf).  We didn't
>>> discuss
>>>>> the case of returning void, though.
>>>>>> 
>>>>>> * Martin was wondering about whether Person#delete() even makes sense.
>>>>> I think it does though; at least an end-user would want to press a
>>> button
>>>>> called "delete" on a domain object.  Behind the covers that might be a
>>>>> contributed action or mixin or double-dispatch back to a repository
>>>>> service.  But that's an implementation detail: the core responsibility
>>> is
>>>>> for a domain object to know how to get itself deleted
>>>>>> 
>>>>>> * Steve suggests that where there is no obvious answer to "which
>>> object
>>>>> should be shown next", then the home page might be a reasonable
>>> default.  I
>>>>> agree, and think we should provide such a capability.
>>>>>> 
>>>>>> * Cesar illustrates how to return a parent object, eg for both delete
>>>>> and also for add.
>>>>>> 
>>>>>> To me it seems that it's unlikely to be a single policy that will
>>>>> support all use cases.  So I propose a new optional SPI service that,
>>> if
>>>>> present, the viewer will consult to determine which object to show
>>> next.  I
>>>>> see this a quite low-level service and we might use it as a building
>>> block
>>>>> to some higher-level strategy (eg based on new annotations) at a later
>>> date.
>>>>>> 
>>>>>> The SPI I suggest is:
>>>>>> 
>>>>>> public interface RoutingService {
>>>>>> 
>>>>>>   public Object route(Object original);
>>>>>> 
>>>>>> }
>>>>>> 
>>>>>> A default implementation could be something like:
>>>>>> 
>>>>>> public class RoutingServiceDefault {
>>>>>> 
>>>>>>  public Object route(Object original) {
>>>>>>      return original != null? original: homePage();
>>>>>>  }
>>>>>> 
>>>>>>  private Object homePage() { ... code to find the @HomePage object if
>>>>> any ... } }
>>>>>> 
>>>>>> This behaviour could be overridden eg to support the aggregate object
>>>>> idea as discussed in [1].
>>>>>> 
>>>>>> So, that's my proposal.
>>>>>> 
>>>>>> Cheers
>>>>>> Dan
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> [1] http://markmail.org/message/xhmeq62ywr2vqvje .
>>>>>> [2] https://issues.apache.org/jira/browse/ISIS-666
>>>>>> 
>>>>>> 
>>>>>>> On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx>
>>>>> wrote:
>>>>>>> 
>>>>>>> Hello. I am just another Isis user like you, but I thought this might
>>>>> help:
>>>>>>> 
>>>>>>> Wicket viewer shows what you "return" in your action method, so,
>>>>>>> because you are returning void, Wicket is showing "no results"
>>>>>>> message. Usually, you return the thing you create or update, but you
>>>>>>> can return the parent if that's what you want, or anything else you
>>>>>>> need, just get it in your code and return it. For example, I have a
>>>>>>> method that adds a Deliverer that belongs to a BusinessLocation, and
>>>>>>> after created shows the parent BusinessLocation entity object instead
>>>>>>> of showing the Deliverer object just created (in my case, when
>>> showing
>>>>>>> the BusinessLocation parent, the Deliverer just  created shows in the
>>>>>>> collection section, which is what I wanted, because Business have
>>> that
>>>>>>> collection). If you adapt this code to your deletePerson method I
>>> think
>>>>> it can work.
>>>>>>> 
>>>>>>> My sample code is:
>>>>>>> 
>>>>>>>  @Action(
>>>>>>>          domainEvent = CreateDomainEvent.class
>>>>>>>  )
>>>>>>>  @MemberOrder(name = "deliverers",sequence = "24")
>>>>>>>  public BusinessLocation addDeliverer(
>>>>>>>          final @ParameterLayout(named="Business Location")
>>>>>>> BusinessLocation businessLocation,
>>>>>>>          final @ParameterLayout(named="Deliverer Id") String
>>>>>>> delivererId,
>>>>>>>          final @ParameterLayout(named="First Name") String
>>> firstName,
>>>>>>>          final @ParameterLayout(named="Middle Name")
>>>>>>> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
>>>>>>>          final @ParameterLayout(named="Last Name") String lastName,
>>>>>>>          final @ParameterLayout(named="Last Name 2")
>>>>>>> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
>>>>>>>          final @ParameterLayout(named="Contact Phone")
>>>>>>> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
>>>>>>>          final @ParameterLayout(named="Delivery Phone")
>>>>>>> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
>>>>>>>          final @ParameterLayout(named="Deliverer Picture")
>>>>>>> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
>>>>>>>  )
>>>>>>>  {
>>>>>>>      final Deliverer obj =
>>>>>>> container.newTransientInstance(Deliverer.class);
>>>>>>>      obj.setBusinessLocation(businessLocation);
>>>>>>>      obj.setDelivererId(delivererId);
>>>>>>>      obj.setFirstName(firstName);
>>>>>>>      obj.setMiddleName(middleName);
>>>>>>>      obj.setLastName(lastName);
>>>>>>>      obj.setLastName2(lastName2);
>>>>>>>      obj.setContactPhone(contactPhone);
>>>>>>>      obj.setDeliveryPhone(deliveryPhone);
>>>>>>>      obj.setDelivererPicture(delivererPicture);
>>>>>>>      obj.setCreationTime(clockService.nowAsDateTime());
>>>>>>>      container.persistIfNotAlready(obj);
>>>>>>>      return obj.getBusinessLocation();
>>>>>>>  }
>>>>>>> 
>>>>>>> If you choose to return the parent of the Person object being
>>> deleted,
>>>>>>> make sure you get the parent before you Delete the person. Have fun!
>>>>>>> 
>>>>>>> Cesar.
>>>>>>> 
>>>>>>> -----Original Message-----
>>>>>>> From: Y.R Tan [mailto:mail@yuritan.nl]
>>>>>>> Sent: Saturday, December 19, 2015 5:44 AM
>>>>>>> To: users
>>>>>>> Subject: How should we handle void and null results
>>>>>>> 
>>>>>>> Hi everyone,
>>>>>>> 
>>>>>>> When using a void action, let’s say a remove action, the user is
>>>>>>> redirected to a page "no results". When clicking the back button in
>>>>>>> the browser the user sees "Object not found" (since you’ve just
>>>>>>> deleted this object).
>>>>>>> 
>>>>>>> Example:
>>>>>>> 
>>>>>>> public class Person {
>>>>>>>  ....
>>>>>>>  public void remove() {
>>>>>>>      ...
>>>>>>>  }
>>>>>>> }
>>>>>>> 
>>>>>>> You can return a list for example to prevent the user from being
>>>>>>> redirect to a "No results" page, but I think it’s not the
>>>>>>> responsibility of the controllers in the domain model. A solution
>>>>>>> could be that wicket viewer goes back one page when encountering a
>>>>>>> deleted object. And refresh the current page when receiving a null
>>>>> response or invoking a void action.
>>>>>>> 
>>>>>>> What do you guys think that is the best solution? Or do you have
>>>>>>> another view on this situation?
>>>>>>> 
>>>>>>> Looking forward hearing from you.
>>>>>>> 
>>>>>>> Regards,
>>>>>>> 
>>>>>>> Yu Ri Tan
>>>>>>> 
>>>>>>> 
>>>>>>> ---
>>>>>>> This email has been checked for viruses by Avast antivirus software.
>>>>>>> https://www.avast.com/antivirus
>>>>>> 
>>>>>> 
>>>>>> ---
>>>>>> This email has been checked for viruses by Avast antivirus software.
>>>>>> https://www.avast.com/antivirus
>>>>>> 
>>>>> 
>>> 
>>> 
>> 


Re: How should we handle void and null results

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
The RoutingService (ISIS-666) was implemented in 1.11.0, and I've now also
added an FAQ [1] which shows how a custom implementation can use the
breadcrumbs to display the previous object in the result of an object being
deleted and returning void/null.

This should give the effect that the OP (Yuri) was original after...

Thx
Dan

[1]
http://isis.apache.org/guides/ugfun.html#_ugfun_faqs_how-to-handle-void-and-null-results

On 23 December 2015 at 14:55, Dan Haywood <da...@haywood-associates.co.uk>
wrote:

> I've raised ISIS-1282 [1] for this idea.
>
> Thx
> Dan
>
> [1] https://issues.apache.org/jira/browse/ISIS-1282
>
> On 23 December 2015 at 09:01, Óscar Bou - GOVERTIS <o....@govertis.com>
> wrote:
>
>> Hi, Dan.
>>
>> I like your proposal to extend the @Action annotation.
>>
>> So, for example, for routing to “this” when returning void or null, would
>> it be annotated with something like ”routeUsing=ThisRouter.class”.
>>
>> Perhaps something clearer would be to have a complementary one like
>> “routeTo=THIS” or similar.
>>
>> Cheers,
>>
>> Oscar
>>
>>
>>
>>
>> > El 22 dic 2015, a las 19:13, Dan Haywood <da...@haywood-associates.co.uk>
>> escribió:
>> >
>> > On 22 December 2015 at 15:19, Óscar Bou - GOVERTIS <o....@govertis.com>
>> > wrote:
>> >
>> >>
>> >> Hi all.
>> >>
>> >> I find the SPI Service really useful for advanced use cases.
>> >>
>> >> But in order to have the desired behavior clearly specified on the same
>> >> class definition, shouldn't be helpful to also have an annotation
>> >> indicating the desired behavior (like returning this instance)?
>> >>
>> >>
>> > Seems better to provide a lower level SPI service that can work in all
>> use
>> > cases, and then use that as a building block for higher level
>> abstractions
>> > that might include annotations (or more likely, a new attribute of the
>> > @Action annotation).
>> >
>> > But to start that conversation, we could have a new "strategy"
>> attribute,
>> > eg:
>> >
>> > @Action(
>> >    routeUsing=MyRouter.class  // implements some sort of "Router"
>> > interface, similar to our Specification interface
>> > )
>> > public void whatever(...) { ... }
>> >
>> > Cheers
>> > Dan
>> >
>> >
>> >
>> >
>> >> Christmas here also :))
>> >>
>> >> HTH,
>> >>
>> >> Oscar
>> >>
>> >>> El 22 dic 2015, a las 15:54, Cesar Lugo <ce...@sisorg.com.mx>
>> >> escribió:
>> >>>
>> >>> Dan,
>> >>>
>> >>> I think your proposal is quite good to have a configurable "default"
>> >> behavior, and having the option to return whatever the developer wants
>> is
>> >> quite useful as well. Probably this could evolve to some kind of
>> wizard (I
>> >> saw a work in progress in Isis add-ons), or even some integration with
>> some
>> >> BPM tool. Just thinking loud here, it's christmas  :) .
>> >>>
>> >>> Cesar.
>> >>>
>> >>> -----Original Message-----
>> >>> From: Dan Haywood [mailto:dan@haywood-associates.co.uk]
>> >>> Sent: Tuesday, December 22, 2015 6:02 AM
>> >>> To: users
>> >>> Subject: Re: How should we handle void and null results
>> >>>
>> >>> There was a related discussion a while back [1], revolving around
>> >> whether the Wicket viewer should always render the returned object, or
>> some
>> >> other object (eg the owning object/aggregate root).  I raised a ticket
>> >> ISIS-666 [2] for this, and have also now referenced this thread [3].
>> >>>
>> >>> To pick up on a couple of points made:
>> >>>
>> >>> * should the object returned by the action determine the next object
>> >> rendered (ie do domain object actions act as "controllers")?  Yu Ri
>> says
>> >> no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think
>> we
>> >> were always saying its ok, but to provide the ability for this to be
>> >> modified (eg to the aggregate root rather than leaf).  We didn't
>> discuss
>> >> the case of returning void, though.
>> >>>
>> >>> * Martin was wondering about whether Person#delete() even makes sense.
>> >> I think it does though; at least an end-user would want to press a
>> button
>> >> called "delete" on a domain object.  Behind the covers that might be a
>> >> contributed action or mixin or double-dispatch back to a repository
>> >> service.  But that's an implementation detail: the core responsibility
>> is
>> >> for a domain object to know how to get itself deleted
>> >>>
>> >>> * Steve suggests that where there is no obvious answer to "which
>> object
>> >> should be shown next", then the home page might be a reasonable
>> default.  I
>> >> agree, and think we should provide such a capability.
>> >>>
>> >>> * Cesar illustrates how to return a parent object, eg for both delete
>> >> and also for add.
>> >>>
>> >>> To me it seems that it's unlikely to be a single policy that will
>> >> support all use cases.  So I propose a new optional SPI service that,
>> if
>> >> present, the viewer will consult to determine which object to show
>> next.  I
>> >> see this a quite low-level service and we might use it as a building
>> block
>> >> to some higher-level strategy (eg based on new annotations) at a later
>> date.
>> >>>
>> >>> The SPI I suggest is:
>> >>>
>> >>> public interface RoutingService {
>> >>>
>> >>>    public Object route(Object original);
>> >>>
>> >>> }
>> >>>
>> >>> A default implementation could be something like:
>> >>>
>> >>> public class RoutingServiceDefault {
>> >>>
>> >>>   public Object route(Object original) {
>> >>>       return original != null? original: homePage();
>> >>>   }
>> >>>
>> >>>   private Object homePage() { ... code to find the @HomePage object if
>> >> any ... } }
>> >>>
>> >>> This behaviour could be overridden eg to support the aggregate object
>> >> idea as discussed in [1].
>> >>>
>> >>> So, that's my proposal.
>> >>>
>> >>> Cheers
>> >>> Dan
>> >>>
>> >>>
>> >>>
>> >>> [1] http://markmail.org/message/xhmeq62ywr2vqvje .
>> >>> [2] https://issues.apache.org/jira/browse/ISIS-666
>> >>>
>> >>>
>> >>>> On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx>
>> >> wrote:
>> >>>>
>> >>>> Hello. I am just another Isis user like you, but I thought this might
>> >> help:
>> >>>>
>> >>>> Wicket viewer shows what you "return" in your action method, so,
>> >>>> because you are returning void, Wicket is showing "no results"
>> >>>> message. Usually, you return the thing you create or update, but you
>> >>>> can return the parent if that's what you want, or anything else you
>> >>>> need, just get it in your code and return it. For example, I have a
>> >>>> method that adds a Deliverer that belongs to a BusinessLocation, and
>> >>>> after created shows the parent BusinessLocation entity object instead
>> >>>> of showing the Deliverer object just created (in my case, when
>> showing
>> >>>> the BusinessLocation parent, the Deliverer just  created shows in the
>> >>>> collection section, which is what I wanted, because Business have
>> that
>> >>>> collection). If you adapt this code to your deletePerson method I
>> think
>> >> it can work.
>> >>>>
>> >>>> My sample code is:
>> >>>>
>> >>>>   @Action(
>> >>>>           domainEvent = CreateDomainEvent.class
>> >>>>   )
>> >>>>   @MemberOrder(name = "deliverers",sequence = "24")
>> >>>>   public BusinessLocation addDeliverer(
>> >>>>           final @ParameterLayout(named="Business Location")
>> >>>> BusinessLocation businessLocation,
>> >>>>           final @ParameterLayout(named="Deliverer Id") String
>> >>>> delivererId,
>> >>>>           final @ParameterLayout(named="First Name") String
>> firstName,
>> >>>>           final @ParameterLayout(named="Middle Name")
>> >>>> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
>> >>>>           final @ParameterLayout(named="Last Name") String lastName,
>> >>>>           final @ParameterLayout(named="Last Name 2")
>> >>>> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
>> >>>>           final @ParameterLayout(named="Contact Phone")
>> >>>> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
>> >>>>           final @ParameterLayout(named="Delivery Phone")
>> >>>> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
>> >>>>           final @ParameterLayout(named="Deliverer Picture")
>> >>>> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
>> >>>>   )
>> >>>>   {
>> >>>>       final Deliverer obj =
>> >>>> container.newTransientInstance(Deliverer.class);
>> >>>>       obj.setBusinessLocation(businessLocation);
>> >>>>       obj.setDelivererId(delivererId);
>> >>>>       obj.setFirstName(firstName);
>> >>>>       obj.setMiddleName(middleName);
>> >>>>       obj.setLastName(lastName);
>> >>>>       obj.setLastName2(lastName2);
>> >>>>       obj.setContactPhone(contactPhone);
>> >>>>       obj.setDeliveryPhone(deliveryPhone);
>> >>>>       obj.setDelivererPicture(delivererPicture);
>> >>>>       obj.setCreationTime(clockService.nowAsDateTime());
>> >>>>       container.persistIfNotAlready(obj);
>> >>>>       return obj.getBusinessLocation();
>> >>>>   }
>> >>>>
>> >>>> If you choose to return the parent of the Person object being
>> deleted,
>> >>>> make sure you get the parent before you Delete the person. Have fun!
>> >>>>
>> >>>> Cesar.
>> >>>>
>> >>>> -----Original Message-----
>> >>>> From: Y.R Tan [mailto:mail@yuritan.nl]
>> >>>> Sent: Saturday, December 19, 2015 5:44 AM
>> >>>> To: users
>> >>>> Subject: How should we handle void and null results
>> >>>>
>> >>>> Hi everyone,
>> >>>>
>> >>>> When using a void action, let’s say a remove action, the user is
>> >>>> redirected to a page "no results". When clicking the back button in
>> >>>> the browser the user sees "Object not found" (since you’ve just
>> >>>> deleted this object).
>> >>>>
>> >>>> Example:
>> >>>>
>> >>>> public class Person {
>> >>>>   ....
>> >>>>   public void remove() {
>> >>>>       ...
>> >>>>   }
>> >>>> }
>> >>>>
>> >>>> You can return a list for example to prevent the user from being
>> >>>> redirect to a "No results" page, but I think it’s not the
>> >>>> responsibility of the controllers in the domain model. A solution
>> >>>> could be that wicket viewer goes back one page when encountering a
>> >>>> deleted object. And refresh the current page when receiving a null
>> >> response or invoking a void action.
>> >>>>
>> >>>> What do you guys think that is the best solution? Or do you have
>> >>>> another view on this situation?
>> >>>>
>> >>>> Looking forward hearing from you.
>> >>>>
>> >>>> Regards,
>> >>>>
>> >>>> Yu Ri Tan
>> >>>>
>> >>>>
>> >>>> ---
>> >>>> This email has been checked for viruses by Avast antivirus software.
>> >>>> https://www.avast.com/antivirus
>> >>>
>> >>>
>> >>> ---
>> >>> This email has been checked for viruses by Avast antivirus software.
>> >>> https://www.avast.com/antivirus
>> >>>
>> >>
>>
>>
>

Re: How should we handle void and null results

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
I've raised ISIS-1282 [1] for this idea.

Thx
Dan

[1] https://issues.apache.org/jira/browse/ISIS-1282

On 23 December 2015 at 09:01, Óscar Bou - GOVERTIS <o....@govertis.com>
wrote:

> Hi, Dan.
>
> I like your proposal to extend the @Action annotation.
>
> So, for example, for routing to “this” when returning void or null, would
> it be annotated with something like ”routeUsing=ThisRouter.class”.
>
> Perhaps something clearer would be to have a complementary one like
> “routeTo=THIS” or similar.
>
> Cheers,
>
> Oscar
>
>
>
>
> > El 22 dic 2015, a las 19:13, Dan Haywood <da...@haywood-associates.co.uk>
> escribió:
> >
> > On 22 December 2015 at 15:19, Óscar Bou - GOVERTIS <o....@govertis.com>
> > wrote:
> >
> >>
> >> Hi all.
> >>
> >> I find the SPI Service really useful for advanced use cases.
> >>
> >> But in order to have the desired behavior clearly specified on the same
> >> class definition, shouldn't be helpful to also have an annotation
> >> indicating the desired behavior (like returning this instance)?
> >>
> >>
> > Seems better to provide a lower level SPI service that can work in all
> use
> > cases, and then use that as a building block for higher level
> abstractions
> > that might include annotations (or more likely, a new attribute of the
> > @Action annotation).
> >
> > But to start that conversation, we could have a new "strategy" attribute,
> > eg:
> >
> > @Action(
> >    routeUsing=MyRouter.class  // implements some sort of "Router"
> > interface, similar to our Specification interface
> > )
> > public void whatever(...) { ... }
> >
> > Cheers
> > Dan
> >
> >
> >
> >
> >> Christmas here also :))
> >>
> >> HTH,
> >>
> >> Oscar
> >>
> >>> El 22 dic 2015, a las 15:54, Cesar Lugo <ce...@sisorg.com.mx>
> >> escribió:
> >>>
> >>> Dan,
> >>>
> >>> I think your proposal is quite good to have a configurable "default"
> >> behavior, and having the option to return whatever the developer wants
> is
> >> quite useful as well. Probably this could evolve to some kind of wizard
> (I
> >> saw a work in progress in Isis add-ons), or even some integration with
> some
> >> BPM tool. Just thinking loud here, it's christmas  :) .
> >>>
> >>> Cesar.
> >>>
> >>> -----Original Message-----
> >>> From: Dan Haywood [mailto:dan@haywood-associates.co.uk]
> >>> Sent: Tuesday, December 22, 2015 6:02 AM
> >>> To: users
> >>> Subject: Re: How should we handle void and null results
> >>>
> >>> There was a related discussion a while back [1], revolving around
> >> whether the Wicket viewer should always render the returned object, or
> some
> >> other object (eg the owning object/aggregate root).  I raised a ticket
> >> ISIS-666 [2] for this, and have also now referenced this thread [3].
> >>>
> >>> To pick up on a couple of points made:
> >>>
> >>> * should the object returned by the action determine the next object
> >> rendered (ie do domain object actions act as "controllers")?  Yu Ri says
> >> no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think we
> >> were always saying its ok, but to provide the ability for this to be
> >> modified (eg to the aggregate root rather than leaf).  We didn't discuss
> >> the case of returning void, though.
> >>>
> >>> * Martin was wondering about whether Person#delete() even makes sense.
> >> I think it does though; at least an end-user would want to press a
> button
> >> called "delete" on a domain object.  Behind the covers that might be a
> >> contributed action or mixin or double-dispatch back to a repository
> >> service.  But that's an implementation detail: the core responsibility
> is
> >> for a domain object to know how to get itself deleted
> >>>
> >>> * Steve suggests that where there is no obvious answer to "which object
> >> should be shown next", then the home page might be a reasonable
> default.  I
> >> agree, and think we should provide such a capability.
> >>>
> >>> * Cesar illustrates how to return a parent object, eg for both delete
> >> and also for add.
> >>>
> >>> To me it seems that it's unlikely to be a single policy that will
> >> support all use cases.  So I propose a new optional SPI service that, if
> >> present, the viewer will consult to determine which object to show
> next.  I
> >> see this a quite low-level service and we might use it as a building
> block
> >> to some higher-level strategy (eg based on new annotations) at a later
> date.
> >>>
> >>> The SPI I suggest is:
> >>>
> >>> public interface RoutingService {
> >>>
> >>>    public Object route(Object original);
> >>>
> >>> }
> >>>
> >>> A default implementation could be something like:
> >>>
> >>> public class RoutingServiceDefault {
> >>>
> >>>   public Object route(Object original) {
> >>>       return original != null? original: homePage();
> >>>   }
> >>>
> >>>   private Object homePage() { ... code to find the @HomePage object if
> >> any ... } }
> >>>
> >>> This behaviour could be overridden eg to support the aggregate object
> >> idea as discussed in [1].
> >>>
> >>> So, that's my proposal.
> >>>
> >>> Cheers
> >>> Dan
> >>>
> >>>
> >>>
> >>> [1] http://markmail.org/message/xhmeq62ywr2vqvje .
> >>> [2] https://issues.apache.org/jira/browse/ISIS-666
> >>>
> >>>
> >>>> On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx>
> >> wrote:
> >>>>
> >>>> Hello. I am just another Isis user like you, but I thought this might
> >> help:
> >>>>
> >>>> Wicket viewer shows what you "return" in your action method, so,
> >>>> because you are returning void, Wicket is showing "no results"
> >>>> message. Usually, you return the thing you create or update, but you
> >>>> can return the parent if that's what you want, or anything else you
> >>>> need, just get it in your code and return it. For example, I have a
> >>>> method that adds a Deliverer that belongs to a BusinessLocation, and
> >>>> after created shows the parent BusinessLocation entity object instead
> >>>> of showing the Deliverer object just created (in my case, when showing
> >>>> the BusinessLocation parent, the Deliverer just  created shows in the
> >>>> collection section, which is what I wanted, because Business have that
> >>>> collection). If you adapt this code to your deletePerson method I
> think
> >> it can work.
> >>>>
> >>>> My sample code is:
> >>>>
> >>>>   @Action(
> >>>>           domainEvent = CreateDomainEvent.class
> >>>>   )
> >>>>   @MemberOrder(name = "deliverers",sequence = "24")
> >>>>   public BusinessLocation addDeliverer(
> >>>>           final @ParameterLayout(named="Business Location")
> >>>> BusinessLocation businessLocation,
> >>>>           final @ParameterLayout(named="Deliverer Id") String
> >>>> delivererId,
> >>>>           final @ParameterLayout(named="First Name") String firstName,
> >>>>           final @ParameterLayout(named="Middle Name")
> >>>> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
> >>>>           final @ParameterLayout(named="Last Name") String lastName,
> >>>>           final @ParameterLayout(named="Last Name 2")
> >>>> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
> >>>>           final @ParameterLayout(named="Contact Phone")
> >>>> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
> >>>>           final @ParameterLayout(named="Delivery Phone")
> >>>> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
> >>>>           final @ParameterLayout(named="Deliverer Picture")
> >>>> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
> >>>>   )
> >>>>   {
> >>>>       final Deliverer obj =
> >>>> container.newTransientInstance(Deliverer.class);
> >>>>       obj.setBusinessLocation(businessLocation);
> >>>>       obj.setDelivererId(delivererId);
> >>>>       obj.setFirstName(firstName);
> >>>>       obj.setMiddleName(middleName);
> >>>>       obj.setLastName(lastName);
> >>>>       obj.setLastName2(lastName2);
> >>>>       obj.setContactPhone(contactPhone);
> >>>>       obj.setDeliveryPhone(deliveryPhone);
> >>>>       obj.setDelivererPicture(delivererPicture);
> >>>>       obj.setCreationTime(clockService.nowAsDateTime());
> >>>>       container.persistIfNotAlready(obj);
> >>>>       return obj.getBusinessLocation();
> >>>>   }
> >>>>
> >>>> If you choose to return the parent of the Person object being deleted,
> >>>> make sure you get the parent before you Delete the person. Have fun!
> >>>>
> >>>> Cesar.
> >>>>
> >>>> -----Original Message-----
> >>>> From: Y.R Tan [mailto:mail@yuritan.nl]
> >>>> Sent: Saturday, December 19, 2015 5:44 AM
> >>>> To: users
> >>>> Subject: How should we handle void and null results
> >>>>
> >>>> Hi everyone,
> >>>>
> >>>> When using a void action, let’s say a remove action, the user is
> >>>> redirected to a page "no results". When clicking the back button in
> >>>> the browser the user sees "Object not found" (since you’ve just
> >>>> deleted this object).
> >>>>
> >>>> Example:
> >>>>
> >>>> public class Person {
> >>>>   ....
> >>>>   public void remove() {
> >>>>       ...
> >>>>   }
> >>>> }
> >>>>
> >>>> You can return a list for example to prevent the user from being
> >>>> redirect to a "No results" page, but I think it’s not the
> >>>> responsibility of the controllers in the domain model. A solution
> >>>> could be that wicket viewer goes back one page when encountering a
> >>>> deleted object. And refresh the current page when receiving a null
> >> response or invoking a void action.
> >>>>
> >>>> What do you guys think that is the best solution? Or do you have
> >>>> another view on this situation?
> >>>>
> >>>> Looking forward hearing from you.
> >>>>
> >>>> Regards,
> >>>>
> >>>> Yu Ri Tan
> >>>>
> >>>>
> >>>> ---
> >>>> This email has been checked for viruses by Avast antivirus software.
> >>>> https://www.avast.com/antivirus
> >>>
> >>>
> >>> ---
> >>> This email has been checked for viruses by Avast antivirus software.
> >>> https://www.avast.com/antivirus
> >>>
> >>
>
>

Re: How should we handle void and null results

Posted by Óscar Bou - GOVERTIS <o....@govertis.com>.
Hi, Dan.

I like your proposal to extend the @Action annotation.

So, for example, for routing to “this” when returning void or null, would it be annotated with something like ”routeUsing=ThisRouter.class”.

Perhaps something clearer would be to have a complementary one like “routeTo=THIS” or similar.

Cheers,

Oscar




> El 22 dic 2015, a las 19:13, Dan Haywood <da...@haywood-associates.co.uk> escribió:
> 
> On 22 December 2015 at 15:19, Óscar Bou - GOVERTIS <o....@govertis.com>
> wrote:
> 
>> 
>> Hi all.
>> 
>> I find the SPI Service really useful for advanced use cases.
>> 
>> But in order to have the desired behavior clearly specified on the same
>> class definition, shouldn't be helpful to also have an annotation
>> indicating the desired behavior (like returning this instance)?
>> 
>> 
> Seems better to provide a lower level SPI service that can work in all use
> cases, and then use that as a building block for higher level abstractions
> that might include annotations (or more likely, a new attribute of the
> @Action annotation).
> 
> But to start that conversation, we could have a new "strategy" attribute,
> eg:
> 
> @Action(
>    routeUsing=MyRouter.class  // implements some sort of "Router"
> interface, similar to our Specification interface
> )
> public void whatever(...) { ... }
> 
> Cheers
> Dan
> 
> 
> 
> 
>> Christmas here also :))
>> 
>> HTH,
>> 
>> Oscar
>> 
>>> El 22 dic 2015, a las 15:54, Cesar Lugo <ce...@sisorg.com.mx>
>> escribió:
>>> 
>>> Dan,
>>> 
>>> I think your proposal is quite good to have a configurable "default"
>> behavior, and having the option to return whatever the developer wants is
>> quite useful as well. Probably this could evolve to some kind of wizard (I
>> saw a work in progress in Isis add-ons), or even some integration with some
>> BPM tool. Just thinking loud here, it's christmas  :) .
>>> 
>>> Cesar.
>>> 
>>> -----Original Message-----
>>> From: Dan Haywood [mailto:dan@haywood-associates.co.uk]
>>> Sent: Tuesday, December 22, 2015 6:02 AM
>>> To: users
>>> Subject: Re: How should we handle void and null results
>>> 
>>> There was a related discussion a while back [1], revolving around
>> whether the Wicket viewer should always render the returned object, or some
>> other object (eg the owning object/aggregate root).  I raised a ticket
>> ISIS-666 [2] for this, and have also now referenced this thread [3].
>>> 
>>> To pick up on a couple of points made:
>>> 
>>> * should the object returned by the action determine the next object
>> rendered (ie do domain object actions act as "controllers")?  Yu Ri says
>> no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think we
>> were always saying its ok, but to provide the ability for this to be
>> modified (eg to the aggregate root rather than leaf).  We didn't discuss
>> the case of returning void, though.
>>> 
>>> * Martin was wondering about whether Person#delete() even makes sense.
>> I think it does though; at least an end-user would want to press a button
>> called "delete" on a domain object.  Behind the covers that might be a
>> contributed action or mixin or double-dispatch back to a repository
>> service.  But that's an implementation detail: the core responsibility is
>> for a domain object to know how to get itself deleted
>>> 
>>> * Steve suggests that where there is no obvious answer to "which object
>> should be shown next", then the home page might be a reasonable default.  I
>> agree, and think we should provide such a capability.
>>> 
>>> * Cesar illustrates how to return a parent object, eg for both delete
>> and also for add.
>>> 
>>> To me it seems that it's unlikely to be a single policy that will
>> support all use cases.  So I propose a new optional SPI service that, if
>> present, the viewer will consult to determine which object to show next.  I
>> see this a quite low-level service and we might use it as a building block
>> to some higher-level strategy (eg based on new annotations) at a later date.
>>> 
>>> The SPI I suggest is:
>>> 
>>> public interface RoutingService {
>>> 
>>>    public Object route(Object original);
>>> 
>>> }
>>> 
>>> A default implementation could be something like:
>>> 
>>> public class RoutingServiceDefault {
>>> 
>>>   public Object route(Object original) {
>>>       return original != null? original: homePage();
>>>   }
>>> 
>>>   private Object homePage() { ... code to find the @HomePage object if
>> any ... } }
>>> 
>>> This behaviour could be overridden eg to support the aggregate object
>> idea as discussed in [1].
>>> 
>>> So, that's my proposal.
>>> 
>>> Cheers
>>> Dan
>>> 
>>> 
>>> 
>>> [1] http://markmail.org/message/xhmeq62ywr2vqvje .
>>> [2] https://issues.apache.org/jira/browse/ISIS-666
>>> 
>>> 
>>>> On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx>
>> wrote:
>>>> 
>>>> Hello. I am just another Isis user like you, but I thought this might
>> help:
>>>> 
>>>> Wicket viewer shows what you "return" in your action method, so,
>>>> because you are returning void, Wicket is showing "no results"
>>>> message. Usually, you return the thing you create or update, but you
>>>> can return the parent if that's what you want, or anything else you
>>>> need, just get it in your code and return it. For example, I have a
>>>> method that adds a Deliverer that belongs to a BusinessLocation, and
>>>> after created shows the parent BusinessLocation entity object instead
>>>> of showing the Deliverer object just created (in my case, when showing
>>>> the BusinessLocation parent, the Deliverer just  created shows in the
>>>> collection section, which is what I wanted, because Business have that
>>>> collection). If you adapt this code to your deletePerson method I think
>> it can work.
>>>> 
>>>> My sample code is:
>>>> 
>>>>   @Action(
>>>>           domainEvent = CreateDomainEvent.class
>>>>   )
>>>>   @MemberOrder(name = "deliverers",sequence = "24")
>>>>   public BusinessLocation addDeliverer(
>>>>           final @ParameterLayout(named="Business Location")
>>>> BusinessLocation businessLocation,
>>>>           final @ParameterLayout(named="Deliverer Id") String
>>>> delivererId,
>>>>           final @ParameterLayout(named="First Name") String firstName,
>>>>           final @ParameterLayout(named="Middle Name")
>>>> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
>>>>           final @ParameterLayout(named="Last Name") String lastName,
>>>>           final @ParameterLayout(named="Last Name 2")
>>>> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
>>>>           final @ParameterLayout(named="Contact Phone")
>>>> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
>>>>           final @ParameterLayout(named="Delivery Phone")
>>>> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
>>>>           final @ParameterLayout(named="Deliverer Picture")
>>>> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
>>>>   )
>>>>   {
>>>>       final Deliverer obj =
>>>> container.newTransientInstance(Deliverer.class);
>>>>       obj.setBusinessLocation(businessLocation);
>>>>       obj.setDelivererId(delivererId);
>>>>       obj.setFirstName(firstName);
>>>>       obj.setMiddleName(middleName);
>>>>       obj.setLastName(lastName);
>>>>       obj.setLastName2(lastName2);
>>>>       obj.setContactPhone(contactPhone);
>>>>       obj.setDeliveryPhone(deliveryPhone);
>>>>       obj.setDelivererPicture(delivererPicture);
>>>>       obj.setCreationTime(clockService.nowAsDateTime());
>>>>       container.persistIfNotAlready(obj);
>>>>       return obj.getBusinessLocation();
>>>>   }
>>>> 
>>>> If you choose to return the parent of the Person object being deleted,
>>>> make sure you get the parent before you Delete the person. Have fun!
>>>> 
>>>> Cesar.
>>>> 
>>>> -----Original Message-----
>>>> From: Y.R Tan [mailto:mail@yuritan.nl]
>>>> Sent: Saturday, December 19, 2015 5:44 AM
>>>> To: users
>>>> Subject: How should we handle void and null results
>>>> 
>>>> Hi everyone,
>>>> 
>>>> When using a void action, let’s say a remove action, the user is
>>>> redirected to a page "no results". When clicking the back button in
>>>> the browser the user sees "Object not found" (since you’ve just
>>>> deleted this object).
>>>> 
>>>> Example:
>>>> 
>>>> public class Person {
>>>>   ....
>>>>   public void remove() {
>>>>       ...
>>>>   }
>>>> }
>>>> 
>>>> You can return a list for example to prevent the user from being
>>>> redirect to a "No results" page, but I think it’s not the
>>>> responsibility of the controllers in the domain model. A solution
>>>> could be that wicket viewer goes back one page when encountering a
>>>> deleted object. And refresh the current page when receiving a null
>> response or invoking a void action.
>>>> 
>>>> What do you guys think that is the best solution? Or do you have
>>>> another view on this situation?
>>>> 
>>>> Looking forward hearing from you.
>>>> 
>>>> Regards,
>>>> 
>>>> Yu Ri Tan
>>>> 
>>>> 
>>>> ---
>>>> This email has been checked for viruses by Avast antivirus software.
>>>> https://www.avast.com/antivirus
>>> 
>>> 
>>> ---
>>> This email has been checked for viruses by Avast antivirus software.
>>> https://www.avast.com/antivirus
>>> 
>> 


Re: How should we handle void and null results

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
On 22 December 2015 at 15:19, Óscar Bou - GOVERTIS <o....@govertis.com>
wrote:

>
> Hi all.
>
> I find the SPI Service really useful for advanced use cases.
>
> But in order to have the desired behavior clearly specified on the same
> class definition, shouldn't be helpful to also have an annotation
> indicating the desired behavior (like returning this instance)?
>
>
Seems better to provide a lower level SPI service that can work in all use
cases, and then use that as a building block for higher level abstractions
that might include annotations (or more likely, a new attribute of the
@Action annotation).

But to start that conversation, we could have a new "strategy" attribute,
eg:

@Action(
    routeUsing=MyRouter.class  // implements some sort of "Router"
interface, similar to our Specification interface
)
public void whatever(...) { ... }

Cheers
Dan




> Christmas here also :))
>
> HTH,
>
> Oscar
>
> > El 22 dic 2015, a las 15:54, Cesar Lugo <ce...@sisorg.com.mx>
> escribió:
> >
> > Dan,
> >
> > I think your proposal is quite good to have a configurable "default"
> behavior, and having the option to return whatever the developer wants is
> quite useful as well. Probably this could evolve to some kind of wizard (I
> saw a work in progress in Isis add-ons), or even some integration with some
> BPM tool. Just thinking loud here, it's christmas  :) .
> >
> > Cesar.
> >
> > -----Original Message-----
> > From: Dan Haywood [mailto:dan@haywood-associates.co.uk]
> > Sent: Tuesday, December 22, 2015 6:02 AM
> > To: users
> > Subject: Re: How should we handle void and null results
> >
> > There was a related discussion a while back [1], revolving around
> whether the Wicket viewer should always render the returned object, or some
> other object (eg the owning object/aggregate root).  I raised a ticket
> ISIS-666 [2] for this, and have also now referenced this thread [3].
> >
> > To pick up on a couple of points made:
> >
> > * should the object returned by the action determine the next object
> rendered (ie do domain object actions act as "controllers")?  Yu Ri says
> no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think we
> were always saying its ok, but to provide the ability for this to be
> modified (eg to the aggregate root rather than leaf).  We didn't discuss
> the case of returning void, though.
> >
> > * Martin was wondering about whether Person#delete() even makes sense.
> I think it does though; at least an end-user would want to press a button
> called "delete" on a domain object.  Behind the covers that might be a
> contributed action or mixin or double-dispatch back to a repository
> service.  But that's an implementation detail: the core responsibility is
> for a domain object to know how to get itself deleted
> >
> > * Steve suggests that where there is no obvious answer to "which object
> should be shown next", then the home page might be a reasonable default.  I
> agree, and think we should provide such a capability.
> >
> > * Cesar illustrates how to return a parent object, eg for both delete
> and also for add.
> >
> > To me it seems that it's unlikely to be a single policy that will
> support all use cases.  So I propose a new optional SPI service that, if
> present, the viewer will consult to determine which object to show next.  I
> see this a quite low-level service and we might use it as a building block
> to some higher-level strategy (eg based on new annotations) at a later date.
> >
> > The SPI I suggest is:
> >
> > public interface RoutingService {
> >
> >     public Object route(Object original);
> >
> > }
> >
> > A default implementation could be something like:
> >
> > public class RoutingServiceDefault {
> >
> >    public Object route(Object original) {
> >        return original != null? original: homePage();
> >    }
> >
> >    private Object homePage() { ... code to find the @HomePage object if
> any ... } }
> >
> > This behaviour could be overridden eg to support the aggregate object
> idea as discussed in [1].
> >
> > So, that's my proposal.
> >
> > Cheers
> > Dan
> >
> >
> >
> > [1] http://markmail.org/message/xhmeq62ywr2vqvje .
> > [2] https://issues.apache.org/jira/browse/ISIS-666
> >
> >
> >> On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx>
> wrote:
> >>
> >> Hello. I am just another Isis user like you, but I thought this might
> help:
> >>
> >> Wicket viewer shows what you "return" in your action method, so,
> >> because you are returning void, Wicket is showing "no results"
> >> message. Usually, you return the thing you create or update, but you
> >> can return the parent if that's what you want, or anything else you
> >> need, just get it in your code and return it. For example, I have a
> >> method that adds a Deliverer that belongs to a BusinessLocation, and
> >> after created shows the parent BusinessLocation entity object instead
> >> of showing the Deliverer object just created (in my case, when showing
> >> the BusinessLocation parent, the Deliverer just  created shows in the
> >> collection section, which is what I wanted, because Business have that
> >> collection). If you adapt this code to your deletePerson method I think
> it can work.
> >>
> >> My sample code is:
> >>
> >>    @Action(
> >>            domainEvent = CreateDomainEvent.class
> >>    )
> >>    @MemberOrder(name = "deliverers",sequence = "24")
> >>    public BusinessLocation addDeliverer(
> >>            final @ParameterLayout(named="Business Location")
> >> BusinessLocation businessLocation,
> >>            final @ParameterLayout(named="Deliverer Id") String
> >> delivererId,
> >>            final @ParameterLayout(named="First Name") String firstName,
> >>            final @ParameterLayout(named="Middle Name")
> >> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
> >>            final @ParameterLayout(named="Last Name") String lastName,
> >>            final @ParameterLayout(named="Last Name 2")
> >> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
> >>            final @ParameterLayout(named="Contact Phone")
> >> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
> >>            final @ParameterLayout(named="Delivery Phone")
> >> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
> >>            final @ParameterLayout(named="Deliverer Picture")
> >> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
> >>    )
> >>    {
> >>        final Deliverer obj =
> >> container.newTransientInstance(Deliverer.class);
> >>        obj.setBusinessLocation(businessLocation);
> >>        obj.setDelivererId(delivererId);
> >>        obj.setFirstName(firstName);
> >>        obj.setMiddleName(middleName);
> >>        obj.setLastName(lastName);
> >>        obj.setLastName2(lastName2);
> >>        obj.setContactPhone(contactPhone);
> >>        obj.setDeliveryPhone(deliveryPhone);
> >>        obj.setDelivererPicture(delivererPicture);
> >>        obj.setCreationTime(clockService.nowAsDateTime());
> >>        container.persistIfNotAlready(obj);
> >>        return obj.getBusinessLocation();
> >>    }
> >>
> >> If you choose to return the parent of the Person object being deleted,
> >> make sure you get the parent before you Delete the person. Have fun!
> >>
> >> Cesar.
> >>
> >> -----Original Message-----
> >> From: Y.R Tan [mailto:mail@yuritan.nl]
> >> Sent: Saturday, December 19, 2015 5:44 AM
> >> To: users
> >> Subject: How should we handle void and null results
> >>
> >> Hi everyone,
> >>
> >> When using a void action, let’s say a remove action, the user is
> >> redirected to a page "no results". When clicking the back button in
> >> the browser the user sees "Object not found" (since you’ve just
> >> deleted this object).
> >>
> >> Example:
> >>
> >> public class Person {
> >>    ....
> >>    public void remove() {
> >>        ...
> >>    }
> >> }
> >>
> >> You can return a list for example to prevent the user from being
> >> redirect to a "No results" page, but I think it’s not the
> >> responsibility of the controllers in the domain model. A solution
> >> could be that wicket viewer goes back one page when encountering a
> >> deleted object. And refresh the current page when receiving a null
> response or invoking a void action.
> >>
> >> What do you guys think that is the best solution? Or do you have
> >> another view on this situation?
> >>
> >> Looking forward hearing from you.
> >>
> >> Regards,
> >>
> >> Yu Ri Tan
> >>
> >>
> >> ---
> >> This email has been checked for viruses by Avast antivirus software.
> >> https://www.avast.com/antivirus
> >
> >
> > ---
> > This email has been checked for viruses by Avast antivirus software.
> > https://www.avast.com/antivirus
> >
>

Re: How should we handle void and null results

Posted by Óscar Bou - GOVERTIS <o....@govertis.com>.
Hi all.

I find the SPI Service really useful for advanced use cases.

But in order to have the desired behavior clearly specified on the same class definition, shouldn't be helpful to also have an annotation indicating the desired behavior (like returning this instance)?

Christmas here also :))

HTH,

Oscar

> El 22 dic 2015, a las 15:54, Cesar Lugo <ce...@sisorg.com.mx> escribió:
> 
> Dan, 
> 
> I think your proposal is quite good to have a configurable "default" behavior, and having the option to return whatever the developer wants is quite useful as well. Probably this could evolve to some kind of wizard (I saw a work in progress in Isis add-ons), or even some integration with some BPM tool. Just thinking loud here, it's christmas  :) .
> 
> Cesar.
> 
> -----Original Message-----
> From: Dan Haywood [mailto:dan@haywood-associates.co.uk] 
> Sent: Tuesday, December 22, 2015 6:02 AM
> To: users
> Subject: Re: How should we handle void and null results
> 
> There was a related discussion a while back [1], revolving around whether the Wicket viewer should always render the returned object, or some other object (eg the owning object/aggregate root).  I raised a ticket ISIS-666 [2] for this, and have also now referenced this thread [3].
> 
> To pick up on a couple of points made:
> 
> * should the object returned by the action determine the next object rendered (ie do domain object actions act as "controllers")?  Yu Ri says no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think we were always saying its ok, but to provide the ability for this to be modified (eg to the aggregate root rather than leaf).  We didn't discuss the case of returning void, though.
> 
> * Martin was wondering about whether Person#delete() even makes sense.  I think it does though; at least an end-user would want to press a button called "delete" on a domain object.  Behind the covers that might be a contributed action or mixin or double-dispatch back to a repository service.  But that's an implementation detail: the core responsibility is for a domain object to know how to get itself deleted
> 
> * Steve suggests that where there is no obvious answer to "which object should be shown next", then the home page might be a reasonable default.  I agree, and think we should provide such a capability.
> 
> * Cesar illustrates how to return a parent object, eg for both delete and also for add.
> 
> To me it seems that it's unlikely to be a single policy that will support all use cases.  So I propose a new optional SPI service that, if present, the viewer will consult to determine which object to show next.  I see this a quite low-level service and we might use it as a building block to some higher-level strategy (eg based on new annotations) at a later date.
> 
> The SPI I suggest is:
> 
> public interface RoutingService {
> 
>     public Object route(Object original);
> 
> }
> 
> A default implementation could be something like:
> 
> public class RoutingServiceDefault {
> 
>    public Object route(Object original) {
>        return original != null? original: homePage();
>    }
> 
>    private Object homePage() { ... code to find the @HomePage object if any ... } }
> 
> This behaviour could be overridden eg to support the aggregate object idea as discussed in [1].
> 
> So, that's my proposal.
> 
> Cheers
> Dan
> 
> 
> 
> [1] http://markmail.org/message/xhmeq62ywr2vqvje .
> [2] https://issues.apache.org/jira/browse/ISIS-666
> 
> 
>> On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx> wrote:
>> 
>> Hello. I am just another Isis user like you, but I thought this might help:
>> 
>> Wicket viewer shows what you "return" in your action method, so, 
>> because you are returning void, Wicket is showing "no results" 
>> message. Usually, you return the thing you create or update, but you 
>> can return the parent if that's what you want, or anything else you 
>> need, just get it in your code and return it. For example, I have a 
>> method that adds a Deliverer that belongs to a BusinessLocation, and 
>> after created shows the parent BusinessLocation entity object instead 
>> of showing the Deliverer object just created (in my case, when showing 
>> the BusinessLocation parent, the Deliverer just  created shows in the 
>> collection section, which is what I wanted, because Business have that 
>> collection). If you adapt this code to your deletePerson method I think it can work.
>> 
>> My sample code is:
>> 
>>    @Action(
>>            domainEvent = CreateDomainEvent.class
>>    )
>>    @MemberOrder(name = "deliverers",sequence = "24")
>>    public BusinessLocation addDeliverer(
>>            final @ParameterLayout(named="Business Location") 
>> BusinessLocation businessLocation,
>>            final @ParameterLayout(named="Deliverer Id") String 
>> delivererId,
>>            final @ParameterLayout(named="First Name") String firstName,
>>            final @ParameterLayout(named="Middle Name") 
>> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
>>            final @ParameterLayout(named="Last Name") String lastName,
>>            final @ParameterLayout(named="Last Name 2") 
>> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
>>            final @ParameterLayout(named="Contact Phone") 
>> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
>>            final @ParameterLayout(named="Delivery Phone") 
>> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
>>            final @ParameterLayout(named="Deliverer Picture") 
>> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
>>    )
>>    {
>>        final Deliverer obj =
>> container.newTransientInstance(Deliverer.class);
>>        obj.setBusinessLocation(businessLocation);
>>        obj.setDelivererId(delivererId);
>>        obj.setFirstName(firstName);
>>        obj.setMiddleName(middleName);
>>        obj.setLastName(lastName);
>>        obj.setLastName2(lastName2);
>>        obj.setContactPhone(contactPhone);
>>        obj.setDeliveryPhone(deliveryPhone);
>>        obj.setDelivererPicture(delivererPicture);
>>        obj.setCreationTime(clockService.nowAsDateTime());
>>        container.persistIfNotAlready(obj);
>>        return obj.getBusinessLocation();
>>    }
>> 
>> If you choose to return the parent of the Person object being deleted, 
>> make sure you get the parent before you Delete the person. Have fun!
>> 
>> Cesar.
>> 
>> -----Original Message-----
>> From: Y.R Tan [mailto:mail@yuritan.nl]
>> Sent: Saturday, December 19, 2015 5:44 AM
>> To: users
>> Subject: How should we handle void and null results
>> 
>> Hi everyone,
>> 
>> When using a void action, let’s say a remove action, the user is 
>> redirected to a page "no results". When clicking the back button in 
>> the browser the user sees "Object not found" (since you’ve just 
>> deleted this object).
>> 
>> Example:
>> 
>> public class Person {
>>    ....
>>    public void remove() {
>>        ...
>>    }
>> }
>> 
>> You can return a list for example to prevent the user from being 
>> redirect to a "No results" page, but I think it’s not the 
>> responsibility of the controllers in the domain model. A solution 
>> could be that wicket viewer goes back one page when encountering a 
>> deleted object. And refresh the current page when receiving a null response or invoking a void action.
>> 
>> What do you guys think that is the best solution? Or do you have 
>> another view on this situation?
>> 
>> Looking forward hearing from you.
>> 
>> Regards,
>> 
>> Yu Ri Tan
>> 
>> 
>> ---
>> This email has been checked for viruses by Avast antivirus software.
>> https://www.avast.com/antivirus
> 
> 
> ---
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
> 

RE: How should we handle void and null results

Posted by Cesar Lugo <ce...@sisorg.com.mx>.
Dan, 

I think your proposal is quite good to have a configurable "default" behavior, and having the option to return whatever the developer wants is quite useful as well. Probably this could evolve to some kind of wizard (I saw a work in progress in Isis add-ons), or even some integration with some BPM tool. Just thinking loud here, it's christmas  :) .

Cesar.

-----Original Message-----
From: Dan Haywood [mailto:dan@haywood-associates.co.uk] 
Sent: Tuesday, December 22, 2015 6:02 AM
To: users
Subject: Re: How should we handle void and null results

There was a related discussion a while back [1], revolving around whether the Wicket viewer should always render the returned object, or some other object (eg the owning object/aggregate root).  I raised a ticket ISIS-666 [2] for this, and have also now referenced this thread [3].

To pick up on a couple of points made:

* should the object returned by the action determine the next object rendered (ie do domain object actions act as "controllers")?  Yu Ri says no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think we were always saying its ok, but to provide the ability for this to be modified (eg to the aggregate root rather than leaf).  We didn't discuss the case of returning void, though.

* Martin was wondering about whether Person#delete() even makes sense.  I think it does though; at least an end-user would want to press a button called "delete" on a domain object.  Behind the covers that might be a contributed action or mixin or double-dispatch back to a repository service.  But that's an implementation detail: the core responsibility is for a domain object to know how to get itself deleted

* Steve suggests that where there is no obvious answer to "which object should be shown next", then the home page might be a reasonable default.  I agree, and think we should provide such a capability.

* Cesar illustrates how to return a parent object, eg for both delete and also for add.

To me it seems that it's unlikely to be a single policy that will support all use cases.  So I propose a new optional SPI service that, if present, the viewer will consult to determine which object to show next.  I see this a quite low-level service and we might use it as a building block to some higher-level strategy (eg based on new annotations) at a later date.

The SPI I suggest is:

public interface RoutingService {

     public Object route(Object original);

}

A default implementation could be something like:

public class RoutingServiceDefault {

    public Object route(Object original) {
        return original != null? original: homePage();
    }

    private Object homePage() { ... code to find the @HomePage object if any ... } }

This behaviour could be overridden eg to support the aggregate object idea as discussed in [1].

So, that's my proposal.

Cheers
Dan



[1] http://markmail.org/message/xhmeq62ywr2vqvje .
[2] https://issues.apache.org/jira/browse/ISIS-666


On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx> wrote:

> Hello. I am just another Isis user like you, but I thought this might help:
>
> Wicket viewer shows what you "return" in your action method, so, 
> because you are returning void, Wicket is showing "no results" 
> message. Usually, you return the thing you create or update, but you 
> can return the parent if that's what you want, or anything else you 
> need, just get it in your code and return it. For example, I have a 
> method that adds a Deliverer that belongs to a BusinessLocation, and 
> after created shows the parent BusinessLocation entity object instead 
> of showing the Deliverer object just created (in my case, when showing 
> the BusinessLocation parent, the Deliverer just  created shows in the 
> collection section, which is what I wanted, because Business have that 
> collection). If you adapt this code to your deletePerson method I think it can work.
>
> My sample code is:
>
>     @Action(
>             domainEvent = CreateDomainEvent.class
>     )
>     @MemberOrder(name = "deliverers",sequence = "24")
>     public BusinessLocation addDeliverer(
>             final @ParameterLayout(named="Business Location") 
> BusinessLocation businessLocation,
>             final @ParameterLayout(named="Deliverer Id") String 
> delivererId,
>             final @ParameterLayout(named="First Name") String firstName,
>             final @ParameterLayout(named="Middle Name") 
> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
>             final @ParameterLayout(named="Last Name") String lastName,
>             final @ParameterLayout(named="Last Name 2") 
> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
>             final @ParameterLayout(named="Contact Phone") 
> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
>             final @ParameterLayout(named="Delivery Phone") 
> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
>             final @ParameterLayout(named="Deliverer Picture") 
> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
>     )
>     {
>         final Deliverer obj =
> container.newTransientInstance(Deliverer.class);
>         obj.setBusinessLocation(businessLocation);
>         obj.setDelivererId(delivererId);
>         obj.setFirstName(firstName);
>         obj.setMiddleName(middleName);
>         obj.setLastName(lastName);
>         obj.setLastName2(lastName2);
>         obj.setContactPhone(contactPhone);
>         obj.setDeliveryPhone(deliveryPhone);
>         obj.setDelivererPicture(delivererPicture);
>         obj.setCreationTime(clockService.nowAsDateTime());
>         container.persistIfNotAlready(obj);
>         return obj.getBusinessLocation();
>     }
>
> If you choose to return the parent of the Person object being deleted, 
> make sure you get the parent before you Delete the person. Have fun!
>
> Cesar.
>
> -----Original Message-----
> From: Y.R Tan [mailto:mail@yuritan.nl]
> Sent: Saturday, December 19, 2015 5:44 AM
> To: users
> Subject: How should we handle void and null results
>
> Hi everyone,
>
> When using a void action, let’s say a remove action, the user is 
> redirected to a page "no results". When clicking the back button in 
> the browser the user sees "Object not found" (since you’ve just 
> deleted this object).
>
> Example:
>
> public class Person {
>     ....
>     public void remove() {
>         ...
>     }
> }
>
> You can return a list for example to prevent the user from being 
> redirect to a "No results" page, but I think it’s not the 
> responsibility of the controllers in the domain model. A solution 
> could be that wicket viewer goes back one page when encountering a 
> deleted object. And refresh the current page when receiving a null response or invoking a void action.
>
> What do you guys think that is the best solution? Or do you have 
> another view on this situation?
>
> Looking forward hearing from you.
>
> Regards,
>
> Yu Ri Tan
>
>
> ---
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>
>


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


Re: How should we handle void and null results

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
There was a related discussion a while back [1], revolving around whether
the Wicket viewer should always render the returned object, or some other
object (eg the owning object/aggregate root).  I raised a ticket ISIS-666
[2] for this, and have also now referenced this thread [3].

To pick up on a couple of points made:

* should the object returned by the action determine the next object
rendered (ie do domain object actions act as "controllers")?  Yu Ri says
no, whereas in the previous conversation (Oscar, Jeroen, Dan) I think we
were always saying its ok, but to provide the ability for this to be
modified (eg to the aggregate root rather than leaf).  We didn't discuss
the case of returning void, though.

* Martin was wondering about whether Person#delete() even makes sense.  I
think it does though; at least an end-user would want to press a button
called "delete" on a domain object.  Behind the covers that might be a
contributed action or mixin or double-dispatch back to a repository
service.  But that's an implementation detail: the core responsibility is
for a domain object to know how to get itself deleted

* Steve suggests that where there is no obvious answer to "which object
should be shown next", then the home page might be a reasonable default.  I
agree, and think we should provide such a capability.

* Cesar illustrates how to return a parent object, eg for both delete and
also for add.

To me it seems that it's unlikely to be a single policy that will support
all use cases.  So I propose a new optional SPI service that, if present,
the viewer will consult to determine which object to show next.  I see this
a quite low-level service and we might use it as a building block to some
higher-level strategy (eg based on new annotations) at a later date.

The SPI I suggest is:

public interface RoutingService {

     public Object route(Object original);

}

A default implementation could be something like:

public class RoutingServiceDefault {

    public Object route(Object original) {
        return original != null? original: homePage();
    }

    private Object homePage() { ... code to find the @HomePage object if
any ... }
}

This behaviour could be overridden eg to support the aggregate object idea
as discussed in [1].

So, that's my proposal.

Cheers
Dan



[1] http://markmail.org/message/xhmeq62ywr2vqvje .
[2] https://issues.apache.org/jira/browse/ISIS-666


On 21 December 2015 at 14:46, Cesar Lugo <ce...@sisorg.com.mx> wrote:

> Hello. I am just another Isis user like you, but I thought this might help:
>
> Wicket viewer shows what you "return" in your action method, so, because
> you are returning void, Wicket is showing "no results" message. Usually,
> you return the thing you create or update, but you can return the parent if
> that's what you want, or anything else you need, just get it in your code
> and return it. For example, I have a method that adds a Deliverer that
> belongs to a BusinessLocation, and after created shows the parent
> BusinessLocation entity object instead of showing the Deliverer object just
> created (in my case, when showing the BusinessLocation parent, the
> Deliverer just  created shows in the collection section, which is what I
> wanted, because Business have that collection). If you adapt this code to
> your deletePerson method I think it can work.
>
> My sample code is:
>
>     @Action(
>             domainEvent = CreateDomainEvent.class
>     )
>     @MemberOrder(name = "deliverers",sequence = "24")
>     public BusinessLocation addDeliverer(
>             final @ParameterLayout(named="Business Location")
> BusinessLocation businessLocation,
>             final @ParameterLayout(named="Deliverer Id") String
> delivererId,
>             final @ParameterLayout(named="First Name") String firstName,
>             final @ParameterLayout(named="Middle Name")
> @Parameter(optionality = Optionality.OPTIONAL)String middleName,
>             final @ParameterLayout(named="Last Name") String lastName,
>             final @ParameterLayout(named="Last Name 2")
> @Parameter(optionality = Optionality.OPTIONAL)String lastName2,
>             final @ParameterLayout(named="Contact Phone")
> @Parameter(optionality = Optionality.OPTIONAL)Long contactPhone,
>             final @ParameterLayout(named="Delivery Phone")
> @Parameter(optionality = Optionality.OPTIONAL)Long deliveryPhone,
>             final @ParameterLayout(named="Deliverer Picture")
> @Parameter(optionality = Optionality.OPTIONAL) Blob delivererPicture
>     )
>     {
>         final Deliverer obj =
> container.newTransientInstance(Deliverer.class);
>         obj.setBusinessLocation(businessLocation);
>         obj.setDelivererId(delivererId);
>         obj.setFirstName(firstName);
>         obj.setMiddleName(middleName);
>         obj.setLastName(lastName);
>         obj.setLastName2(lastName2);
>         obj.setContactPhone(contactPhone);
>         obj.setDeliveryPhone(deliveryPhone);
>         obj.setDelivererPicture(delivererPicture);
>         obj.setCreationTime(clockService.nowAsDateTime());
>         container.persistIfNotAlready(obj);
>         return obj.getBusinessLocation();
>     }
>
> If you choose to return the parent of the Person object being deleted,
> make sure you get the parent before you Delete the person. Have fun!
>
> Cesar.
>
> -----Original Message-----
> From: Y.R Tan [mailto:mail@yuritan.nl]
> Sent: Saturday, December 19, 2015 5:44 AM
> To: users
> Subject: How should we handle void and null results
>
> Hi everyone,
>
> When using a void action, let’s say a remove action, the user is
> redirected to a page "no results". When clicking the back button in the
> browser the user sees "Object not found" (since you’ve just deleted this
> object).
>
> Example:
>
> public class Person {
>     ....
>     public void remove() {
>         ...
>     }
> }
>
> You can return a list for example to prevent the user from being redirect
> to a "No results" page, but I think it’s not the responsibility of the
> controllers in the domain model. A solution could be that wicket viewer
> goes back one page when encountering a deleted object. And refresh the
> current page when receiving a null response or invoking a void action.
>
> What do you guys think that is the best solution? Or do you have another
> view on this situation?
>
> Looking forward hearing from you.
>
> Regards,
>
> Yu Ri Tan
>
>
> ---
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>
>