Uploaded image for project: 'Causeway'
  1. Causeway
  2. CAUSEWAY-493

Annotation to identify domain services/repositories

    XMLWordPrintableJSON

Details

    • New Feature
    • Status: Closed
    • Major
    • Resolution: Fixed
    • core-1.2.0
    • core-1.6.0
    • Core
    • None

    Description

      Introduce a new @DomainService annotation, that can optionally indicate that it is a repository for an entity.

      eg for a service that is a repository:

      @DomainService(repositoryFor=Organization.class)
      public class Organizations {
      public List<Organization> findByName(...)

      { ... }

      ...
      }

      and for a service that isn't a repository, eg:

      @DomainService
      public class BarcodeScanner {
      ...
      }

      ~~~~~~~~

      background to this request originally raised by Oscar Bou, :http://markmail.org/thread/7xa2gtcytwvq7ogp

      copied in for convenience:

      We are implementing some BDD tests. And we have the need to always write custom spec transformers (one for each domain entity class) like this one:

      public class ETO {
      private ETO() {}
      ...

      public static class Party extends NullRecognizingTransformer<org.estatio.dom.party.Party> {
      @Override
      public org.estatio.dom.party.Party transformNonNull(String id) {
      try

      { return ScenarioExecution.current().getVar("party", id, org.estatio.dom.party.Party.class); }

      catch(IllegalStateException e)

      { return ScenarioExecution.current().service(Parties.class).findPartyByReferenceOrName(id); }

      }
      }

      If we had an annotation like "@IsisRepository(org.estatio.dom.party.Party.class)" for annotating the Party's repository, the previous transformer could be "generalized" (previously searching also for a var on the Scenario context with the class name in camelCase).

      Obviously, if none is found it should be mandatory to declare a transformer.

      There could be also other scenarios where could be useful to be able to know what's the repository for a given domain entity class. Sure you can think about more.

      The container (or any other Isis class) could have a method for returning the proper repository for a class.

      What do you think? Could it be useful? Any problems derived from it?

      ~~~~~~~
      Dan's response:

      Hi Oscar,
      yup, I like the idea, I think... though I'd probably use @DomainService
      instead of @IsisRepository.

      Another benefit is that we can use it to automatically locate services so
      that they don't need to be explicitly registered - something that you've
      asked for in the past, IIRC. A suitable implementation of
      org.apache.isis.core.runtime.services.ServicesInstaller would do the trick,
      I think.

      It might need a few iterations to get exactly correct, however. A couple
      of questions I have is:

      • is it your intention to generalize the
        "findPartyByReferenceOrName(String)" bit (in the catch block) also? If so,
        wouldn't that require that DomainService would need to be an interface
        (declaring findById(...)) rather than a simple annotation?
      • I'm not sure about how hierarchies of classes work. for example, we have
        Parties domain service, for any sort of Party, but also Organisations
        domain service, for Organisation (subtype of Party) and Persons domain
        service (for Person, subtype of Party). The entities are closely related
        through inheritance, but I don't really have a pattern to explain to myself
        what the relationship should be (if any) between their corresponding domain
        services of Parties, Organisations and Persons.

      Let's exchange a few more mails on this before going ahead and writing some
      new code on it....

      Dan

      ~~~
      Oscar's response:

      Hi, Dan.

      yup, I like the idea, I think... though I'd probably use @DomainService
      instead of @IsisRepository.

      Well, perhaps we need two. But I consider relevant to be able to distinguish
      "Repositories" as defined in DDD from the other kind of Domain Services.

      The @DomainService annotation would mark a service as that.

      But the @IsisRepository(entity=XXXX), @Repository(entity=XXXX), etc. would have
      the additional meaning to be acting as the repository for a specific kind of
      Domain Entities, so the "entity=XXXX" param should be mandatory.

      They should also be considered as Domain Services.

      • is it your intention to generalize the
        "findPartyByReferenceOrName(String)" bit (in the catch block) also? If so,
        wouldn't that require that DomainService would need to be an interface
        (declaring findById(...)) rather than a simple annotation?

      Yes. In fact, we currently have a generic "findByName", "findByProperty", etc
      methods on a generic abstract repository, implemented with the help of the
      IsisJdoSupport service. We are "multi-tenant", and that allows us to always
      filter by tenant and apply some other business filters. We use those protected
      methods on the domain "finders" defined on each entity's repository.

      As we are sharing the implementation, we chose inheritance, but an interface
      would also do the trick.

      But we consider that an "implementation detail" in addition to the annotation,
      not a replacement.

      • I'm not sure about how hierarchies of classes work. for example, we have
        Parties domain service, for any sort of Party, but also Organisations
        domain service, for Organisation (subtype of Party) and Persons domain
        service (for Person, subtype of Party). The entities are closely related
        through inheritance, but I don't really have a pattern to explain to myself
        what the relationship should be (if any) between their corresponding domain
        services of Parties, Organisations and Persons.

      In our case, we have references to "Parties" on other Domain Entities, so we
      need to be able to associate "Parties", in addition to "Organizations" and
      "Persons". So we need to have "finders" for Parties. If that's the case, we need
      the "Party Repository", in addition to the "Organization Repository" and the
      "Person Repository". No need for inheritance between them, unless you have to
      share the implementation of some methods, validations, etc. That was not our
      case. All them inherit from the "abstract base domain repository".

      But what we have needed is the ability to distinguish between "creation" actions
      or "factory methods" (we firstly implemented it by searching for methods defined
      on services and starting with "create", but we changed after to an annotation
      called "@FactoryMethod" - perhaps other names are better, and names are
      important on DDD, we know ) in order to be able to know "how" to create a
      "Party" descendant (on Edit forms and action params we are offering the user the
      option to create a new entity in addition to select from an existing one).

      Attachments

        1. PastedGraphic-3.png
          91 kB
          Daniel Keir Haywood

        Activity

          People

            danhaywood Daniel Keir Haywood
            danhaywood Daniel Keir Haywood
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: