[#domain-services]
= Domain Services

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
:page-partial:


_Domain services_ are (usually) singleton stateless services that provide additional functionality.
This may be exposed in the UI, or might be invoked programmatically.

However, a service cannot have (persisted) properties, nor can it have (persisted) collections.

Domain services that are visible in the UI or REST API are annotated with xref:refguide:applib:index/annotation/DomainService.adoc[@DomainService()], while services that are _programmatic_ in nature should be simply annotated using Spring's xref:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Component.html[@Component] or one of its specializations, eg
xref:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Service.html[@Service]
orxref:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Repository.html[@Repository].

Apache Isis runs on top of Spring Boot, and relies on Spring Boot for dependency injection using `@javax.inject.Inject`.
The `@javax.annotation.Priority` annotation is used to prioritize multiple service implementations, effectively allowing any framework-provided domain service to be substituted out by a user-defined one encountered with an earlier precedence (= higher priority) if required.

This section looks at the programming model for writing your own domain services.


== Nature of Service

Apache Isis uses Spring Boot to instantiate and manage the dependency injection of domain services.
The vast majority of these are singleton (application) scoped; a smaller number are request scoped (using the xref:refguide:applib:index/annotation/InteractionScope.adoc[@IsisSessionScope] annotation).

Accordingly, all domain services are annotated or meta-annotated using Spring's link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html[@Component] annotation.

For domain services to be visible in the Apache Isis UI, they must be annotated with xref:refguide:applib:index/annotation/DomainService.adoc[@DomainService].
Its xref:refguide:applib:index/annotation/DomainService.adoc#nature[#nature()] attribute is either:

* `VIEW` (the default if not specified)
+
which indicates that the actions should appear on the menu of the xref:vw:ROOT:about.adoc[Web UI (Wicket viewer)], and as top-level actions for the REST API provided by the xref:vro:ROOT:about.adoc[REST API (Restful Objects viewer)].

* `REST`
+
which indicates that the actions should appear in the REST API provided by the xref:vro:ROOT:about.adoc[REST API (Restful Objects viewer)], but not rendered by the xref:vw:ROOT:about.adoc[Web UI (Wicket viewer)].

It's also possible to define a "programmatic" domain service, meaning one that is instantiated and injected by Spring Boot, but is not visible in the UI or REST API.
Such programmatic services are usually annotated with Spring's link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Service.html[@Service] annotation or link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Repository.html[@Repository].

== Repository and Factory

The repository/factory uses an injected xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService] to both instantiate new objects and to query the database for existing objects of a given entity type.
Generally these services are not visible in UI, and so are annotated with link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Repository.html[@Repository]

For example:

[source,java]
----
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;

@Repository                                                     // <.>
@RequiredArgsConstructor(onConstructor_ = {@Inject} )           // <.>
public CustomerRepository {

    private final RepositoryService repositoryService;

    public List<Customer> findByName(String name) {
        return repositoryService.allMatches(                    // <.>
                Query.named(Customer.class, "findByName")
                    .withParameter("name", name));
    }

    public Customer newCustomer(...) {
        Customer Customer =
            repositoryService.detachedEntity(Customer.class);   // <.>
        ...
        return repositoryService.persistAndFlush(Customer);     // <.>
    }

    public List<Customer> allCustomers() {                      // <.>
        return repositoryService.allInstances(Customer.class);
    }
}
----
<.> Detected and managed by Spring Boot.
<.> Lombok annotation for dependency injection of xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService] through generated constructor.
<.> uses injected `RepositoryService` to query via JDOQL.
<.> uses injected `RepositoryService` to instantiate a not-yet-persisted domain entity ...
<.> \... and then save into the database a new `Customer` instance.
<.> Returns all instances (useful for prototyping, probably not for production).

There is no need to annotate the actions; they are implicitly hidden because of the domain service's nature.

[TIP]
====
JDO/Datanucleus also supports link:http://www.datanucleus.org:15080/products/accessplatform_5_2/jdo/query.html#jdoql_typed[type-safe queries].
These can be executed through the xref:refguide:persistence:index/jdo/applib/services/JdoSupportService.adoc[JdoSupportService] domain service.
====

== Menu

Menu services provide actions to be rendered on the menu.

For the xref:vw:ROOT:about.adoc[Web UI (Wicket viewer)], each service's actions appear as a collection of menu items of a named menu, and this menu is on one of the three menu bars provided by the Wicket viewer.
Although these can be organised using annotations, it's usually easier to use a xref:userguide:fun:ui/menubars-layout.adoc#file-based-menus[file-based layout file] (`menubars.layout.xml`).

For the xref:vro:ROOT:about.adoc[REST API (Restful Objects viewer)], all menu services are shown in the services representation.

[source,java]
----
import lombok.RequiredArgsConstructor;

@DomainService(nature = NatureOfService.VIEW)                   // <.>
@RequiredArgsConstructor(onConstructor_ = {@Inject} )           // <.>
public class Customers {

    @Inject
    protected final CustomerRepository customerRepository;      // <.>

    @Action(semantics = SemanticsOf.SAFE)
    @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT)
    public List<Customer> findByName(                           // <.>
            @ParameterLayout(named="Name")                      // <.>
            final String name ) {
        return customerRepository.findByName(name);             // <.>
    }

    @Action(semantics = SemanticsOf.NON_IDEMPOTENT)
    public Customer newCustomer(...) {
        return customerRepository.newCustomer(...);
    }

    @Action( semantics = SemanticsOf.SAFE,
             restrictTo = RestrictTo.PROTOTYPING )              // <.>
    public List<Customer> listAll() {
        return customerRepository.listAll();
    }
}
----

<.> Identify the class as a domain service, to render in the menu.

<.> Rendered in the UI as a "Find By Name" menu item underneath the "Customers" menu.

<.> The xref:refguide:applib:index/annotation/ParameterLayout.adoc[@ParameterLayout] provides metadata for the parameter itself, in this case its name.
+
[TIP]
====
There's no need to name the action parameters if the code is compiled using the `-parameters` flag to the Java compiler (javac); the framework will then use the name of the parameter itself.
====

<.> the action implementation delegates to an injected repository.
The framework can inject into not just other domain services but will also automatically into domain entities and view models.
There is further discussion of service injection xref:userguide:fun:domain-entities-and-services.adoc#injecting-services[below].

<.> xref:refguide:applib:index/annotation/Action.adoc#restrictTo[Prototype] actions are rendered only in prototyping mode.
A "list all" action such as this can be useful when exploring the domain with a small dataset.

<.> Menu services typically delegate to an underlying repository/ies specific to the domain (rather than use `RepositoryService` directly, for example).

Whether you separate out menu services from repository services is to some extent a matter of style.
One perspective is that these two closely related domain services nevertheless have different responsibilities, and so could be kept separate.
An alternative perspective is that the duplication is just unnecessary boilerplate, and conflicts with the naked objects philosophy.

== Event Subscribers

Domain services acting as event subscribers can subscribe to xref:userguide:fun:overview.adoc#lifecycle-events[lifecycle] events, influencing the rendering and behaviour of other objects.
Behind the scenes this uses Spring's (in-memory) link:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#context-functionality-events-annotation[event bus].

[source,java]
----
import org.springframework.stereotype.Service;
import org.springframework.context.event.EventListener;
import lombok.RequiredArgsConstructor;

@Service                                                        // <.>
@lombok.RequiredArgsConstructor(onConstructor_ = {@Inject} )
public class OnCustomerDeletedCascadeDeleteOrders {

    private final OrderRepository orderRepository;

    @EventListener(Customer.DeletedEvent.class)                 // <.>
    public void on(final Customer.DeletedEvent ev) {            // <.>
        Customer customer = ev.getSource();
        orderRepository.delete(customer);
    }
}
----
<.> subscriptions do not appear in the UI at all

<.> use Spring Framework's link:https://javadoc.io/doc/org.springframework/spring-context/latest/org/springframework/context/event/EventListener.html[@EventListener]

<.> the parameter type of the method corresponds to the event emitted on the event bus.
The actual method name does not matter (though it must have `public` visibility).

== Scoped services

By default all domain services are application-scoped, in other words singletons.
Such domain services are required to be thread-safe, usually satisfied by being intrinsically stateless.

Sometimes though a service's lifetime is applicable only to a single (http) request.
The framework has a number of such services, including a xref:refguide:applib:index/services/scratchpad/Scratchpad.adoc[Scratchpad] service (to share adhoc data between methods), and xref:refguide:applib:index/services/queryresultscache/QueryResultsCache.adoc[QueryResultsCache], which as its name suggests will cache query results.
Such services _do_ hold state, but that state is scoped per (possibly concurrent) request and should be removed afterwards.

The requirement for request-scoped services is supported using Apache Isis' own xref:refguide:applib:index/annotation/InteractionScope.adoc[@IsisSessionScope] annotation (named because a short-lived `IsisSession` is created for each request).
This is used by the framework services and can also be used for user-defined services.

For example:

[source,java]
----
@Service
@IsisSessionScope
public class MyService {
    ...
    public void doSomething() { ... }
}
----

Unlike application-scoped services, these request-scoped services must be injected using a slightly different idiom (borrowed from CDI), using a `javax.inject.Provider`.
For example:

[source,java]
----
import javax.inject.Provider;

public class SomeClient {
    ...
    @Inject
    Provider<MyService> myServiceProvider;  // <.>

    public void someMethod() {
        myServiceProvider.get()             // <.>
                         .doSomething();
}
----
<.> Inject using `Provider`
<.> Obtain an instance using `Provider#get()`


== Configuration

Spring provides numerous mechanisms to configure domain services, both in terms of binding or passing in the configuration property to the service, and in terms of setting the value within some sort of configuration file.

The mechanism prefered by Apache Isis itself, and which you are free to use for your own services, is the type-safe link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/ConfigurationProperties.html[ConfigurationProperties], whereby the configuration properties are expressed in a series of nested static classes.

The xref:docs:starters:simpleapp.adoc[simpleapp starter app] includes an example:

[source,java]
----
import org.springframework.validation.annotation.Validated;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("app.simple-module")
@lombok.Data
@Validated
public static class Configuration {
    private final Types types = new Types();
    @lombok.Data
    public static class Types {
        private final Name name = new Name();
        @lombok.Data
        public static class Name {
            private final Validation validation = new Validation();
            @lombok.Data
            public static class Validation {
                private char[] prohibitedCharacters =
                    "!&%$".toCharArray();
                private String message =
                    "Character '{character}' is not allowed";
            }
        }
    }
}
----

This configuration property can be injected, like any other component, and makes the configuration value available in a type-safe fashion:

[source,java]
----
val prohibitedCharacters =
  config.getTypes().getName().getValidation().getProhibitedCharacters();
----

For this configuration property service to be discovered and managed by Spring, we need to use the link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/EnableConfigurationProperties.html[EnableConfigurationProperties] annotation.
This normally would reside on the owning module (discussed in more detail xref:modules.adoc[later]):

[source,java]
.SimpleModule.java
----
import org.springframework.context.annotation.Configuration

@Configuration
// ...
@EnableConfigurationProperties({
        SimpleModule.Configuration.class,
})
public class SimpleModule /* ... */ {
    // ...
}
----


These configuration properties can then be specified using either Spring's `application.yml` or `application.properties`.
For example:

[source,yml]
.application.yml
----
app:
  simple-module:
    types:
      name:
        validation:
          message: "'{character}' is invalid."
          prohibited-characters: "&%$"
----

Moreover, Spring is able to configure the IDE so that these configuration values can be specified using code completion.
All that is required is this dependency:

[source,xml]
.pom.xml
----
<!-- IDE support  -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
----

== Initialization

Sometimes a domain service needs to perform initialization logic before it is ready to be used.

In many cases, such initialization can be performed within the constructor.
If the initialization has dependencies, then these can be injected using standard link:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-spring-beans-and-dependency-injection[constructor injection].

Alternatively, initialization can be moved into a `@PostConstruct` link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-postconstruct-and-predestroy-annotations[lifecycle callback].
Shutdown is similar; the framework will call any method annotated with `javax.annotation.PreDestroy`.





