1

I am working on a project using ISIS 1.16.2. I have a superclass, called ConfigurationItem, which has some common properties (name, createdTimestamp etc.). For example it has a delete action method, annotated with @Action(invokeOn = InvokeOn.OBJECT_AND_COLLECTION, ...), which I need to be callable from entitys detail view as well as from collection views with selection boxes.

Example:

public class ConfigurationItem {

    @Action(
            invokeOn = InvokeOn.OBJECT_AND_COLLECTION,
            semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE,
            domainEvent = DeletedDomainEvent.class)
    public Object delete() {
        repositoryService.remove(this);
        return null;
    }

    // ...
}

public class ConfigurationItems {

    @Action(semantics = SemanticsOf.SAFE)
    public List<T> listAll() {
        return repositoryService.allInstances(<item-subclass>.class);
    }

    // ...
}

This works pretty well but the "invokeOn" annotation is now deprecated. The JavaDoc says that one should switch to @Action(associateWith="...") but I don't know how to transfer the semantics of 'InvokeOn' since I have no collection field for reference. Instead I only have the collection of objects returned by the database retrieve action.

My question is: How do I transfer the deprecated @Action(invokeOn=...) semantics to the new @Action(associateWith="...") concept for collection return values with no backed property field?

Thanks in advance!

JND
  • 65
  • 7

1 Answers1

1

Good question, this obviously isn't explained well enough in the Apache Isis documentation.

The @Action(invokeOn=InvokeOn.OBJECT_AND_COLLECTION) has always been a bit of a kludge, because it involves invoking an action against a standalone collection (which is to say, the list of object returned from a previous query). We don't like this because there is no "single" object to invoke the action on.

When we implemented that feature, the support for view models was nowhere near as comprehensive as it now is. So, our recommendation now is, rather than returning a bare standalone collection, instead wrap it in a view model which holds the collection.

The view model then gives us a single target to invoke some behaviour on; the idea being that it is the responsibility of the view model to iterate over all selected items and invoke an action on them.

With your code, we can introduce SomeConfigItems as the view model:

@XmlRootElement("configItems")
public class SomeConfigItems {

    @lombok.Getter @lombok.Setter
    private List<ConfigurationItem> items = new ArrayList<>();

    @Action(
        associateWith = "items",  // associates with the items collection
        semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE,
        domainEvent = DeletedDomainEvent.class)
    public SomeConfigItems delete(List<ConfigurationItem> items) {
        for(ConfigurationItem item: items) {
           repositoryService.remove(item);
        }
        return this;
    }
    // optionally, select all items for deletion by default
    public List<ConfigurationItem> default0Delete() { return getItems(); }

    // I don't *think* that a choices method is required, but if present then 
    // is the potential list of items for the argument
    //public List<ConfigurationItem> choices0Delete() { return getItems(); }
}

and then change the ConfigurationItems action to return this view model:

public class ConfigurationItems {

    @Action(semantics = SemanticsOf.SAFE)
    public SelectedItems listAll() {
        List<T> items = repositoryService.allInstances(<item-subclass>.class);
        return new SelectedItems(items);
    }
}

Now that you have a view model to represent the output, you'll probably find other things you can do with it.

Hope that makes sense!

Dan Haywood
  • 2,215
  • 2
  • 17
  • 23
  • Thank you very much! That makes a lot of sense. Do I have to annotate the JAXB view model with @DomainObject(nature=VIEW_MODEL) or something similar or is it optional? – JND Feb 01 '19 at 08:34
  • I *think* its optional, but there's no harm in adding it. – Dan Haywood Feb 01 '19 at 16:53
  • I have tried your solution. It works. But it is no full one-to-one replacement for the `invokeOn` annotation since it introduces a lot of boilerplate code and opens an additional popup dialog which breaks user experience. Is there a way to get rid of this popup (which btw. throws some NPE from time to time when removing all elements)? – JND Feb 05 '19 at 08:02
  • No, I guess at the moment there isn't. Raise a ticket on our JIRA to get an enhancement/improvement on this. – Dan Haywood Feb 05 '19 at 17:16