# Service

Ein Service ist die generischste Schnittstelle, die ein Plugin bereitstellen kann, denn es wird eine beliebige Anzahl Parameter beliebigen Typs entgegengenommen und ein Objekt beliebigen Typs zurückgegeben.

```kotlin
fun registerService(serviceName: String, service: Service)
```

`serviceName` ist eine frei wählbare ID, die über alle Services eines Plugins hinweg eindeutig sein muss. Es ist kein Problem, wenn mehrere Plugins einen Service mit derselben ID bereitstellen, da zum Ansprechen eines Services auch die `id` des Plugins herangezogen wird.

Ein Service muss `com.batix.plugins.Service` implementieren. Hier gibt es nur eine Methode, `call`. Diese Methode nimmt eine beliebige Anzahl an Argumenten vom Typ `Any?` (entspricht `Object` in Java) entgegen und gibt ein Objekt vom Typ `Any?` zurück (kann auch `null` sein).

Es liegt an der Implementierung selbst, herauszufinden, wie viele Argumente übergeben wurden, welchen Typ diese haben, dementsprechend Code auszuführen und ein Ergebnis zurückzugeben. Nutzern dieses Services sollte in einer Anleitung die `id` des Plugins und des Services sowie die Semantik mitgeteilt werden, also wie sich die Methode bei welchen Parametern verhält.

<p class="callout warning">**Typen**  
Die Typen der Parameter und des zurückgegebenen Objektes (und jeweils eventueller weiterer, darin eingebetteter Typen – wie bei Listen oder Maps) sollte sich auf **Standard-JVM- und Framework-Typen** wie beispielsweise `String` oder `ContainerRecord` beschränken.  
  
Das hat den Hintergrund, dass die Klassen des Plugins und seiner Dependencies nicht im Framework und anderen Plugins bekannt sind. Außerdem hilft es Leaks zu vermeiden, wenn das Plugin entladen wird.  
</p>

Mithilfe der Klasse `com.batix.plugins.Plugin` kann auf einen Service zugegriffen werden. Dafür holt man sich zunächst mittels der statischen Methode `byId` eine Referenz auf das Plugin und dann davon weiter eine Referenz auf den Service via `getService`. Beide Referenzen können befragt werden, ob das Plugin geladen bzw. der Service verfügbar ist.

Die Service-Referenz stellt eine `call` Methode (blockiert den aktuellen Thread) sowie eine asynchrone `callAsync` Methode (gibt ein `Future` Objekt zurück) bereit. Beide Methoden liefern eine Exception, falls das Plugin oder der Service nicht verfügbar ist. Eine andere Möglichkeit stellen die `tryCall` und `tryCallAsync` Methoden bereit. Diese werfen keine Exception, wenn etwas nicht verfügbar ist, sondern haben dann als Ergebnis das Objekt `com.batix.plugins.PluginRef.ServiceRef.UNAVAILABLE`.

## Beispiel

Die `Service`-Klasse im Beispiel besteht nur aus einer Methode, die eine Anzahl von `String`-Parametern erwartet und einen `String` zurückgibt (je nach Anzahl der Parameter einen anderen).

```kotlin
import com.batix.plugins.Service

class HelloService : Service {
  override fun call(vararg args: Any?): Any {
    return when {
      args.isEmpty()   -> "Hello."
      args.size == 1   -> "Hi ${args[0]}!"
      else             -> "Welcome ${args.joinToString(separator = ", ")}."
    }
  }
}
```

In der Plugin-Hauptklasse wird der Service registriert.

```kotlin
override fun load() {
  registerService(`"hello-service"`, HelloService())
}
```

Aufrufen kann man diesen Service dann z. B. mittels Groovy-Code im Framework.

```groovy
import com.batix.plugins.Plugin
import com.batix.plugins.PluginRef

def service = Plugin.byId("com.batix.website:mitarbeiter-import")
  .getService("hello-service")

println(service.call())                         // "Hello."
println(service.call("John"))                   // "Hi John!"
println(service.call("Joe", "Jack", "Jill"))    // "Welcome Joe, Jack, Jill."
```