OLS4 is available at [https://www.ebi.ac.uk/ols4/](https://www.ebi.ac.uk/ols4/). Please report any issues to the
tracker in this repository.

---

Version 4 of the EMBL-EBI Ontology Lookup Service (OLS), featuring:

* Much faster dataload (loads the OBO foundry in hours instead of days)
* Modular dataload pipeline with decoupled, individually testable stages
* Automated CI testing of the dataload with minimal testcase ontologies
* A lossless data representation: everything in the ontology is preserved in the databases
* Coverage of the whole OWL2 spec, and also loads vocabularies defined purely in RDFS
* Uses updated versions of Solr and Neo4j (no embedded databases, no MongoDB)
* React frontend using Redux and Tailwind
* Backwards compatibility with the OLS3 API

This repository contains three projects:

* The dataloader (`dataload` directory)
* The API server (`backend` directory)
* The React frontend (`frontend` directory)

# Deploying OLS4

If you want to try OLS4 out, this should get you going:

    export OLS4_CONFIG=./dataload/configs/efo.json
    docker compose up

You should now be able to access the OLS4 frontend at `http://localhost:8081`.

If you need to set the heap size, you can do so using:

    JAVA_OPTS="-Xms5G -Xmx25G"  docker compose up

If you want to test it with your own ontology, copy the OWL or RDFS ontology file to the `testcases` folder (which is
mounted in Docker). Then make a new config file for your ontology in `dataload/configs` (you can use `efo.json` as a
template). For the `ontology_purl` property in the config, use e.g. `file:///opt/dataload/testcases/myontology.owl` if
your ontology is in `testcases/myontology.owl`. Then follow the above steps for efo with the config filename you
created.

## Deployment: Using Kubernetes with GitHub Packages

To deploy OLS4 using Kubernetes, Docker images built and uploaded to this repository (using GitHub Packages) are
utilized. Software requirements are as follows:

1. Kubernetes command-line tool, _kubectl_
2. Kubernetes package manager, _helm_

### Create data archives for Solr and Neo4j

To create your own Solr and Neo4j data archives, follow the steps on [how to load data locally](#running-the-dataload-locally).

### Startup dataserver

Uninstall existing `dataserver` deployments, if any, before installing a new one. Do not forget to set `KUBECONFIG`
environment variable.

    export KUBECONFIG=<K8S_CONFIG>
    helm install ols4-dataserver --wait <OLS4_DIR>/k8chart/dataserver

### Copy data to dataserver

From your local directory, copy the Solr and Neo4j data archive files to the `dataserver`.

    kubectl cp <LOCAL_DIR>/neo4j.tgz $(/srv/data/k8s/kubectl get pods -l app=ols4-dataserver -o custom-columns=:metadata.name):/usr/share/nginx/html/neo4j.tgz
    kubectl cp <LOCAL_DIR>/solr.tgz $(/srv/data/k8s/kubectl get pods -l app=ols4-dataserver -o custom-columns=:metadata.name):/usr/share/nginx/html/solr.tgz

### Startup OLS4 deployment

Uninstall existing `ols4` deployments, if any, before installing a new one. Do not forget to set `KUBECONFIG`
environment variable.

**IMPORTANT**: The use of `imageTag` is to specify the Docker image (uploaded to this repository) that will be used in the deployment. If not familiar, simply
use either the `dev` or `stable` image.

    export KUBECONFIG=<K8S_CONFIG>
    helm install ols4 <OLS4_DIR>/k8chart/ols4 --set imageTag=dev

# Developing OLS4

OLS is different to most webapps in that its API provides both full text search and recursive graph queries, neither of
which are possible and/or performant using traditional RDBMS. It therefore uses two specialized database servers: [**Solr**](https://solr.apache.org), a Lucene server similar to ElasticSearch; and [**Neo4j**](https://neo4j.com), a graph
database.

* The `dataload` directory contains the code which turns ontologies from RDF (specified using OWL and/or RDFS) into JSON
  and CSV datasets which can be loaded into Solr and Neo4j, respectively; and some minimal bash scripts which help with
  loading them.
* The `backend` directory contains a Spring Boot application which hosts the OLS API over the above Solr and Neo4j
  instances
* The `frontend` directory contains the React frontend built upon the `backend` above.

![OLS4 overview](docs/overview.png)

## Development: Running OLS4 using Docker

You can run OLS4, or any combination of its consistuent parts (dataload, backend, frontend) in Docker. When developing,
it is often useful to run, for example, just Solr and Neo4j in Docker, while running the API server locally; or to run
Solr, Neo4j, and the backend API server in Docker while running the frontend locally.

First install the latest version of Docker Desktop if you are on Mac or Windows. This now includes the `docker compose`
command. If you are on Linux, make sure you have the `docker compose` plugin
installed (`apt install docker.io docker-compose-plugin` on Ubuntu).

You will need a config file, which configures the ontologies to load into OLS4. You can provide this to `docker compose`
using the `OLS4_CONFIG` environment variable. For example:

	export OLS4_CONFIG=./dataload/configs/efo.json

Then, start up the components you would like to run. For example, Solr and Neo4j only (to develop the backend API server
and/or frontend):

    docker compose up --force-recreate --build --always-recreate-deps --attach-dependencies ols4-solr ols4-neo4j

This will build and run the dataload, and start up Solr and Neo4j with your new dataset on ports 8983 and 7474,
respectively. To start Solr and Neo4j **AND** the backend API server (to develop the frontend):

    docker compose up --force-recreate --build --always-recreate-deps --attach-dependencies ols4-solr ols4-neo4j ols4-backend

To start everything, including the frontend:

    docker compose up --force-recreate --build --always-recreate-deps --attach-dependencies ols4-solr ols4-neo4j ols4-backend ols4-frontend

## Development: Running OLS4 locally

Alternatively, you can run OLS4 or any of its constituent parts locally, which is more useful for development. Software
requirements are as follows:

1. Java 11. Later versions of Java are probably fine, though the Neo4j we use only works with Java 11.
2. Maven 3.x.x
3. Neo4J 4.4.x
4. Solr 9.0.0
5. Your favourite Git client

### Acquire source and build

Clone repo:

    git clone git@github.com:EBISPOT/ols4.git

Build backend:

    mvn clean package

Build frontend:

    npm install

### Test testcases from dataload to UI

The scripts below assume you have the following environment variables set:

`NEO4J_HOME`

`SOLR_HOME`

`OLS4_HOME` - this should point to the root folder where you have the OLS4 code.

Change the directory to $OLS4_HOME.

    cd $OLS4_HOME

To load a testcase and start Neo4J and Solr, run:

    ./dev-testing/teststack.sh <rel_json_config_url> <rel_output_dir>

where `<rel_json_config_url>` can be a JSON config file or a directory with JSON file, and `<rel_outdir>`
the output directory, both relative from $OLS4_HOME, i.e.:

    ./dev-testing/teststack.sh ./testcases/owl2-primer/minimal.json ./output

or if you want to load all testcases, you can use

    ./dev-testing/teststack.sh ./testcases ./output

If you need to set the Java heap size, you can set the environment the JAVA_OPTS variable as follows:

     export JAVA_OPTS="-Xms5G -Xmx10G"

Once Neo4J and Solr is up, to start the backend (REST API) you can run:

    ./dev-testing/start-backend.sh

Once the backend is up, you can start the frontend with:

    ./dev-testing/start-frontend.sh

Once you are done testing, to stop everything:

    ./stopall.sh

### Running the dataload locally

All related files for loading and processing data are in `dataload`.
First, make sure the configuration files (that determine which ontologies to load) are ready and to build all the JAR files:

    cd dataload
    mvn clean package

#### Pre-download RDF

    java \
    -DentityExpansionLimit=0 \
    -DtotalEntitySizeLimit=0 \
    -Djdk.xml.totalEntitySizeLimit=0 \
    -Djdk.xml.entityExpansionLimit=0 \
    -jar predownloader.jar \
    --config <CONFIG_FILE> \
    --downloadPath <DOWNLOAD_PATH>

#### Convert RDF to JSON

    java \
    -DentityExpansionLimit=0 \
    -DtotalEntitySizeLimit=0 \
    -Djdk.xml.totalEntitySizeLimit=0 \
    -Djdk.xml.entityExpansionLimit=0 \
    -jar rdf2json.jar \
    --downloadedPath <DOWNLOAD_PATH> \
    --config <CONFIG_FILE> \
    --output <LOCAL_DIR>/output_json/ontologies.json

#### Run ontologies linker

    java \
    -jar linker.jar \
    --input <LOCAL_DIR>/output_json/ontologies.json \
    --output <LOCAL_DIR>/output_json/ontologies_linked.json \
    --leveldbPath <LEVEL_DB_DIR>

#### Convert JSON to Neo4j CSV

    java \
    -jar json2neo.jar \
    --input <LOCAL_DIR>/output_json/ontologies_linked.json \
    --outDir <LOCAL_DIR>/output_csv/

#### Create Neo4j from CSV

Run Neo4j `import` command:

    ./neo4j-admin import \
    --ignore-empty-strings=true \
    --legacy-style-quoting=false \
    --array-delimiter="|" \
    --multiline-fields=true \
    --database=neo4j \
    --read-buffer-size=134217728 \
    $(<LOCAL_DIR>/make_csv_import_cmd.sh)

Here is a sample `make_csv_import_cmd.sh` file:

    for f in ./output_csv/*_ontologies.csv
    do
    echo -n "--nodes=$f "
    done

    for f in ./output_csv/*_classes.csv
    do
    echo -n "--nodes=$f "
    done

    for f in ./output_csv/*_properties.csv
    do
    echo -n "--nodes=$f "
    done

    for f in ./output_csv/*_individuals.csv
    do
    echo -n "--nodes=$f "
    done

    for f in ./output_csv/*_edges.csv
    do
    echo -n "--relationships=$f "
    done

#### Make Neo4j indexes

Start Neo4j locally and then run the sample database commands, which are also defined in `create_indexes.cypher` inside the `dataload` directory:

    CREATE INDEX FOR (n:OntologyClass) ON n.id;
    CREATE INDEX FOR (n:OntologyIndividual) ON n.id;
    CREATE INDEX FOR (n:OntologyProperty) ON n.id;
    CREATE INDEX FOR (n:OntologyEntity) ON n.id;

    CALL db.awaitIndexes(10800);

After creating the indexes, stop Neo4j as needed.

#### Convert JSON output to Solr JSON

    java \
    -jar json2solr.jar \
    --input <LOCAL_DIR>/output_json/ontologies_linked.json \
    --outDir <LOCAL_DIR>/output_jsonl/

#### Update Solr indexes

Before running Solr, make sure to copy the configuration (`solr_config`) from inside `dataload` directory to local, e.g., `<SOLR_DIR>/server/solr/`.
Then, start Solr locally and use the generated JSON files to update. See sample commands below:

    wget \
    --method POST --no-proxy -O - --server-response --content-on-error=on \
    --header="Content-Type: application/json" \
    --body-file <LOCAL_DIR>/output_jsonl/ontologies.jsonl \
    http://localhost:8983/solr/ols4_entities/update/json/docs?commit=true

    wget \
    --method POST --no-proxy -O - --server-response --content-on-error=on \
    --header="Content-Type: application/json" \
    --body-file <LOCAL_DIR>/output_jsonl/classes.jsonl \
    http://localhost:8983/solr/ols4_entities/update/json/docs?commit=true

    wget --method POST --no-proxy -O - --server-response --content-on-error=on \
    --header="Content-Type: application/json" \
    --body-file <LOCAL_DIR>/output_jsonl/properties.jsonl \
    http://localhost:8983/solr/ols4_entities/update/json/docs?commit=true

    wget --method POST --no-proxy -O - --server-response --content-on-error=on \
    --header="Content-Type: application/json" \
    --body-file <LOCAL_DIR>/output_jsonl/individuals.jsonl \
    http://localhost:8983/solr/ols4_entities/update/json/docs?commit=true

    wget --method POST --no-proxy -O - --server-response --content-on-error=on \
    --header="Content-Type: application/json" \
    --body-file <LOCAL_DIR>/output_jsonl/autocomplete.jsonl \
    http://localhost:8983/solr/ols4_autocomplete/update/json/docs?commit=true

Update `ols4_entities` core:

    wget --no-proxy -O - --server-response --content-on-error=on \
    http://localhost:8983/solr/ols4_entities/update?commit=true

Update `ols4_autocomplete` core:

    wget --no-proxy -O - --server-response --content-on-error=on \
    http://localhost:8983/solr/ols4_autocomplete/update?commit=true

After updating the indexes, stop Solr as needed.

#### Create data archives for Solr and Neo4j

Finally, create archives for both Solr and Neo4j data folders.

    tar --use-compress-program="pigz --fast --recursive" \
    -cf <LOCAL_DIR>/neo4j.tgz -C <LOCAL_DIR>/neo4j/data .

    tar --use-compress-program="pigz --fast --recursive" \
    -cf <LOCAL_DIR>/solr.tgz -C <LOCAL_DIR>/solr/server solr

### Running the API server backend locally

The API server Spring Boot application located in `backend`. Set the following environment variables to point it at your
local (Dockerized) Solr and Neo4j servers:

    OLS_SOLR_HOST=http://localhost:8983
    OLS_NEO4J_HOST=bolt://localhost:7687

### Running the frontend locally

The frontend is a React application in `frontend`. See [frontend docs](frontend/README.md)
for details on how to run the frontend.

## Development: Updating `testcases_expected_output` and `testcases_expected_output_api`
If you make changes to the data load or API of OLS, you need to run testcases and compare it against the expected outputs
to ensure backward compatibility. This testing consists of

1. testing the dataload outputs by comparing test outputs to expected outputs,
2. API testing which compares API responses to expected responses, and
3. adding the latest expected outputs to Git.

### Testing dataload
These tests are run locally as described in [Test testcases from dataload to UI](#test-testcases-from-dataload-to-ui).
Ensure that the environment variables `NEO4J_HOME`, `SOLR_HOME` and `OLS4_HOME` are set up accordingly.

1. First make sure all the OLS4 JARs are up to date by running :

       mvn clean package

2. Generate new output files and import into Neo4J and Solr:

       ./dev-testing/teststack.sh ./testcases ./testcases_output

3. Compare `/testcases_output` with `/testcases_expected_output`:

       ./compare_testcase_output.sh

4. The output of step 3 is written to `testcases_compare_result.log`. If no differences are found, this file will be empty.
Ensure that all differences in this file can be explained and that they do make sense.

5. Once you are happy with the output in `testcases_output`, remove the old `testcases_expected_output` and replace with
new expected output:

       rm -rf testcases_expected_output
       cp -r testcases_output testcases_expected_output

6. Now continue with API testing.

### Testing API
Before doing API testing you must have completed the [dataload testing](#testing-dataload).

7. Start the backend:

        ./dev-testing/start-backend.sh

8. Run API tests against backend using:

       ./test_api_fast.sh http://localhost:8080 ./testcases_output_api ./testcases_expected_output_api --deep

9. The results of step 8 is written to `./apitester4.log`. Differences are written to the end of the file. When there are no
differences, this file will end with these lines:

       RecursiveJsonDiff.diff() reported success
       apitester reported success; exit code 0

10. Ensure that all differences listed in `./apitester4.log` are accounted for. Once you are happy with the output, remove
the old `testcases_expected_output_api` and replace with new expected output:

        rm -rf testcases_expected_output_api
        cp -r testcases_output testcases_expected_output_api

11. Add the latest expected outputs to Git:

        git add -A testcases_expected_output
        git add -A testcases_expected_output_api

    **You should do this in the same commit as your code/test changes because then we can track exactly
    what changed in the output.**

12. You can stop the OLS4 backend with "Ctrl-C", and Solr and Neo4J with:

        ./dev-testing/stopall.sh


[maven-central]: https://img.shields.io/maven-central/v/net.dv8tion/JDA?color=blue
[jitpack]: https://img.shields.io/badge/Snapshots-JitPack-blue
[download]: #download
[discord-invite]: https://discord.gg/0hMr4ce0tIl3SLv5
[migration]: https://jda.wiki/introduction/migration-v4-v5/
[jenkins]: https://ci.dv8tion.net/job/JDA5
[license]: https://github.com/discord-jda/JDA/tree/master/LICENSE
[faq]: https://jda.wiki/introduction/faq/
[docs]: https://docs.jda.wiki/index.html
[wiki]: https://jda.wiki/introduction/jda/
[troubleshooting]: https://jda.wiki/using-jda/troubleshooting/
[discord-shield]: https://discord.com/api/guilds/125227483518861312/widget.png
[faq-shield]: https://img.shields.io/badge/Wiki-FAQ-blue.svg
[docs-shield]: https://img.shields.io/badge/Wiki-Docs-blue.svg
[troubleshooting-shield]: https://img.shields.io/badge/Wiki-Troubleshooting-darkgreen.svg
[jenkins-shield]: https://img.shields.io/badge/Download-Jenkins-purple.svg
[license-shield]: https://img.shields.io/badge/License-Apache%202.0-white.svg
[migration-shield]: https://img.shields.io/badge/Wiki-Migrating%20from%20V4-darkgreen.svg
[GatewayIntent]: https://docs.jda.wiki/net/dv8tion/jda/api/requests/GatewayIntent.html
[JDABuilder]: https://docs.jda.wiki/net/dv8tion/jda/api/JDABuilder.html
[DefaultShardManagerBuilder]: https://docs.jda.wiki/net/dv8tion/jda/api/sharding/DefaultShardManagerBuilder.html

<img align="right" src="https://github.com/discord-jda/JDA/blob/assets/assets/readme/logo.png?raw=true" height="150" width="150">

[![maven-central][]][download]
[![jitpack][]](https://jitpack.io/#discord-jda/JDA)
[![jenkins-shield][]][jenkins]
[![license-shield][]][license]

[![discord-shield][]][discord-invite]
[![faq-shield]][faq]
[![docs-shield]][docs]
[![troubleshooting-shield]][troubleshooting]
[![migration-shield][]][migration]

# JDA (Java Discord API)

This open source library is intended for implementing bots on Discord using the real-time gateway and REST API. It provides event based functionality to implement bots of any kind, allowing for effective and scalable applications.

## 📖 Overview

The core concepts of JDA have been developed to make building scalable apps easy:

1. Event System
    Providing simplified events from the gateway API, to respond to any platform events in real-time without much hassle.
1. Rest Actions
    Easy to use and scalable implementation of REST API functionality, letting you choose between callbacks with combinators, futures, and blocking.
    The library also handles rate-limits imposed by Discord automatically, while still offering ways to replace the default implementation.
1. Customizable Cache
    Trading memory usage for better performance where necessary, with sane default presets to choose from and customize.

You can learn more by visiting our [wiki][wiki] or referencing our [Javadocs][docs].

## 🔬 Installation

[![maven-central][]](https://mvnrepository.com/artifact/net.dv8tion/JDA/latest)
[![jitpack][]](https://jitpack.io/#discord-jda/JDA)

This library is available on maven central. The latest version is always shown in the [GitHub Release](https://github.com/discord-jda/JDA/releases/latest).

The minimum java version supported by JDA is **Java SE 8**. JDA also uses JSR 305 to support solid interoperability with Kotlin out of the box.

### Gradle

```gradle
repositories {
    mavenCentral()
}

dependencies {
    implementation("net.dv8tion:JDA:$version") { // replace $version with the latest version
      // Optionally disable audio natives to reduce jar size by excluding `opus-java`
      // Gradle DSL:
      // exclude module: 'opus-java'
      // Kotlin DSL:
      // exclude(module="opus-java")
    }
}
```

### Maven

```xml
<dependency>
    <groupId>net.dv8tion</groupId>
    <artifactId>JDA</artifactId>
    <version>$version</version> <!-- replace $version with the latest version -->
    <!-- Optionally disable audio natives to reduce jar size by excluding `opus-java`
    <exclusions>
        <exclusion>
            <groupId>club.minnced</groupId>
            <artifactId>opus-java</artifactId>
        </exclusion>
    </exclusions>
    -->
</dependency>
```

## 🤖 Creating a Bot

To use this library, you have to create an Application in the [Discord Application Dashboard](https://discord.com/developers/applications) and grab your bot token. You can find a step-by-step guide for this in our wiki page [Creating a Discord Bot](https://jda.wiki/using-jda/getting-started/#creating-a-discord-bot).

## 🏃♂ Getting Started

We provide a number of [examples](https://github.com/discord-jda/JDA/tree/master/src/examples/java) to introduce you to JDA. You can also take a look at our official [Wiki][wiki], [Documentation][docs], and [FAQ][faq].

Every bot implemented by JDA starts out using the [JDABuilder][JDABuilder] or [DefaultShardManagerBuilder][DefaultShardManagerBuilder]. Both builders provide a set of default presets for cache usage and events it wants to receive:

- `createDefault` - Enables cache for users who are active in voice channels and all cache flags
- `createLight` - Disables all user cache and cache flags
- `create` - Enables member chunking, caches all users, and enables all cache flags

We recommend reading the guide on [caching and intents](https://jda.wiki/using-jda/gateway-intents-and-member-cache-policy/) to get a feel for configuring your bot properly. Here are some possible use-cases:

### Example: Message Logging

> [!NOTE]
> The following example makes use of the **privileged intent** `GatewayIntent.MESSAGE_CONTENT`, which must be explicitly enabled in your application dashboard. You can find out more about intents in our [wiki guide](https://jda.wiki/using-jda/gateway-intents-and-member-cache-policy/).

Simply logging messages to the console. Making use of [JDABuilder][JDABuilder], the intended entry point for smaller bots that don't intend to grow to thousands of guilds.

Starting your bot and attaching an event listener, using the right [intents][GatewayIntent]:

```java
public static void main(String[] args) {
  JDABuilder.createLight(token, EnumSet.of(GatewayIntent.GUILD_MESSAGES, GatewayIntent.MESSAGE_CONTENT))
      .addEventListener(new MessageReceiveListener())
      .build();
}
```

Your event listener could look like this:

```java
public class MessageReceiveListener extends ListenerAdapter {
  @Override
  public void onMessageReceived(MessageReceivedEvent event) {
    System.out.printf("[%s] %#s: %s\n",
      event.getChannel(),
      event.getAuthor(),
      event.getMessage().getContentDisplay());
  }
}
```

You can find a more thorough example with the [MessageLoggerExample](https://github.com/discord-jda/JDA/blob/master/src/examples/java/MessageLoggerExample.java) class.

### Example: Slash Command Bot

This is a bot that makes use of [interactions](https://jda.wiki/using-jda/interactions/) to respond to user commands. Unlike the message logging bot, this bot can work without any enabled intents, since interactions are always available.

```java
public static void main(String[] args) {
  JDA jda = JDABuilder.createLight(token, Collections.emptyList())
      .addEventListener(new SlashCommandListener())
      .build();

  // Register your commands to make them visible globally on Discord:

  CommandListUpdateAction commands = jda.updateCommands();

  // Add all your commands on this action instance
  commands.addCommands(
    Commands.slash("say", "Makes the bot say what you tell it to")
      .addOption(STRING, "content", "What the bot should say", true), // Accepting a user input
    Commands.slash("leave", "Makes the bot leave the server")
      .setGuildOnly(true) // this doesn't make sense in DMs
      .setDefaultPermissions(DefaultMemberPermissions.DISABLED) // only admins should be able to use this command.
  );

  // Then finally send your commands to discord using the API
  commands.queue();
}
```

An event listener that responds to commands could look like this:

```java
public class SlashCommandListener extends ListenerAdapter {
  @Override
  public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
    switch (event.getName()) {
      case "say" -> {
        String content = event.getOption("content", OptionMapping::getAsString);
        event.reply(content).queue();
      };
      case "leave" -> {
        event.reply("I'm leaving the server now!")
          .setEphemeral(true) // this message is only visible to the command user
          .flatMap(m -> event.getGuild().leave()) // append a follow-up action using flatMap
          .queue(); // enqueue both actions to run in sequence (send message -> leave guild)
      };
      default -> return;
    }
  }
}
```

You can find a more thorough example with the [SlashBotExample](https://github.com/discord-jda/JDA/blob/master/src/examples/java/SlashBotExample.java) class.

## 🚀 RestAction

In this library, the [RestAction](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html) interface is used as a request builder for all API endpoints.
This interface represents a lazy request builder, as shown in this simple example:

```java
channel.sendMessage("Hello Friend!")
  .addFiles(FileUpload.fromData(greetImage)) // Chain builder methods to configure the request
  .queue() // Send the request asynchronously
```

> [!IMPORTANT]
> The final call to [`queue()`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#queue%28%29) sends the request.
> You can also send the request synchronously or using futures, check out our extended guide in the [RestAction Wiki](https://jda.wiki/using-jda/using-restaction/).

The RestAction interface also supports a number of operators to avoid callback hell:

- [`map`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#map%28java.util.function.Function%29)
    Convert the result of the `RestAction` to a different value
- [`flatMap`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#flatMap%28java.util.function.Function%29)
    Chain another `RestAction` on the result
- [`delay`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#delay%28java.time.Duration%29)
    Delay the element of the previous step

As well as combinators like:

- [`and`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#and(net.dv8tion.jda.api.requests.RestAction,java.util.function.BiFunction))
   Require another RestAction to complete successfully, running in parallel
- [`allOf`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#allOf(java.util.Collection))
   Accumulate a list of many actions into one (see also [`mapToResult`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#mapToResult()))
- [`zip`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#zip(net.dv8tion.jda.api.requests.RestAction,net.dv8tion.jda.api.requests.RestAction...))
   Similar to `and`, but combines the results into a list

And configurators like:

- [`timeout`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#timeout(long,java.util.concurrent.TimeUnit)) and [`deadline`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#deadline(long))
   Configure how long the action is allowed to be in queue, cancelling if it takes too long
- [`setCheck`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html#setCheck(java.util.function.BooleanSupplier))
   Running some checks right before the request is sent, this can be helpful when it is in queue for a while
- [`reason`](https://docs.jda.wiki/net/dv8tion/jda/api/requests/restaction/AuditableRestAction.html#reason(java.lang.String))
   The [audit log reason](https://discord.com/developers/docs/resources/audit-log) for an action

**Example**:

```java
public RestAction<Void> selfDestruct(MessageChannel channel, String content) {
    return channel.sendMessage("The following message will destroy itself in 1 minute!")
        .addActionRow(Button.danger("delete", "Delete now")) // further amend message before sending
        .delay(10, SECONDS, scheduler) // after sending, wait 10 seconds
        .flatMap((it) -> it.editMessage(content)) // then edit the message
        .delay(1, MINUTES, scheduler) // wait another minute
        .flatMap(Message::delete); // then delete
}
```

This could then be used in code:

```java
selfDestruct(channel, "Hello friend, this is my secret message").queue();
```

## 🧩 Extensions

### [jda-ktx](https://github.com/MinnDevelopment/jda-ktx)

Created and maintained by [MinnDevelopment](https://github.com/MinnDevelopment).
Provides [Kotlin](https://kotlinlang.org/) extensions for **RestAction** and events that provide a more idiomatic Kotlin experience.

```kotlin
fun main() {
    val jda = light(BOT_TOKEN)

    jda.onCommand("ping") { event ->
        val time = measureTime {
            event.reply("Pong!").await() // suspending
        }.inWholeMilliseconds

        event.hook.editOriginal("Pong: $time ms").queue()
    }
}
```

There are a number of examples available in the [README](https://github.com/MinnDevelopment/jda-ktx/#jda-ktx).

### [Lavaplayer](https://github.com/lavalink-devs/lavaplayer)

Created by [sedmelluq](https://github.com/sedmelluq) and now maintained by the [lavalink community](https://github.com/lavalink-devs)
Lavaplayer is the most popular library used by Music Bots created in Java.
It is highly compatible with JDA and Discord4J and allows playing audio from
YouTube, Soundcloud, Twitch, Bandcamp and [more providers](https://github.com/lavalink-devs/lavaplayer#supported-formats).
The library can easily be expanded to more services by implementing your own AudioSourceManager and registering it.
We recommend to also use [udpqueue](#udpqueue-an-extension-of-jda-nas) in addition to lavaplayer, to avoid stuttering issues caused by GC pauses.

It is recommended to read the [Usage](https://github.com/lavalink-devs/lavaplayer#usage) section of Lavaplayer
to understand a proper implementation.
Sedmelluq provided a demo in his repository which presents an example implementation for JDA:
https://github.com/lavalink-devs/lavaplayer/tree/master/demo-jda

### [udpqueue](https://github.com/MinnDevelopment/udpqueue.rs) (an extension of [jda-nas](https://github.com/sedmelluq/jda-nas))

Created and maintained by [sedmelluq](https://github.com/sedmelluq) and extended by [MinnDevelopment](https://github.com/MinnDevelopment)
Provides a native implementation for the JDA Audio Send-System **to avoid GC pauses potentially causing problems** with continuous audio playback.

Note that this send-system creates an extra UDP-Client which causes audio receive to no longer function properly,
since Discord identifies the sending UDP-Client as the receiver.

```java
JDABuilder builder = JDABuilder.createDefault(BOT_TOKEN)
    .setAudioSendFactory(new NativeAudioSendFactory());
```

### [Lavalink](https://github.com/lavalink-devs/Lavalink)

Created by [Freya Arbjerg](https://github.com/freyacodes) and now maintained by the [lavalink community](https://github.com/lavalink-devs).

Lavalink is a popular standalone audio sending node based on Lavaplayer. Lavalink was built with scalability in mind,
and allows streaming music via many servers. It supports most of Lavaplayer's features.

Lavalink is used by many large bots, as well as bot developers who can not use a Java library like Lavaplayer.
If you plan on serving music on a smaller scale with JDA, it is often preferable to just use Lavaplayer directly
as it is easier.

[Lavalink-Client](https://github.com/FredBoat/Lavalink-Client) is the official Lavalink client for JDA.

## 🛠 Contributing to JDA

If you want to contribute to JDA, make sure to base your branch off of our **master** branch (or a feature-branch)
and create your PR into that **same** branch.

Please follow our [Contributing Guidelines](https://github.com/discord-jda/JDA/blob/master/.github/CONTRIBUTING.md).

Do not expect your pull request to get immediate attention, sometimes it will take a long time to get a response.
You can join our [discord server][discord-invite] and ask in [#lib-dev](https://discord.com/channels/125227483518861312/869965829024915466) before starting to work on a new PR, to get more immediate feedback from our community members.

## 🚨 Breaking Changes

Due to the nature of the Discord API, the library will regularly introduce breaking changes to allow for a quick adoption of newer features. We try to keep these breaking changes minimal, but cannot avoid them entirely.

Most breaking changes will result in a **minor** version bump (`5.1.2` → `5.2.0`).


### 🎉 项目备注
项目：KCloud-Platform-Alibaba
作者：老寇
语言：Java
时间：2022.06.15 ~ 至今

### 📣 项目介绍

KCloud-Platform-Alibaba（老寇云平台）是一个企业级微服务架构的云平台。基于Spring Boot 3.2.5、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.0 最新版本开发的云服务多租户平台。
遵循SpringBoot编程思想，使用阿里COLA应用框架构建，高度模块化和可配置化。具备服务注册&发现、配置中心、灰度路由、服务限流、熔断降级、监控报警、多数据源、工作流、高亮搜索、定时任务、分布式链路、分布式缓存、分布式事务、分布式存储、分布式锁等功能，用于快速构建微服务项目。目前支持Shell、Docker等多种部署方式，并且支持GraalVM和虚拟线程。实现RBAC权限、其中包含系统管理、系统监控、工作流程、数据分析等几大模块。
遵循阿里代码规范，采用RESTful设计风格及DDD(领域驱动设计)思想，代码简洁、架构清晰，非常适合作为基础框架使用。

### 😋 项目背景
- 学习微服务架构设计并实践于生产
- 整合所学技术方便快速搭建项目
- 持续优化代码来提高代码质量
- 复制粘贴代码提高生产效率
- 学习DDD思想并落地实践

### 🔗 在线体验
[老寇云平台在线体验（请点击我，境外服务器网络延迟请稍候）](https://www.laokou.org.cn)

### 🔖 在线文档
[老寇云平台在线文档（请点击我）](https://koushenhai.github.io)

### 😎 开发计划
[开发计划（需要登录）](https://docs.qq.com/sheet/DUGhCdGVZWmVxT0VJ?tab=BB08J2)

### 💪 版本号
特此说明，与Spring Boot版本保持一致

### ⌛ 浏览器
推荐 Microsoft Edge 浏览器
推荐 Microsoft Edge 浏览器
推荐 Microsoft Edge 浏览器

### 🔎 功能介绍
🚀 IP管理：黑名单、白名单增删查（默认数据库）
🚀 用户管理：用户信息增删改查（数据库隔离）（可重置密码）
🚀 角色管理：角色信息增删改查，基于部门的数据权限、角色权限（数据库隔离）
🚀 菜单管理：菜单信息增删改查（数据库隔离）（自定义菜单图标）
🚀 部门管理：部门信息增删改查（数据库隔离）
🚀 日志管理：操作日志、登录日志查询、导出（数据库隔离）
🚀 字典管理：字典信息管理（数据库隔离）
🚀 消息管理：消息提醒和消息通知（数据库隔离）（分布式消息）
🚀 流程定义：流程定义、挂起、激活、查看、删除（默认数据库）
🚀 接口文档：Open Api Doc 3
🚀 服务监控：服务监控及报警
🚀 缓存监控：Redis内存监控
🚀 主机监控：服务器监控
🚀 索引管理：索引属性及分布式链路索引查看（默认ES）
🚀 OSS管理：对象存储信息增删改查，兼容Amazon S3（数据库隔离）
🚀 租户管理：租户信息增删改查增删改查（默认数据库）
🚀 套餐管理：自定义租户菜单增删改查（默认数据库）
🚀 集群管理：服务实例查看与优雅停机（服务自动下线）
🚀 数据源管理：数据源信息增删改查（默认数据库）
🚀 代码生成器：自定义模板生成代码
🚀 资源管理：资源信息管理增删改查，审批（Seata Saga模式）、处理、转办、委派，审批日志（数据库隔离），通过关键字搜索并高亮显示（默认ES）
🚀 用户登录：账号密码登录（多租户）、授权码登录（默认数据库）、手机号或邮件登录、设备授权码登录（请运行认证模式测试脚本.http）

### 💡 系统架构
![](doc/image/老寇云平台架构图-阿里巴巴.png)

### ✂ 技术体系
#### 🎯 Spring全家桶及核心技术版本
| 组件                          | 版本            |
|:----------------------------|:--------------|
| Spring Boot                 | 3.2.5         |
| Spring Cloud                | 2023.0.1      |
| Spring Cloud Alibaba        | 2023.0.1.0    |
| Spring Boot Admin           | 3.2.3         |
| Spring Authorization Server | 1.2.4         |
| Mybatis Plus                | 3.5.6         |
| Nacos                       | 2.3.2         |
| Seata                       | 2.0.0         |
| Sentinel                    | 1.8.7         |
| Mysql                       | 8.3.0         |
| Redis                       | 7.2.4         |
| Elasticsearch               | 8.12.2        |
| RocketMQ                    | 5.2.0         |
| Flowable                    | 7.0.1         |
| ShardingSphere              | 5.4.1         |
| OpenResty                   | 1.21.4.1      |
| Netty                       | 4.1.109.Final |
| Dubbo                       | 3.3.0-beta.1  |
| Kafka                       | 3.6.1         |
| EMQX                        | 5.3.0         |
| Postgresql                  | 16.1          |
| Flyway                      | 10.12.0       |
| Canal                       | 1.1.7         |
#### 🍺 相关技术
- 配置中心&服务注册&发现：Nacos
- API网关：Spring Cloud Gateway
- 认证授权：Spring Security OAuth2 Authorization Server
- 远程调用：Dubbo & Spring Cloud OpenFeign & OkHttp & HttpClient & WebClient
- 负载均衡：Spring Cloud Loadbalancer & OpenResty
- 服务熔断&降级&限流：Sentinel
- 分库分表&读写分离：Mybatis Plus & ShardingSphere
- 分布式事务：Seata & RocketMQ
- 消息队列：RocketMQ & Kafka & MQTT
- 服务监控：Spring Boot Admin & Prometheus
- 高亮搜索：Elasticsearch
- 链路跟踪：SkyWalking
- 任务调度：XXL Job
- 日志分析：EFK
- 缓存&分布式锁：Redis & Redisson
- 统计报表：MongoDB
- 对象存储：Amazon S3
- 自动化部署：Docker
- 网络通讯：Netty
- 持续集成&交付：Jenkins
- 持久层框架：Mybatis Plus
- JSON序列化：Jackson
- 对象转换：MapStruct
- 数据库：Mysql & Postgresql
- 工作流：Flowable
- 数据库迁移：Flyway
- 数据同步：Canal

#### 🌴 项目结构
~~~
├── laokou-common
        └── laokou-common-log                      --- 日志组件
        └── laokou-common-core                     --- 核心组件
        └── laokou-common-cors                     --- 跨域组件
        └── laokou-common-mqtt                     --- 消息组件
        └── laokou-common-redis                    --- 缓存组件
        └── laokou-common-kafka                    --- 消息组件
        └── laokou-common-log4j2                   --- 日志组件
        └── laokou-common-mongodb                  --- 报表组件
        └── laokou-common-rocketmq                 --- 消息组件
        └── laokou-common-algorithm                --- 算法组件
        └── laokou-common-prometheus               --- 监控组件
        └── laokou-common-openapi-doc              --- 文档组件
        └── laokou-common-rate-limiter             --- 限流组件
        └── laokou-common-elasticsearch            --- 搜索组件
        └── laokou-common-bom                      --- 依赖版本库
        └── laokou-common-i18n                     --- 国际化组件
        └── laokou-common-sensitive                --- 敏感词组件
        └── laokou-common-lock                     --- 分布式锁组件
        └── laokou-common-trace                    --- 链路跟踪组件
        └── laokou-common-dubbo                    --- 远程调用组件
        └── laokou-common-nacos                    --- 注册发现组件
        └── laokou-common-netty                    --- 网络通讯组件
        └── laokou-common-domain                   --- 领域事件组件
        └── laokou-common-crypto                   --- 加密解密组件
        └── laokou-common-secret                   --- 接口验签组件
        └── laokou-common-xxl-job                  --- 任务调度组件
        └── laokou-common-security                 --- 认证授权组件
        └── laokou-common-openfeign                --- 远程调用组件
        └── laokou-common-data-cache               --- 数据缓存组件
        └── laokou-common-mybatis-plus             --- 对象映射组件
        └── laokou-common-shardingsphere           --- 分库分表组件
        └── laokou-common-seata                    --- 分布式事务组件
        └── laokou-common-sentinel                 --- 服务限流&熔断降级组件
├── laokou-cloud
        └── laokou-gateway                         --- API网关
        └── laokou-monitor                         --- 服务监控
        └── laokou-xxl-job                         --- 任务调度
        └── laokou-register                        --- 服务治理
        └── laokou-sentinel                        --- 流量治理
        └── laokou-seata                           --- 分布式事务
├── laokou-service
        └── laokou-auth                            --- 认证授权模块
        └── laokou-admin                           --- 后台管理模块
        └── laokou-report                          --- 报表统计模块
        └── laokou-generator                       --- 模板生成模块
        └── laokou-modlule
                └── laokou-api                     --- API模块
                └── laokou-iot                     --- 物联网模块
                └── laokou-im                      --- 即时通讯模块
                └── laokou-flowable                --- 工作流程模块
                └── laokou-logstash                --- 日志收集模块
                └── laokou-flyway                  --- 数据库版本控制模块
~~~

### 🎵 项目截图(持续更新，仅供参考)

### 👊 性能评测
[请点击我，查看详情](性能测试.md)

### 😛 用户权益（点个Star，拜托啦~🙏）
- 采用Apache2.0开源协议，免费商用无需授权（如需书面授权请联系作者），请保留作者、Copyright信息
- 采用Apache2.0开源协议，免费商用无需授权（如需书面授权请联系作者），请保留作者、Copyright信息
- 采用Apache2.0开源协议，免费商用无需授权（如需书面授权请联系作者），请保留作者、Copyright信息

### 😻 开源协议
KCloud-Platform-Alibaba 开源软件遵循 [Apache 2.0 协议](https://www.apache.org/licenses/LICENSE-2.0.html) 请务必保留作者、Copyright信息

### 🔧 参与贡献
请查看 [提交规范（请点击我）](CONTRIBUTING.md)

### 👀 项目地址
Github 地址：[KCloud-Platform-Alibaba](https://github.com/KouShenhai/KCloud-Platform-Alibaba)
Gtiee 地址：[KCloud-Platform-Alibaba](https://gitee.com/laokouyun/KCloud-Platform-Alibaba)

### 🍚 赞助打赏（用于服务器日常维护）

### 🙋 技术交流

### 🐭 鸣谢组织
[Spring社区](https://spring.io)
[Jetbrains社区](https://www.jetbrains.com/community)
[阿里巴巴社区](https://github.com/alibaba)
[人人社区](https://www.renren.io)
[若依社区](https://www.ruoyi.vip)
[苞米豆社区](https://baomidou.com)
[livk-cloud社区](https://gitter.im/livk-cloud/community)
[laokouyun社区](https://github.com/laokouyun)

非常感谢 Jetbrains 提供的开源 License

### 🐼 鸣谢个人
|                                                👤                                                |                                                👤                                                |                                                👤                                                |                                                👤                                                |                                                👤                                                 |                                                👤                                                |
|:------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|
|  |  |  |  |  |  |
|                           [KouShenhai](https://github.com/KouShenhai)                            |                              [liang99](https://github.com/liang99)                               |                           [livk-cloud](https://github.com/livk-cloud)                            |                          [liukefu2050](https://github.com/liukefu2050)                           |                            [HalfPomelo](https://github.com/HalfPomelo)                            |                                [lixin](https://github.com/lixin)                                 |
|   |  |  |  |
|                               [simman](https://github.com/simman)                                |                             [suhengli](https://github.com/suhengli)                              |                            [gitkakafu](https://github.com/gitkakafu)                             |                                                [LeiZhiMin1](https://github.com/LeiZhiMin1)                                                 |

### ⛳ 赞助列表（感谢各位大佬的赞助）

        时间
        网名
        金额/物品
        备注

        2024/04/19
        *保熟
        ￥188.00
        越做越好

        2024/03/20
        A细节*
        ￥66.00
        无

        2024/03/03
        y*i
        ￥58.88
        无

        2024/01/30
        *阳
        ￥10
        无

        2023/12/22
        *民
        服务器
        无

        2023/12/08
        *来
        ￥10
        希望越来越好，一直坚持下去

        2023/12/08
        *迪
        ￥20
        越来越好，继续干下去

        2023/10/07
        何*
        ￥399
        作者说：感谢支持

        2023/08/27
        *界
        ￥10
        希望越来越好

        2023/06/29
        顺
        ￥20
        希望项目一直做下去就好

        2023/03/27
        s*e
        ￥10
        无

### 🚫 免责声明
禁止使用本项目从事一切违法犯罪活动。作者不承担任何法律责任，特此声明

### 🐸 联系作者
博客：[https://kcloud.blog.csdn.net](https://kcloud.blog.csdn.net)

邮箱：[2413176044@qq.com](https://mail.qq.com)

QQ：[2413176044]( http://wpa.qq.com/msgrd?v=3&uin=2413176044&Site=gitee&Menu=yes)

[![加入QQ群](https://img.shields.io/badge/Q群-465450496-blue.svg)](https://jq.qq.com/?_wv=1027&k=Ec8T76dR)

![GitHub Star 趋势](https://starchart.cc/KouShenhai/KCloud-Platform-Alibaba.svg)


[![Build Status](https://github.com/bioimage-io/model-runner-java/actions/workflows/build.yml/badge.svg)](https://github.com/bioimage-io/model-runner-java/actions/workflows/build.yml)

# JDLL (Java Deep Learning Library)

This project provides a Java library for running Deep Learning (DL) models agnostically, enabling communication between Java software and various Deep Learning frameworks (engines). It also allows the use of multiple DL frameworks in the same session, manages the different DL frameworks and brings the models from the
[Bioimage.io](https://bioimage.io/#/) repository to Java.

JDLL was originally developed by the Icy team as the foundational component for the DeepIcy plugin; however, it evolved over time into a standalone library designed to facilitate the integration of Deep Learning methodologies into other software applications. Its first target was software developers but the Icy team realised that other potential end-users, such as Bioimage analysts with some Python background, could also benefit from it using JDLL for [scripting with Jython](https://imagej.net/scripting/jython/). Some example scripts can be found [here](https://github.com/bioimage-io/JDLL/tree/main/scripts). Also have a look at the section [*Quickstart for end-users*](https://github.com/bioimage-io/JDLL#quickstart-for-analystsscripting) to get more information about how to use JDLL for scripting.

[JDLL](<https://github.com/bioimage-io/model-runner-java/tree/main>) is able to load models and make inference, create tensors, download Bioimage.io models and manage the supported DL frameworks. The library is designed in a modular way, allowing the main software to avoid dealing with the various objects and structures required by different DL frameworks. Instead the Java model runner provides interfaces for models and tensors that handle internally their creation and inference in the differnet Java engines. The main software only needs to interact with the Java model runner and does not need to worry whether the model is in PyTorch, Tensorflow or other framework.

**FOR A MORE COMPREHENSIVE AND COMPLETE EXPLANATION OF JDLL, PLEASE VISIT THE [WIKI](https://github.com/bioimage-io/JDLL/wiki).**
## Table of Contents

1. [Supported engines](https://github.com/bioimage-io/JDLL#supported-engines)
2. [Quickstart](https://github.com/bioimage-io/JDLL#quickstart)
3. [Examples for developers](https://github.com/bioimage-io/JDLL#examples)
4. [Scripting examples](https://github.com/bioimage-io/JDLL#scripting-examples)
5. [Quickstart for developers](https://github.com/bioimage-io/JDLL#quickstart-for-developers)
6. [Quickstart for analysts/scripting](https://github.com/bioimage-io/JDLL#quickstart-for-analystsscripting)
7. [Acknowledgements](https://github.com/bioimage-io/JDLL#acknowledgements)
8. [References](https://github.com/bioimage-io/JDLL#references)

# Supported engines

Currently, the following frameworks are supported:

| Framework                       | Source code                                                    | Tag used in JDLL to refer to the framework     |
|---------------------------------|----------------------------------------------------------------|------------------------------------------------|
| PyTorch                         | https://github.com/bioimage-io/pytorch-java-interface          | `pytorch` or `torchscript`                      |
| Tensorflow 1                    | https://github.com/bioimage-io/tensorflow-1-java-interface     | `tensorflow` or `tensorflow_saved_model_bundle` |
| Tensorflow 2 API 0.2.0          | https://github.com/bioimage-io/tensorflow-2-java-interface-0.2.0 | `tensorflow` or `tensorflow_saved_model_bundle` |
| Tensorflow 2 API 0.3-0.4 | https://github.com/bioimage-io/tensorflow-2-java-interface     | `tensorflow` or `tensorflow_saved_model_bundle` |
| Tensorflow 2 API 0.5.0 | https://github.com/bioimage-io/tensorflow-2-java-interface-0.5.0 | `tensorflow` or `tensorflow_saved_model_bundle` |
| Onnx                            | https://github.com/bioimage-io/onnx-java-interface             | `onnx`                                         |

The information about the engines supported currently by JDLL, for which OS and architectures, their minimum required Java version and which JAR files are required for each of the engines is stored in [this json file](https://github.com/bioimage-io/model-runner-java/blob/main/src/main/resources/availableDLVersions.json) and can be found [here](https://github.com/bioimage-io/JDLL/wiki/List-of-supported-engines).

Note that JDLL will be in **constant development** and that it is open to community collaboration, so **pull requests** to the official repository of JDLL to improve functionality or to add new engines are **very welcomed**.

# Quickstart
As mentioned above, JDLL was originally developed for the purpose of seamlessly integrating Deep Learning capabilities into other software applications. Its main objective was to empower these software applications to effectively execute Deep Learning models. For that use case, JDLL was mainly oriented for application developers that wanted to incorporate DL methods in their softwares.

But after a couple of stable releases, the JDLL team noticed that because of its user-friendly interface, the library could be accessible not just to software developers but also to everyday users with basic scripting knowledge in languages like Python or Matlab. This makes it suitable for anyone interested in crafting processing routines that require Deep Learning models. Using a Java based or Java compatible scripting laguage such as Jython, one can easily use JDLL to run DL models.

Due to the dual possibilities of JDLL, there are 2 Quickstarts available depending on the interests of the user:
- [Quickstart for developers](https://github.com/bioimage-io/JDLL#quickstart-for-developers) if the user is interested in the integration of JDLL into their application.
- [Quickstart for analysts/scripting](https://github.com/bioimage-io/JDLL#quickstart-for-analystsscripting) if the user is interested in creating scripts in Jython that can run DL models easily to improve their processing routines. Not much experience with Python/Jython is required.

# Examples

* [ExampleLoadAndRunModel](https://github.com/bioimage-io/model-runner-java/blob/main/src/main/java/io/bioimage/modelrunner/example/ExampleLoadAndRunModel.java) (PyTorch)
* [ExampleLoadTensorflow1Tensorflow2](https://github.com/bioimage-io/model-runner-java/blob/main/src/main/java/io/bioimage/modelrunner/example/ExampleLoadTensorflow1Tensorflow2.java)
* [ExampleDownloadEngine](https://github.com/bioimage-io/JDLL/blob/main/src/main/java/io/bioimage/modelrunner/example/ExampleDownloadEngine.java)
* [ExampleDownloadModel](https://github.com/bioimage-io/JDLL/blob/main/src/main/java/io/bioimage/modelrunner/example/ExampleDownloadModel.java)

# Scripting examples

* [example-run-model-in-fiji](https://github.com/bioimage-io/JDLL/blob/main/scripts/example-run-model-in-fiji.py) (Requires to be executed from Fiji, as it uses the application to display the result image, cannot be executed on Apple Silicon computers)
* [example-run-pytorch-model-in-fiji.py](https://github.com/bioimage-io/JDLL/blob/main/scripts/example-run-pytorch-model-in-fiji.py) (Requires to be executed from Fiji, as it uses the application to display the result image)
* [example-download-bmz-model](https://github.com/bioimage-io/JDLL/blob/main/scripts/example-download-bmz-model.py)
* [example-download-engine](https://github.com/bioimage-io/JDLL/blob/main/scripts/example-download-engine.py)

# Quickstart for developers
The next section (~10 min read) provides essential instructions for using JDLL divided in the following subsections:
- [0. Setting Up JDLL](https://github.com/bioimage-io/JDLL#0-setting-up-jdll)
- [1. Downloading a model (optional)](https://github.com/bioimage-io/JDLL#1-getting-a-model-optional)
- [2. Installing DL engines](https://github.com/bioimage-io/JDLL#2-installing-dl-engines)
- [3. Creating the tensors](https://github.com/bioimage-io/JDLL#3-creating-the-tensors)
- [4. Loading the model](https://github.com/bioimage-io/JDLL#4-loading-the-model)
- [5. Running the model](https://github.com/bioimage-io/JDLL#5-running-the-model)
- [6. Closing the model and the tensors](https://github.com/bioimage-io/JDLL#6-closing-the-model-and-the-tensors)

## 0. Setting Up JDLL

Download the dependency and include it in your project

   In order to benefit from the library, include the dependency in your code. The dependency can be added manually or using a dependency manager such as Maven. If you are using Maven, add the following dependency to the project pom file:

   ```xml
   <dependency>
     <groupId>io.bioimage</groupId>
     <artifactId>dl-modelrunner</artifactId>
     <version>0.4.0</version>
   </dependency>
   ```

   and add to `<repositories>` the following:

   ```xml
   <repository>
     <id>scijava.public</id>
     <url>https://maven.scijava.org/content/groups/public</url>
   </repository>
   ```
## 1. Downloading a model (optional)
If a model from the supported by JDLL is already available you can skip this step. Note that for Tensorflow the models need to be saved in the [`SavedModel`](https://www.tensorflow.org/guide/saved_model) format.

If no model is available, a good starting point is downloading any of the models of the [Bioimage.io respository](https://bioimage.io/#/). The download can be done manually or using JDLL. Bioimag.io is seamlessly integrated into JDLL, offering multiple methods to effortlessly mange and use its models.

Here is an emaple of how JDLL can be used to download any Bioimage.io model, in this case the [`B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet`](https://bioimage.io/#/?tags=placid-llama&id=10.5281%2Fzenodo.7261974) model.
```java
// Name of the model of interest, note that each model is unique. The names are case sensitive.
String modelName = "B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet";
// Directory where the model folder will be downloaded
String modelsDir = "/path/to/wanted/model/directory";

// First create an instance of the Bioimage.io repository
BioimageioRepo br = BioimageioRepo.connect();
try {
	br.downloadByName(modelName, modelsDir);
        System.out.println("Great success!");
} catch (IOException | InterruptedException e) {
	// If the download is interrumpted or any of the model files cannot be downloaded
	// and exception will be thrown
	e.printStackTrace();
        System.out.println("Error downloading the model");
}
```
Output:
```
Great success!
```
More information on how to download  Bioimage.io models can be found [here](https://github.com/bioimage-io/JDLL/wiki/Engine-Installation-(EngineInstall)).

## 2. Installing DL engines
JDLL is installed empty. Several models might require different Deep Learning framework versions, each of them consuming considerable amounts of disk space. In order to make JDLL setup light and fast JDLL is installed without default DL engines. The user can then get the Dl engines that they want depending on their needs.

JDLL provides the needed methods to install the wanted engines in an easy manner. Following the above example, find below some code that can be used to install a DL engine. As it can be observed the model that was downloaded [supports Tensorflow 2 and Keras weights](https://github.com/bioimage-io/collection-bioimage-io/blob/19ea59e662410c3ee49b7da184730919336d7568/rdfs/10.5281/zenodo.7261974/7782776/rdf.yaml#L146). Keras is not supported so in order to load and run the model, Tensorflow weights need to be installed.

**Important: Note that not every engine is compatible with every OS and Java version. For example Tensorflow 2.10 is only compatible with Java 11 or higher and Apple Silicon (ARMS64 chips) are only compatible with one version of Tensorflow (Tensorflow 2.7.4) used with Java 11 or newer.**

```
String framework = "tensorflow";
String version = "2.7.0";
boolean cpu = true;
boolean gpu = true;

String enginesDir = "/path/to/wanted/engines/dir";
boolean installed = EngineInstall.installEngineWithArgsInDir(framework, version, cpu, gpu, enginesDir);
if (installed)
	System.out.println("Great success!");
else
	System.out.println("Error installing");
```
Output:
```
Great success!
```

As previously mentioned, JDLL integrates deeply with Bioimage.io models. An easier way to install the engines needed for Bioimage.io models is shown in the code below.

In the example it is shown how simply providing the name of the model of interest, JDLL will know which engines to install.
```java
String modelName = "B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet";
String enginesDir = "/path/to/wanted/engines/dir";
boolean installed =  EngineInstall.installEnginesForModelByNameinDir(modelName, enginesDir);
if (installed)
	System.out.println("Great success!");
else
	System.out.println("Error installing");
```
Output:
```
Great success!
```
The Wiki covers extensively engine installation ([here](https://github.com/bioimage-io/JDLL/wiki/Understanding-engine-installation) and [here](https://github.com/bioimage-io/JDLL/wiki/Engine-Installation-(EngineInstall))). In addtion JDLL also includes methods to manage the engines and know: [the information about each engine](https://github.com/bioimage-io/JDLL/wiki/Engine-Management-I-(DeepLearningVersion)), [which engines are supported](https://github.com/bioimage-io/JDLL/wiki/Engine-Management-II-(AvailableEngines)) and [which engines have already been installed](https://github.com/bioimage-io/JDLL/wiki/Engine-Management-III-(InstalledEngines))

## 3. Creating the tensors
Once the model and the engine are already installed it is the moment to start the process of running the model on the tensors. In this section, creation of the tensors will be explained.

JDLL tensors are agnostic to the DL framework to be used, they are always creted in the same way. JDLL manages internally the conversion of the agnostic tensor into the framework specific tensor once the model is going to be run. The unified method of creating tensors facilitates the integration of every supported DL framework into any software.

JDLL tensors use ImgLib2 to store the tensor information. In practice, JDLL tensors are just wrappers of ImgLib2 `RandomAccessibleIntervals` that contain all the data needed to convert them back and forth into the framework specific tensors.

The example below will show how to create the input and output tensors required to run the [example model](https://bioimage.io/#/?tags=placid-llama&id=10.5281%2Fzenodo.7261974). As per its [rdf.yaml file](https://github.com/bioimage-io/collection-bioimage-io/blob/19ea59e662410c3ee49b7da184730919336d7568/rdfs/10.5281/zenodo.7261974/7782776/rdf.yaml), the model has one input named `input_1`, with `bxyc` axes ([explanation here](https://github.com/bioimage-io/spec-bioimage-io/blob/gh-pages/model_spec_latest.md)) and a required shape of[1, 512, 512, 1]. The ouptut of the model is named `conv2d_19` with with `bxyc` axes and fixed shape [1, 512, 512, 3].
```java
final ImgFactory<FloatType> imgFactory = new ArrayImgFactory<>(new FloatType());
final Img<FloatType> img1 = imgFactory.create(new long[]{1, 512, 512, 1});
// Create the input tensor with the nameand axes given by the rdf.yaml file
// and add it to the list of input tensors
Tensor<FloatType> inpTensor = Tensor.build("input_1", "bxyc", img1);

// Ouput tensors can be created empty, if the output shape is not known.
// Note that this method does not preallocate memory for the output tensor
Tensor<FloatType> outputEmptyTensor = Tensor.buildEmptyTensor("conv2d_19", "bxyc");

// Or ouptut tensors can also be built blank, to pre-allocate memory
// if the shape and data type are known.
Tensor<FloatType> outputBlankTensor = Tensor.buildBlankTensor("conv2d_19",
                "bxyc", new long[]{1, 512, 512, 3}, new FloatType());

```

More information about tensors can be found in the [JDLL wiki](https://github.com/bioimage-io/JDLL/wiki/JDLL-tensors-I-(Tensor)).

## 4. Loading the model
Before making inference with a model, it needs to be loaded. Similar to [tensor creation](https://github.com/bioimage-io/JDLL#3-creating-the-tensors) JDLL provides an unified way to load models from any DL framework.

Loading a model implies first defining which engine is going to be used for the model and then loading the model. The engine is defined as an instance of the class `io.bioimage.modelrunner.engine.EngineInfo`. The engine used to load a model can be either the exact same version wanted, or a [compatible](https://github.com/bioimage-io/JDLL/wiki/Potential-errors#compatible-versions) one. Using the exact same version guarantees that the model loading and inference are going to be smooth but implies that many more engines will have to be installed.

An example of defining the `EngineInfo` instance needed to load a model is shown below. The engine required in this code is required to be the exact engine wanted.

Note that `String enginesDir` is the directory where the wanted engines have been installed. [Click here and look at the example in the redirected section](https://github.com/bioimage-io/JDLL#2-installing-dl-engines).
```java
String framework = "tensorflow";
String version = "2.7.0";
boolean cpu = true;
boolean gpu = true;
String enginesDir = "/path/to/wanted/engines/dir";

EngineInfo enigneInfoExact = EngineInfo.defineDLEngine(framework, version, cpu, gpu, enginesDir);
```

In order to require a compatible engine, not the exact one:

```java
String framework = "tensorflow";
String version = "2.11.0";
boolean cpu = true;
boolean gpu = true;
String enginesDir = "/path/to/wanted/engines/dir";

EngineInfo enigneInfoCompat = EngineInfo.defineCompatibleDLEngine(framework, version, cpu, gpu, enginesDir);
```

The developer acknowledges that the class `io.bioimage.modelrunner.engine.EngineInfo` can be difficult to understand. This is why the [wiki contains a detailed sections trying to explain it in an understandable manner with several examples](https://github.com/bioimage-io/JDLL/wiki/Load-and-run-models-I-(EngineInfo)).

Once the `EngineInfo` instance has been created, loading the model is easy. The only parameters needed now are the path to the `model folder` and the path to the `source file`.
The model folder is the folder that contains the `.pb` file in Tensorflow, the `.pt` file in Pytorch and the `.onnx` file in Onnx. The source file is not needed for Tensorflow, is the path to the `.pt` file in Pytorch and the path to the `.onnx` file in Onnx.

Then with the arguments `String modelFolder`, `String modelSource` and the previously created `EngineInfo enigneInfoExact` or `EngineInfo enigneInfoCompat` an instance of `io.bioimage.modelrunner.model.Model` can be created. Tha object then can be loaded and run inference.

```
//Path to the example model folder
String modelFolder = "path/to/models/dir/B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet";
String modelSource = null; // Not needed in Tensorflow

Model model = Model.createDeepLearningModel(modelFolder, modelSource, enigneInfoCompat);
model.loadModel();

System.out.println("Great sucess!");
```

Output:
```
Great sucess!
```

JDLL tight integration with Bioimage.io models makes loading them easier. To load a Bioimage.io model it is not necessary to create the `EngineInfo` object.

For Bioimage.io models, loading is reduced to the next example:
```
// Path to the Bioimage.io model folder
String modelFolder = "path/to/models/dir/B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet";
String enginesDir = "/path/to/wanted/engines/dir";

Model bioimageioModel = Model.createBioimageioModel(modelFolder, enginesDir);
bioimageioModel.load();

System.out.println("Great sucess!");
```

Output:
```
Great sucess!
```

More information about loading models and models in general can be found in [this Wiki page](https://github.com/bioimage-io/JDLL/wiki/Load-and-run-models-II-(Model)).

## 5. Running the model
Once the model has been loaded and the input and output tensors have been created. Running the model is simple. The input tensors should be added to a `List<?>` in the same order the model expects. Same for the ouptuts in another `List<?>`.
```
List<Tensor<?>> inputList = new ArrayList<Tensor<?>>();
List<Tensor<?>> outputputList = new ArrayList<Tensor<?>>();

inputList.add(inputTensor);
outputputList.add(outputEmptyTensor);
System.out.println("Ouptut tensor is empty: " + outputEmptyTensor.isEmpty());

model.runModel(inputList, outputputList);
System.out.println("Ouptut tensor after inference is empty: " + outputEmptyTensor.isEmpty());
```
Output:
```
Ouptut tensor is empty: true
Ouptut tensor after inference is empty: false
```

## 6. Closing the model and the tensors
Models and tensors need to be closed to be released and free the memory that they were using
```
model.close();
inputTensor.close;
outputBlankTensor.close();
outputEmptyTensor.close();
```

# Quickstart for analysts/scripting
This section (~15 min read) explains how to use JDLL in a [Jython](https://www.jython.org/) script. Jython is an implementation of Python in Java, thus it allows calling Java methods and classes in a Pythonic way. With Jython, Java methods and classes can be called in a script as Python methods.

Scripting is powerfull and usefull because it allows creating processing routines in a simple manner that otherwise would require a full software for them. This is the reason why many software applications such as Icy, Fiji or Napari have a script editor. Scripts can perform complex tasks reducing the need of developing specific plugins in each platform. Scripts are also mostly compatible with every software application that supports the language they are writen in.

The examples for JDLL use Jython because it supports Java and uses Python syntax. Python is one of the mostwidely used programming languages and also one of the easiers to learn. Python has a big community and many Open Source libraries that can be used in Jython too. However, note that Jython at the moment only supports Python2. The support for [Python 3 is still in development](https://github.com/jython/jython/tree/main). A good tutorial on how to create Jython scripts can be found [here](https://imagej.net/scripting/jython/).

In addition, Jython scripts can be then used in softwares such as Icy or Fiji to create Image Processing tasks together with the tools they have available.

The following subsections provide essential instructions to use JDLL in Jyhton scripts:
- [0. Setting Up JDLL](https://github.com/bioimage-io/JDLL#0-setting-up-jdll-1)
- [1. Downloading a model (optional)](https://github.com/bioimage-io/JDLL#1-getting-a-model-optional-1)
- [2. Installing DL engines](https://github.com/bioimage-io/JDLL#2-installing-dl-engines-1)
- [3. Creating the tensors](https://github.com/bioimage-io/JDLL#3-creating-the-tensors-1)
- [4. Loading the model](https://github.com/bioimage-io/JDLL#4-loading-the-model-1)
- [5. Running the model](https://github.com/bioimage-io/JDLL#5-running-the-model-1)
- [6. Closing the model and the tensors](https://github.com/bioimage-io/JDLL#6-closing-the-model-and-the-tensors-1)

Note that the [JDLL Wiki](https://github.com/bioimage-io/JDLL/wiki) contains an extensive documentation of the JDLL API. The API methods can be used with Jython. Consider going over the API to get a more in-depth idea of the scripting possibilities of JDLL.

## 0. Setting up JDLL

Download the dependency and include it in your project. Depending on the application, dependencies are installed differently. For example, in Icy, click on the `Plugins` tab, then `Setup>Online plugin`. In the window that opens look for the name `JDLL` within the plugin list, click on it and then click on `Install` on the middle right of the window.

In Fiji, the JDLL library and its dependencies are shipped from the deepImageJ update site. In order to install JDLL in Fiji, [add the deepImageJ update site to the Fiji updater](https://imagej.net/list-of-update-sites/) and update. The URL for the deepImageJ update site is: https://sites.imagej.net/DeepImageJ/

Once installed, JDLL should be ready to be used.

If the software application JDLL wants to be used in does not support automatic installation of libraries, download JDLL and its dependencies and locate them in the corresponding directory.
The download links are:
- [JDLL](https://maven.scijava.org/service/local/repositories/releases/content/io/bioimage/dl-modelrunner/0.4.0/dl-modelrunner-0.4.0.jar)
- [GSON](https://repo1.maven.org/maven2/com/google/code/gson/gson/2.10.1/gson-2.10.1.jar)
- [ImgLib2](https://repo1.maven.org/maven2/net/imglib2/imglib2/6.1.0/imglib2-6.1.0.jar)
- [SnakeYAML](https://repo1.maven.org/maven2/org/yaml/snakeyaml/2.0/snakeyaml-2.0.jar)
- [jackson-dataformat-msgpack](https://repo1.maven.org/maven2/org/msgpack/jackson-dataformat-msgpack/0.9.5/jackson-dataformat-msgpack-0.9.5.jar)
- [msgpack-core](https://repo1.maven.org/maven2/org/msgpack/msgpack-core/0.9.5/msgpack-core-0.9.5.jar)
- [jackson-databind](https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.14.2/jackson-databind-2.14.2.jar)
- [jackson-core](https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar)
- [jackson-annotations](https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.14.2/jackson-annotations-2.14.2.jar)

## 1. Downloading a model (optional)
If a model from the supported by JDLL is already available you can skip this step. Note that for Tensorflow the models need to be saved in the [`SavedModel`](https://www.tensorflow.org/guide/saved_model) format.

If no model is available, a good starting point is downloading any of the models of the [Bioimage.io respository](https://bioimage.io/#/). The download can be done manually or using JDLL. Bioimag.io is seamlessly integrated into JDLL, offering multiple methods to effortlessly mange and use its models. An example Jython script to download a Bioimage.io model can be found [here](https://github.com/bioimage-io/JDLL/blob/main/scripts/example-download-bmz-model.py).

Here is an emaple of how JDLL can be used to download any Bioimage.io model, in this case the [`B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet`](https://bioimage.io/#/?tags=placid-llama&id=10.5281%2Fzenodo.7261974) model.
```python
from io.bioimage.modelrunner.bioimageio import BioimageioRepo

# Name of the model of interest, note that each model is unique. The names are case sensitive.
modelName = "B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet"
# Directory where the model folder will be downloaded
modelsDir = "/path/to/wanted/model/directory"

# First create an instance of the Bioimage.io repository
br = BioimageioRepo.connect()
try:
	br.downloadByName(modelName, modelsDir)
	print("Great success!")
except Exception as e:
	# If the download is interrumpted or any of the model files cannot be downloaded
	# and exception will be thrown
	print("Error downloading the model: ", str(e))
```
Output:
```
Great success!
```
More information on how to download  Bioimage.io models can be found [here](https://github.com/bioimage-io/JDLL/wiki/Engine-Installation-(EngineInstall)). Note that all the methods decribed in JAva can be used in a pythonic way with Jytho. The static ones do not need the instantiation of a class and the non-static ones do require it.

## 2. Installing DL engines
JDLL is installed empty. Several models might require different Deep Learning framework versions, each of them consuming considerable amounts of disk space. In order to make JDLL setup light and fast JDLL is installed without default DL engines. The user can then get the Dl engines that they want depending on their needs.

JDLL provides the needed methods to install the wanted engines in an easy manner. Following the above example, find below some code that can be used to install a DL engine. As it can be observed the model that was downloaded [supports Tensorflow 2 and Keras weights](https://github.com/bioimage-io/collection-bioimage-io/blob/19ea59e662410c3ee49b7da184730919336d7568/rdfs/10.5281/zenodo.7261974/7782776/rdf.yaml#L146). Keras is not supported so in order to load and run the model, Tensorflow weights need to be installed.

**Important: Note that not every engine is compatible with every OS and Java version. For example Tensorflow 2.10 is only compatible with Java 11 or higher and Apple Silicon (ARMS64 chips) are only compatible with one version of Tensorflow (Tensorflow 2.7.4) used with Java 11 or newer. This means that TENSORFLOW CANNOT BE USED IN FIJI IN APPLE SILICON.**

```python
from io.bioimage.modelrunner.engine.installation import EngineInstall

framework = "tensorflow"
version = "2.7.0"
cpu = True
gpu = True

enginesDir = "/path/to/wanted/engines/dir"
installed = EngineInstall.installEngineWithArgsInDir(framework, version, cpu, gpu, enginesDir)
if (installed):
	print("Great success!")
else:
	print("Error installing")
```
Output:
```
Great success!
```

As previously mentioned, JDLL integrates deeply with Bioimage.io models. An easier way to install the engines needed for Bioimage.io models is shown in the code below.

In the example it is shown how simply providing the name of the model of interest, JDLL will know which engines to install.
```python
from io.bioimage.modelrunner.engine.installation import EngineInstall

modelName = "B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet"
modelsDir = "/path/to/wanted/models/dir"
installed =  EngineInstall.installEnginesForModelByNameinDir(modelName, modelsDir)
if (installed):
	print("Great success!")
else:
	print("Error installing")
```
Output:
```
Great success!
```
The Wiki covers extensively engine installation ([here](https://github.com/bioimage-io/JDLL/wiki/Understanding-engine-installation) and [here](https://github.com/bioimage-io/JDLL/wiki/Engine-Installation-(EngineInstall))). In addtion JDLL also includes methods to manage the engines and know: [the information about each engine](https://github.com/bioimage-io/JDLL/wiki/Engine-Management-I-(DeepLearningVersion)), [which engines are supported](https://github.com/bioimage-io/JDLL/wiki/Engine-Management-II-(AvailableEngines)) and [which engines have already been installed](https://github.com/bioimage-io/JDLL/wiki/Engine-Management-III-(InstalledEngines)) Again, not that the methods explained in the Wiki can easily be used in Jython scripts.

In addition, a more detailed Jython script with an example on how to install an engine can be found [here](https://github.com/bioimage-io/JDLL/blob/main/scripts/example-download-engine.py).

## 3. Creating the tensors
Once the model and the engine are already installed it is the moment to start the process of running the model on the tensors. In this section, creation of the tensors will be explained.

JDLL tensors are agnostic to the DL framework to be used, they are always creted in the same way. JDLL manages internally the conversion of the agnostic tensor into the framework specific tensor once the model is going to be run. The unified method of creating tensors facilitates the integration of every supported DL framework into any software.

JDLL tensors use ImgLib2 to store the tensor information. In practice, JDLL tensors are just wrappers of ImgLib2 `RandomAccessibleIntervals` that contain all the data needed to convert them back and forth into the framework specific tensors.

The example below will show how to create the input and output tensors required to run the [example model](https://bioimage.io/#/?tags=placid-llama&id=10.5281%2Fzenodo.7261974). As per its [rdf.yaml file](https://github.com/bioimage-io/collection-bioimage-io/blob/19ea59e662410c3ee49b7da184730919336d7568/rdfs/10.5281/zenodo.7261974/7782776/rdf.yaml), the model has one input named `input_1`, with `bxyc` axes ([explanation here](https://github.com/bioimage-io/spec-bioimage-io/blob/gh-pages/model_spec_latest.md)) and a required shape of[1, 512, 512, 1]. The ouptut of the model is named `conv2d_19` with with `bxyc` axes and fixed shape [1, 512, 512, 3].
```python
from io.bioimage.modelrunner.tensor import Tensor

from net.imglib2.img.array import ArrayImgFactory
from net.imglib2.type.numeric.real import FloatType

imgFactory = ArrayImgFactory( FloatType() )
img1 = imgFactory.create( [1, 512, 512, 1] )
# Create the input tensor with the nameand axes given by the rdf.yaml file
# and add it to the list of input tensors
inpTensor = Tensor.build("input_1", "bxyc", img1)

# Ouput tensors can be created empty, if the output shape is not known.
# Note that this method does not preallocate memory for the output tensor
outputEmptyTensor = Tensor.buildEmptyTensor("conv2d_19", "bxyc")

# Or ouptut tensors can also be built blank, to pre-allocate memory
# if the shape and data type are known.
outputBlankTensor = Tensor.buildBlankTensor("conv2d_19",
			"bxyc", [1, 512, 512, 3], FloatType())

```

More information about tensors can be found in the [JDLL wiki](https://github.com/bioimage-io/JDLL/wiki/JDLL-tensors-I-(Tensor)).

Another option is to create the tensors directly from images are open on the software. The next example shows how an `ImagePlus` opened by Fiji can be converted into a tensor.
```python
import os
from io.bioimage.modelrunner.tensor import Tensor
from ij import IJ
from net.imglib2.img.display.imagej import ImageJFunctions
from net.imglib2.view import Views

# Path to the model whose sample image is going to be displayed
model_name = "B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet"
models_dir = "/path/to/wanted/models/dir"
model_of_interest_path = os.path.join(models_dir, model_name)

#Open the image and show it
imp = IJ.openImage(os.path.join(model_of_interest_path, "sample_input_0.tif"))
imp.show()

# Convert the image into a float32 ImgLib2 image.
# Note that as a 2D image the dimensions are just "xy"
wrapImg = ImageJFunctions.convertFloat(imp)
# Convert to the required axes order "bxyc"
# Permute from "xy" to "yx"
wrapImg = Views.permute(wrapImg, 0, 1)
# Add one dimension to "yxb", from (512, 512) to (512, 512, 1)
wrapImg = Views.addDimension(wrapImg, 0, 0)
# Permute from "yxb" and (512, 512, 1) to "bxy" and (1, 512, 512)
wrapImg = Views.permute(wrapImg, 0, 2)
# Add one dimension to get "bxyc", from (1, 512, 512) to (1, 512, 512, 1)
wrapImg = Views.addDimension(wrapImg, 0, 0)

# Build the corresponding tensor
inputTensor = Tensor.build("input_1", "bxyc", wrapImg)
```

In order to get the orginal image back from the tensor after all the permutations and dimensions added:
```python
from net.imglib2.img.display.imagej import ImageJFunctions
from net.imglib2.view import Views

# Convert from "bxyc" (1, 512, 512, 1) into "xy" (512, 512)
wrapImg = Views.dropSingletonDimensions(wrapImg)
ImageJFunctions.show(wrapImg)
```

A complete example that contains tensor creation from Fiji ImagePlus images can be found [here](https://github.com/bioimage-io/JDLL/blob/c037809a3695632487cc024bcefe93b529cc89fe/scripts/example-run-model-in-fiji.py#L67).

## 4. Loading the model
Before making inference with a model, it needs to be loaded. Similar to [tensor creation](https://github.com/bioimage-io/JDLL#3-creating-the-tensors) JDLL provides an unified way to load models from any DL framework.

Loading a model implies first defining which engine is going to be used for the model and then loading the model. The engine is defined as an instance of the class `io.bioimage.modelrunner.engine.EngineInfo`. The engine used to load a model can be either the exact same version wanted, or a [compatible](https://github.com/bioimage-io/JDLL/wiki/Potential-errors#compatible-versions) one. Using the exact same version guarantees that the model loading and inference are going to be smooth but implies that many more engines will have to be installed.

An example of defining the `EngineInfo` instance needed to load a model is shown below. The engine required in this code is required to be the exact engine wanted.

Note that `enginesDir` is the directory where the wanted engines have been installed. [Click here and look at the example in the redirected section](https://github.com/bioimage-io/JDLL#2-installing-dl-engines).
```python
from io.bioimage.modelrunner.engine import EngineInfo

framework = "tensorflow"
version = "2.7.0"
cpu = True
gpu = True
enginesDir = "/path/to/wanted/engines/dir"

enigneInfoExact = EngineInfo.defineDLEngine(framework, version, cpu, gpu, enginesDir)
```

In order to require a compatible engine, not the exact one:

```python
from io.bioimage.modelrunner.engine import EngineInfo

framework = "tensorflow"
version = "2.10.0"
cpu = True
gpu = True
enginesDir = "/path/to/wanted/engines/dir"

enigneInfoCompat = EngineInfo.defineCompatibleDLEngine(framework, version, cpu, gpu, enginesDir)
```

The developer acknowledges that the class `io.bioimage.modelrunner.engine.EngineInfo` can be difficult to understand. This is why the [wiki contains a detailed sections trying to explain it in an understandable manner with several examples](https://github.com/bioimage-io/JDLL/wiki/Load-and-run-models-I-(EngineInfo)).

Once the `EngineInfo` instance has been created, loading the model is easy. The only parameters needed now are the path to the `model folder` and the path to the `source file`.
The model folder is the folder that contains the `.pb` file in Tensorflow, the `.pt` file in Pytorch and the `.onnx` file in Onnx. The source file is not needed for Tensorflow, is the path to the `.pt` file in Pytorch and the path to the `.onnx` file in Onnx.

Then with the arguments `modelFolder`, `modelSource` and the previously created `enigneInfoExact` or `enigneInfoCompat` an instance of `io.bioimage.modelrunner.model.Model` can be created. Tha object then can be loaded and run inference.

```python
from io.bioimage.modelrunner.model import Model

# Path to the example model folder
modelFolder = "path/to/models/dir/B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet"
modelSource = None # Not needed in Tensorflow

model = Model.createDeepLearningModel(modelFolder, modelSource, enigneInfoCompat)
model.loadModel()

print("Great sucess!")
```

Output:
```
Great sucess!
```

JDLL tight integration with Bioimage.io models makes loading them easier. To load a Bioimage.io model it is not necessary to create the `EngineInfo` object.

For Bioimage.io models, loading is reduced to the next example:
```python
from io.bioimage.modelrunner.model import Model

# Path to the Bioimage.io model folder
modelFolder = "path/to/models/dir/B. Sutilist bacteria segmentation - Widefield microscopy - 2D UNet"
enginesDir = "/path/to/wanted/engines/dir"

bioimageioModel = Model.createBioimageioModel(modelFolder, enginesDir)
bioimageioModel.load()

print("Great sucess!")
```

Output:
```
Great sucess!
```

More information about loading models and models in general can be found in [this Wiki page](https://github.com/bioimage-io/JDLL/wiki/Load-and-run-models-II-(Model)).

In addition, a complete example showing how to load a Bioimage.io model can be found [here](https://github.com/bioimage-io/JDLL/blob/c037809a3695632487cc024bcefe93b529cc89fe/scripts/example-run-model-in-fiji.py#L87).

## 5. Running the model
Once the model has been loaded and the input and output tensors have been created. Running the model is simple. The input tensors should be added to a `List<?>` in the same order the model expects. Same for the ouptuts in another `List`.
```python
inputList = []
outputputList = []

inputList.append(inputTensor)
outputputList.append(outputEmptyTensor)
print("Ouptut tensor is empty: ",  outputEmptyTensor.isEmpty())

model.runModel(inputList, outputputList)
print("Ouptut tensor after inference is empty: ", outputEmptyTensor.isEmpty())
```
Output:
```
Ouptut tensor is empty: true
Ouptut tensor after inference is empty: false
```

## 6. Closing the model and the tensors
Models and tensors need to be closed to be released and free the memory that they were using
```python
model.closeModel()
inputTensor.close()
outputBlankTensor.close()
outputEmptyTensor.close()
```

# Acknowledgements.

This library was initially developed by the Icy team following the development of the DeepImageJ project.
We acknowledge the financial support of France-Bioimaging.
We also acknowledge the AI for Life consortium that supported a hackathon in Milan (February 2023) during which we received feedback and advices from an excellent community.

# References
* If you used one of the material provided within JDLL, please consider citing their authors' work.
* [C. García-López-de-Haro, S. Dallongeville, T. Musset, E. Gomez de Mariscal, D. Sage, W. Ouyang, A. Munoz-Barrutia, J. Tinevez, J. Olivo-Marin,
*JDLL: A library to run Deep Learning models on Java bioimage informatics platforms*, arXiv preprint arXiv:2306.04796 (2023).](https://arxiv.org/abs/2306.04796)

```bibtex
@article{de2023jdll,
  title={JDLL: A library to run Deep Learning models on Java bioimage informatics platforms},
  author={de Haro, Carlos Garcia Lopez and Dallongeville, Stephane and Musset, Thomas and de Mariscal, Estibaliz Gomez and Sage, Daniel and Ouyang, Wei and Munoz-Barrutia, Arrate and Tinevez, Jean-Yves and Olivo-Marin, Jean-Christophe},
  journal={arXiv preprint arXiv:2306.04796},
  year={2023}
}
```


[![CI status](https://img.shields.io/github/actions/workflow/status/apache/eventmesh/ci.yml?logo=github&style=for-the-badge)](https://github.com/apache/eventmesh/actions/workflows/ci.yml)
[![CodeCov](https://img.shields.io/codecov/c/gh/apache/eventmesh/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/apache/eventmesh)
[![Code Quality: Java](https://img.shields.io/lgtm/grade/java/g/apache/eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/eventmesh/context:java)
[![Total Alerts](https://img.shields.io/lgtm/alerts/g/apache/eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/eventmesh/alerts/)

[![License](https://img.shields.io/github/license/apache/eventmesh?style=for-the-badge)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![GitHub Release](https://img.shields.io/github/v/release/apache/eventmesh?style=for-the-badge)](https://github.com/apache/eventmesh/releases)
[![Slack Status](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack&style=for-the-badge)](https://join.slack.com/t/the-asf/shared_invite/zt-1y375qcox-UW1898e4kZE_pqrNsrBM2g)

[📦 Documentation](https://eventmesh.apache.org/docs/introduction) |
[📔 Examples](https://github.com/apache/eventmesh/tree/master/eventmesh-examples) |
[⚙ Roadmap](https://eventmesh.apache.org/docs/roadmap) |
[🌐 简体中文](README.zh-CN.md)

# Apache EventMesh

**Apache EventMesh** is a new generation serverless event middleware for building distributed [event-driven](https://en.wikipedia.org/wiki/Event-driven_architecture) applications.

### EventMesh Architecture

![EventMesh Architecture](resources/eventmesh-architecture-5.png)

### EventMesh K8S deployment

![EventMesh Operator](resources/eventmesh-operator.png)

## Features

Apache EventMesh has a vast amount of features to help users achieve their goals. Let us share with you some of the key features EventMesh has to offer:

- Built around the [CloudEvents](https://cloudevents.io) specification.
- Rapidty extendsible interconnector layer [connectors](https://github.com/apache/eventmesh/tree/master/eventmesh-connectors) using [openConnect](https://github.com/apache/eventmesh/tree/master/eventmesh-openconnect) such as the source or sink of Saas, CloudService, and Database etc.
- Rapidty extendsible storage layer such as [Apache RocketMQ](https://rocketmq.apache.org), [Apache Kafka](https://kafka.apache.org), [Apache Pulsar](https://pulsar.apache.org), [RabbitMQ](https://rabbitmq.com), [Redis](https://redis.io).
- Rapidty extendsible meta such as [Consul](https://consulproject.org/en/), [Nacos](https://nacos.io), [ETCD](https://etcd.io) and [Zookeeper](https://zookeeper.apache.org/).
- Guaranteed at-least-once delivery.
- Deliver events between multiple EventMesh deployments.
- Event schema management by catalog service.
- Powerful event orchestration by [Serverless workflow](https://serverlessworkflow.io/) engine.
- Powerful event filtering and transformation.
- Rapid, seamless scalability.
- Easy Function develop and framework integration.

## Roadmap

Please go to the [roadmap](https://eventmesh.apache.org/docs/roadmap) to get the release history and new features of Apache EventMesh.

## Subprojects

- [EventMesh-site](https://github.com/apache/eventmesh-site): Apache official website resources for EventMesh.
- [EventMesh-workflow](https://github.com/apache/eventmesh-workflow): Serverless workflow runtime for event Orchestration on EventMesh.
- [EventMesh-dashboard](https://github.com/apache/eventmesh-dashboard): Operation and maintenance console of EventMesh.
- [EventMesh-catalog](https://github.com/apache/eventmesh-catalog): Catalog service for event schema management using AsyncAPI.
- [EventMesh-go](https://github.com/apache/eventmesh-go): A go implementation for EventMesh runtime.

## Quick start

This section of the guide will show you the steps to deploy EventMesh from [Local](#run-eventmesh-runtime-locally), [Docker](#run-eventmesh-runtime-in-docker), [K8s](#run-eventmesh-runtime-in-kubernetes).

This section guides the launch of EventMesh according to the default configuration, if you need more detailed EventMesh deployment steps, please visit the [EventMesh official document](https://eventmesh.apache.org/docs/introduction).

### Deployment Event Store

> EventMesh supports [multiple Event Stores](https://eventmesh.apache.org/docs/roadmap#event-store-implementation-status), the default storage mode is `standalone`, and does not rely on other event stores as layers.

### Run EventMesh Runtime locally

#### 1. Download EventMesh

Download the latest version of the Binary Distribution from the [EventMesh Download](https://eventmesh.apache.org/download/) page and extract it:

```shell
wget https://dlcdn.apache.org/eventmesh/1.10.0/apache-eventmesh-1.10.0-bin.tar.gz
tar -xvzf apache-eventmesh-1.10.0-bin.tar.gz
cd apache-eventmesh-1.10.0
```

#### 2. Run EventMesh

Execute the `start.sh` script to start the EventMesh Runtime server.

```shell
bash bin/start.sh
```

View the output log:

```shell
tail -n 50 -f logs/eventmesh.out
```

When the log output shows server `state:RUNNING`, it means EventMesh Runtime has started successfully.

You can stop the run with the following command:

```shell
bash bin/stop.sh
```

When the script prints `shutdown server ok!`, it means EventMesh Runtime has stopped.

### Run EventMesh Runtime in Docker

#### 1. Pull EventMesh Image

Use the following command line to download the latest version of [EventMesh](https://hub.docker.com/r/apache/eventmesh):

```shell
sudo docker pull apache/eventmesh:latest
```

#### 2. Run and Manage EventMesh Container

Use the following command to start the EventMesh container:

```shell
sudo docker run -d --name eventmesh -p 10000:10000 -p 10105:10105 -p 10205:10205 -p 10106:10106 -t apache/eventmesh:latest
```

Enter the container:

```shell
sudo docker exec -it eventmesh /bin/bash
```

view the log:

```shell
cd logs
tail -n 50 -f eventmesh.out
```

### Run EventMesh Runtime in Kubernetes

#### 1. Deploy operator

Run the following commands(To delete a deployment, simply replace `deploy` with `undeploy`):

```shell
$ cd eventmesh-operator && make deploy
```

Run `kubectl get pods` 、`kubectl get crd | grep eventmesh-operator.eventmesh`to see the status of the deployed eventmesh-operator.

```shell
$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
eventmesh-operator-59c59f4f7b-nmmlm   1/1     Running   0          20s

$ kubectl get crd | grep eventmesh-operator.eventmesh
connectors.eventmesh-operator.eventmesh   2024-01-10T02:40:27Z
runtimes.eventmesh-operator.eventmesh     2024-01-10T02:40:27Z
```

#### 2. Deploy EventMesh Runtime

Execute the following command to deploy runtime, connector-rocketmq (To delete, simply replace `create` with `delete`):

```shell
$ make create
```

Run `kubectl get pods` to see if the deployment was successful.

```shell
NAME                                  READY   STATUS    RESTARTS   AGE
connector-rocketmq-0                  1/1     Running   0          9s
eventmesh-operator-59c59f4f7b-nmmlm   1/1     Running   0          3m12s
eventmesh-runtime-0-a-0               1/1     Running   0          15s
```

## Contributing

Each contributor has played an important role in promoting the robust development of Apache EventMesh. We sincerely appreciate all contributors who have contributed code and documents.

- [Contributing Guideline](https://eventmesh.apache.org/community/contribute/contribute)
- [Good First Issues](https://github.com/apache/eventmesh/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)

Here is the [List of Contributors](https://github.com/apache/eventmesh/graphs/contributors), thank you all! :)

## CNCF Landscape

Apache EventMesh enriches the CNCF Cloud Native Landscape.

## License

Apache EventMesh is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).

## Community

| WeChat Assistant                                        | WeChat Public Account                                  | Slack                                                                                |
|---------------------------------------------------------|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
|  |  | [Join Slack Chat](https://join.slack.com/t/the-asf/shared_invite/zt-1y375qcox-UW1898e4kZE_pqrNsrBM2g)(Please open an issue if this link is expired) |

Bi-weekly meeting : [#Tencent meeting](https://meeting.tencent.com/dm/wes6Erb9ioVV) : 346-6926-0133

Bi-weekly meeting record : [bilibili](https://space.bilibili.com/1057662180)

### Mailing List

| Name        | Description                                             | Subscribe                                                  | Unsubscribe                                                    | Archive                                                                          |
|-------------|---------------------------------------------------------|------------------------------------------------------------|----------------------------------------------------------------|----------------------------------------------------------------------------------|
| Users       | User discussion                                         | [Subscribe](mailto:users-subscribe@eventmesh.apache.org)   | [Unsubscribe](mailto:users-unsubscribe@eventmesh.apache.org)   | [Mail Archives](https://lists.apache.org/list.html?users@eventmesh.apache.org)   |
| Development | Development discussion (Design Documents, Issues, etc.) | [Subscribe](mailto:dev-subscribe@eventmesh.apache.org)     | [Unsubscribe](mailto:dev-unsubscribe@eventmesh.apache.org)     | [Mail Archives](https://lists.apache.org/list.html?dev@eventmesh.apache.org)     |
| Commits     | Commits to related repositories                         | [Subscribe](mailto:commits-subscribe@eventmesh.apache.org) | [Unsubscribe](mailto:commits-unsubscribe@eventmesh.apache.org) | [Mail Archives](https://lists.apache.org/list.html?commits@eventmesh.apache.org) |
| Issues      | Issues or PRs comments and reviews                      | [Subscribe](mailto:issues-subscribe@eventmesh.apache.org)  | [Unsubscribe](mailto:issues-unsubscribe@eventmesh.apache.org)  | [Mail Archives](https://lists.apache.org/list.html?issues@eventmesh.apache.org)  |


# Ballerina Code2cloud Extension

Code2cloud extension implementation for ballerina.

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Daily build](https://github.com/ballerina-platform/module-ballerina-c2c/workflows/Daily%20build/badge.svg)](https://github.com/ballerina-platform/module-ballerina-c2c/actions?query=workflow%3A%22Daily+build%22)
[![Build master branch](https://github.com/ballerina-platform/module-ballerina-c2c/actions/workflows/build-timestamped-master.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerina-c2c/actions/workflows/build-timestamped-master.yml)
[![codecov](https://codecov.io/gh/ballerina-platform/module-ballerina-c2c/branch/master/graph/badge.svg)](https://codecov.io/gh/ballerina-platform/module-ballerina-c2c)
## Features:
- Kubernetes deployment support.
- Kubernetes service support.
- Kubernetes liveness probe support
- Kubernetes readiness probe support
- Kubernetes horizontal pod autoscaler support.
- Docker image generation.
- Dockerfile generation.
- Kubernetes config map support.

**Refer [samples](examples) for more info.**

## How to build

1. Download and install JDK 17
1. Export github personal access token & user name as environment variables.
   ```bash
       export packagePAT=<Token>
       export packageUser=<username>
   ```
1. (optional) Specify the Java home path for JDK 17 ie;
    ```bash
        export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-17.jdk/Contents/Home/
    ```
1. Install Docker
1. Get a clone or download the source from this repository (https://github.com/ballerina-platform/module-ballerina-c2c)
1. Run the Gradle command ``gradle build`` from within the ``module-ballerina-c2c`` directory.
1. Copy ``c2c-extension/build/c2c-extension-***.jar`` file to ``<BALLERINA_HOME>/bre/lib`` directory.
1. Copy `c2c-ballerina/build/target/c2c-ballerina-zip/bala/ballerina/cloud` directory to `<BALLERINA_HOME>/repo/bala/ballerina` directory.
1. Copy `c2c-ballerina/build/target/c2c-ballerina-zip/cache/ballerina/cloud` directory to `<BALLERINA_HOME>/repo/cache/ballerina` directory.

### Enabling debug logs
- Use the "BAL_DOCKER_DEBUG=true" environment variable to enable docker related debug logs when building the ballerina
source(s).
- Use the "BAL_KUBERNETES_DEBUG=true" environment variable to enable kubernetes related debug logs when building the
ballerina source(s).

### Usage Sample:

```ballerina
import ballerina/http;
import ballerina/log;

listener http:Listener helloEP = new(9090);

service /helloWorld on helloEP {
    resource function get sayHello() returns string {
        return "Hello, World from service helloWorld ! ";
    }
}
```

Build the program with `--cloud=k8s` or `--cloud=docker` build option.

```bash
$ bal build --cloud=k8s <source_file>.bal
```

The Kubernetes and Docker artifacts will be created in following structure.
```bash
$> tree
├── docker
│   └── Dockerfile
|-kubernetes
    └── hello-world.yaml
```